Skip to content
Snippets Groups Projects
dos_fs.c 63.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • Alexandre Julliard's avatar
    Alexandre Julliard committed
    /*
     * DOS file system functions
     *
     * Copyright 1993 Erik Bos
     * Copyright 1996 Alexandre Julliard
     */
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #include "config.h"
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #include <sys/types.h>
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #include <ctype.h>
    #include <dirent.h>
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #include <errno.h>
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #include <sys/errno.h>
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #include <fcntl.h>
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #include <string.h>
    #include <stdlib.h>
    #include <sys/stat.h>
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #include <sys/ioctl.h>
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #include <time.h>
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #include <unistd.h>
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
    #include "winuser.h"
    #include "wine/winbase16.h"
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #include "winerror.h"
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #include "drive.h"
    #include "file.h"
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #include "heap.h"
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #include "msdos.h"
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #include "syslevel.h"
    
    #include "server.h"
    #include "process.h"
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
    DEFAULT_DEBUG_CHANNEL(dosfs)
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    /* Define the VFAT ioctl to get both short and long file names */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    /* FIXME: is it possible to get this to work on other systems? */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #ifdef linux
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    /* We want the real kernel dirent structure, not the libc one */
    typedef struct
    {
        long d_ino;
        long d_off;
        unsigned short d_reclen;
        char d_name[256];
    } KERNEL_DIRENT;
    
    
    #define VFAT_IOCTL_READDIR_BOTH  _IOR('r', 1, KERNEL_DIRENT [2] )
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #else   /* linux */
    #undef VFAT_IOCTL_READDIR_BOTH  /* just in case... */
    #endif  /* linux */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    /* Chars we don't want to see in DOS file names */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #define INVALID_DOS_CHARS  "*?<>|\"+=,;[] \345"
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    static const DOS_DEVICE DOSFS_Devices[] =
    /* name, device flags (see Int 21/AX=0x4400) */
    {
        { "CON",		0xc0d3 },
        { "PRN",		0xa0c0 },
        { "NUL",		0x80c4 },
        { "AUX",		0x80c0 },
        { "LPT1",		0xa0c0 },
        { "LPT2",		0xa0c0 },
        { "LPT3",		0xa0c0 },
        { "LPT4",		0xc0d3 },
        { "COM1",		0x80c0 },
        { "COM2",		0x80c0 },
        { "COM3",		0x80c0 },
        { "COM4",		0x80c0 },
        { "SCSIMGR$",	0xc0c0 },
        { "HPSCAN",		0xc0c0 }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    };
    
    #define GET_DRIVE(path) \
        (((path)[1] == ':') ? toupper((path)[0]) - 'A' : DOSFS_CurDrive)
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    /* Directory info for DOSFS_ReadDir */
    typedef struct
    {
        DIR           *dir;
    #ifdef VFAT_IOCTL_READDIR_BOTH
        int            fd;
        char           short_name[12];
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        KERNEL_DIRENT  dirent[2];
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #endif
    } DOS_DIR;
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    /* Info structure for FindFirstFile handle */
    typedef struct
    {
        LPSTR path;
        LPSTR long_mask;
        LPSTR short_mask;
        BYTE  attr;
        int   drive;
        int   cur_pos;
        DOS_DIR *dir;
    } FIND_FIRST_INFO;
    
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    /***********************************************************************
     *           DOSFS_ValidDOSName
     *
     * Return 1 if Unix file 'name' is also a valid MS-DOS name
     * (i.e. contains only valid DOS chars, lower-case only, fits in 8.3 format).
     * File name can be terminated by '\0', '\\' or '/'.
     */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    static int DOSFS_ValidDOSName( const char *name, int ignore_case )
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        static const char invalid_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" INVALID_DOS_CHARS;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        const char *p = name;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        const char *invalid = ignore_case ? (invalid_chars + 26) : invalid_chars;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        int len = 0;
    
        if (*p == '.')
        {
            /* Check for "." and ".." */
            p++;
            if (*p == '.') p++;
            /* All other names beginning with '.' are invalid */
            return (IS_END_OF_NAME(*p));
        }
        while (!IS_END_OF_NAME(*p))
        {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            if (strchr( invalid, *p )) return 0;  /* Invalid char */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            if (*p == '.') break;  /* Start of the extension */
            if (++len > 8) return 0;  /* Name too long */
            p++;
        }
        if (*p != '.') return 1;  /* End of name */
        p++;
        if (IS_END_OF_NAME(*p)) return 0;  /* Empty extension not allowed */
        len = 0;
        while (!IS_END_OF_NAME(*p))
        {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            if (strchr( invalid, *p )) return 0;  /* Invalid char */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            if (*p == '.') return 0;  /* Second extension not allowed */
            if (++len > 3) return 0;  /* Extension too long */
            p++;
        }
        return 1;
    }
    
    
    /***********************************************************************
     *           DOSFS_ToDosFCBFormat
     *
     * Convert a file name to DOS FCB format (8+3 chars, padded with blanks),
     * expanding wild cards and converting to upper-case in the process.
     * File name can be terminated by '\0', '\\' or '/'.
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     * Return FALSE if the name is not a valid DOS name.
     * 'buffer' must be at least 12 characters long.
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     */
    
    BOOL DOSFS_ToDosFCBFormat( LPCSTR name, LPSTR buffer )
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    {
        static const char invalid_chars[] = INVALID_DOS_CHARS;
        const char *p = name;
        int i;
    
        /* Check for "." and ".." */
        if (*p == '.')
        {
            p++;
            strcpy( buffer, ".          " );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            if (*p == '.')
            {
                buffer[1] = '.';
                p++;
            }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            return (!*p || (*p == '/') || (*p == '\\'));
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        }
    
        for (i = 0; i < 8; i++)
        {
            switch(*p)
            {
            case '\0':
            case '\\':
            case '/':
            case '.':
                buffer[i] = ' ';
                break;
            case '?':
                p++;
                /* fall through */
            case '*':
                buffer[i] = '?';
                break;
            default:
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                if (strchr( invalid_chars, *p )) return FALSE;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                buffer[i] = toupper(*p);
                p++;
                break;
            }
        }
    
        if (*p == '*')
        {
            /* Skip all chars after wildcard up to first dot */
            while (*p && (*p != '/') && (*p != '\\') && (*p != '.')) p++;
        }
        else
        {
            /* Check if name too long */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            if (*p && (*p != '/') && (*p != '\\') && (*p != '.')) return FALSE;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        }
        if (*p == '.') p++;  /* Skip dot */
    
        for (i = 8; i < 11; i++)
        {
            switch(*p)
            {
            case '\0':
            case '\\':
            case '/':
                buffer[i] = ' ';
                break;
            case '.':
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                return FALSE;  /* Second extension not allowed */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            case '?':
                p++;
                /* fall through */
            case '*':
                buffer[i] = '?';
                break;
            default:
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                if (strchr( invalid_chars, *p )) return FALSE;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                buffer[i] = toupper(*p);
                p++;
                break;
            }
        }
        buffer[11] = '\0';
    
    
        /* at most 3 character of the extension are processed
         * is something behind this ? 
         */
    
        while (*p == '*' || *p == ' ') p++; /* skip wildcards and spaces */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    }
    
    
    /***********************************************************************
     *           DOSFS_ToDosDTAFormat
     *
     * Convert a file name from FCB to DTA format (name.ext, null-terminated)
     * converting to upper-case in the process.
     * File name can be terminated by '\0', '\\' or '/'.
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     * 'buffer' must be at least 13 characters long.
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    static void DOSFS_ToDosDTAFormat( LPCSTR name, LPSTR buffer )
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    {
        char *p;
    
        memcpy( buffer, name, 8 );
        for (p = buffer + 8; (p > buffer) && (p[-1] == ' '); p--);
        *p++ = '.';
        memcpy( p, name + 8, 3 );
        for (p += 3; p[-1] == ' '; p--);
        if (p[-1] == '.') p--;
        *p = '\0';
    }
    
    
    /***********************************************************************
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     *           DOSFS_MatchShort
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     *
     * Check a DOS file name against a mask (both in FCB format).
     */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    static int DOSFS_MatchShort( const char *mask, const char *name )
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    {
        int i;
        for (i = 11; i > 0; i--, mask++, name++)
            if ((*mask != '?') && (*mask != *name)) return 0;
        return 1;
    }
    
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    /***********************************************************************
     *           DOSFS_MatchLong
     *
     * Check a long file name against a mask.
     */
    static int DOSFS_MatchLong( const char *mask, const char *name,
                                int case_sensitive )
    {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        if (!strcmp( mask, "*.*" )) return 1;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        while (*name && *mask)
        {
            if (*mask == '*')
            {
                mask++;
                while (*mask == '*') mask++;  /* Skip consecutive '*' */
                if (!*mask) return 1;
                if (case_sensitive) while (*name && (*name != *mask)) name++;
                else while (*name && (toupper(*name) != toupper(*mask))) name++;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            }
            else if (*mask != '?')
            {
                if (case_sensitive)
                {
                    if (*mask != *name) return 0;
                }
                else if (toupper(*mask) != toupper(*name)) return 0;
            }
            mask++;
            name++;
        }
    
        if (*mask == '.') mask++;  /* Ignore trailing '.' in mask */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        return (!*name && !*mask);
    }
    
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    /***********************************************************************
     *           DOSFS_OpenDir
     */
    static DOS_DIR *DOSFS_OpenDir( LPCSTR path )
    {
    
        DOS_DIR *dir = HeapAlloc( GetProcessHeap(), 0, sizeof(*dir) );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        if (!dir)
        {
    
            SetLastError( ERROR_NOT_ENOUGH_MEMORY );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            return NULL;
        }
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        /* Treat empty path as root directory. This simplifies path split into
           directory and mask in several other places */
        if (!*path) path = "/";
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    #ifdef VFAT_IOCTL_READDIR_BOTH
    
        /* Check if the VFAT ioctl is supported on this directory */
    
        if ((dir->fd = open( path, O_RDONLY )) != -1)
        {
            if (ioctl( dir->fd, VFAT_IOCTL_READDIR_BOTH, (long)dir->dirent ) == -1)
            {
                close( dir->fd );
                dir->fd = -1;
            }
            else
            {
                /* Set the file pointer back at the start of the directory */
                lseek( dir->fd, 0, SEEK_SET );
                dir->dir = NULL;
                return dir;
            }
        }
    #endif  /* VFAT_IOCTL_READDIR_BOTH */
    
        /* Now use the standard opendir/readdir interface */
    
        if (!(dir->dir = opendir( path )))
        {
    
            HeapFree( GetProcessHeap(), 0, dir );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            return NULL;
        }
        return dir;
    }
    
    
    /***********************************************************************
     *           DOSFS_CloseDir
     */
    static void DOSFS_CloseDir( DOS_DIR *dir )
    {
    #ifdef VFAT_IOCTL_READDIR_BOTH
        if (dir->fd != -1) close( dir->fd );
    #endif  /* VFAT_IOCTL_READDIR_BOTH */
        if (dir->dir) closedir( dir->dir );
    
        HeapFree( GetProcessHeap(), 0, dir );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    }
    
    
    /***********************************************************************
     *           DOSFS_ReadDir
     */
    
    static BOOL DOSFS_ReadDir( DOS_DIR *dir, LPCSTR *long_name,
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                                 LPCSTR *short_name )
    {
        struct dirent *dirent;
    
    #ifdef VFAT_IOCTL_READDIR_BOTH
        if (dir->fd != -1)
        {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            if (ioctl( dir->fd, VFAT_IOCTL_READDIR_BOTH, (long)dir->dirent ) != -1) {
    	    if (!dir->dirent[0].d_reclen) return FALSE;
    	    if (!DOSFS_ToDosFCBFormat( dir->dirent[0].d_name, dir->short_name ))
    		dir->short_name[0] = '\0';
    	    *short_name = dir->short_name;
    	    if (dir->dirent[1].d_name[0]) *long_name = dir->dirent[1].d_name;
    	    else *long_name = dir->dirent[0].d_name;
    	    return TRUE;
    	}
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        }
    #endif  /* VFAT_IOCTL_READDIR_BOTH */
    
        if (!(dirent = readdir( dir->dir ))) return FALSE;
        *long_name  = dirent->d_name;
        *short_name = NULL;
        return TRUE;
    }
    
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    /***********************************************************************
     *           DOSFS_Hash
     *
     * Transform a Unix file name into a hashed DOS name. If the name is a valid
     * DOS name, it is converted to upper-case; otherwise it is replaced by a
     * hashed version that fits in 8.3 format.
     * File name can be terminated by '\0', '\\' or '/'.
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     * 'buffer' must be at least 13 characters long.
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     */
    
    static void DOSFS_Hash( LPCSTR name, LPSTR buffer, BOOL dir_format,
                            BOOL ignore_case )
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    {
        static const char invalid_chars[] = INVALID_DOS_CHARS "~.";
        static const char hash_chars[32] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
    
        const char *p, *ext;
        char *dst;
        unsigned short hash;
        int i;
    
        if (dir_format) strcpy( buffer, "           " );
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        if (DOSFS_ValidDOSName( name, ignore_case ))
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        {
            /* Check for '.' and '..' */
            if (*name == '.')
            {
                buffer[0] = '.';
                if (!dir_format) buffer[1] = buffer[2] = '\0';
                if (name[1] == '.') buffer[1] = '.';
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                return;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            }
    
            /* Simply copy the name, converting to uppercase */
    
            for (dst = buffer; !IS_END_OF_NAME(*name) && (*name != '.'); name++)
                *dst++ = toupper(*name);
            if (*name == '.')
            {
                if (dir_format) dst = buffer + 8;
                else *dst++ = '.';
                for (name++; !IS_END_OF_NAME(*name); name++)
                    *dst++ = toupper(*name);
            }
            if (!dir_format) *dst = '\0';
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            return;
        }
    
        /* Compute the hash code of the file name */
        /* If you know something about hash functions, feel free to */
        /* insert a better algorithm here... */
        if (ignore_case)
        {
            for (p = name, hash = 0xbeef; !IS_END_OF_NAME(p[1]); p++)
                hash = (hash<<3) ^ (hash>>5) ^ tolower(*p) ^ (tolower(p[1]) << 8);
            hash = (hash<<3) ^ (hash>>5) ^ tolower(*p); /* Last character*/
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        }
        else
        {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            for (p = name, hash = 0xbeef; !IS_END_OF_NAME(p[1]); p++)
                hash = (hash << 3) ^ (hash >> 5) ^ *p ^ (p[1] << 8);
            hash = (hash << 3) ^ (hash >> 5) ^ *p;  /* Last character */
        }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        /* Find last dot for start of the extension */
        for (p = name+1, ext = NULL; !IS_END_OF_NAME(*p); p++)
            if (*p == '.') ext = p;
        if (ext && IS_END_OF_NAME(ext[1]))
            ext = NULL;  /* Empty extension ignored */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        /* Copy first 4 chars, replacing invalid chars with '_' */
        for (i = 4, p = name, dst = buffer; i > 0; i--, p++)
        {
            if (IS_END_OF_NAME(*p) || (p == ext)) break;
            *dst++ = strchr( invalid_chars, *p ) ? '_' : toupper(*p);
        }
        /* Pad to 5 chars with '~' */
        while (i-- >= 0) *dst++ = '~';
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        /* Insert hash code converted to 3 ASCII chars */
        *dst++ = hash_chars[(hash >> 10) & 0x1f];
        *dst++ = hash_chars[(hash >> 5) & 0x1f];
        *dst++ = hash_chars[hash & 0x1f];
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        /* Copy the first 3 chars of the extension (if any) */
        if (ext)
        {
            if (!dir_format) *dst++ = '.';
            for (i = 3, ext++; (i > 0) && !IS_END_OF_NAME(*ext); i--, ext++)
                *dst++ = strchr( invalid_chars, *ext ) ? '_' : toupper(*ext);
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        if (!dir_format) *dst = '\0';
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    }
    
    
    /***********************************************************************
     *           DOSFS_FindUnixName
     *
     * Find the Unix file name in a given directory that corresponds to
     * a file name (either in Unix or DOS format).
     * File name can be terminated by '\0', '\\' or '/'.
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     * Return TRUE if OK, FALSE if no file name matches.
     *
     * 'long_buf' must be at least 'long_len' characters long. If the long name
     * turns out to be larger than that, the function returns FALSE.
     * 'short_buf' must be at least 13 characters long.
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     */
    
    BOOL DOSFS_FindUnixName( LPCSTR path, LPCSTR name, LPSTR long_buf,
                               INT long_len, LPSTR short_buf, BOOL ignore_case)
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        DOS_DIR *dir;
        LPCSTR long_name, short_name;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        char dos_name[12], tmp_buf[13];
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
        const char *p = strchr( name, '/' );
        int len = p ? (int)(p - name) : strlen(name);
    
        if ((p = strchr( name, '\\' ))) len = min( (int)(p - name), len );
    
        /* Ignore trailing dots */
        while (len > 1 && name[len-1] == '.') len--;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        if (long_len < len + 1) return FALSE;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
        TRACE("%s,%s\n", path, name );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        if (!DOSFS_ToDosFCBFormat( name, dos_name )) dos_name[0] = '\0';
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
        if (!(dir = DOSFS_OpenDir( path )))
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        {
    
            WARN("(%s,%s): can't open dir: %s\n",
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                           path, name, strerror(errno) );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            return FALSE;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
        while ((ret = DOSFS_ReadDir( dir, &long_name, &short_name )))
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        {
            /* Check against Unix name */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            if (len == strlen(long_name))
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                if (!ignore_case)
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                {
    
                    if (!strncmp( long_name, name, len )) break;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                }
                else
                {
    
                    if (!lstrncmpiA( long_name, name, len )) break;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            if (dos_name[0])
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            {
                /* Check against hashed DOS name */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                if (!short_name)
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                {
                    DOSFS_Hash( long_name, tmp_buf, TRUE, ignore_case );
                    short_name = tmp_buf;
                }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                if (!strcmp( dos_name, short_name )) break;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            }
        }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        if (ret)
        {
            if (long_buf) strcpy( long_buf, long_name );
            if (short_buf)
            {
                if (short_name)
                    DOSFS_ToDosDTAFormat( short_name, short_buf );
                else
                    DOSFS_Hash( long_name, short_buf, FALSE, ignore_case );
            }
    
            TRACE("(%s,%s) -> %s (%s)\n",
                  path, name, long_name, short_buf ? short_buf : "***");
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        }
        else
    
            WARN("'%s' not found in '%s'\n", name, path);
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        DOSFS_CloseDir( dir );
        return ret;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    }
    
    
    /***********************************************************************
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     *           DOSFS_GetDevice
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     *
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     * Check if a DOS file name represents a DOS device and return the device.
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    const DOS_DEVICE *DOSFS_GetDevice( const char *name )
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    {
        int	i;
        const char *p;
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        if (!name) return NULL; /* if FILE_DupUnixHandle was used */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        if (name[0] && (name[1] == ':')) name += 2;
        if ((p = strrchr( name, '/' ))) name = p + 1;
        if ((p = strrchr( name, '\\' ))) name = p + 1;
        for (i = 0; i < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]); i++)
        {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            const char *dev = DOSFS_Devices[i].name;
    
            if (!lstrncmpiA( dev, name, strlen(dev) ))
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            {
                p = name + strlen( dev );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                if (!*p || (*p == '.')) return &DOSFS_Devices[i];
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        return NULL;
    
    
    /***********************************************************************
     *           DOSFS_GetDeviceByHandle
     */
    
    const DOS_DEVICE *DOSFS_GetDeviceByHandle( HFILE hFile )
    
        struct get_file_info_request *req = get_req_buffer();
    
        req->handle = hFile;
        if (!server_call( REQ_GET_FILE_INFO ) && (req->type == FILE_TYPE_UNKNOWN))
    
            if ((req->attr >= 0) &&
                (req->attr < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0])))
                return &DOSFS_Devices[req->attr];
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    /***********************************************************************
     *           DOSFS_OpenDevice
     *
     * Open a DOS device. This might not map 1:1 into the UNIX device concept.
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     */
    
    HFILE DOSFS_OpenDevice( const char *name, DWORD access )
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    {
        int i;
        const char *p;
    
    
        if (!name) return (HFILE)NULL; /* if FILE_DupUnixHandle was used */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        if (name[0] && (name[1] == ':')) name += 2;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        if ((p = strrchr( name, '/' ))) name = p + 1;
        if ((p = strrchr( name, '\\' ))) name = p + 1;
        for (i = 0; i < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]); i++)
        {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            const char *dev = DOSFS_Devices[i].name;
    
            if (!lstrncmpiA( dev, name, strlen(dev) ))
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            {
                p = name + strlen( dev );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                if (!*p || (*p == '.')) {
    	    	/* got it */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    		if (!strcmp(DOSFS_Devices[i].name,"NUL"))
    
                        return FILE_CreateFile( "/dev/null", access,
                                                FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
    
                                                OPEN_EXISTING, 0, -1, TRUE );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    		if (!strcmp(DOSFS_Devices[i].name,"CON")) {
    
    			switch (access & (GENERIC_READ|GENERIC_WRITE)) {
    			case GENERIC_READ:
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    				to_dup = GetStdHandle( STD_INPUT_HANDLE );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    				break;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    				to_dup = GetStdHandle( STD_OUTPUT_HANDLE );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    				break;
    			default:
    
    				FIXME("can't open CON read/write\n");
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    				break;
    			}
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    			if (!DuplicateHandle( GetCurrentProcess(), to_dup, GetCurrentProcess(),
    					      &handle, 0, FALSE, DUPLICATE_SAME_ACCESS ))
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    			return handle;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    		}
    
    		if (!strcmp(DOSFS_Devices[i].name,"SCSIMGR$") ||
                        !strcmp(DOSFS_Devices[i].name,"HPSCAN"))
                    {
    
                        return FILE_CreateDevice( i, access, NULL );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    		}
    
    		{
    		    HFILE r;
    		    char devname[40];
    		    PROFILE_GetWineIniString("serialports",name,"",devname,sizeof devname);
    
    		    if(devname[0])
    		    {
    
    			TRACE_(file)("DOSFS_OpenDevice %s is %s\n",
    
                                         DOSFS_Devices[i].name,devname);
    
    			r =  FILE_CreateFile( devname, access,
    				FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
    
    				OPEN_EXISTING, 0, -1, TRUE );
    
    			TRACE_(file)("Create_File return %08X\n",r);
    
    		FIXME("device open %s not supported (yet)\n",DOSFS_Devices[i].name);
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    	    }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            }
        }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    /***********************************************************************
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     *           DOSFS_GetPathDrive
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     *
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     * Get the drive specified by a given path name (DOS or Unix format).
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    static int DOSFS_GetPathDrive( const char **name )
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        int drive;
        const char *p = *name;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        if (*p && (p[1] == ':'))
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            drive = toupper(*p) - 'A';
            *name += 2;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        else if (*p == '/') /* Absolute Unix path? */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            if ((drive = DRIVE_FindDriveRoot( name )) == -1)
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            {
    
                MESSAGE("Warning: %s not accessible from a DOS drive\n", *name );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                /* Assume it really was a DOS name */
                drive = DRIVE_GetCurrentDrive();            
            }
        }
        else drive = DRIVE_GetCurrentDrive();
    
        if (!DRIVE_IsValid(drive))
        {
    
            SetLastError( ERROR_INVALID_DRIVE );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            return -1;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        return drive;
    }
    
    
    /***********************************************************************
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     *           DOSFS_GetFullName
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     *
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     * Convert a file name (DOS or mixed DOS/Unix format) to a valid
     * Unix name / short DOS name pair.
     * Return FALSE if one of the path components does not exist. The last path
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     * component is only checked if 'check_last' is non-zero.
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     * The buffers pointed to by 'long_buf' and 'short_buf' must be
     * at least MAX_PATHNAME_LEN long.
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     */
    
    BOOL DOSFS_GetFullName( LPCSTR name, BOOL check_last, DOS_FULL_NAME *full )
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        char *p_l, *p_s, *root;
    
    
        TRACE("%s (last=%d)\n", name, check_last );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
        if ((full->drive = DOSFS_GetPathDrive( &name )) == -1) return FALSE;
        flags = DRIVE_GetFlags( full->drive );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
        lstrcpynA( full->long_name, DRIVE_GetRoot( full->drive ),
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                     sizeof(full->long_name) );
        if (full->long_name[1]) root = full->long_name + strlen(full->long_name);
        else root = full->long_name;  /* root directory */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        strcpy( full->short_name, "A:\\" );
        full->short_name[0] += full->drive;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        if ((*name == '\\') || (*name == '/'))  /* Absolute path */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        {
            while ((*name == '\\') || (*name == '/')) name++;
        }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        else  /* Relative path */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        {
    
            lstrcpynA( root + 1, DRIVE_GetUnixCwd( full->drive ),
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                         sizeof(full->long_name) - (root - full->long_name) - 1 );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            if (root[1]) *root = '/';
    
            lstrcpynA( full->short_name + 3, DRIVE_GetDosCwd( full->drive ),
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                         sizeof(full->short_name) - 3 );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        p_l = full->long_name[1] ? full->long_name + strlen(full->long_name)
                                 : full->long_name;
        p_s = full->short_name[3] ? full->short_name + strlen(full->short_name)
                                  : full->short_name + 2;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        found = TRUE;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        while (*name && found)
        {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            /* Check for '.' and '..' */
    
            if (*name == '.')
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                if (IS_END_OF_NAME(name[1]))
                {
                    name++;
                    while ((*name == '\\') || (*name == '/')) name++;
                    continue;
                }
                else if ((name[1] == '.') && IS_END_OF_NAME(name[2]))
                {
                    name += 2;
                    while ((*name == '\\') || (*name == '/')) name++;
                    while ((p_l > root) && (*p_l != '/')) p_l--;
                    while ((p_s > full->short_name + 2) && (*p_s != '\\')) p_s--;
                    *p_l = *p_s = '\0';  /* Remove trailing separator */
                    continue;
                }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
            /* Make sure buffers are large enough */
    
            if ((p_s >= full->short_name + sizeof(full->short_name) - 14) ||
                (p_l >= full->long_name + sizeof(full->long_name) - 1))
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            {
    
                SetLastError( ERROR_PATH_NOT_FOUND );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                return FALSE;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
            /* Get the long and short name matching the file name */
    
            if ((found = DOSFS_FindUnixName( full->long_name, name, p_l + 1,
                             sizeof(full->long_name) - (p_l - full->long_name) - 1,
                             p_s + 1, !(flags & DRIVE_CASE_SENSITIVE) )))
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                *p_l++ = '/';
                p_l   += strlen(p_l);
                *p_s++ = '\\';
                p_s   += strlen(p_s);
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                while (!IS_END_OF_NAME(*name)) name++;
            }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            else if (!check_last)
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                *p_l++ = '/';
                *p_s++ = '\\';
                while (!IS_END_OF_NAME(*name) &&
                       (p_s < full->short_name + sizeof(full->short_name) - 1) &&
                       (p_l < full->long_name + sizeof(full->long_name) - 1))
                {
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                    *p_s++ = tolower(*name);
                    /* If the drive is case-sensitive we want to create new */
                    /* files in lower-case otherwise we can't reopen them   */
                    /* under the same short name. */
    	    	if (flags & DRIVE_CASE_SENSITIVE) *p_l++ = tolower(*name);
    		else *p_l++ = *name;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                    name++;
                }
                *p_l = *p_s = '\0';
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            }
            while ((*name == '\\') || (*name == '/')) name++;
        }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        if (!found)
        {
    
            if (check_last)
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            {
    
                SetLastError( ERROR_FILE_NOT_FOUND );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                return FALSE;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            }
    
            if (*name)  /* Not last */
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            {
    
                SetLastError( ERROR_PATH_NOT_FOUND );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                return FALSE;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
            }
        }
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        if (!full->long_name[0]) strcpy( full->long_name, "/" );
        if (!full->short_name[2]) strcpy( full->short_name + 2, "\\" );
    
        TRACE("returning %s = %s\n", full->long_name, full->short_name );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        return TRUE;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    }
    
    
    /***********************************************************************
    
     *           GetShortPathNameA   (KERNEL32.271)
    
     *
     * NOTES
     *  observed:
     *  longpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0
     *  *longpath="" or invalid: LastError=ERROR_BAD_PATHNAME, ret=0
    
     * 
     * more observations ( with NT 3.51 (WinDD) ):
     * longpath <= 8.3 -> just copy longpath to shortpath
     * longpath > 8.3  -> 
     *             a) file does not exist -> return 0, LastError = ERROR_FILE_NOT_FOUND
     *             b) file does exist     -> set the short filename.
     * - trailing slashes are reproduced in the short name, even if the
     *   file is not a directory
    
    Peter Ganten's avatar
    Peter Ganten committed
     * - the absolute/relative path of the short name is reproduced like found
     *   in the long name
    
     * - longpath and shortpath may have the same adress
     * Peter Ganten, 1999
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     */
    
    DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath,
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                                      DWORD shortlen )
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    {
        DOS_FULL_NAME full_name;
    
        LPSTR tmpshortpath;
    
    Peter Ganten's avatar
    Peter Ganten committed
        DWORD sp = 0, lp = 0;
        int tmplen, drive;
        UINT flags;
    
    
        TRACE("%s\n", debugstr_a(longpath));
    
    
        if (!longpath) {
          SetLastError(ERROR_INVALID_PARAMETER);
          return 0;
        }
        if (!longpath[0]) {
          SetLastError(ERROR_BAD_PATHNAME);
          return 0;
    
    Peter Ganten's avatar
    Peter Ganten committed
        if ( ( tmpshortpath = HeapAlloc ( GetProcessHeap(), 0, MAX_PATHNAME_LEN ) ) == NULL ) {
    
          SetLastError ( ERROR_NOT_ENOUGH_MEMORY );
          return 0;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
    Peter Ganten's avatar
    Peter Ganten committed
        /* check for drive letter */
    
        if ( longpath[1] == ':' ) {
    
    Peter Ganten's avatar
    Peter Ganten committed
          tmpshortpath[0] = longpath[0];
          tmpshortpath[1] = ':';
          sp = 2;
        }
    
    Peter Ganten's avatar
    Peter Ganten committed
        if ( ( drive = DOSFS_GetPathDrive ( &longpath )) == -1 ) return 0;
        flags = DRIVE_GetFlags ( drive );
    
    Peter Ganten's avatar
    Peter Ganten committed
        while ( longpath[lp] ) {
    
          /* check for path delimiters and reproduce them */
          if ( longpath[lp] == '\\' || longpath[lp] == '/' ) {
    
    	if (!sp || tmpshortpath[sp-1]!= '\\') 
            {
    	    /* strip double "\\" */
    	    tmpshortpath[sp] = '\\';
    	    sp++;
            }
    
            tmpshortpath[sp]=0;/*terminate string*/
    
    Peter Ganten's avatar
    Peter Ganten committed
    	lp++;
    
    Peter Ganten's avatar
    Peter Ganten committed
          tmplen = strcspn ( longpath + lp, "\\/" ); 
          lstrcpynA ( tmpshortpath+sp, longpath + lp, tmplen+1 );
          
          /* Check, if the current element is a valid dos name */
          if ( DOSFS_ValidDOSName ( longpath + lp, !(flags & DRIVE_CASE_SENSITIVE) ) ) {
    	sp += tmplen;
    	lp += tmplen;
    	continue;
    
    Peter Ganten's avatar
    Peter Ganten committed
    
          /* Check if the file exists and use the existing file name */
          if ( DOSFS_GetFullName ( tmpshortpath, TRUE, &full_name ) ) {
    	lstrcpyA ( tmpshortpath+sp, strrchr ( full_name.short_name, '\\' ) + 1 );
    	sp += lstrlenA ( tmpshortpath+sp );
    	lp += tmplen;
    	continue;
          }
    
          TRACE("not found!\n" );
          SetLastError ( ERROR_FILE_NOT_FOUND );
          return 0;
    
        lstrcpynA ( shortpath, tmpshortpath, shortlen );
    
        TRACE("returning %s\n", debugstr_a(shortpath) );
    
    Peter Ganten's avatar
    Peter Ganten committed
        tmplen = lstrlenA ( tmpshortpath );
    
        HeapFree ( GetProcessHeap(), 0, tmpshortpath );
        
    
    Peter Ganten's avatar
    Peter Ganten committed
        return tmplen;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    }
    
    
    /***********************************************************************
    
     *           GetShortPathNameW   (KERNEL32.272)
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
     */
    
    DWORD WINAPI GetShortPathNameW( LPCWSTR longpath, LPWSTR shortpath,
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
                                      DWORD shortlen )
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    {
    
        LPSTR longpathA, shortpathA;
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
        DWORD ret = 0;
    
    
        longpathA = HEAP_strdupWtoA( GetProcessHeap(), 0, longpath );
    
        shortpathA = HeapAlloc ( GetProcessHeap(), 0, shortlen );
    
    Alexandre Julliard's avatar
    Alexandre Julliard committed
    
    
        ret = GetShortPathNameA ( longpathA, shortpathA, shortlen );
        lstrcpynAtoW ( shortpath, shortpathA, shortlen );