Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1 | /* |
| 2 | * DOS file system functions |
| 3 | * |
| 4 | * Copyright 1993 Erik Bos |
| 5 | * Copyright 1996 Alexandre Julliard |
| 6 | */ |
| 7 | |
Alexandre Julliard | c7c217b | 1998-04-13 12:21:30 +0000 | [diff] [blame] | 8 | #include "config.h" |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 9 | #include <sys/types.h> |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 10 | #include <ctype.h> |
| 11 | #include <dirent.h> |
Alexandre Julliard | 44ed71f | 1997-12-21 19:17:50 +0000 | [diff] [blame] | 12 | #include <errno.h> |
Howard Abrams | 1327748 | 1999-07-10 13:16:29 +0000 | [diff] [blame] | 13 | #ifdef HAVE_SYS_ERRNO_H |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 14 | #include <sys/errno.h> |
Howard Abrams | 1327748 | 1999-07-10 13:16:29 +0000 | [diff] [blame] | 15 | #endif |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 16 | #include <fcntl.h> |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 17 | #include <string.h> |
| 18 | #include <stdlib.h> |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 19 | #include <sys/stat.h> |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 20 | #include <sys/ioctl.h> |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 21 | #include <time.h> |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 22 | #include <unistd.h> |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 23 | |
Marcus Meissner | 317af32 | 1999-02-17 13:51:06 +0000 | [diff] [blame] | 24 | #include "windef.h" |
| 25 | #include "winuser.h" |
| 26 | #include "wine/winbase16.h" |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 27 | #include "winerror.h" |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 28 | #include "drive.h" |
| 29 | #include "file.h" |
Alexandre Julliard | 7ebe1a4 | 1996-12-22 18:27:48 +0000 | [diff] [blame] | 30 | #include "heap.h" |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 31 | #include "msdos.h" |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 32 | #include "syslevel.h" |
Alexandre Julliard | 62a8b43 | 1999-01-19 17:48:23 +0000 | [diff] [blame] | 33 | #include "server.h" |
| 34 | #include "process.h" |
Marcus Meissner | 6b9dd2e | 1999-03-18 17:39:57 +0000 | [diff] [blame] | 35 | #include "options.h" |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 36 | #include "debugtools.h" |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 37 | |
Patrik Stridvall | b4b9fae | 1999-04-19 14:56:29 +0000 | [diff] [blame] | 38 | DECLARE_DEBUG_CHANNEL(dosfs) |
| 39 | DECLARE_DEBUG_CHANNEL(file) |
| 40 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 41 | /* Define the VFAT ioctl to get both short and long file names */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 42 | /* FIXME: is it possible to get this to work on other systems? */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 43 | #ifdef linux |
Alexandre Julliard | df2673b | 1997-03-29 17:20:20 +0000 | [diff] [blame] | 44 | /* We want the real kernel dirent structure, not the libc one */ |
| 45 | typedef struct |
| 46 | { |
| 47 | long d_ino; |
| 48 | long d_off; |
| 49 | unsigned short d_reclen; |
| 50 | char d_name[256]; |
| 51 | } KERNEL_DIRENT; |
| 52 | |
Peter Ganten | 0bac5e9 | 1999-09-27 11:46:27 +0000 | [diff] [blame] | 53 | #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, KERNEL_DIRENT [2] ) |
| 54 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 55 | #else /* linux */ |
| 56 | #undef VFAT_IOCTL_READDIR_BOTH /* just in case... */ |
| 57 | #endif /* linux */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 58 | |
| 59 | /* Chars we don't want to see in DOS file names */ |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 60 | #define INVALID_DOS_CHARS "*?<>|\"+=,;[] \345" |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 61 | |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 62 | static const DOS_DEVICE DOSFS_Devices[] = |
| 63 | /* name, device flags (see Int 21/AX=0x4400) */ |
| 64 | { |
| 65 | { "CON", 0xc0d3 }, |
| 66 | { "PRN", 0xa0c0 }, |
| 67 | { "NUL", 0x80c4 }, |
| 68 | { "AUX", 0x80c0 }, |
| 69 | { "LPT1", 0xa0c0 }, |
| 70 | { "LPT2", 0xa0c0 }, |
| 71 | { "LPT3", 0xa0c0 }, |
| 72 | { "LPT4", 0xc0d3 }, |
| 73 | { "COM1", 0x80c0 }, |
| 74 | { "COM2", 0x80c0 }, |
| 75 | { "COM3", 0x80c0 }, |
| 76 | { "COM4", 0x80c0 }, |
| 77 | { "SCSIMGR$", 0xc0c0 }, |
| 78 | { "HPSCAN", 0xc0c0 } |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 79 | }; |
| 80 | |
| 81 | #define GET_DRIVE(path) \ |
| 82 | (((path)[1] == ':') ? toupper((path)[0]) - 'A' : DOSFS_CurDrive) |
| 83 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 84 | /* Directory info for DOSFS_ReadDir */ |
| 85 | typedef struct |
| 86 | { |
| 87 | DIR *dir; |
| 88 | #ifdef VFAT_IOCTL_READDIR_BOTH |
| 89 | int fd; |
| 90 | char short_name[12]; |
Alexandre Julliard | df2673b | 1997-03-29 17:20:20 +0000 | [diff] [blame] | 91 | KERNEL_DIRENT dirent[2]; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 92 | #endif |
| 93 | } DOS_DIR; |
| 94 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 95 | /* Info structure for FindFirstFile handle */ |
| 96 | typedef struct |
| 97 | { |
| 98 | LPSTR path; |
| 99 | LPSTR long_mask; |
| 100 | LPSTR short_mask; |
| 101 | BYTE attr; |
| 102 | int drive; |
| 103 | int cur_pos; |
| 104 | DOS_DIR *dir; |
| 105 | } FIND_FIRST_INFO; |
| 106 | |
| 107 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 108 | |
| 109 | /*********************************************************************** |
| 110 | * DOSFS_ValidDOSName |
| 111 | * |
| 112 | * Return 1 if Unix file 'name' is also a valid MS-DOS name |
| 113 | * (i.e. contains only valid DOS chars, lower-case only, fits in 8.3 format). |
| 114 | * File name can be terminated by '\0', '\\' or '/'. |
| 115 | */ |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 116 | static int DOSFS_ValidDOSName( const char *name, int ignore_case ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 117 | { |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 118 | static const char invalid_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" INVALID_DOS_CHARS; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 119 | const char *p = name; |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 120 | const char *invalid = ignore_case ? (invalid_chars + 26) : invalid_chars; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 121 | int len = 0; |
| 122 | |
| 123 | if (*p == '.') |
| 124 | { |
| 125 | /* Check for "." and ".." */ |
| 126 | p++; |
| 127 | if (*p == '.') p++; |
| 128 | /* All other names beginning with '.' are invalid */ |
| 129 | return (IS_END_OF_NAME(*p)); |
| 130 | } |
| 131 | while (!IS_END_OF_NAME(*p)) |
| 132 | { |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 133 | if (strchr( invalid, *p )) return 0; /* Invalid char */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 134 | if (*p == '.') break; /* Start of the extension */ |
| 135 | if (++len > 8) return 0; /* Name too long */ |
| 136 | p++; |
| 137 | } |
| 138 | if (*p != '.') return 1; /* End of name */ |
| 139 | p++; |
| 140 | if (IS_END_OF_NAME(*p)) return 0; /* Empty extension not allowed */ |
| 141 | len = 0; |
| 142 | while (!IS_END_OF_NAME(*p)) |
| 143 | { |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 144 | if (strchr( invalid, *p )) return 0; /* Invalid char */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 145 | if (*p == '.') return 0; /* Second extension not allowed */ |
| 146 | if (++len > 3) return 0; /* Extension too long */ |
| 147 | p++; |
| 148 | } |
| 149 | return 1; |
| 150 | } |
| 151 | |
| 152 | |
| 153 | /*********************************************************************** |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 154 | * DOSFS_ToDosFCBFormat |
| 155 | * |
| 156 | * Convert a file name to DOS FCB format (8+3 chars, padded with blanks), |
| 157 | * expanding wild cards and converting to upper-case in the process. |
| 158 | * File name can be terminated by '\0', '\\' or '/'. |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 159 | * Return FALSE if the name is not a valid DOS name. |
| 160 | * 'buffer' must be at least 12 characters long. |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 161 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 162 | BOOL DOSFS_ToDosFCBFormat( LPCSTR name, LPSTR buffer ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 163 | { |
| 164 | static const char invalid_chars[] = INVALID_DOS_CHARS; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 165 | const char *p = name; |
| 166 | int i; |
| 167 | |
| 168 | /* Check for "." and ".." */ |
| 169 | if (*p == '.') |
| 170 | { |
| 171 | p++; |
| 172 | strcpy( buffer, ". " ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 173 | if (*p == '.') |
| 174 | { |
| 175 | buffer[1] = '.'; |
| 176 | p++; |
| 177 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 178 | return (!*p || (*p == '/') || (*p == '\\')); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 179 | } |
| 180 | |
| 181 | for (i = 0; i < 8; i++) |
| 182 | { |
| 183 | switch(*p) |
| 184 | { |
| 185 | case '\0': |
| 186 | case '\\': |
| 187 | case '/': |
| 188 | case '.': |
| 189 | buffer[i] = ' '; |
| 190 | break; |
| 191 | case '?': |
| 192 | p++; |
| 193 | /* fall through */ |
| 194 | case '*': |
| 195 | buffer[i] = '?'; |
| 196 | break; |
| 197 | default: |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 198 | if (strchr( invalid_chars, *p )) return FALSE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 199 | buffer[i] = toupper(*p); |
| 200 | p++; |
| 201 | break; |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | if (*p == '*') |
| 206 | { |
| 207 | /* Skip all chars after wildcard up to first dot */ |
| 208 | while (*p && (*p != '/') && (*p != '\\') && (*p != '.')) p++; |
| 209 | } |
| 210 | else |
| 211 | { |
| 212 | /* Check if name too long */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 213 | if (*p && (*p != '/') && (*p != '\\') && (*p != '.')) return FALSE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 214 | } |
| 215 | if (*p == '.') p++; /* Skip dot */ |
| 216 | |
| 217 | for (i = 8; i < 11; i++) |
| 218 | { |
| 219 | switch(*p) |
| 220 | { |
| 221 | case '\0': |
| 222 | case '\\': |
| 223 | case '/': |
| 224 | buffer[i] = ' '; |
| 225 | break; |
| 226 | case '.': |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 227 | return FALSE; /* Second extension not allowed */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 228 | case '?': |
| 229 | p++; |
| 230 | /* fall through */ |
| 231 | case '*': |
| 232 | buffer[i] = '?'; |
| 233 | break; |
| 234 | default: |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 235 | if (strchr( invalid_chars, *p )) return FALSE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 236 | buffer[i] = toupper(*p); |
| 237 | p++; |
| 238 | break; |
| 239 | } |
| 240 | } |
| 241 | buffer[11] = '\0'; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 242 | return TRUE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 243 | } |
| 244 | |
| 245 | |
| 246 | /*********************************************************************** |
| 247 | * DOSFS_ToDosDTAFormat |
| 248 | * |
| 249 | * Convert a file name from FCB to DTA format (name.ext, null-terminated) |
| 250 | * converting to upper-case in the process. |
| 251 | * File name can be terminated by '\0', '\\' or '/'. |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 252 | * 'buffer' must be at least 13 characters long. |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 253 | */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 254 | static void DOSFS_ToDosDTAFormat( LPCSTR name, LPSTR buffer ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 255 | { |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 256 | char *p; |
| 257 | |
| 258 | memcpy( buffer, name, 8 ); |
| 259 | for (p = buffer + 8; (p > buffer) && (p[-1] == ' '); p--); |
| 260 | *p++ = '.'; |
| 261 | memcpy( p, name + 8, 3 ); |
| 262 | for (p += 3; p[-1] == ' '; p--); |
| 263 | if (p[-1] == '.') p--; |
| 264 | *p = '\0'; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 265 | } |
| 266 | |
| 267 | |
| 268 | /*********************************************************************** |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 269 | * DOSFS_MatchShort |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 270 | * |
| 271 | * Check a DOS file name against a mask (both in FCB format). |
| 272 | */ |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 273 | static int DOSFS_MatchShort( const char *mask, const char *name ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 274 | { |
| 275 | int i; |
| 276 | for (i = 11; i > 0; i--, mask++, name++) |
| 277 | if ((*mask != '?') && (*mask != *name)) return 0; |
| 278 | return 1; |
| 279 | } |
| 280 | |
| 281 | |
| 282 | /*********************************************************************** |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 283 | * DOSFS_MatchLong |
| 284 | * |
| 285 | * Check a long file name against a mask. |
| 286 | */ |
| 287 | static int DOSFS_MatchLong( const char *mask, const char *name, |
| 288 | int case_sensitive ) |
| 289 | { |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 290 | if (!strcmp( mask, "*.*" )) return 1; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 291 | while (*name && *mask) |
| 292 | { |
| 293 | if (*mask == '*') |
| 294 | { |
| 295 | mask++; |
| 296 | while (*mask == '*') mask++; /* Skip consecutive '*' */ |
| 297 | if (!*mask) return 1; |
| 298 | if (case_sensitive) while (*name && (*name != *mask)) name++; |
| 299 | else while (*name && (toupper(*name) != toupper(*mask))) name++; |
Robert W Hall | 9132a78 | 1999-04-18 14:38:17 +0000 | [diff] [blame] | 300 | if (!*name) break; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 301 | } |
| 302 | else if (*mask != '?') |
| 303 | { |
| 304 | if (case_sensitive) |
| 305 | { |
| 306 | if (*mask != *name) return 0; |
| 307 | } |
| 308 | else if (toupper(*mask) != toupper(*name)) return 0; |
| 309 | } |
| 310 | mask++; |
| 311 | name++; |
| 312 | } |
Robert W Hall | 9132a78 | 1999-04-18 14:38:17 +0000 | [diff] [blame] | 313 | if (*mask == '.') mask++; /* Ignore trailing '.' in mask */ |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 314 | return (!*name && !*mask); |
| 315 | } |
| 316 | |
| 317 | |
| 318 | /*********************************************************************** |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 319 | * DOSFS_OpenDir |
| 320 | */ |
| 321 | static DOS_DIR *DOSFS_OpenDir( LPCSTR path ) |
| 322 | { |
| 323 | DOS_DIR *dir = HeapAlloc( SystemHeap, 0, sizeof(*dir) ); |
| 324 | if (!dir) |
| 325 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 326 | SetLastError( ERROR_NOT_ENOUGH_MEMORY ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 327 | return NULL; |
| 328 | } |
| 329 | |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 330 | /* Treat empty path as root directory. This simplifies path split into |
| 331 | directory and mask in several other places */ |
| 332 | if (!*path) path = "/"; |
| 333 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 334 | #ifdef VFAT_IOCTL_READDIR_BOTH |
| 335 | |
| 336 | /* Check if the VFAT ioctl is supported on this directory */ |
| 337 | |
| 338 | if ((dir->fd = open( path, O_RDONLY )) != -1) |
| 339 | { |
| 340 | if (ioctl( dir->fd, VFAT_IOCTL_READDIR_BOTH, (long)dir->dirent ) == -1) |
| 341 | { |
| 342 | close( dir->fd ); |
| 343 | dir->fd = -1; |
| 344 | } |
| 345 | else |
| 346 | { |
| 347 | /* Set the file pointer back at the start of the directory */ |
| 348 | lseek( dir->fd, 0, SEEK_SET ); |
| 349 | dir->dir = NULL; |
| 350 | return dir; |
| 351 | } |
| 352 | } |
| 353 | #endif /* VFAT_IOCTL_READDIR_BOTH */ |
| 354 | |
| 355 | /* Now use the standard opendir/readdir interface */ |
| 356 | |
| 357 | if (!(dir->dir = opendir( path ))) |
| 358 | { |
| 359 | HeapFree( SystemHeap, 0, dir ); |
| 360 | return NULL; |
| 361 | } |
| 362 | return dir; |
| 363 | } |
| 364 | |
| 365 | |
| 366 | /*********************************************************************** |
| 367 | * DOSFS_CloseDir |
| 368 | */ |
| 369 | static void DOSFS_CloseDir( DOS_DIR *dir ) |
| 370 | { |
| 371 | #ifdef VFAT_IOCTL_READDIR_BOTH |
| 372 | if (dir->fd != -1) close( dir->fd ); |
| 373 | #endif /* VFAT_IOCTL_READDIR_BOTH */ |
| 374 | if (dir->dir) closedir( dir->dir ); |
| 375 | HeapFree( SystemHeap, 0, dir ); |
| 376 | } |
| 377 | |
| 378 | |
| 379 | /*********************************************************************** |
| 380 | * DOSFS_ReadDir |
| 381 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 382 | static BOOL DOSFS_ReadDir( DOS_DIR *dir, LPCSTR *long_name, |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 383 | LPCSTR *short_name ) |
| 384 | { |
| 385 | struct dirent *dirent; |
| 386 | |
| 387 | #ifdef VFAT_IOCTL_READDIR_BOTH |
| 388 | if (dir->fd != -1) |
| 389 | { |
Alexandre Julliard | 44ed71f | 1997-12-21 19:17:50 +0000 | [diff] [blame] | 390 | if (ioctl( dir->fd, VFAT_IOCTL_READDIR_BOTH, (long)dir->dirent ) != -1) { |
| 391 | if (!dir->dirent[0].d_reclen) return FALSE; |
| 392 | if (!DOSFS_ToDosFCBFormat( dir->dirent[0].d_name, dir->short_name )) |
| 393 | dir->short_name[0] = '\0'; |
| 394 | *short_name = dir->short_name; |
| 395 | if (dir->dirent[1].d_name[0]) *long_name = dir->dirent[1].d_name; |
| 396 | else *long_name = dir->dirent[0].d_name; |
| 397 | return TRUE; |
| 398 | } |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 399 | } |
| 400 | #endif /* VFAT_IOCTL_READDIR_BOTH */ |
| 401 | |
| 402 | if (!(dirent = readdir( dir->dir ))) return FALSE; |
| 403 | *long_name = dirent->d_name; |
| 404 | *short_name = NULL; |
| 405 | return TRUE; |
| 406 | } |
| 407 | |
| 408 | |
| 409 | /*********************************************************************** |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 410 | * DOSFS_Hash |
| 411 | * |
| 412 | * Transform a Unix file name into a hashed DOS name. If the name is a valid |
| 413 | * DOS name, it is converted to upper-case; otherwise it is replaced by a |
| 414 | * hashed version that fits in 8.3 format. |
| 415 | * File name can be terminated by '\0', '\\' or '/'. |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 416 | * 'buffer' must be at least 13 characters long. |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 417 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 418 | static void DOSFS_Hash( LPCSTR name, LPSTR buffer, BOOL dir_format, |
| 419 | BOOL ignore_case ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 420 | { |
| 421 | static const char invalid_chars[] = INVALID_DOS_CHARS "~."; |
| 422 | static const char hash_chars[32] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"; |
| 423 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 424 | const char *p, *ext; |
| 425 | char *dst; |
| 426 | unsigned short hash; |
| 427 | int i; |
| 428 | |
| 429 | if (dir_format) strcpy( buffer, " " ); |
| 430 | |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 431 | if (DOSFS_ValidDOSName( name, ignore_case )) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 432 | { |
| 433 | /* Check for '.' and '..' */ |
| 434 | if (*name == '.') |
| 435 | { |
| 436 | buffer[0] = '.'; |
| 437 | if (!dir_format) buffer[1] = buffer[2] = '\0'; |
| 438 | if (name[1] == '.') buffer[1] = '.'; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 439 | return; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 440 | } |
| 441 | |
| 442 | /* Simply copy the name, converting to uppercase */ |
| 443 | |
| 444 | for (dst = buffer; !IS_END_OF_NAME(*name) && (*name != '.'); name++) |
| 445 | *dst++ = toupper(*name); |
| 446 | if (*name == '.') |
| 447 | { |
| 448 | if (dir_format) dst = buffer + 8; |
| 449 | else *dst++ = '.'; |
| 450 | for (name++; !IS_END_OF_NAME(*name); name++) |
| 451 | *dst++ = toupper(*name); |
| 452 | } |
| 453 | if (!dir_format) *dst = '\0'; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 454 | return; |
| 455 | } |
| 456 | |
| 457 | /* Compute the hash code of the file name */ |
| 458 | /* If you know something about hash functions, feel free to */ |
| 459 | /* insert a better algorithm here... */ |
| 460 | if (ignore_case) |
| 461 | { |
| 462 | for (p = name, hash = 0xbeef; !IS_END_OF_NAME(p[1]); p++) |
| 463 | hash = (hash<<3) ^ (hash>>5) ^ tolower(*p) ^ (tolower(p[1]) << 8); |
| 464 | hash = (hash<<3) ^ (hash>>5) ^ tolower(*p); /* Last character*/ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 465 | } |
| 466 | else |
| 467 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 468 | for (p = name, hash = 0xbeef; !IS_END_OF_NAME(p[1]); p++) |
| 469 | hash = (hash << 3) ^ (hash >> 5) ^ *p ^ (p[1] << 8); |
| 470 | hash = (hash << 3) ^ (hash >> 5) ^ *p; /* Last character */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 471 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 472 | |
| 473 | /* Find last dot for start of the extension */ |
| 474 | for (p = name+1, ext = NULL; !IS_END_OF_NAME(*p); p++) |
| 475 | if (*p == '.') ext = p; |
| 476 | if (ext && IS_END_OF_NAME(ext[1])) |
| 477 | ext = NULL; /* Empty extension ignored */ |
| 478 | |
| 479 | /* Copy first 4 chars, replacing invalid chars with '_' */ |
| 480 | for (i = 4, p = name, dst = buffer; i > 0; i--, p++) |
| 481 | { |
| 482 | if (IS_END_OF_NAME(*p) || (p == ext)) break; |
| 483 | *dst++ = strchr( invalid_chars, *p ) ? '_' : toupper(*p); |
| 484 | } |
| 485 | /* Pad to 5 chars with '~' */ |
| 486 | while (i-- >= 0) *dst++ = '~'; |
| 487 | |
| 488 | /* Insert hash code converted to 3 ASCII chars */ |
| 489 | *dst++ = hash_chars[(hash >> 10) & 0x1f]; |
| 490 | *dst++ = hash_chars[(hash >> 5) & 0x1f]; |
| 491 | *dst++ = hash_chars[hash & 0x1f]; |
| 492 | |
| 493 | /* Copy the first 3 chars of the extension (if any) */ |
| 494 | if (ext) |
| 495 | { |
| 496 | if (!dir_format) *dst++ = '.'; |
| 497 | for (i = 3, ext++; (i > 0) && !IS_END_OF_NAME(*ext); i--, ext++) |
| 498 | *dst++ = strchr( invalid_chars, *ext ) ? '_' : toupper(*ext); |
| 499 | } |
| 500 | if (!dir_format) *dst = '\0'; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 501 | } |
| 502 | |
| 503 | |
| 504 | /*********************************************************************** |
| 505 | * DOSFS_FindUnixName |
| 506 | * |
| 507 | * Find the Unix file name in a given directory that corresponds to |
| 508 | * a file name (either in Unix or DOS format). |
| 509 | * File name can be terminated by '\0', '\\' or '/'. |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 510 | * Return TRUE if OK, FALSE if no file name matches. |
| 511 | * |
| 512 | * 'long_buf' must be at least 'long_len' characters long. If the long name |
| 513 | * turns out to be larger than that, the function returns FALSE. |
| 514 | * 'short_buf' must be at least 13 characters long. |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 515 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 516 | BOOL DOSFS_FindUnixName( LPCSTR path, LPCSTR name, LPSTR long_buf, |
| 517 | INT long_len, LPSTR short_buf, BOOL ignore_case) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 518 | { |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 519 | DOS_DIR *dir; |
| 520 | LPCSTR long_name, short_name; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 521 | char dos_name[12], tmp_buf[13]; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 522 | BOOL ret; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 523 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 524 | const char *p = strchr( name, '/' ); |
| 525 | int len = p ? (int)(p - name) : strlen(name); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 526 | if ((p = strchr( name, '\\' ))) len = MIN( (int)(p - name), len ); |
Andreas Mohr | 0c3f70d | 1999-04-25 12:27:58 +0000 | [diff] [blame] | 527 | /* Ignore trailing dots */ |
| 528 | while (len > 1 && name[len-1] == '.') len--; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 529 | if (long_len < len + 1) return FALSE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 530 | |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 531 | TRACE_(dosfs)("%s,%s\n", path, name ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 532 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 533 | if (!DOSFS_ToDosFCBFormat( name, dos_name )) dos_name[0] = '\0'; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 534 | |
| 535 | if (!(dir = DOSFS_OpenDir( path ))) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 536 | { |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 537 | WARN_(dosfs)("(%s,%s): can't open dir: %s\n", |
Alexandre Julliard | 44ed71f | 1997-12-21 19:17:50 +0000 | [diff] [blame] | 538 | path, name, strerror(errno) ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 539 | return FALSE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 540 | } |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 541 | |
| 542 | while ((ret = DOSFS_ReadDir( dir, &long_name, &short_name ))) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 543 | { |
| 544 | /* Check against Unix name */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 545 | if (len == strlen(long_name)) |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 546 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 547 | if (!ignore_case) |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 548 | { |
Alexandre Julliard | 89f079b | 1999-08-08 18:54:47 +0000 | [diff] [blame] | 549 | if (!strncmp( long_name, name, len )) break; |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 550 | } |
| 551 | else |
| 552 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 553 | if (!lstrncmpiA( long_name, name, len )) break; |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 554 | } |
| 555 | } |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 556 | if (dos_name[0]) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 557 | { |
| 558 | /* Check against hashed DOS name */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 559 | if (!short_name) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 560 | { |
| 561 | DOSFS_Hash( long_name, tmp_buf, TRUE, ignore_case ); |
| 562 | short_name = tmp_buf; |
| 563 | } |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 564 | if (!strcmp( dos_name, short_name )) break; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 565 | } |
| 566 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 567 | if (ret) |
| 568 | { |
| 569 | if (long_buf) strcpy( long_buf, long_name ); |
| 570 | if (short_buf) |
| 571 | { |
| 572 | if (short_name) |
| 573 | DOSFS_ToDosDTAFormat( short_name, short_buf ); |
| 574 | else |
| 575 | DOSFS_Hash( long_name, short_buf, FALSE, ignore_case ); |
| 576 | } |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 577 | TRACE_(dosfs)("(%s,%s) -> %s (%s)\n", |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 578 | path, name, long_name, short_buf ? short_buf : "***"); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 579 | } |
| 580 | else |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 581 | WARN_(dosfs)("'%s' not found in '%s'\n", name, path); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 582 | DOSFS_CloseDir( dir ); |
| 583 | return ret; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 584 | } |
| 585 | |
| 586 | |
| 587 | /*********************************************************************** |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 588 | * DOSFS_GetDevice |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 589 | * |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 590 | * Check if a DOS file name represents a DOS device and return the device. |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 591 | */ |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 592 | const DOS_DEVICE *DOSFS_GetDevice( const char *name ) |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 593 | { |
| 594 | int i; |
| 595 | const char *p; |
| 596 | |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 597 | if (!name) return NULL; /* if FILE_DupUnixHandle was used */ |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 598 | if (name[0] && (name[1] == ':')) name += 2; |
| 599 | if ((p = strrchr( name, '/' ))) name = p + 1; |
| 600 | if ((p = strrchr( name, '\\' ))) name = p + 1; |
| 601 | for (i = 0; i < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]); i++) |
| 602 | { |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 603 | const char *dev = DOSFS_Devices[i].name; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 604 | if (!lstrncmpiA( dev, name, strlen(dev) )) |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 605 | { |
| 606 | p = name + strlen( dev ); |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 607 | if (!*p || (*p == '.')) return &DOSFS_Devices[i]; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 608 | } |
| 609 | } |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 610 | return NULL; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 611 | } |
| 612 | |
Alexandre Julliard | 62a8b43 | 1999-01-19 17:48:23 +0000 | [diff] [blame] | 613 | |
| 614 | /*********************************************************************** |
| 615 | * DOSFS_GetDeviceByHandle |
| 616 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 617 | const DOS_DEVICE *DOSFS_GetDeviceByHandle( HFILE hFile ) |
Alexandre Julliard | 62a8b43 | 1999-01-19 17:48:23 +0000 | [diff] [blame] | 618 | { |
Alexandre Julliard | ebe29ef | 1999-06-26 08:43:26 +0000 | [diff] [blame] | 619 | struct get_file_info_request *req = get_req_buffer(); |
Alexandre Julliard | 62a8b43 | 1999-01-19 17:48:23 +0000 | [diff] [blame] | 620 | |
Alexandre Julliard | ebe29ef | 1999-06-26 08:43:26 +0000 | [diff] [blame] | 621 | req->handle = hFile; |
| 622 | if (!server_call( REQ_GET_FILE_INFO ) && (req->type == FILE_TYPE_UNKNOWN)) |
Alexandre Julliard | 62a8b43 | 1999-01-19 17:48:23 +0000 | [diff] [blame] | 623 | { |
Alexandre Julliard | ebe29ef | 1999-06-26 08:43:26 +0000 | [diff] [blame] | 624 | if ((req->attr >= 0) && |
| 625 | (req->attr < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]))) |
| 626 | return &DOSFS_Devices[req->attr]; |
Alexandre Julliard | 62a8b43 | 1999-01-19 17:48:23 +0000 | [diff] [blame] | 627 | } |
| 628 | return NULL; |
| 629 | } |
| 630 | |
| 631 | |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 632 | /*********************************************************************** |
| 633 | * DOSFS_OpenDevice |
| 634 | * |
| 635 | * Open a DOS device. This might not map 1:1 into the UNIX device concept. |
| 636 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 637 | HFILE DOSFS_OpenDevice( const char *name, DWORD access ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 638 | { |
| 639 | int i; |
| 640 | const char *p; |
| 641 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 642 | if (!name) return (HFILE)NULL; /* if FILE_DupUnixHandle was used */ |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 643 | if (name[0] && (name[1] == ':')) name += 2; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 644 | if ((p = strrchr( name, '/' ))) name = p + 1; |
| 645 | if ((p = strrchr( name, '\\' ))) name = p + 1; |
| 646 | for (i = 0; i < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]); i++) |
| 647 | { |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 648 | const char *dev = DOSFS_Devices[i].name; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 649 | if (!lstrncmpiA( dev, name, strlen(dev) )) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 650 | { |
| 651 | p = name + strlen( dev ); |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 652 | if (!*p || (*p == '.')) { |
| 653 | /* got it */ |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 654 | if (!strcmp(DOSFS_Devices[i].name,"NUL")) |
Alexandre Julliard | 0562539 | 1999-01-03 11:55:56 +0000 | [diff] [blame] | 655 | return FILE_CreateFile( "/dev/null", access, |
| 656 | FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, |
| 657 | OPEN_EXISTING, 0, -1 ); |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 658 | if (!strcmp(DOSFS_Devices[i].name,"CON")) { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 659 | HFILE to_dup; |
| 660 | HFILE handle; |
Alexandre Julliard | 0562539 | 1999-01-03 11:55:56 +0000 | [diff] [blame] | 661 | switch (access & (GENERIC_READ|GENERIC_WRITE)) { |
| 662 | case GENERIC_READ: |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 663 | to_dup = GetStdHandle( STD_INPUT_HANDLE ); |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 664 | break; |
Alexandre Julliard | 0562539 | 1999-01-03 11:55:56 +0000 | [diff] [blame] | 665 | case GENERIC_WRITE: |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 666 | to_dup = GetStdHandle( STD_OUTPUT_HANDLE ); |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 667 | break; |
| 668 | default: |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 669 | FIXME_(dosfs)("can't open CON read/write\n"); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 670 | return HFILE_ERROR; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 671 | break; |
| 672 | } |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 673 | if (!DuplicateHandle( GetCurrentProcess(), to_dup, GetCurrentProcess(), |
| 674 | &handle, 0, FALSE, DUPLICATE_SAME_ACCESS )) |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 675 | handle = HFILE_ERROR; |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 676 | return handle; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 677 | } |
Alexandre Julliard | fbe63ad | 1998-12-30 12:10:06 +0000 | [diff] [blame] | 678 | if (!strcmp(DOSFS_Devices[i].name,"SCSIMGR$") || |
| 679 | !strcmp(DOSFS_Devices[i].name,"HPSCAN")) |
| 680 | { |
Alexandre Julliard | 62a8b43 | 1999-01-19 17:48:23 +0000 | [diff] [blame] | 681 | return FILE_CreateDevice( i, access, NULL ); |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 682 | } |
Michael McCormack | a848607 | 1999-03-14 12:25:36 +0000 | [diff] [blame] | 683 | { |
| 684 | HFILE r; |
| 685 | char devname[40]; |
| 686 | PROFILE_GetWineIniString("serialports",name,"",devname,sizeof devname); |
| 687 | |
| 688 | if(devname[0]) |
| 689 | { |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 690 | TRACE_(file)("DOSFS_OpenDevice %s is %s\n", |
Michael McCormack | a848607 | 1999-03-14 12:25:36 +0000 | [diff] [blame] | 691 | DOSFS_Devices[i].name,devname); |
| 692 | r = FILE_CreateFile( devname, access, |
| 693 | FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, |
| 694 | OPEN_EXISTING, 0, -1 ); |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 695 | TRACE_(file)("Create_File return %08X\n",r); |
Michael McCormack | a848607 | 1999-03-14 12:25:36 +0000 | [diff] [blame] | 696 | return r; |
| 697 | } |
| 698 | } |
| 699 | |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 700 | FIXME_(dosfs)("device open %s not supported (yet)\n",DOSFS_Devices[i].name); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 701 | return HFILE_ERROR; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 702 | } |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 703 | } |
| 704 | } |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 705 | return HFILE_ERROR; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 706 | } |
| 707 | |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 708 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 709 | /*********************************************************************** |
| 710 | * DOSFS_GetPathDrive |
| 711 | * |
| 712 | * Get the drive specified by a given path name (DOS or Unix format). |
| 713 | */ |
| 714 | static int DOSFS_GetPathDrive( const char **name ) |
| 715 | { |
| 716 | int drive; |
| 717 | const char *p = *name; |
| 718 | |
| 719 | if (*p && (p[1] == ':')) |
| 720 | { |
| 721 | drive = toupper(*p) - 'A'; |
| 722 | *name += 2; |
| 723 | } |
| 724 | else if (*p == '/') /* Absolute Unix path? */ |
| 725 | { |
| 726 | if ((drive = DRIVE_FindDriveRoot( name )) == -1) |
| 727 | { |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 728 | MESSAGE("Warning: %s not accessible from a DOS drive\n", *name ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 729 | /* Assume it really was a DOS name */ |
| 730 | drive = DRIVE_GetCurrentDrive(); |
| 731 | } |
| 732 | } |
| 733 | else drive = DRIVE_GetCurrentDrive(); |
| 734 | |
| 735 | if (!DRIVE_IsValid(drive)) |
| 736 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 737 | SetLastError( ERROR_INVALID_DRIVE ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 738 | return -1; |
| 739 | } |
| 740 | return drive; |
| 741 | } |
| 742 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 743 | |
| 744 | /*********************************************************************** |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 745 | * DOSFS_GetFullName |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 746 | * |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 747 | * Convert a file name (DOS or mixed DOS/Unix format) to a valid |
| 748 | * Unix name / short DOS name pair. |
| 749 | * Return FALSE if one of the path components does not exist. The last path |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 750 | * component is only checked if 'check_last' is non-zero. |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 751 | * The buffers pointed to by 'long_buf' and 'short_buf' must be |
| 752 | * at least MAX_PATHNAME_LEN long. |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 753 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 754 | BOOL DOSFS_GetFullName( LPCSTR name, BOOL check_last, DOS_FULL_NAME *full ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 755 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 756 | BOOL found; |
| 757 | UINT flags; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 758 | char *p_l, *p_s, *root; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 759 | |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 760 | TRACE_(dosfs)("%s (last=%d)\n", |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 761 | name, check_last ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 762 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 763 | if ((full->drive = DOSFS_GetPathDrive( &name )) == -1) return FALSE; |
| 764 | flags = DRIVE_GetFlags( full->drive ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 765 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 766 | lstrcpynA( full->long_name, DRIVE_GetRoot( full->drive ), |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 767 | sizeof(full->long_name) ); |
| 768 | if (full->long_name[1]) root = full->long_name + strlen(full->long_name); |
| 769 | else root = full->long_name; /* root directory */ |
| 770 | |
| 771 | strcpy( full->short_name, "A:\\" ); |
| 772 | full->short_name[0] += full->drive; |
| 773 | |
| 774 | if ((*name == '\\') || (*name == '/')) /* Absolute path */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 775 | { |
| 776 | while ((*name == '\\') || (*name == '/')) name++; |
| 777 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 778 | else /* Relative path */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 779 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 780 | lstrcpynA( root + 1, DRIVE_GetUnixCwd( full->drive ), |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 781 | sizeof(full->long_name) - (root - full->long_name) - 1 ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 782 | if (root[1]) *root = '/'; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 783 | lstrcpynA( full->short_name + 3, DRIVE_GetDosCwd( full->drive ), |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 784 | sizeof(full->short_name) - 3 ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 785 | } |
| 786 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 787 | p_l = full->long_name[1] ? full->long_name + strlen(full->long_name) |
| 788 | : full->long_name; |
| 789 | p_s = full->short_name[3] ? full->short_name + strlen(full->short_name) |
| 790 | : full->short_name + 2; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 791 | found = TRUE; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 792 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 793 | while (*name && found) |
| 794 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 795 | /* Check for '.' and '..' */ |
| 796 | |
| 797 | if (*name == '.') |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 798 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 799 | if (IS_END_OF_NAME(name[1])) |
| 800 | { |
| 801 | name++; |
| 802 | while ((*name == '\\') || (*name == '/')) name++; |
| 803 | continue; |
| 804 | } |
| 805 | else if ((name[1] == '.') && IS_END_OF_NAME(name[2])) |
| 806 | { |
| 807 | name += 2; |
| 808 | while ((*name == '\\') || (*name == '/')) name++; |
| 809 | while ((p_l > root) && (*p_l != '/')) p_l--; |
| 810 | while ((p_s > full->short_name + 2) && (*p_s != '\\')) p_s--; |
| 811 | *p_l = *p_s = '\0'; /* Remove trailing separator */ |
| 812 | continue; |
| 813 | } |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 814 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 815 | |
| 816 | /* Make sure buffers are large enough */ |
| 817 | |
| 818 | if ((p_s >= full->short_name + sizeof(full->short_name) - 14) || |
| 819 | (p_l >= full->long_name + sizeof(full->long_name) - 1)) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 820 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 821 | SetLastError( ERROR_PATH_NOT_FOUND ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 822 | return FALSE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 823 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 824 | |
| 825 | /* Get the long and short name matching the file name */ |
| 826 | |
| 827 | if ((found = DOSFS_FindUnixName( full->long_name, name, p_l + 1, |
| 828 | sizeof(full->long_name) - (p_l - full->long_name) - 1, |
| 829 | p_s + 1, !(flags & DRIVE_CASE_SENSITIVE) ))) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 830 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 831 | *p_l++ = '/'; |
| 832 | p_l += strlen(p_l); |
| 833 | *p_s++ = '\\'; |
| 834 | p_s += strlen(p_s); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 835 | while (!IS_END_OF_NAME(*name)) name++; |
| 836 | } |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 837 | else if (!check_last) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 838 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 839 | *p_l++ = '/'; |
| 840 | *p_s++ = '\\'; |
| 841 | while (!IS_END_OF_NAME(*name) && |
| 842 | (p_s < full->short_name + sizeof(full->short_name) - 1) && |
| 843 | (p_l < full->long_name + sizeof(full->long_name) - 1)) |
| 844 | { |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 845 | *p_s++ = tolower(*name); |
| 846 | /* If the drive is case-sensitive we want to create new */ |
| 847 | /* files in lower-case otherwise we can't reopen them */ |
| 848 | /* under the same short name. */ |
| 849 | if (flags & DRIVE_CASE_SENSITIVE) *p_l++ = tolower(*name); |
| 850 | else *p_l++ = *name; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 851 | name++; |
| 852 | } |
| 853 | *p_l = *p_s = '\0'; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 854 | } |
| 855 | while ((*name == '\\') || (*name == '/')) name++; |
| 856 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 857 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 858 | if (!found) |
| 859 | { |
Alexander Larsson | a8745ea | 1998-12-02 10:04:52 +0000 | [diff] [blame] | 860 | if (check_last) |
| 861 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 862 | SetLastError( ERROR_FILE_NOT_FOUND ); |
Alexander Larsson | a8745ea | 1998-12-02 10:04:52 +0000 | [diff] [blame] | 863 | return FALSE; |
| 864 | } |
Alexander Larsson | 2772a67 | 1998-12-07 16:23:42 +0000 | [diff] [blame] | 865 | if (*name) /* Not last */ |
| 866 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 867 | SetLastError( ERROR_PATH_NOT_FOUND ); |
Alexander Larsson | 2772a67 | 1998-12-07 16:23:42 +0000 | [diff] [blame] | 868 | return FALSE; |
| 869 | } |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 870 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 871 | if (!full->long_name[0]) strcpy( full->long_name, "/" ); |
| 872 | if (!full->short_name[2]) strcpy( full->short_name + 2, "\\" ); |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 873 | TRACE_(dosfs)("returning %s = %s\n", |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 874 | full->long_name, full->short_name ); |
| 875 | return TRUE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 876 | } |
| 877 | |
| 878 | |
| 879 | /*********************************************************************** |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 880 | * GetShortPathNameA (KERNEL32.271) |
Juergen Schmied | 4658e4d | 1998-11-22 12:21:05 +0000 | [diff] [blame] | 881 | * |
| 882 | * NOTES |
| 883 | * observed: |
| 884 | * longpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0 |
| 885 | * *longpath="" or invalid: LastError=ERROR_BAD_PATHNAME, ret=0 |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 886 | * |
| 887 | * more observations ( with NT 3.51 (WinDD) ): |
| 888 | * longpath <= 8.3 -> just copy longpath to shortpath |
| 889 | * longpath > 8.3 -> |
| 890 | * a) file does not exist -> return 0, LastError = ERROR_FILE_NOT_FOUND |
| 891 | * b) file does exist -> set the short filename. |
| 892 | * - trailing slashes are reproduced in the short name, even if the |
| 893 | * file is not a directory |
| 894 | * - the absolute/relative path of the short name is reproduced in the |
| 895 | * same way, like the long name |
| 896 | * - longpath and shortpath may have the same adress |
| 897 | * Peter Ganten, 1999 |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 898 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 899 | DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 900 | DWORD shortlen ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 901 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 902 | DOS_FULL_NAME full_name; |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 903 | LPSTR tmpshortpath; |
| 904 | DWORD length = 0, pos = 0; |
| 905 | INT start=-1, end=-1, tmplen; |
| 906 | |
| 907 | if (!longpath) { |
| 908 | SetLastError(ERROR_INVALID_PARAMETER); |
| 909 | return 0; |
| 910 | } |
| 911 | if (!longpath[0]) { |
| 912 | SetLastError(ERROR_BAD_PATHNAME); |
| 913 | return 0; |
| 914 | } |
| 915 | |
| 916 | tmpshortpath = HeapAlloc( GetProcessHeap(), 0, MAX_PATHNAME_LEN ); |
| 917 | if ( !tmpshortpath ) { |
| 918 | SetLastError ( ERROR_NOT_ENOUGH_MEMORY ); |
| 919 | return 0; |
| 920 | } |
| 921 | |
| 922 | /* Check for Drive-Letter */ |
| 923 | if ( longpath[1] == ':' ) { |
| 924 | lstrcpynA ( tmpshortpath, longpath, 3 ); |
| 925 | length = 2; |
| 926 | pos = 2; |
| 927 | } |
| 928 | |
| 929 | /* loop over each part of the name */ |
| 930 | while ( longpath[pos] ) { |
| 931 | |
| 932 | if (( longpath[pos] == '\\' ) || |
| 933 | ( longpath[pos+1] == '\0' ) || |
| 934 | ( longpath[pos] == '/')) { |
| 935 | |
| 936 | if ( start != -1 ) { |
| 937 | if ( DOSFS_ValidDOSName ( longpath + start, TRUE )) { |
| 938 | tmplen = end - start + ( (( longpath[pos] == '\\' ) || ( longpath[pos] == '/' )) ? 1 : 2 ); |
| 939 | lstrcpynA ( tmpshortpath+length, longpath+start, tmplen ); |
| 940 | length += tmplen - 1; |
| 941 | } |
| 942 | else { |
| 943 | DOSFS_Hash ( longpath + start, tmpshortpath+length, FALSE, FALSE ); |
| 944 | length = lstrlenA ( tmpshortpath ); |
| 945 | |
| 946 | /* Check if the path, up to this point exists */ |
| 947 | if ( !DOSFS_GetFullName ( tmpshortpath, TRUE, &full_name ) ) { |
| 948 | SetLastError ( ERROR_FILE_NOT_FOUND ); |
| 949 | return 0; |
| 950 | } |
| 951 | |
| 952 | } |
| 953 | } |
| 954 | |
| 955 | if (( longpath[pos] == '\\' ) || ( longpath[pos] == '/' )) { |
| 956 | tmpshortpath[length] = '\\'; |
| 957 | tmpshortpath[length+1]='\0'; |
| 958 | length++; |
| 959 | } |
| 960 | pos++; |
| 961 | |
| 962 | start = -1; |
| 963 | end = -1; |
| 964 | continue; |
| 965 | } |
| 966 | |
| 967 | if ( start == -1 ) { |
| 968 | start = pos; |
| 969 | } |
| 970 | pos++; |
| 971 | end = pos; |
| 972 | } |
Juergen Schmied | 4658e4d | 1998-11-22 12:21:05 +0000 | [diff] [blame] | 973 | |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 974 | lstrcpynA ( shortpath, tmpshortpath, shortlen ); |
| 975 | length = lstrlenA ( tmpshortpath ); |
| 976 | HeapFree ( GetProcessHeap(), 0, tmpshortpath ); |
| 977 | |
| 978 | return length; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 979 | } |
| 980 | |
| 981 | |
| 982 | /*********************************************************************** |
| 983 | * GetShortPathName32W (KERNEL32.272) |
| 984 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 985 | DWORD WINAPI GetShortPathNameW( LPCWSTR longpath, LPWSTR shortpath, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 986 | DWORD shortlen ) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 987 | { |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 988 | LPSTR longpathA, shortpathA; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 989 | DWORD ret = 0; |
Juergen Schmied | 4658e4d | 1998-11-22 12:21:05 +0000 | [diff] [blame] | 990 | |
Juergen Schmied | 4658e4d | 1998-11-22 12:21:05 +0000 | [diff] [blame] | 991 | longpathA = HEAP_strdupWtoA( GetProcessHeap(), 0, longpath ); |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 992 | shortpathA = HEAP_xalloc ( GetProcessHeap(), 0, shortlen ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 993 | |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 994 | ret = GetShortPathNameA ( longpathA, shortpathA, shortlen ); |
| 995 | lstrcpynAtoW ( shortpath, shortpathA, shortlen ); |
Juergen Schmied | 4658e4d | 1998-11-22 12:21:05 +0000 | [diff] [blame] | 996 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 997 | HeapFree( GetProcessHeap(), 0, longpathA ); |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 998 | HeapFree( GetProcessHeap(), 0, shortpathA ); |
| 999 | |
| 1000 | return ret; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1001 | } |
| 1002 | |
| 1003 | |
| 1004 | /*********************************************************************** |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1005 | * GetLongPathName32A (KERNEL32.xxx) |
| 1006 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1007 | DWORD WINAPI GetLongPathNameA( LPCSTR shortpath, LPSTR longpath, |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1008 | DWORD longlen ) |
| 1009 | { |
| 1010 | DOS_FULL_NAME full_name; |
Alexander Larsson | c1190fe | 1998-10-11 13:57:09 +0000 | [diff] [blame] | 1011 | char *p; |
| 1012 | char *longfilename; |
| 1013 | DWORD shortpathlen; |
| 1014 | |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1015 | if (!DOSFS_GetFullName( shortpath, TRUE, &full_name )) return 0; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1016 | lstrcpynA( longpath, full_name.short_name, longlen ); |
Alexander Larsson | c1190fe | 1998-10-11 13:57:09 +0000 | [diff] [blame] | 1017 | /* Do some hackery to get the long filename. |
| 1018 | * FIXME: Would be better if it returned the |
| 1019 | * long version of the directories too |
| 1020 | */ |
| 1021 | longfilename = strrchr(full_name.long_name, '/')+1; |
| 1022 | if (longpath != NULL) { |
| 1023 | if ((p = strrchr( longpath, '\\' )) != NULL) { |
| 1024 | p++; |
| 1025 | longlen -= (p-longpath); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1026 | lstrcpynA( p, longfilename , longlen); |
Alexander Larsson | c1190fe | 1998-10-11 13:57:09 +0000 | [diff] [blame] | 1027 | } |
| 1028 | } |
| 1029 | shortpathlen = |
| 1030 | ((strrchr( full_name.short_name, '\\' ) - full_name.short_name) + 1); |
| 1031 | return shortpathlen + strlen( longfilename ); |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1032 | } |
| 1033 | |
| 1034 | |
| 1035 | /*********************************************************************** |
| 1036 | * GetLongPathName32W (KERNEL32.269) |
| 1037 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1038 | DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1039 | DWORD longlen ) |
| 1040 | { |
| 1041 | DOS_FULL_NAME full_name; |
| 1042 | DWORD ret = 0; |
| 1043 | LPSTR shortpathA = HEAP_strdupWtoA( GetProcessHeap(), 0, shortpath ); |
| 1044 | |
| 1045 | /* FIXME: is it correct to always return a fully qualified short path? */ |
| 1046 | if (DOSFS_GetFullName( shortpathA, TRUE, &full_name )) |
| 1047 | { |
| 1048 | ret = strlen( full_name.short_name ); |
| 1049 | lstrcpynAtoW( longpath, full_name.long_name, longlen ); |
| 1050 | } |
| 1051 | HeapFree( GetProcessHeap(), 0, shortpathA ); |
| 1052 | return ret; |
| 1053 | } |
| 1054 | |
| 1055 | |
| 1056 | /*********************************************************************** |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1057 | * DOSFS_DoGetFullPathName |
| 1058 | * |
| 1059 | * Implementation of GetFullPathName32A/W. |
| 1060 | */ |
| 1061 | static DWORD DOSFS_DoGetFullPathName( LPCSTR name, DWORD len, LPSTR result, |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1062 | BOOL unicode ) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1063 | { |
| 1064 | char buffer[MAX_PATHNAME_LEN]; |
| 1065 | int drive; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1066 | char *p; |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1067 | DWORD ret; |
| 1068 | |
| 1069 | /* last possible position for a char != 0 */ |
| 1070 | char *endchar = buffer + sizeof(buffer) - 2; |
| 1071 | *endchar = '\0'; |
| 1072 | |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 1073 | TRACE_(dosfs)("converting '%s'\n", name ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1074 | |
Alexandre Julliard | 08b9b4f | 1999-06-06 17:09:21 +0000 | [diff] [blame] | 1075 | if (!name || ((drive = DOSFS_GetPathDrive( &name )) == -1) ) |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1076 | { SetLastError( ERROR_INVALID_PARAMETER ); |
| 1077 | return 0; |
| 1078 | } |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1079 | |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 1080 | p = buffer; |
| 1081 | *p++ = 'A' + drive; |
| 1082 | *p++ = ':'; |
Alexandre Julliard | 44ed71f | 1997-12-21 19:17:50 +0000 | [diff] [blame] | 1083 | if (IS_END_OF_NAME(*name) && (*name)) /* Absolute path */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1084 | { |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1085 | while (((*name == '\\') || (*name == '/')) && (!*endchar) ) |
| 1086 | *p++ = *name++; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1087 | } |
Alexandre Julliard | 44ed71f | 1997-12-21 19:17:50 +0000 | [diff] [blame] | 1088 | else /* Relative path or empty path */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1089 | { |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 1090 | *p++ = '\\'; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1091 | lstrcpynA( p, DRIVE_GetDosCwd(drive), sizeof(buffer) - 4 ); |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1092 | if ( *p ) |
| 1093 | { |
| 1094 | p += strlen(p); |
| 1095 | *p++ = '\\'; |
| 1096 | } |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1097 | } |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 1098 | *p = '\0'; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1099 | |
| 1100 | while (*name) |
| 1101 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1102 | if (*name == '.') |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1103 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1104 | if (IS_END_OF_NAME(name[1])) |
| 1105 | { |
| 1106 | name++; |
| 1107 | while ((*name == '\\') || (*name == '/')) name++; |
| 1108 | continue; |
| 1109 | } |
| 1110 | else if ((name[1] == '.') && IS_END_OF_NAME(name[2])) |
| 1111 | { |
| 1112 | name += 2; |
| 1113 | while ((*name == '\\') || (*name == '/')) name++; |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1114 | |
| 1115 | if (p < buffer + 3) /* no previous dir component */ |
| 1116 | continue; |
| 1117 | p--; /* skip previously added '\\' */ |
| 1118 | while ((*p == '\\') || (*p == '/')) p--; |
| 1119 | /* skip previous dir component */ |
| 1120 | while ((*p != '\\') && (*p != '/')) p--; |
| 1121 | p++; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1122 | continue; |
| 1123 | } |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1124 | } |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1125 | if ( *endchar ) |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 1126 | { SetLastError( ERROR_PATH_NOT_FOUND ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1127 | return 0; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1128 | } |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1129 | while (!IS_END_OF_NAME(*name) && (!*endchar) ) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1130 | *p++ = *name++; |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1131 | while (((*name == '\\') || (*name == '/')) && (!*endchar) ) |
| 1132 | *p++ = *name++; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1133 | } |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1134 | *p = '\0'; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1135 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1136 | if (!(DRIVE_GetFlags(drive) & DRIVE_CASE_PRESERVING)) |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1137 | CharUpperA( buffer ); |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1138 | |
Alexandre Julliard | 08b9b4f | 1999-06-06 17:09:21 +0000 | [diff] [blame] | 1139 | if (result) |
| 1140 | { |
| 1141 | if (unicode) |
| 1142 | lstrcpynAtoW( (LPWSTR)result, buffer, len ); |
| 1143 | else |
| 1144 | lstrcpynA( result, buffer, len ); |
| 1145 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1146 | |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 1147 | TRACE_(dosfs)("returning '%s'\n", buffer ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1148 | |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1149 | /* If the lpBuffer buffer is too small, the return value is the |
| 1150 | size of the buffer, in characters, required to hold the path. */ |
| 1151 | |
| 1152 | ret = strlen(buffer); |
| 1153 | |
| 1154 | if (ret >= len ) |
| 1155 | SetLastError( ERROR_INSUFFICIENT_BUFFER ); |
| 1156 | |
| 1157 | return ret; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1158 | } |
| 1159 | |
| 1160 | |
| 1161 | /*********************************************************************** |
| 1162 | * GetFullPathName32A (KERNEL32.272) |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1163 | * NOTES |
| 1164 | * if the path closed with '\', *lastpart is 0 |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1165 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1166 | DWORD WINAPI GetFullPathNameA( LPCSTR name, DWORD len, LPSTR buffer, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 1167 | LPSTR *lastpart ) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1168 | { |
| 1169 | DWORD ret = DOSFS_DoGetFullPathName( name, len, buffer, FALSE ); |
Alexandre Julliard | 08b9b4f | 1999-06-06 17:09:21 +0000 | [diff] [blame] | 1170 | if (ret && buffer && lastpart) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1171 | { |
| 1172 | LPSTR p = buffer + strlen(buffer); |
Juergen Schmied | 30f503f | 1998-12-15 17:28:26 +0000 | [diff] [blame] | 1173 | |
Juergen Schmied | 30f503f | 1998-12-15 17:28:26 +0000 | [diff] [blame] | 1174 | if (*p != '\\') |
| 1175 | { |
| 1176 | while ((p > buffer + 2) && (*p != '\\')) p--; |
| 1177 | *lastpart = p + 1; |
| 1178 | } |
| 1179 | else *lastpart = NULL; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1180 | } |
| 1181 | return ret; |
| 1182 | } |
| 1183 | |
| 1184 | |
| 1185 | /*********************************************************************** |
| 1186 | * GetFullPathName32W (KERNEL32.273) |
| 1187 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1188 | DWORD WINAPI GetFullPathNameW( LPCWSTR name, DWORD len, LPWSTR buffer, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 1189 | LPWSTR *lastpart ) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1190 | { |
| 1191 | LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name ); |
| 1192 | DWORD ret = DOSFS_DoGetFullPathName( nameA, len, (LPSTR)buffer, TRUE ); |
| 1193 | HeapFree( GetProcessHeap(), 0, nameA ); |
Alexandre Julliard | 08b9b4f | 1999-06-06 17:09:21 +0000 | [diff] [blame] | 1194 | if (ret && buffer && lastpart) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1195 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1196 | LPWSTR p = buffer + lstrlenW(buffer); |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1197 | if (*p != (WCHAR)'\\') |
| 1198 | { |
| 1199 | while ((p > buffer + 2) && (*p != (WCHAR)'\\')) p--; |
| 1200 | *lastpart = p + 1; |
| 1201 | } |
| 1202 | else *lastpart = NULL; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1203 | } |
| 1204 | return ret; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1205 | } |
| 1206 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1207 | /*********************************************************************** |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1208 | * DOSFS_FindNextEx |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1209 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1210 | static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAA *entry ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1211 | { |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1212 | BYTE attr = info->attr | FA_UNUSED | FA_ARCHIVE | FA_RDONLY; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1213 | UINT flags = DRIVE_GetFlags( info->drive ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1214 | char *p, buffer[MAX_PATHNAME_LEN]; |
| 1215 | const char *drive_path; |
| 1216 | int drive_root; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1217 | LPCSTR long_name, short_name; |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1218 | BY_HANDLE_FILE_INFORMATION fileinfo; |
| 1219 | char dos_name[13]; |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 1220 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1221 | if ((info->attr & ~(FA_UNUSED | FA_ARCHIVE | FA_RDONLY)) == FA_LABEL) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1222 | { |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1223 | if (info->cur_pos) return 0; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1224 | entry->dwFileAttributes = FILE_ATTRIBUTE_LABEL; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1225 | DOSFS_UnixTimeToFileTime( (time_t)0, &entry->ftCreationTime, 0 ); |
| 1226 | DOSFS_UnixTimeToFileTime( (time_t)0, &entry->ftLastAccessTime, 0 ); |
| 1227 | DOSFS_UnixTimeToFileTime( (time_t)0, &entry->ftLastWriteTime, 0 ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1228 | entry->nFileSizeHigh = 0; |
| 1229 | entry->nFileSizeLow = 0; |
| 1230 | entry->dwReserved0 = 0; |
| 1231 | entry->dwReserved1 = 0; |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1232 | DOSFS_ToDosDTAFormat( DRIVE_GetLabel( info->drive ), entry->cFileName ); |
| 1233 | strcpy( entry->cAlternateFileName, entry->cFileName ); |
| 1234 | info->cur_pos++; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1235 | return 1; |
| 1236 | } |
| 1237 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1238 | drive_path = info->path + strlen(DRIVE_GetRoot( info->drive )); |
| 1239 | while ((*drive_path == '/') || (*drive_path == '\\')) drive_path++; |
| 1240 | drive_root = !*drive_path; |
| 1241 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1242 | lstrcpynA( buffer, info->path, sizeof(buffer) - 1 ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1243 | strcat( buffer, "/" ); |
| 1244 | p = buffer + strlen(buffer); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1245 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1246 | while (DOSFS_ReadDir( info->dir, &long_name, &short_name )) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1247 | { |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1248 | info->cur_pos++; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1249 | |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 1250 | /* Don't return '.' and '..' in the root of the drive */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1251 | if (drive_root && (long_name[0] == '.') && |
| 1252 | (!long_name[1] || ((long_name[1] == '.') && !long_name[2]))) |
| 1253 | continue; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1254 | |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1255 | /* Check the long mask */ |
| 1256 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1257 | if (info->long_mask) |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1258 | { |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1259 | if (!DOSFS_MatchLong( info->long_mask, long_name, |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1260 | flags & DRIVE_CASE_SENSITIVE )) continue; |
| 1261 | } |
| 1262 | |
| 1263 | /* Check the short mask */ |
| 1264 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1265 | if (info->short_mask) |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1266 | { |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1267 | if (!short_name) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1268 | { |
| 1269 | DOSFS_Hash( long_name, dos_name, TRUE, |
| 1270 | !(flags & DRIVE_CASE_SENSITIVE) ); |
| 1271 | short_name = dos_name; |
| 1272 | } |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1273 | if (!DOSFS_MatchShort( info->short_mask, short_name )) continue; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1274 | } |
| 1275 | |
| 1276 | /* Check the file attributes */ |
| 1277 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1278 | lstrcpynA( p, long_name, sizeof(buffer) - (int)(p - buffer) ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1279 | if (!FILE_Stat( buffer, &fileinfo )) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1280 | { |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 1281 | WARN_(dosfs)("can't stat %s\n", buffer); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1282 | continue; |
| 1283 | } |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1284 | if (fileinfo.dwFileAttributes & ~attr) continue; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1285 | |
| 1286 | /* We now have a matching entry; fill the result and return */ |
| 1287 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1288 | entry->dwFileAttributes = fileinfo.dwFileAttributes; |
| 1289 | entry->ftCreationTime = fileinfo.ftCreationTime; |
| 1290 | entry->ftLastAccessTime = fileinfo.ftLastAccessTime; |
| 1291 | entry->ftLastWriteTime = fileinfo.ftLastWriteTime; |
| 1292 | entry->nFileSizeHigh = fileinfo.nFileSizeHigh; |
| 1293 | entry->nFileSizeLow = fileinfo.nFileSizeLow; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1294 | |
| 1295 | if (short_name) |
| 1296 | DOSFS_ToDosDTAFormat( short_name, entry->cAlternateFileName ); |
| 1297 | else |
| 1298 | DOSFS_Hash( long_name, entry->cAlternateFileName, FALSE, |
| 1299 | !(flags & DRIVE_CASE_SENSITIVE) ); |
| 1300 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1301 | lstrcpynA( entry->cFileName, long_name, sizeof(entry->cFileName) ); |
| 1302 | if (!(flags & DRIVE_CASE_PRESERVING)) CharLowerA( entry->cFileName ); |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 1303 | TRACE_(dosfs)("returning %s (%s) %02lx %ld\n", |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1304 | entry->cFileName, entry->cAlternateFileName, |
| 1305 | entry->dwFileAttributes, entry->nFileSizeLow ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1306 | return 1; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1307 | } |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1308 | return 0; /* End of directory */ |
| 1309 | } |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1310 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1311 | /*********************************************************************** |
| 1312 | * DOSFS_FindNext |
| 1313 | * |
| 1314 | * Find the next matching file. Return the number of entries read to find |
| 1315 | * the matching one, or 0 if no more entries. |
| 1316 | * 'short_mask' is the 8.3 mask (in FCB format), 'long_mask' is the long |
| 1317 | * file name mask. Either or both can be NULL. |
| 1318 | * |
| 1319 | * NOTE: This is supposed to be only called by the int21 emulation |
| 1320 | * routines. Thus, we should own the Win16Mutex anyway. |
| 1321 | * Nevertheless, we explicitly enter it to ensure the static |
| 1322 | * directory cache is protected. |
| 1323 | */ |
| 1324 | int DOSFS_FindNext( const char *path, const char *short_mask, |
| 1325 | const char *long_mask, int drive, BYTE attr, |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1326 | int skip, WIN32_FIND_DATAA *entry ) |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1327 | { |
| 1328 | static FIND_FIRST_INFO info = { NULL }; |
| 1329 | LPCSTR short_name, long_name; |
| 1330 | int count; |
| 1331 | |
| 1332 | SYSLEVEL_EnterWin16Lock(); |
| 1333 | |
| 1334 | /* Check the cached directory */ |
| 1335 | if (!(info.dir && info.path == path && info.short_mask == short_mask |
| 1336 | && info.long_mask == long_mask && info.drive == drive |
| 1337 | && info.attr == attr && info.cur_pos <= skip)) |
| 1338 | { |
| 1339 | /* Not in the cache, open it anew */ |
| 1340 | if (info.dir) DOSFS_CloseDir( info.dir ); |
| 1341 | |
| 1342 | info.path = (LPSTR)path; |
| 1343 | info.long_mask = (LPSTR)long_mask; |
| 1344 | info.short_mask = (LPSTR)short_mask; |
| 1345 | info.attr = attr; |
| 1346 | info.drive = drive; |
| 1347 | info.cur_pos = 0; |
| 1348 | info.dir = DOSFS_OpenDir( info.path ); |
| 1349 | } |
| 1350 | |
| 1351 | /* Skip to desired position */ |
| 1352 | while (info.cur_pos < skip) |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 1353 | if (info.dir && DOSFS_ReadDir( info.dir, &long_name, &short_name )) |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1354 | info.cur_pos++; |
| 1355 | else |
| 1356 | break; |
| 1357 | |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 1358 | if (info.dir && info.cur_pos == skip && DOSFS_FindNextEx( &info, entry )) |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1359 | count = info.cur_pos - skip; |
| 1360 | else |
| 1361 | count = 0; |
| 1362 | |
| 1363 | if (!count) |
| 1364 | { |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 1365 | if (info.dir) DOSFS_CloseDir( info.dir ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1366 | memset( &info, '\0', sizeof(info) ); |
| 1367 | } |
| 1368 | |
| 1369 | SYSLEVEL_LeaveWin16Lock(); |
| 1370 | |
| 1371 | return count; |
| 1372 | } |
| 1373 | |
| 1374 | |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1375 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1376 | /************************************************************************* |
| 1377 | * FindFirstFile16 (KERNEL.413) |
| 1378 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1379 | HANDLE16 WINAPI FindFirstFile16( LPCSTR path, WIN32_FIND_DATAA *data ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1380 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1381 | DOS_FULL_NAME full_name; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1382 | HGLOBAL16 handle; |
| 1383 | FIND_FIRST_INFO *info; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1384 | |
Andreas Mohr | c21650e | 1998-10-11 17:37:53 +0000 | [diff] [blame] | 1385 | data->dwReserved0 = data->dwReserved1 = 0x0; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1386 | if (!path) return 0; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1387 | if (!DOSFS_GetFullName( path, FALSE, &full_name )) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1388 | return INVALID_HANDLE_VALUE16; |
| 1389 | if (!(handle = GlobalAlloc16( GMEM_MOVEABLE, sizeof(FIND_FIRST_INFO) ))) |
| 1390 | return INVALID_HANDLE_VALUE16; |
| 1391 | info = (FIND_FIRST_INFO *)GlobalLock16( handle ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1392 | info->path = HEAP_strdupA( SystemHeap, 0, full_name.long_name ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1393 | info->long_mask = strrchr( info->path, '/' ); |
| 1394 | *(info->long_mask++) = '\0'; |
| 1395 | info->short_mask = NULL; |
| 1396 | info->attr = 0xff; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1397 | if (path[0] && (path[1] == ':')) info->drive = toupper(*path) - 'A'; |
| 1398 | else info->drive = DRIVE_GetCurrentDrive(); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1399 | info->cur_pos = 0; |
| 1400 | |
| 1401 | info->dir = DOSFS_OpenDir( info->path ); |
| 1402 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1403 | GlobalUnlock16( handle ); |
| 1404 | if (!FindNextFile16( handle, data )) |
| 1405 | { |
| 1406 | FindClose16( handle ); |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 1407 | SetLastError( ERROR_NO_MORE_FILES ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1408 | return INVALID_HANDLE_VALUE16; |
| 1409 | } |
| 1410 | return handle; |
| 1411 | } |
| 1412 | |
| 1413 | |
| 1414 | /************************************************************************* |
| 1415 | * FindFirstFile32A (KERNEL32.123) |
| 1416 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1417 | HANDLE WINAPI FindFirstFileA( LPCSTR path, WIN32_FIND_DATAA *data ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1418 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1419 | HANDLE handle = FindFirstFile16( path, data ); |
| 1420 | if (handle == INVALID_HANDLE_VALUE16) return INVALID_HANDLE_VALUE; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1421 | return handle; |
| 1422 | } |
| 1423 | |
| 1424 | |
| 1425 | /************************************************************************* |
| 1426 | * FindFirstFile32W (KERNEL32.124) |
| 1427 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1428 | HANDLE WINAPI FindFirstFileW( LPCWSTR path, WIN32_FIND_DATAW *data ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1429 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1430 | WIN32_FIND_DATAA dataA; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1431 | LPSTR pathA = HEAP_strdupWtoA( GetProcessHeap(), 0, path ); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1432 | HANDLE handle = FindFirstFileA( pathA, &dataA ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1433 | HeapFree( GetProcessHeap(), 0, pathA ); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1434 | if (handle != INVALID_HANDLE_VALUE) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1435 | { |
| 1436 | data->dwFileAttributes = dataA.dwFileAttributes; |
| 1437 | data->ftCreationTime = dataA.ftCreationTime; |
| 1438 | data->ftLastAccessTime = dataA.ftLastAccessTime; |
| 1439 | data->ftLastWriteTime = dataA.ftLastWriteTime; |
| 1440 | data->nFileSizeHigh = dataA.nFileSizeHigh; |
| 1441 | data->nFileSizeLow = dataA.nFileSizeLow; |
| 1442 | lstrcpyAtoW( data->cFileName, dataA.cFileName ); |
| 1443 | lstrcpyAtoW( data->cAlternateFileName, dataA.cAlternateFileName ); |
| 1444 | } |
| 1445 | return handle; |
| 1446 | } |
| 1447 | |
| 1448 | |
| 1449 | /************************************************************************* |
| 1450 | * FindNextFile16 (KERNEL.414) |
| 1451 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1452 | BOOL16 WINAPI FindNextFile16( HANDLE16 handle, WIN32_FIND_DATAA *data ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1453 | { |
| 1454 | FIND_FIRST_INFO *info; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1455 | |
| 1456 | if (!(info = (FIND_FIRST_INFO *)GlobalLock16( handle ))) |
| 1457 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 1458 | SetLastError( ERROR_INVALID_HANDLE ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1459 | return FALSE; |
| 1460 | } |
| 1461 | GlobalUnlock16( handle ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1462 | if (!info->path || !info->dir) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1463 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 1464 | SetLastError( ERROR_NO_MORE_FILES ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1465 | return FALSE; |
| 1466 | } |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1467 | if (!DOSFS_FindNextEx( info, data )) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1468 | { |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1469 | DOSFS_CloseDir( info->dir ); info->dir = NULL; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1470 | HeapFree( SystemHeap, 0, info->path ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1471 | info->path = info->long_mask = NULL; |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 1472 | SetLastError( ERROR_NO_MORE_FILES ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1473 | return FALSE; |
| 1474 | } |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1475 | return TRUE; |
| 1476 | } |
| 1477 | |
| 1478 | |
| 1479 | /************************************************************************* |
| 1480 | * FindNextFile32A (KERNEL32.126) |
| 1481 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1482 | BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1483 | { |
| 1484 | return FindNextFile16( handle, data ); |
| 1485 | } |
| 1486 | |
| 1487 | |
| 1488 | /************************************************************************* |
| 1489 | * FindNextFile32W (KERNEL32.127) |
| 1490 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1491 | BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1492 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1493 | WIN32_FIND_DATAA dataA; |
| 1494 | if (!FindNextFileA( handle, &dataA )) return FALSE; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1495 | data->dwFileAttributes = dataA.dwFileAttributes; |
| 1496 | data->ftCreationTime = dataA.ftCreationTime; |
| 1497 | data->ftLastAccessTime = dataA.ftLastAccessTime; |
| 1498 | data->ftLastWriteTime = dataA.ftLastWriteTime; |
| 1499 | data->nFileSizeHigh = dataA.nFileSizeHigh; |
| 1500 | data->nFileSizeLow = dataA.nFileSizeLow; |
| 1501 | lstrcpyAtoW( data->cFileName, dataA.cFileName ); |
| 1502 | lstrcpyAtoW( data->cAlternateFileName, dataA.cAlternateFileName ); |
| 1503 | return TRUE; |
| 1504 | } |
| 1505 | |
| 1506 | |
| 1507 | /************************************************************************* |
| 1508 | * FindClose16 (KERNEL.415) |
| 1509 | */ |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 1510 | BOOL16 WINAPI FindClose16( HANDLE16 handle ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1511 | { |
| 1512 | FIND_FIRST_INFO *info; |
| 1513 | |
| 1514 | if ((handle == INVALID_HANDLE_VALUE16) || |
| 1515 | !(info = (FIND_FIRST_INFO *)GlobalLock16( handle ))) |
| 1516 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 1517 | SetLastError( ERROR_INVALID_HANDLE ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1518 | return FALSE; |
| 1519 | } |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1520 | if (info->dir) DOSFS_CloseDir( info->dir ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1521 | if (info->path) HeapFree( SystemHeap, 0, info->path ); |
| 1522 | GlobalUnlock16( handle ); |
| 1523 | GlobalFree16( handle ); |
| 1524 | return TRUE; |
| 1525 | } |
| 1526 | |
| 1527 | |
| 1528 | /************************************************************************* |
| 1529 | * FindClose32 (KERNEL32.119) |
| 1530 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1531 | BOOL WINAPI FindClose( HANDLE handle ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1532 | { |
| 1533 | return FindClose16( (HANDLE16)handle ); |
| 1534 | } |
| 1535 | |
| 1536 | |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1537 | /*********************************************************************** |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1538 | * DOSFS_UnixTimeToFileTime |
| 1539 | * |
| 1540 | * Convert a Unix time to FILETIME format. |
| 1541 | * The FILETIME structure is a 64-bit value representing the number of |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1542 | * 100-nanosecond intervals since January 1, 1601, 0:00. |
| 1543 | * 'remainder' is the nonnegative number of 100-ns intervals |
| 1544 | * corresponding to the time fraction smaller than 1 second that |
| 1545 | * couldn't be stored in the time_t value. |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1546 | */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1547 | void DOSFS_UnixTimeToFileTime( time_t unix_time, FILETIME *filetime, |
| 1548 | DWORD remainder ) |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1549 | { |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1550 | /* NOTES: |
| 1551 | |
| 1552 | CONSTANTS: |
| 1553 | The time difference between 1 January 1601, 00:00:00 and |
| 1554 | 1 January 1970, 00:00:00 is 369 years, plus the leap years |
| 1555 | from 1604 to 1968, excluding 1700, 1800, 1900. |
| 1556 | This makes (1968 - 1600) / 4 - 3 = 89 leap days, and a total |
| 1557 | of 134774 days. |
| 1558 | |
| 1559 | Any day in that period had 24 * 60 * 60 = 86400 seconds. |
| 1560 | |
| 1561 | The time difference is 134774 * 86400 * 10000000, which can be written |
| 1562 | 116444736000000000 |
| 1563 | 27111902 * 2^32 + 3577643008 |
| 1564 | 413 * 2^48 + 45534 * 2^32 + 54590 * 2^16 + 32768 |
| 1565 | |
| 1566 | If you find that these constants are buggy, please change them in all |
| 1567 | instances in both conversion functions. |
| 1568 | |
| 1569 | VERSIONS: |
| 1570 | There are two versions, one of them uses long long variables and |
| 1571 | is presumably faster but not ISO C. The other one uses standard C |
| 1572 | data types and operations but relies on the assumption that negative |
| 1573 | numbers are stored as 2's complement (-1 is 0xffff....). If this |
| 1574 | assumption is violated, dates before 1970 will not convert correctly. |
| 1575 | This should however work on any reasonable architecture where WINE |
| 1576 | will run. |
| 1577 | |
| 1578 | DETAILS: |
| 1579 | |
| 1580 | Take care not to remove the casts. I have tested these functions |
| 1581 | (in both versions) for a lot of numbers. I would be interested in |
| 1582 | results on other compilers than GCC. |
| 1583 | |
| 1584 | The operations have been designed to account for the possibility |
| 1585 | of 64-bit time_t in future UNICES. Even the versions without |
| 1586 | internal long long numbers will work if time_t only is 64 bit. |
| 1587 | A 32-bit shift, which was necessary for that operation, turned out |
| 1588 | not to work correctly in GCC, besides giving the warning. So I |
| 1589 | used a double 16-bit shift instead. Numbers are in the ISO version |
| 1590 | represented by three limbs, the most significant with 32 bit, the |
| 1591 | other two with 16 bit each. |
| 1592 | |
| 1593 | As the modulo-operator % is not well-defined for negative numbers, |
| 1594 | negative divisors have been avoided in DOSFS_FileTimeToUnixTime. |
| 1595 | |
| 1596 | There might be quicker ways to do this in C. Certainly so in |
| 1597 | assembler. |
| 1598 | |
| 1599 | Claus Fischer, fischer@iue.tuwien.ac.at |
| 1600 | */ |
| 1601 | |
Patrik Stridvall | 9633632 | 1999-10-24 22:13:47 +0000 | [diff] [blame] | 1602 | #if SIZEOF_LONG_LONG >= 8 |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1603 | # define USE_LONG_LONG 1 |
| 1604 | #else |
| 1605 | # define USE_LONG_LONG 0 |
| 1606 | #endif |
| 1607 | |
| 1608 | #if USE_LONG_LONG /* gcc supports long long type */ |
| 1609 | |
| 1610 | long long int t = unix_time; |
| 1611 | t *= 10000000; |
| 1612 | t += 116444736000000000LL; |
| 1613 | t += remainder; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1614 | filetime->dwLowDateTime = (UINT)t; |
| 1615 | filetime->dwHighDateTime = (UINT)(t >> 32); |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1616 | |
| 1617 | #else /* ISO version */ |
| 1618 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1619 | UINT a0; /* 16 bit, low bits */ |
| 1620 | UINT a1; /* 16 bit, medium bits */ |
| 1621 | UINT a2; /* 32 bit, high bits */ |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1622 | |
| 1623 | /* Copy the unix time to a2/a1/a0 */ |
| 1624 | a0 = unix_time & 0xffff; |
| 1625 | a1 = (unix_time >> 16) & 0xffff; |
| 1626 | /* This is obsolete if unix_time is only 32 bits, but it does not hurt. |
| 1627 | Do not replace this by >> 32, it gives a compiler warning and it does |
| 1628 | not work. */ |
| 1629 | a2 = (unix_time >= 0 ? (unix_time >> 16) >> 16 : |
| 1630 | ~((~unix_time >> 16) >> 16)); |
| 1631 | |
| 1632 | /* Multiply a by 10000000 (a = a2/a1/a0) |
| 1633 | Split the factor into 10000 * 1000 which are both less than 0xffff. */ |
| 1634 | a0 *= 10000; |
| 1635 | a1 = a1 * 10000 + (a0 >> 16); |
| 1636 | a2 = a2 * 10000 + (a1 >> 16); |
| 1637 | a0 &= 0xffff; |
| 1638 | a1 &= 0xffff; |
| 1639 | |
| 1640 | a0 *= 1000; |
| 1641 | a1 = a1 * 1000 + (a0 >> 16); |
| 1642 | a2 = a2 * 1000 + (a1 >> 16); |
| 1643 | a0 &= 0xffff; |
| 1644 | a1 &= 0xffff; |
| 1645 | |
| 1646 | /* Add the time difference and the remainder */ |
| 1647 | a0 += 32768 + (remainder & 0xffff); |
| 1648 | a1 += 54590 + (remainder >> 16 ) + (a0 >> 16); |
| 1649 | a2 += 27111902 + (a1 >> 16); |
| 1650 | a0 &= 0xffff; |
| 1651 | a1 &= 0xffff; |
| 1652 | |
| 1653 | /* Set filetime */ |
| 1654 | filetime->dwLowDateTime = (a1 << 16) + a0; |
| 1655 | filetime->dwHighDateTime = a2; |
| 1656 | #endif |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1657 | } |
| 1658 | |
| 1659 | |
| 1660 | /*********************************************************************** |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1661 | * DOSFS_FileTimeToUnixTime |
| 1662 | * |
| 1663 | * Convert a FILETIME format to Unix time. |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1664 | * If not NULL, 'remainder' contains the fractional part of the filetime, |
| 1665 | * in the range of [0..9999999] (even if time_t is negative). |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1666 | */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1667 | time_t DOSFS_FileTimeToUnixTime( const FILETIME *filetime, DWORD *remainder ) |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1668 | { |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1669 | /* Read the comment in the function DOSFS_UnixTimeToFileTime. */ |
| 1670 | #if USE_LONG_LONG |
| 1671 | |
| 1672 | long long int t = filetime->dwHighDateTime; |
| 1673 | t <<= 32; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1674 | t += (UINT)filetime->dwLowDateTime; |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1675 | t -= 116444736000000000LL; |
| 1676 | if (t < 0) |
| 1677 | { |
| 1678 | if (remainder) *remainder = 9999999 - (-t - 1) % 10000000; |
| 1679 | return -1 - ((-t - 1) / 10000000); |
| 1680 | } |
| 1681 | else |
| 1682 | { |
| 1683 | if (remainder) *remainder = t % 10000000; |
| 1684 | return t / 10000000; |
| 1685 | } |
| 1686 | |
| 1687 | #else /* ISO version */ |
| 1688 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1689 | UINT a0; /* 16 bit, low bits */ |
| 1690 | UINT a1; /* 16 bit, medium bits */ |
| 1691 | UINT a2; /* 32 bit, high bits */ |
| 1692 | UINT r; /* remainder of division */ |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1693 | unsigned int carry; /* carry bit for subtraction */ |
| 1694 | int negative; /* whether a represents a negative value */ |
| 1695 | |
| 1696 | /* Copy the time values to a2/a1/a0 */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1697 | a2 = (UINT)filetime->dwHighDateTime; |
| 1698 | a1 = ((UINT)filetime->dwLowDateTime ) >> 16; |
| 1699 | a0 = ((UINT)filetime->dwLowDateTime ) & 0xffff; |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1700 | |
| 1701 | /* Subtract the time difference */ |
| 1702 | if (a0 >= 32768 ) a0 -= 32768 , carry = 0; |
| 1703 | else a0 += (1 << 16) - 32768 , carry = 1; |
| 1704 | |
| 1705 | if (a1 >= 54590 + carry) a1 -= 54590 + carry, carry = 0; |
| 1706 | else a1 += (1 << 16) - 54590 - carry, carry = 1; |
| 1707 | |
| 1708 | a2 -= 27111902 + carry; |
| 1709 | |
| 1710 | /* If a is negative, replace a by (-1-a) */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1711 | negative = (a2 >= ((UINT)1) << 31); |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1712 | if (negative) |
| 1713 | { |
| 1714 | /* Set a to -a - 1 (a is a2/a1/a0) */ |
| 1715 | a0 = 0xffff - a0; |
| 1716 | a1 = 0xffff - a1; |
| 1717 | a2 = ~a2; |
| 1718 | } |
| 1719 | |
| 1720 | /* Divide a by 10000000 (a = a2/a1/a0), put the rest into r. |
| 1721 | Split the divisor into 10000 * 1000 which are both less than 0xffff. */ |
| 1722 | a1 += (a2 % 10000) << 16; |
| 1723 | a2 /= 10000; |
| 1724 | a0 += (a1 % 10000) << 16; |
| 1725 | a1 /= 10000; |
| 1726 | r = a0 % 10000; |
| 1727 | a0 /= 10000; |
| 1728 | |
| 1729 | a1 += (a2 % 1000) << 16; |
| 1730 | a2 /= 1000; |
| 1731 | a0 += (a1 % 1000) << 16; |
| 1732 | a1 /= 1000; |
| 1733 | r += (a0 % 1000) * 10000; |
| 1734 | a0 /= 1000; |
| 1735 | |
| 1736 | /* If a was negative, replace a by (-1-a) and r by (9999999 - r) */ |
| 1737 | if (negative) |
| 1738 | { |
| 1739 | /* Set a to -a - 1 (a is a2/a1/a0) */ |
| 1740 | a0 = 0xffff - a0; |
| 1741 | a1 = 0xffff - a1; |
| 1742 | a2 = ~a2; |
| 1743 | |
| 1744 | r = 9999999 - r; |
| 1745 | } |
| 1746 | |
| 1747 | if (remainder) *remainder = r; |
| 1748 | |
| 1749 | /* Do not replace this by << 32, it gives a compiler warning and it does |
| 1750 | not work. */ |
| 1751 | return ((((time_t)a2) << 16) << 16) + (a1 << 16) + a0; |
| 1752 | #endif |
Alexandre Julliard | b1bac32 | 1996-12-15 19:45:59 +0000 | [diff] [blame] | 1753 | } |
| 1754 | |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1755 | |
| 1756 | /*********************************************************************** |
| 1757 | * DosDateTimeToFileTime (KERNEL32.76) |
| 1758 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1759 | BOOL WINAPI DosDateTimeToFileTime( WORD fatdate, WORD fattime, LPFILETIME ft) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1760 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1761 | struct tm newtm; |
| 1762 | |
| 1763 | newtm.tm_sec = (fattime & 0x1f) * 2; |
| 1764 | newtm.tm_min = (fattime >> 5) & 0x3f; |
| 1765 | newtm.tm_hour = (fattime >> 11); |
| 1766 | newtm.tm_mday = (fatdate & 0x1f); |
| 1767 | newtm.tm_mon = ((fatdate >> 5) & 0x0f) - 1; |
| 1768 | newtm.tm_year = (fatdate >> 9) + 80; |
| 1769 | DOSFS_UnixTimeToFileTime( mktime( &newtm ), ft, 0 ); |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1770 | return TRUE; |
| 1771 | } |
| 1772 | |
| 1773 | |
| 1774 | /*********************************************************************** |
| 1775 | * FileTimeToDosDateTime (KERNEL32.111) |
| 1776 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1777 | BOOL WINAPI FileTimeToDosDateTime( const FILETIME *ft, LPWORD fatdate, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 1778 | LPWORD fattime ) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1779 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1780 | time_t unixtime = DOSFS_FileTimeToUnixTime( ft, NULL ); |
| 1781 | struct tm *tm = localtime( &unixtime ); |
| 1782 | if (fattime) |
| 1783 | *fattime = (tm->tm_hour << 11) + (tm->tm_min << 5) + (tm->tm_sec / 2); |
| 1784 | if (fatdate) |
| 1785 | *fatdate = ((tm->tm_year - 80) << 9) + ((tm->tm_mon + 1) << 5) |
| 1786 | + tm->tm_mday; |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1787 | return TRUE; |
| 1788 | } |
| 1789 | |
| 1790 | |
| 1791 | /*********************************************************************** |
| 1792 | * LocalFileTimeToFileTime (KERNEL32.373) |
| 1793 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1794 | BOOL WINAPI LocalFileTimeToFileTime( const FILETIME *localft, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 1795 | LPFILETIME utcft ) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1796 | { |
| 1797 | struct tm *xtm; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1798 | DWORD remainder; |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1799 | |
| 1800 | /* convert from local to UTC. Perhaps not correct. FIXME */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1801 | time_t unixtime = DOSFS_FileTimeToUnixTime( localft, &remainder ); |
| 1802 | xtm = gmtime( &unixtime ); |
| 1803 | DOSFS_UnixTimeToFileTime( mktime(xtm), utcft, remainder ); |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1804 | return TRUE; |
| 1805 | } |
| 1806 | |
| 1807 | |
| 1808 | /*********************************************************************** |
| 1809 | * FileTimeToLocalFileTime (KERNEL32.112) |
| 1810 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1811 | BOOL WINAPI FileTimeToLocalFileTime( const FILETIME *utcft, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 1812 | LPFILETIME localft ) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1813 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1814 | DWORD remainder; |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1815 | /* convert from UTC to local. Perhaps not correct. FIXME */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1816 | time_t unixtime = DOSFS_FileTimeToUnixTime( utcft, &remainder ); |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 1817 | #ifdef HAVE_TIMEGM |
| 1818 | struct tm *xtm = localtime( &unixtime ); |
| 1819 | time_t localtime; |
| 1820 | |
| 1821 | localtime = timegm(xtm); |
| 1822 | DOSFS_UnixTimeToFileTime( localtime, localft, remainder ); |
| 1823 | |
| 1824 | #else |
| 1825 | struct tm *xtm,*gtm; |
| 1826 | time_t time1,time2; |
| 1827 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1828 | xtm = localtime( &unixtime ); |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 1829 | gtm = gmtime( &unixtime ); |
| 1830 | time1 = mktime(xtm); |
| 1831 | time2 = mktime(gtm); |
| 1832 | DOSFS_UnixTimeToFileTime( 2*time1-time2, localft, remainder ); |
| 1833 | #endif |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1834 | return TRUE; |
| 1835 | } |
| 1836 | |
| 1837 | |
| 1838 | /*********************************************************************** |
| 1839 | * FileTimeToSystemTime (KERNEL32.113) |
| 1840 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1841 | BOOL WINAPI FileTimeToSystemTime( const FILETIME *ft, LPSYSTEMTIME syst ) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1842 | { |
| 1843 | struct tm *xtm; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1844 | DWORD remainder; |
| 1845 | time_t xtime = DOSFS_FileTimeToUnixTime( ft, &remainder ); |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1846 | xtm = gmtime(&xtime); |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 1847 | syst->wYear = xtm->tm_year+1900; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 1848 | syst->wMonth = xtm->tm_mon + 1; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1849 | syst->wDayOfWeek = xtm->tm_wday; |
| 1850 | syst->wDay = xtm->tm_mday; |
| 1851 | syst->wHour = xtm->tm_hour; |
| 1852 | syst->wMinute = xtm->tm_min; |
| 1853 | syst->wSecond = xtm->tm_sec; |
| 1854 | syst->wMilliseconds = remainder / 10000; |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1855 | return TRUE; |
| 1856 | } |
| 1857 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1858 | /*********************************************************************** |
| 1859 | * QueryDosDeviceA (KERNEL32.413) |
| 1860 | * |
| 1861 | * returns array of strings terminated by \0, terminated by \0 |
| 1862 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1863 | DWORD WINAPI QueryDosDeviceA(LPCSTR devname,LPSTR target,DWORD bufsize) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1864 | { |
| 1865 | LPSTR s; |
| 1866 | char buffer[200]; |
| 1867 | |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 1868 | TRACE_(dosfs)("(%s,...)\n",devname?devname:"<null>"); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1869 | if (!devname) { |
| 1870 | /* return known MSDOS devices */ |
Alexandre Julliard | 89f079b | 1999-08-08 18:54:47 +0000 | [diff] [blame] | 1871 | strcpy(buffer,"CON COM1 COM2 LPT1 NUL "); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1872 | while ((s=strchr(buffer,' '))) |
| 1873 | *s='\0'; |
| 1874 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1875 | lstrcpynA(target,buffer,bufsize); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1876 | return strlen(buffer); |
| 1877 | } |
Alexandre Julliard | 89f079b | 1999-08-08 18:54:47 +0000 | [diff] [blame] | 1878 | strcpy(buffer,"\\DEV\\"); |
| 1879 | strcat(buffer,devname); |
Alexandre Julliard | 01d6346 | 1997-01-20 19:43:45 +0000 | [diff] [blame] | 1880 | if ((s=strchr(buffer,':'))) *s='\0'; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1881 | lstrcpynA(target,buffer,bufsize); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1882 | return strlen(buffer); |
| 1883 | } |
| 1884 | |
| 1885 | |
| 1886 | /*********************************************************************** |
| 1887 | * QueryDosDeviceW (KERNEL32.414) |
| 1888 | * |
| 1889 | * returns array of strings terminated by \0, terminated by \0 |
| 1890 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1891 | DWORD WINAPI QueryDosDeviceW(LPCWSTR devname,LPWSTR target,DWORD bufsize) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1892 | { |
| 1893 | LPSTR devnameA = devname?HEAP_strdupWtoA(GetProcessHeap(),0,devname):NULL; |
| 1894 | LPSTR targetA = (LPSTR)HEAP_xalloc(GetProcessHeap(),0,bufsize); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1895 | DWORD ret = QueryDosDeviceA(devnameA,targetA,bufsize); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1896 | |
| 1897 | lstrcpynAtoW(target,targetA,bufsize); |
| 1898 | if (devnameA) HeapFree(GetProcessHeap(),0,devnameA); |
| 1899 | if (targetA) HeapFree(GetProcessHeap(),0,targetA); |
| 1900 | return ret; |
| 1901 | } |
| 1902 | |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1903 | |
| 1904 | /*********************************************************************** |
| 1905 | * SystemTimeToFileTime (KERNEL32.526) |
| 1906 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1907 | BOOL WINAPI SystemTimeToFileTime( const SYSTEMTIME *syst, LPFILETIME ft ) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1908 | { |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 1909 | #ifdef HAVE_TIMEGM |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1910 | struct tm xtm; |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 1911 | time_t utctime; |
| 1912 | #else |
| 1913 | struct tm xtm,*local_tm,*utc_tm; |
| 1914 | time_t localtim,utctime; |
| 1915 | #endif |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1916 | |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 1917 | xtm.tm_year = syst->wYear-1900; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 1918 | xtm.tm_mon = syst->wMonth - 1; |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1919 | xtm.tm_wday = syst->wDayOfWeek; |
| 1920 | xtm.tm_mday = syst->wDay; |
| 1921 | xtm.tm_hour = syst->wHour; |
| 1922 | xtm.tm_min = syst->wMinute; |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 1923 | xtm.tm_sec = syst->wSecond; /* this is UTC */ |
| 1924 | xtm.tm_isdst = -1; |
| 1925 | #ifdef HAVE_TIMEGM |
| 1926 | utctime = timegm(&xtm); |
| 1927 | DOSFS_UnixTimeToFileTime( utctime, ft, |
| 1928 | syst->wMilliseconds * 10000 ); |
| 1929 | #else |
| 1930 | localtim = mktime(&xtm); /* now we've got local time */ |
| 1931 | local_tm = localtime(&localtim); |
| 1932 | utc_tm = gmtime(&localtim); |
| 1933 | utctime = mktime(utc_tm); |
| 1934 | DOSFS_UnixTimeToFileTime( 2*localtim -utctime, ft, |
| 1935 | syst->wMilliseconds * 10000 ); |
| 1936 | #endif |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 1937 | return TRUE; |
| 1938 | } |
Marcus Meissner | 575a165 | 1998-10-21 16:47:29 +0000 | [diff] [blame] | 1939 | |
Patrik Stridvall | 3a9c476 | 1999-10-31 02:07:05 +0000 | [diff] [blame] | 1940 | /*********************************************************************** |
| 1941 | * DefineDosDeviceA (KERNEL32.182) |
| 1942 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1943 | BOOL WINAPI DefineDosDeviceA(DWORD flags,LPCSTR devname,LPCSTR targetpath) { |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 1944 | FIXME_(dosfs)("(0x%08lx,%s,%s),stub!\n",flags,devname,targetpath); |
Marcus Meissner | 575a165 | 1998-10-21 16:47:29 +0000 | [diff] [blame] | 1945 | SetLastError(ERROR_CALL_NOT_IMPLEMENTED); |
| 1946 | return FALSE; |
| 1947 | } |