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" |
Patrik Stridvall | 33929be | 2001-07-18 21:04:23 +0000 | [diff] [blame] | 9 | |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 10 | #include <sys/types.h> |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 11 | #include <ctype.h> |
| 12 | #include <dirent.h> |
Alexandre Julliard | 44ed71f | 1997-12-21 19:17:50 +0000 | [diff] [blame] | 13 | #include <errno.h> |
Howard Abrams | 1327748 | 1999-07-10 13:16:29 +0000 | [diff] [blame] | 14 | #ifdef HAVE_SYS_ERRNO_H |
Alexandre Julliard | d30dfd2 | 1998-09-27 18:28:36 +0000 | [diff] [blame] | 15 | #include <sys/errno.h> |
Howard Abrams | 1327748 | 1999-07-10 13:16:29 +0000 | [diff] [blame] | 16 | #endif |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 17 | #include <fcntl.h> |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 18 | #include <string.h> |
| 19 | #include <stdlib.h> |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 20 | #include <sys/stat.h> |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 21 | #include <sys/ioctl.h> |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 22 | #include <time.h> |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 23 | #include <unistd.h> |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 24 | |
Marcus Meissner | 317af32 | 1999-02-17 13:51:06 +0000 | [diff] [blame] | 25 | #include "windef.h" |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 26 | #include "winerror.h" |
Patrik Stridvall | 33929be | 2001-07-18 21:04:23 +0000 | [diff] [blame] | 27 | #include "wingdi.h" |
| 28 | |
| 29 | #include "wine/unicode.h" |
| 30 | #include "wine/winbase16.h" |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 31 | #include "drive.h" |
| 32 | #include "file.h" |
Alexandre Julliard | 7ebe1a4 | 1996-12-22 18:27:48 +0000 | [diff] [blame] | 33 | #include "heap.h" |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 34 | #include "msdos.h" |
Patrik Stridvall | 33929be | 2001-07-18 21:04:23 +0000 | [diff] [blame] | 35 | #include "ntddk.h" |
Marcus Meissner | 6b9dd2e | 1999-03-18 17:39:57 +0000 | [diff] [blame] | 36 | #include "options.h" |
Alexandre Julliard | 37e9503 | 2001-07-19 00:39:09 +0000 | [diff] [blame] | 37 | #include "wine/server.h" |
Patrik Stridvall | 33929be | 2001-07-18 21:04:23 +0000 | [diff] [blame] | 38 | |
Alexandre Julliard | 06c275a | 1999-05-02 14:32:27 +0000 | [diff] [blame] | 39 | #include "debugtools.h" |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 40 | |
Alexandre Julliard | 5ab9d86 | 2000-08-09 22:35:05 +0000 | [diff] [blame] | 41 | DEFAULT_DEBUG_CHANNEL(dosfs); |
| 42 | DECLARE_DEBUG_CHANNEL(file); |
Patrik Stridvall | b4b9fae | 1999-04-19 14:56:29 +0000 | [diff] [blame] | 43 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 44 | /* Define the VFAT ioctl to get both short and long file names */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 45 | /* FIXME: is it possible to get this to work on other systems? */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 46 | #ifdef linux |
Alexandre Julliard | df2673b | 1997-03-29 17:20:20 +0000 | [diff] [blame] | 47 | /* We want the real kernel dirent structure, not the libc one */ |
| 48 | typedef struct |
| 49 | { |
| 50 | long d_ino; |
| 51 | long d_off; |
| 52 | unsigned short d_reclen; |
| 53 | char d_name[256]; |
| 54 | } KERNEL_DIRENT; |
| 55 | |
Peter Ganten | 0bac5e9 | 1999-09-27 11:46:27 +0000 | [diff] [blame] | 56 | #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, KERNEL_DIRENT [2] ) |
| 57 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 58 | #else /* linux */ |
| 59 | #undef VFAT_IOCTL_READDIR_BOTH /* just in case... */ |
| 60 | #endif /* linux */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 61 | |
| 62 | /* Chars we don't want to see in DOS file names */ |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 63 | #define INVALID_DOS_CHARS "*?<>|\"+=,;[] \345" |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 64 | |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 65 | static const DOS_DEVICE DOSFS_Devices[] = |
| 66 | /* name, device flags (see Int 21/AX=0x4400) */ |
| 67 | { |
| 68 | { "CON", 0xc0d3 }, |
| 69 | { "PRN", 0xa0c0 }, |
| 70 | { "NUL", 0x80c4 }, |
| 71 | { "AUX", 0x80c0 }, |
| 72 | { "LPT1", 0xa0c0 }, |
| 73 | { "LPT2", 0xa0c0 }, |
| 74 | { "LPT3", 0xa0c0 }, |
| 75 | { "LPT4", 0xc0d3 }, |
| 76 | { "COM1", 0x80c0 }, |
| 77 | { "COM2", 0x80c0 }, |
| 78 | { "COM3", 0x80c0 }, |
| 79 | { "COM4", 0x80c0 }, |
| 80 | { "SCSIMGR$", 0xc0c0 }, |
| 81 | { "HPSCAN", 0xc0c0 } |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 82 | }; |
| 83 | |
| 84 | #define GET_DRIVE(path) \ |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 85 | (((path)[1] == ':') ? FILE_toupper((path)[0]) - 'A' : DOSFS_CurDrive) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 86 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 87 | /* Directory info for DOSFS_ReadDir */ |
| 88 | typedef struct |
| 89 | { |
| 90 | DIR *dir; |
| 91 | #ifdef VFAT_IOCTL_READDIR_BOTH |
| 92 | int fd; |
| 93 | char short_name[12]; |
Alexandre Julliard | df2673b | 1997-03-29 17:20:20 +0000 | [diff] [blame] | 94 | KERNEL_DIRENT dirent[2]; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 95 | #endif |
| 96 | } DOS_DIR; |
| 97 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 98 | /* Info structure for FindFirstFile handle */ |
| 99 | typedef struct |
| 100 | { |
| 101 | LPSTR path; |
| 102 | LPSTR long_mask; |
| 103 | LPSTR short_mask; |
| 104 | BYTE attr; |
| 105 | int drive; |
| 106 | int cur_pos; |
| 107 | DOS_DIR *dir; |
| 108 | } FIND_FIRST_INFO; |
| 109 | |
| 110 | |
Dominik Strasser | 4f46b5d | 2001-04-20 18:38:41 +0000 | [diff] [blame] | 111 | static WINE_EXCEPTION_FILTER(page_fault) |
| 112 | { |
| 113 | if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) |
| 114 | return EXCEPTION_EXECUTE_HANDLER; |
| 115 | return EXCEPTION_CONTINUE_SEARCH; |
| 116 | } |
| 117 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 118 | |
| 119 | /*********************************************************************** |
| 120 | * DOSFS_ValidDOSName |
| 121 | * |
| 122 | * Return 1 if Unix file 'name' is also a valid MS-DOS name |
| 123 | * (i.e. contains only valid DOS chars, lower-case only, fits in 8.3 format). |
| 124 | * File name can be terminated by '\0', '\\' or '/'. |
| 125 | */ |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 126 | static int DOSFS_ValidDOSName( const char *name, int ignore_case ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 127 | { |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 128 | static const char invalid_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" INVALID_DOS_CHARS; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 129 | const char *p = name; |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 130 | const char *invalid = ignore_case ? (invalid_chars + 26) : invalid_chars; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 131 | int len = 0; |
| 132 | |
| 133 | if (*p == '.') |
| 134 | { |
| 135 | /* Check for "." and ".." */ |
| 136 | p++; |
| 137 | if (*p == '.') p++; |
| 138 | /* All other names beginning with '.' are invalid */ |
| 139 | return (IS_END_OF_NAME(*p)); |
| 140 | } |
| 141 | while (!IS_END_OF_NAME(*p)) |
| 142 | { |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 143 | if (strchr( invalid, *p )) return 0; /* Invalid char */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 144 | if (*p == '.') break; /* Start of the extension */ |
| 145 | if (++len > 8) return 0; /* Name too long */ |
| 146 | p++; |
| 147 | } |
| 148 | if (*p != '.') return 1; /* End of name */ |
| 149 | p++; |
| 150 | if (IS_END_OF_NAME(*p)) return 0; /* Empty extension not allowed */ |
| 151 | len = 0; |
| 152 | while (!IS_END_OF_NAME(*p)) |
| 153 | { |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 154 | if (strchr( invalid, *p )) return 0; /* Invalid char */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 155 | if (*p == '.') return 0; /* Second extension not allowed */ |
| 156 | if (++len > 3) return 0; /* Extension too long */ |
| 157 | p++; |
| 158 | } |
| 159 | return 1; |
| 160 | } |
| 161 | |
| 162 | |
| 163 | /*********************************************************************** |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 164 | * DOSFS_ToDosFCBFormat |
| 165 | * |
| 166 | * Convert a file name to DOS FCB format (8+3 chars, padded with blanks), |
| 167 | * expanding wild cards and converting to upper-case in the process. |
| 168 | * File name can be terminated by '\0', '\\' or '/'. |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 169 | * Return FALSE if the name is not a valid DOS name. |
| 170 | * 'buffer' must be at least 12 characters long. |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 171 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 172 | BOOL DOSFS_ToDosFCBFormat( LPCSTR name, LPSTR buffer ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 173 | { |
| 174 | static const char invalid_chars[] = INVALID_DOS_CHARS; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 175 | const char *p = name; |
| 176 | int i; |
| 177 | |
| 178 | /* Check for "." and ".." */ |
| 179 | if (*p == '.') |
| 180 | { |
| 181 | p++; |
| 182 | strcpy( buffer, ". " ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 183 | if (*p == '.') |
| 184 | { |
| 185 | buffer[1] = '.'; |
| 186 | p++; |
| 187 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 188 | return (!*p || (*p == '/') || (*p == '\\')); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 189 | } |
| 190 | |
| 191 | for (i = 0; i < 8; i++) |
| 192 | { |
| 193 | switch(*p) |
| 194 | { |
| 195 | case '\0': |
| 196 | case '\\': |
| 197 | case '/': |
| 198 | case '.': |
| 199 | buffer[i] = ' '; |
| 200 | break; |
| 201 | case '?': |
| 202 | p++; |
| 203 | /* fall through */ |
| 204 | case '*': |
| 205 | buffer[i] = '?'; |
| 206 | break; |
| 207 | default: |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 208 | if (strchr( invalid_chars, *p )) return FALSE; |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 209 | buffer[i] = FILE_toupper(*p); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 210 | p++; |
| 211 | break; |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | if (*p == '*') |
| 216 | { |
| 217 | /* Skip all chars after wildcard up to first dot */ |
| 218 | while (*p && (*p != '/') && (*p != '\\') && (*p != '.')) p++; |
| 219 | } |
| 220 | else |
| 221 | { |
| 222 | /* Check if name too long */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 223 | if (*p && (*p != '/') && (*p != '\\') && (*p != '.')) return FALSE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 224 | } |
| 225 | if (*p == '.') p++; /* Skip dot */ |
| 226 | |
| 227 | for (i = 8; i < 11; i++) |
| 228 | { |
| 229 | switch(*p) |
| 230 | { |
| 231 | case '\0': |
| 232 | case '\\': |
| 233 | case '/': |
| 234 | buffer[i] = ' '; |
| 235 | break; |
| 236 | case '.': |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 237 | return FALSE; /* Second extension not allowed */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 238 | case '?': |
| 239 | p++; |
| 240 | /* fall through */ |
| 241 | case '*': |
| 242 | buffer[i] = '?'; |
| 243 | break; |
| 244 | default: |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 245 | if (strchr( invalid_chars, *p )) return FALSE; |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 246 | buffer[i] = FILE_toupper(*p); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 247 | p++; |
| 248 | break; |
| 249 | } |
| 250 | } |
| 251 | buffer[11] = '\0'; |
Stefan Leichter | 7cc51fa | 2000-03-26 20:25:59 +0000 | [diff] [blame] | 252 | |
| 253 | /* at most 3 character of the extension are processed |
| 254 | * is something behind this ? |
| 255 | */ |
Alexandre Julliard | 199aeba | 2000-03-28 13:20:32 +0000 | [diff] [blame] | 256 | while (*p == '*' || *p == ' ') p++; /* skip wildcards and spaces */ |
Stefan Leichter | 7cc51fa | 2000-03-26 20:25:59 +0000 | [diff] [blame] | 257 | return IS_END_OF_NAME(*p); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 258 | } |
| 259 | |
| 260 | |
| 261 | /*********************************************************************** |
| 262 | * DOSFS_ToDosDTAFormat |
| 263 | * |
| 264 | * Convert a file name from FCB to DTA format (name.ext, null-terminated) |
| 265 | * converting to upper-case in the process. |
| 266 | * File name can be terminated by '\0', '\\' or '/'. |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 267 | * 'buffer' must be at least 13 characters long. |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 268 | */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 269 | static void DOSFS_ToDosDTAFormat( LPCSTR name, LPSTR buffer ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 270 | { |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 271 | char *p; |
| 272 | |
| 273 | memcpy( buffer, name, 8 ); |
Alexandre Julliard | 566a52a | 2001-03-05 19:34:17 +0000 | [diff] [blame] | 274 | p = buffer + 8; |
| 275 | while ((p > buffer) && (p[-1] == ' ')) p--; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 276 | *p++ = '.'; |
| 277 | memcpy( p, name + 8, 3 ); |
Alexandre Julliard | 566a52a | 2001-03-05 19:34:17 +0000 | [diff] [blame] | 278 | p += 3; |
| 279 | while (p[-1] == ' ') p--; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 280 | if (p[-1] == '.') p--; |
| 281 | *p = '\0'; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 282 | } |
| 283 | |
| 284 | |
| 285 | /*********************************************************************** |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 286 | * DOSFS_MatchShort |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 287 | * |
| 288 | * Check a DOS file name against a mask (both in FCB format). |
| 289 | */ |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 290 | static int DOSFS_MatchShort( const char *mask, const char *name ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 291 | { |
| 292 | int i; |
| 293 | for (i = 11; i > 0; i--, mask++, name++) |
| 294 | if ((*mask != '?') && (*mask != *name)) return 0; |
| 295 | return 1; |
| 296 | } |
| 297 | |
| 298 | |
| 299 | /*********************************************************************** |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 300 | * DOSFS_MatchLong |
| 301 | * |
| 302 | * Check a long file name against a mask. |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 303 | * |
| 304 | * Tests (done in W95 DOS shell - case insensitive): |
| 305 | * *.txt test1.test.txt * |
| 306 | * *st1* test1.txt * |
| 307 | * *.t??????.t* test1.ta.tornado.txt * |
| 308 | * *tornado* test1.ta.tornado.txt * |
| 309 | * t*t test1.ta.tornado.txt * |
| 310 | * ?est* test1.txt * |
| 311 | * ?est??? test1.txt - |
| 312 | * *test1.txt* test1.txt * |
| 313 | * h?l?o*t.dat hellothisisatest.dat * |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 314 | */ |
| 315 | static int DOSFS_MatchLong( const char *mask, const char *name, |
| 316 | int case_sensitive ) |
| 317 | { |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 318 | const char *lastjoker = NULL; |
| 319 | const char *next_to_retry = NULL; |
| 320 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 321 | if (!strcmp( mask, "*.*" )) return 1; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 322 | while (*name && *mask) |
| 323 | { |
| 324 | if (*mask == '*') |
| 325 | { |
| 326 | mask++; |
| 327 | while (*mask == '*') mask++; /* Skip consecutive '*' */ |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 328 | lastjoker = mask; |
| 329 | if (!*mask) return 1; /* end of mask is all '*', so match */ |
| 330 | |
| 331 | /* skip to the next match after the joker(s) */ |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 332 | if (case_sensitive) while (*name && (*name != *mask)) name++; |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 333 | else while (*name && (FILE_toupper(*name) != FILE_toupper(*mask))) name++; |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 334 | |
Robert W Hall | 9132a78 | 1999-04-18 14:38:17 +0000 | [diff] [blame] | 335 | if (!*name) break; |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 336 | next_to_retry = name; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 337 | } |
| 338 | else if (*mask != '?') |
| 339 | { |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 340 | int mismatch = 0; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 341 | if (case_sensitive) |
| 342 | { |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 343 | if (*mask != *name) mismatch = 1; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 344 | } |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 345 | else |
| 346 | { |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 347 | if (FILE_toupper(*mask) != FILE_toupper(*name)) mismatch = 1; |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 348 | } |
| 349 | if (!mismatch) |
| 350 | { |
| 351 | mask++; |
| 352 | name++; |
| 353 | if (*mask == '\0') |
| 354 | { |
| 355 | if (*name == '\0') |
| 356 | return 1; |
| 357 | if (lastjoker) |
| 358 | mask = lastjoker; |
| 359 | } |
| 360 | } |
| 361 | else /* mismatch ! */ |
| 362 | { |
| 363 | if (lastjoker) /* we had an '*', so we can try unlimitedly */ |
| 364 | { |
| 365 | mask = lastjoker; |
| 366 | |
| 367 | /* this scan sequence was a mismatch, so restart |
| 368 | * 1 char after the first char we checked last time */ |
| 369 | next_to_retry++; |
| 370 | name = next_to_retry; |
| 371 | } |
| 372 | else |
| 373 | return 0; /* bad luck */ |
| 374 | } |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 375 | } |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 376 | else /* '?' */ |
| 377 | { |
| 378 | mask++; |
| 379 | name++; |
| 380 | } |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 381 | } |
Andreas Mohr | 0729105 | 2000-09-07 21:03:02 +0000 | [diff] [blame] | 382 | while ((*mask == '.') || (*mask == '*')) |
| 383 | mask++; /* Ignore trailing '.' or '*' in mask */ |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 384 | return (!*name && !*mask); |
| 385 | } |
| 386 | |
| 387 | |
| 388 | /*********************************************************************** |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 389 | * DOSFS_OpenDir |
| 390 | */ |
| 391 | static DOS_DIR *DOSFS_OpenDir( LPCSTR path ) |
| 392 | { |
Alexandre Julliard | 90476d6 | 2000-02-16 22:47:24 +0000 | [diff] [blame] | 393 | DOS_DIR *dir = HeapAlloc( GetProcessHeap(), 0, sizeof(*dir) ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 394 | if (!dir) |
| 395 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 396 | SetLastError( ERROR_NOT_ENOUGH_MEMORY ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 397 | return NULL; |
| 398 | } |
| 399 | |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 400 | /* Treat empty path as root directory. This simplifies path split into |
| 401 | directory and mask in several other places */ |
| 402 | if (!*path) path = "/"; |
| 403 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 404 | #ifdef VFAT_IOCTL_READDIR_BOTH |
| 405 | |
| 406 | /* Check if the VFAT ioctl is supported on this directory */ |
| 407 | |
| 408 | if ((dir->fd = open( path, O_RDONLY )) != -1) |
| 409 | { |
| 410 | if (ioctl( dir->fd, VFAT_IOCTL_READDIR_BOTH, (long)dir->dirent ) == -1) |
| 411 | { |
| 412 | close( dir->fd ); |
| 413 | dir->fd = -1; |
| 414 | } |
| 415 | else |
| 416 | { |
| 417 | /* Set the file pointer back at the start of the directory */ |
| 418 | lseek( dir->fd, 0, SEEK_SET ); |
| 419 | dir->dir = NULL; |
| 420 | return dir; |
| 421 | } |
| 422 | } |
| 423 | #endif /* VFAT_IOCTL_READDIR_BOTH */ |
| 424 | |
| 425 | /* Now use the standard opendir/readdir interface */ |
| 426 | |
| 427 | if (!(dir->dir = opendir( path ))) |
| 428 | { |
Alexandre Julliard | 90476d6 | 2000-02-16 22:47:24 +0000 | [diff] [blame] | 429 | HeapFree( GetProcessHeap(), 0, dir ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 430 | return NULL; |
| 431 | } |
| 432 | return dir; |
| 433 | } |
| 434 | |
| 435 | |
| 436 | /*********************************************************************** |
| 437 | * DOSFS_CloseDir |
| 438 | */ |
| 439 | static void DOSFS_CloseDir( DOS_DIR *dir ) |
| 440 | { |
| 441 | #ifdef VFAT_IOCTL_READDIR_BOTH |
| 442 | if (dir->fd != -1) close( dir->fd ); |
| 443 | #endif /* VFAT_IOCTL_READDIR_BOTH */ |
| 444 | if (dir->dir) closedir( dir->dir ); |
Alexandre Julliard | 90476d6 | 2000-02-16 22:47:24 +0000 | [diff] [blame] | 445 | HeapFree( GetProcessHeap(), 0, dir ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 446 | } |
| 447 | |
| 448 | |
| 449 | /*********************************************************************** |
| 450 | * DOSFS_ReadDir |
| 451 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 452 | static BOOL DOSFS_ReadDir( DOS_DIR *dir, LPCSTR *long_name, |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 453 | LPCSTR *short_name ) |
| 454 | { |
| 455 | struct dirent *dirent; |
| 456 | |
| 457 | #ifdef VFAT_IOCTL_READDIR_BOTH |
| 458 | if (dir->fd != -1) |
| 459 | { |
Alexandre Julliard | 44ed71f | 1997-12-21 19:17:50 +0000 | [diff] [blame] | 460 | if (ioctl( dir->fd, VFAT_IOCTL_READDIR_BOTH, (long)dir->dirent ) != -1) { |
| 461 | if (!dir->dirent[0].d_reclen) return FALSE; |
| 462 | if (!DOSFS_ToDosFCBFormat( dir->dirent[0].d_name, dir->short_name )) |
| 463 | dir->short_name[0] = '\0'; |
| 464 | *short_name = dir->short_name; |
| 465 | if (dir->dirent[1].d_name[0]) *long_name = dir->dirent[1].d_name; |
| 466 | else *long_name = dir->dirent[0].d_name; |
| 467 | return TRUE; |
| 468 | } |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 469 | } |
| 470 | #endif /* VFAT_IOCTL_READDIR_BOTH */ |
| 471 | |
| 472 | if (!(dirent = readdir( dir->dir ))) return FALSE; |
| 473 | *long_name = dirent->d_name; |
| 474 | *short_name = NULL; |
| 475 | return TRUE; |
| 476 | } |
| 477 | |
| 478 | |
| 479 | /*********************************************************************** |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 480 | * DOSFS_Hash |
| 481 | * |
| 482 | * Transform a Unix file name into a hashed DOS name. If the name is a valid |
| 483 | * DOS name, it is converted to upper-case; otherwise it is replaced by a |
| 484 | * hashed version that fits in 8.3 format. |
| 485 | * File name can be terminated by '\0', '\\' or '/'. |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 486 | * 'buffer' must be at least 13 characters long. |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 487 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 488 | static void DOSFS_Hash( LPCSTR name, LPSTR buffer, BOOL dir_format, |
| 489 | BOOL ignore_case ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 490 | { |
| 491 | static const char invalid_chars[] = INVALID_DOS_CHARS "~."; |
| 492 | static const char hash_chars[32] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"; |
| 493 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 494 | const char *p, *ext; |
| 495 | char *dst; |
| 496 | unsigned short hash; |
| 497 | int i; |
| 498 | |
| 499 | if (dir_format) strcpy( buffer, " " ); |
| 500 | |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 501 | if (DOSFS_ValidDOSName( name, ignore_case )) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 502 | { |
| 503 | /* Check for '.' and '..' */ |
| 504 | if (*name == '.') |
| 505 | { |
| 506 | buffer[0] = '.'; |
| 507 | if (!dir_format) buffer[1] = buffer[2] = '\0'; |
| 508 | if (name[1] == '.') buffer[1] = '.'; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 509 | return; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 510 | } |
| 511 | |
| 512 | /* Simply copy the name, converting to uppercase */ |
| 513 | |
| 514 | for (dst = buffer; !IS_END_OF_NAME(*name) && (*name != '.'); name++) |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 515 | *dst++ = FILE_toupper(*name); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 516 | if (*name == '.') |
| 517 | { |
| 518 | if (dir_format) dst = buffer + 8; |
| 519 | else *dst++ = '.'; |
| 520 | for (name++; !IS_END_OF_NAME(*name); name++) |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 521 | *dst++ = FILE_toupper(*name); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 522 | } |
| 523 | if (!dir_format) *dst = '\0'; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 524 | return; |
| 525 | } |
| 526 | |
| 527 | /* Compute the hash code of the file name */ |
| 528 | /* If you know something about hash functions, feel free to */ |
| 529 | /* insert a better algorithm here... */ |
| 530 | if (ignore_case) |
| 531 | { |
| 532 | for (p = name, hash = 0xbeef; !IS_END_OF_NAME(p[1]); p++) |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 533 | hash = (hash<<3) ^ (hash>>5) ^ FILE_tolower(*p) ^ (FILE_tolower(p[1]) << 8); |
| 534 | hash = (hash<<3) ^ (hash>>5) ^ FILE_tolower(*p); /* Last character*/ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 535 | } |
| 536 | else |
| 537 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 538 | for (p = name, hash = 0xbeef; !IS_END_OF_NAME(p[1]); p++) |
| 539 | hash = (hash << 3) ^ (hash >> 5) ^ *p ^ (p[1] << 8); |
| 540 | hash = (hash << 3) ^ (hash >> 5) ^ *p; /* Last character */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 541 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 542 | |
| 543 | /* Find last dot for start of the extension */ |
| 544 | for (p = name+1, ext = NULL; !IS_END_OF_NAME(*p); p++) |
| 545 | if (*p == '.') ext = p; |
| 546 | if (ext && IS_END_OF_NAME(ext[1])) |
| 547 | ext = NULL; /* Empty extension ignored */ |
| 548 | |
| 549 | /* Copy first 4 chars, replacing invalid chars with '_' */ |
| 550 | for (i = 4, p = name, dst = buffer; i > 0; i--, p++) |
| 551 | { |
| 552 | if (IS_END_OF_NAME(*p) || (p == ext)) break; |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 553 | *dst++ = strchr( invalid_chars, *p ) ? '_' : FILE_toupper(*p); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 554 | } |
| 555 | /* Pad to 5 chars with '~' */ |
| 556 | while (i-- >= 0) *dst++ = '~'; |
| 557 | |
| 558 | /* Insert hash code converted to 3 ASCII chars */ |
| 559 | *dst++ = hash_chars[(hash >> 10) & 0x1f]; |
| 560 | *dst++ = hash_chars[(hash >> 5) & 0x1f]; |
| 561 | *dst++ = hash_chars[hash & 0x1f]; |
| 562 | |
| 563 | /* Copy the first 3 chars of the extension (if any) */ |
| 564 | if (ext) |
| 565 | { |
| 566 | if (!dir_format) *dst++ = '.'; |
| 567 | for (i = 3, ext++; (i > 0) && !IS_END_OF_NAME(*ext); i--, ext++) |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 568 | *dst++ = strchr( invalid_chars, *ext ) ? '_' : FILE_toupper(*ext); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 569 | } |
| 570 | if (!dir_format) *dst = '\0'; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 571 | } |
| 572 | |
| 573 | |
| 574 | /*********************************************************************** |
| 575 | * DOSFS_FindUnixName |
| 576 | * |
| 577 | * Find the Unix file name in a given directory that corresponds to |
| 578 | * a file name (either in Unix or DOS format). |
| 579 | * File name can be terminated by '\0', '\\' or '/'. |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 580 | * Return TRUE if OK, FALSE if no file name matches. |
| 581 | * |
| 582 | * 'long_buf' must be at least 'long_len' characters long. If the long name |
| 583 | * turns out to be larger than that, the function returns FALSE. |
| 584 | * 'short_buf' must be at least 13 characters long. |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 585 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 586 | BOOL DOSFS_FindUnixName( LPCSTR path, LPCSTR name, LPSTR long_buf, |
| 587 | INT long_len, LPSTR short_buf, BOOL ignore_case) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 588 | { |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 589 | DOS_DIR *dir; |
| 590 | LPCSTR long_name, short_name; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 591 | char dos_name[12], tmp_buf[13]; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 592 | BOOL ret; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 593 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 594 | const char *p = strchr( name, '/' ); |
| 595 | int len = p ? (int)(p - name) : strlen(name); |
Francois Gouget | 6d77d3a | 2000-03-25 21:44:35 +0000 | [diff] [blame] | 596 | if ((p = strchr( name, '\\' ))) len = min( (int)(p - name), len ); |
Dave Hawkes | bb9e66e | 2000-06-25 12:46:40 +0000 | [diff] [blame] | 597 | /* Ignore trailing dots and spaces */ |
| 598 | while (len > 1 && (name[len-1] == '.' || name[len-1] == ' ')) len--; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 599 | if (long_len < len + 1) return FALSE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 600 | |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 601 | TRACE("%s,%s\n", path, name ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 602 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 603 | if (!DOSFS_ToDosFCBFormat( name, dos_name )) dos_name[0] = '\0'; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 604 | |
| 605 | if (!(dir = DOSFS_OpenDir( path ))) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 606 | { |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 607 | WARN("(%s,%s): can't open dir: %s\n", |
Alexandre Julliard | 44ed71f | 1997-12-21 19:17:50 +0000 | [diff] [blame] | 608 | path, name, strerror(errno) ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 609 | return FALSE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 610 | } |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 611 | |
| 612 | while ((ret = DOSFS_ReadDir( dir, &long_name, &short_name ))) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 613 | { |
| 614 | /* Check against Unix name */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 615 | if (len == strlen(long_name)) |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 616 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 617 | if (!ignore_case) |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 618 | { |
Alexandre Julliard | 89f079b | 1999-08-08 18:54:47 +0000 | [diff] [blame] | 619 | if (!strncmp( long_name, name, len )) break; |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 620 | } |
| 621 | else |
| 622 | { |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 623 | if (!FILE_strncasecmp( long_name, name, len )) break; |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 624 | } |
| 625 | } |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 626 | if (dos_name[0]) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 627 | { |
| 628 | /* Check against hashed DOS name */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 629 | if (!short_name) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 630 | { |
| 631 | DOSFS_Hash( long_name, tmp_buf, TRUE, ignore_case ); |
| 632 | short_name = tmp_buf; |
| 633 | } |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 634 | if (!strcmp( dos_name, short_name )) break; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 635 | } |
| 636 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 637 | if (ret) |
| 638 | { |
| 639 | if (long_buf) strcpy( long_buf, long_name ); |
| 640 | if (short_buf) |
| 641 | { |
| 642 | if (short_name) |
| 643 | DOSFS_ToDosDTAFormat( short_name, short_buf ); |
| 644 | else |
| 645 | DOSFS_Hash( long_name, short_buf, FALSE, ignore_case ); |
| 646 | } |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 647 | TRACE("(%s,%s) -> %s (%s)\n", |
| 648 | path, name, long_name, short_buf ? short_buf : "***"); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 649 | } |
| 650 | else |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 651 | WARN("'%s' not found in '%s'\n", name, path); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 652 | DOSFS_CloseDir( dir ); |
| 653 | return ret; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 654 | } |
| 655 | |
| 656 | |
| 657 | /*********************************************************************** |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 658 | * DOSFS_GetDevice |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 659 | * |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 660 | * 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] | 661 | */ |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 662 | const DOS_DEVICE *DOSFS_GetDevice( const char *name ) |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 663 | { |
| 664 | int i; |
| 665 | const char *p; |
| 666 | |
Alexandre Julliard | 767e6f6 | 1998-08-09 12:47:43 +0000 | [diff] [blame] | 667 | if (!name) return NULL; /* if FILE_DupUnixHandle was used */ |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 668 | if (name[0] && (name[1] == ':')) name += 2; |
| 669 | if ((p = strrchr( name, '/' ))) name = p + 1; |
| 670 | if ((p = strrchr( name, '\\' ))) name = p + 1; |
| 671 | for (i = 0; i < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]); i++) |
| 672 | { |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 673 | const char *dev = DOSFS_Devices[i].name; |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 674 | if (!FILE_strncasecmp( dev, name, strlen(dev) )) |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 675 | { |
| 676 | p = name + strlen( dev ); |
Lawson Whitney | e3178f9 | 2000-12-27 03:28:13 +0000 | [diff] [blame] | 677 | if (!*p || (*p == '.') || (*p == ':')) return &DOSFS_Devices[i]; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 678 | } |
| 679 | } |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 680 | return NULL; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 681 | } |
| 682 | |
Alexandre Julliard | 62a8b43 | 1999-01-19 17:48:23 +0000 | [diff] [blame] | 683 | |
| 684 | /*********************************************************************** |
| 685 | * DOSFS_GetDeviceByHandle |
| 686 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 687 | const DOS_DEVICE *DOSFS_GetDeviceByHandle( HFILE hFile ) |
Alexandre Julliard | 62a8b43 | 1999-01-19 17:48:23 +0000 | [diff] [blame] | 688 | { |
Alexandre Julliard | 9264300 | 2000-08-31 01:59:51 +0000 | [diff] [blame] | 689 | const DOS_DEVICE *ret = NULL; |
Alexandre Julliard | 67a7499 | 2001-02-27 02:09:16 +0000 | [diff] [blame] | 690 | SERVER_START_REQ( get_file_info ) |
Alexandre Julliard | 62a8b43 | 1999-01-19 17:48:23 +0000 | [diff] [blame] | 691 | { |
Alexandre Julliard | 9264300 | 2000-08-31 01:59:51 +0000 | [diff] [blame] | 692 | req->handle = hFile; |
Alexandre Julliard | 67a7499 | 2001-02-27 02:09:16 +0000 | [diff] [blame] | 693 | if (!SERVER_CALL() && (req->type == FILE_TYPE_UNKNOWN)) |
Alexandre Julliard | 9264300 | 2000-08-31 01:59:51 +0000 | [diff] [blame] | 694 | { |
| 695 | if ((req->attr >= 0) && |
| 696 | (req->attr < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]))) |
| 697 | ret = &DOSFS_Devices[req->attr]; |
| 698 | } |
Alexandre Julliard | 62a8b43 | 1999-01-19 17:48:23 +0000 | [diff] [blame] | 699 | } |
Alexandre Julliard | 9264300 | 2000-08-31 01:59:51 +0000 | [diff] [blame] | 700 | SERVER_END_REQ; |
| 701 | return ret; |
Alexandre Julliard | 62a8b43 | 1999-01-19 17:48:23 +0000 | [diff] [blame] | 702 | } |
| 703 | |
| 704 | |
Mike McCormack | 11776c1 | 2000-10-13 17:11:30 +0000 | [diff] [blame] | 705 | /************************************************************************** |
| 706 | * DOSFS_CreateCommPort |
| 707 | */ |
Eric Pouech | 3bbeb72 | 2001-10-14 16:08:45 +0000 | [diff] [blame] | 708 | static HANDLE DOSFS_CreateCommPort(LPCSTR name, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa) |
Mike McCormack | 11776c1 | 2000-10-13 17:11:30 +0000 | [diff] [blame] | 709 | { |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 710 | HANDLE ret; |
Mike McCormack | 11776c1 | 2000-10-13 17:11:30 +0000 | [diff] [blame] | 711 | char devname[40]; |
Alexandre Julliard | 67a7499 | 2001-02-27 02:09:16 +0000 | [diff] [blame] | 712 | size_t len; |
Mike McCormack | 11776c1 | 2000-10-13 17:11:30 +0000 | [diff] [blame] | 713 | |
Mike McCormack | 568c67e | 2001-10-08 20:40:57 +0000 | [diff] [blame] | 714 | TRACE_(file)("%s %lx %lx\n", name, access, attributes); |
Mike McCormack | 11776c1 | 2000-10-13 17:11:30 +0000 | [diff] [blame] | 715 | |
| 716 | PROFILE_GetWineIniString("serialports",name,"",devname,sizeof devname); |
| 717 | if(!devname[0]) |
| 718 | return 0; |
| 719 | |
| 720 | TRACE("opening %s as %s\n", devname, name); |
| 721 | |
Alexandre Julliard | 67a7499 | 2001-02-27 02:09:16 +0000 | [diff] [blame] | 722 | len = strlen(devname); |
| 723 | SERVER_START_VAR_REQ( create_serial, len ) |
Alexandre Julliard | 57f05e1 | 2000-10-15 00:40:25 +0000 | [diff] [blame] | 724 | { |
Alexandre Julliard | 57f05e1 | 2000-10-15 00:40:25 +0000 | [diff] [blame] | 725 | req->access = access; |
Eric Pouech | 3bbeb72 | 2001-10-14 16:08:45 +0000 | [diff] [blame] | 726 | req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle); |
Mike McCormack | 568c67e | 2001-10-08 20:40:57 +0000 | [diff] [blame] | 727 | req->attributes = attributes; |
Alexandre Julliard | 57f05e1 | 2000-10-15 00:40:25 +0000 | [diff] [blame] | 728 | req->sharing = FILE_SHARE_READ|FILE_SHARE_WRITE; |
| 729 | memcpy( server_data_ptr(req), devname, len ); |
| 730 | SetLastError(0); |
Alexandre Julliard | 67a7499 | 2001-02-27 02:09:16 +0000 | [diff] [blame] | 731 | SERVER_CALL_ERR(); |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 732 | ret = req->handle; |
Alexandre Julliard | 57f05e1 | 2000-10-15 00:40:25 +0000 | [diff] [blame] | 733 | } |
Alexandre Julliard | 67a7499 | 2001-02-27 02:09:16 +0000 | [diff] [blame] | 734 | SERVER_END_VAR_REQ; |
Alexandre Julliard | 57f05e1 | 2000-10-15 00:40:25 +0000 | [diff] [blame] | 735 | |
Rein Klazes | 0a78857 | 2001-02-20 01:52:41 +0000 | [diff] [blame] | 736 | if(!ret) |
Andreas Mohr | e15badb | 2001-10-21 15:18:15 +0000 | [diff] [blame] | 737 | ERR("Couldn't open device '%s' ! (check permissions)\n",devname); |
Rein Klazes | 0a78857 | 2001-02-20 01:52:41 +0000 | [diff] [blame] | 738 | else |
| 739 | TRACE("return %08X\n", ret ); |
Alexandre Julliard | 57f05e1 | 2000-10-15 00:40:25 +0000 | [diff] [blame] | 740 | return ret; |
Mike McCormack | 11776c1 | 2000-10-13 17:11:30 +0000 | [diff] [blame] | 741 | } |
| 742 | |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 743 | /*********************************************************************** |
| 744 | * DOSFS_OpenDevice |
| 745 | * |
| 746 | * Open a DOS device. This might not map 1:1 into the UNIX device concept. |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 747 | * Returns 0 on failure. |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 748 | */ |
Eric Pouech | 3bbeb72 | 2001-10-14 16:08:45 +0000 | [diff] [blame] | 749 | HANDLE DOSFS_OpenDevice( const char *name, DWORD access, DWORD attributes, LPSECURITY_ATTRIBUTES sa ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 750 | { |
| 751 | int i; |
| 752 | const char *p; |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 753 | HANDLE handle; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 754 | |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 755 | if (name[0] && (name[1] == ':')) name += 2; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 756 | if ((p = strrchr( name, '/' ))) name = p + 1; |
| 757 | if ((p = strrchr( name, '\\' ))) name = p + 1; |
| 758 | for (i = 0; i < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]); i++) |
| 759 | { |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 760 | const char *dev = DOSFS_Devices[i].name; |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 761 | if (!FILE_strncasecmp( dev, name, strlen(dev) )) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 762 | { |
| 763 | p = name + strlen( dev ); |
Lawson Whitney | e3178f9 | 2000-12-27 03:28:13 +0000 | [diff] [blame] | 764 | if (!*p || (*p == '.') || (*p == ':')) { |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 765 | /* got it */ |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 766 | if (!strcmp(DOSFS_Devices[i].name,"NUL")) |
Alexandre Julliard | 0562539 | 1999-01-03 11:55:56 +0000 | [diff] [blame] | 767 | return FILE_CreateFile( "/dev/null", access, |
Eric Pouech | 3bbeb72 | 2001-10-14 16:08:45 +0000 | [diff] [blame] | 768 | FILE_SHARE_READ|FILE_SHARE_WRITE, sa, |
Ove Kaaven | 708a846 | 2001-10-24 00:23:25 +0000 | [diff] [blame] | 769 | OPEN_EXISTING, 0, 0, TRUE, DRIVE_UNKNOWN ); |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 770 | if (!strcmp(DOSFS_Devices[i].name,"CON")) { |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 771 | HANDLE to_dup; |
Alexandre Julliard | 0562539 | 1999-01-03 11:55:56 +0000 | [diff] [blame] | 772 | switch (access & (GENERIC_READ|GENERIC_WRITE)) { |
| 773 | case GENERIC_READ: |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 774 | to_dup = GetStdHandle( STD_INPUT_HANDLE ); |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 775 | break; |
Alexandre Julliard | 0562539 | 1999-01-03 11:55:56 +0000 | [diff] [blame] | 776 | case GENERIC_WRITE: |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 777 | to_dup = GetStdHandle( STD_OUTPUT_HANDLE ); |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 778 | break; |
| 779 | default: |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 780 | FIXME("can't open CON read/write\n"); |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 781 | return 0; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 782 | } |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 783 | if (!DuplicateHandle( GetCurrentProcess(), to_dup, GetCurrentProcess(), |
Eric Pouech | 3bbeb72 | 2001-10-14 16:08:45 +0000 | [diff] [blame] | 784 | &handle, 0, |
| 785 | sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle, |
| 786 | DUPLICATE_SAME_ACCESS )) |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 787 | handle = 0; |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 788 | return handle; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 789 | } |
Alexandre Julliard | fbe63ad | 1998-12-30 12:10:06 +0000 | [diff] [blame] | 790 | if (!strcmp(DOSFS_Devices[i].name,"SCSIMGR$") || |
| 791 | !strcmp(DOSFS_Devices[i].name,"HPSCAN")) |
| 792 | { |
Eric Pouech | 3bbeb72 | 2001-10-14 16:08:45 +0000 | [diff] [blame] | 793 | return FILE_CreateDevice( i, access, sa ); |
Alexandre Julliard | f90efa9 | 1998-06-14 15:24:15 +0000 | [diff] [blame] | 794 | } |
Michael McCormack | a848607 | 1999-03-14 12:25:36 +0000 | [diff] [blame] | 795 | |
Eric Pouech | 3bbeb72 | 2001-10-14 16:08:45 +0000 | [diff] [blame] | 796 | if( (handle=DOSFS_CreateCommPort(DOSFS_Devices[i].name,access,attributes,sa)) ) |
Mike McCormack | 44b5bf5 | 2000-09-07 18:39:51 +0000 | [diff] [blame] | 797 | return handle; |
Rein Klazes | 0a78857 | 2001-02-20 01:52:41 +0000 | [diff] [blame] | 798 | FIXME("device open %s not supported (yet)\n",DOSFS_Devices[i].name); |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 799 | return 0; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 800 | } |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 801 | } |
| 802 | } |
Alexandre Julliard | 8081e5a | 2001-01-05 04:08:07 +0000 | [diff] [blame] | 803 | return 0; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 804 | } |
| 805 | |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 806 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 807 | /*********************************************************************** |
| 808 | * DOSFS_GetPathDrive |
| 809 | * |
| 810 | * Get the drive specified by a given path name (DOS or Unix format). |
| 811 | */ |
| 812 | static int DOSFS_GetPathDrive( const char **name ) |
| 813 | { |
| 814 | int drive; |
| 815 | const char *p = *name; |
| 816 | |
| 817 | if (*p && (p[1] == ':')) |
| 818 | { |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 819 | drive = FILE_toupper(*p) - 'A'; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 820 | *name += 2; |
| 821 | } |
| 822 | else if (*p == '/') /* Absolute Unix path? */ |
| 823 | { |
| 824 | if ((drive = DRIVE_FindDriveRoot( name )) == -1) |
| 825 | { |
Andreas Mohr | 7bed696 | 2001-09-19 22:34:38 +0000 | [diff] [blame] | 826 | MESSAGE("Warning: %s not accessible from a configured DOS drive\n", *name ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 827 | /* Assume it really was a DOS name */ |
| 828 | drive = DRIVE_GetCurrentDrive(); |
| 829 | } |
| 830 | } |
| 831 | else drive = DRIVE_GetCurrentDrive(); |
| 832 | |
| 833 | if (!DRIVE_IsValid(drive)) |
| 834 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 835 | SetLastError( ERROR_INVALID_DRIVE ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 836 | return -1; |
| 837 | } |
| 838 | return drive; |
| 839 | } |
| 840 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 841 | |
| 842 | /*********************************************************************** |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 843 | * DOSFS_GetFullName |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 844 | * |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 845 | * Convert a file name (DOS or mixed DOS/Unix format) to a valid |
| 846 | * Unix name / short DOS name pair. |
| 847 | * 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] | 848 | * component is only checked if 'check_last' is non-zero. |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 849 | * The buffers pointed to by 'long_buf' and 'short_buf' must be |
| 850 | * at least MAX_PATHNAME_LEN long. |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 851 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 852 | BOOL DOSFS_GetFullName( LPCSTR name, BOOL check_last, DOS_FULL_NAME *full ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 853 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 854 | BOOL found; |
| 855 | UINT flags; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 856 | char *p_l, *p_s, *root; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 857 | |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 858 | TRACE("%s (last=%d)\n", name, check_last ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 859 | |
Gerard Patel | d52e1c4 | 2001-02-16 19:05:42 +0000 | [diff] [blame] | 860 | if ((!*name) || (*name=='\n')) |
| 861 | { /* error code for Win98 */ |
| 862 | SetLastError(ERROR_BAD_PATHNAME); |
| 863 | return FALSE; |
| 864 | } |
| 865 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 866 | if ((full->drive = DOSFS_GetPathDrive( &name )) == -1) return FALSE; |
| 867 | flags = DRIVE_GetFlags( full->drive ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 868 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 869 | lstrcpynA( full->long_name, DRIVE_GetRoot( full->drive ), |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 870 | sizeof(full->long_name) ); |
| 871 | if (full->long_name[1]) root = full->long_name + strlen(full->long_name); |
| 872 | else root = full->long_name; /* root directory */ |
| 873 | |
| 874 | strcpy( full->short_name, "A:\\" ); |
| 875 | full->short_name[0] += full->drive; |
| 876 | |
| 877 | if ((*name == '\\') || (*name == '/')) /* Absolute path */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 878 | { |
| 879 | while ((*name == '\\') || (*name == '/')) name++; |
| 880 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 881 | else /* Relative path */ |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 882 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 883 | lstrcpynA( root + 1, DRIVE_GetUnixCwd( full->drive ), |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 884 | sizeof(full->long_name) - (root - full->long_name) - 1 ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 885 | if (root[1]) *root = '/'; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 886 | lstrcpynA( full->short_name + 3, DRIVE_GetDosCwd( full->drive ), |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 887 | sizeof(full->short_name) - 3 ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 888 | } |
| 889 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 890 | p_l = full->long_name[1] ? full->long_name + strlen(full->long_name) |
| 891 | : full->long_name; |
| 892 | p_s = full->short_name[3] ? full->short_name + strlen(full->short_name) |
| 893 | : full->short_name + 2; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 894 | found = TRUE; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 895 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 896 | while (*name && found) |
| 897 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 898 | /* Check for '.' and '..' */ |
| 899 | |
| 900 | if (*name == '.') |
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 | if (IS_END_OF_NAME(name[1])) |
| 903 | { |
| 904 | name++; |
| 905 | while ((*name == '\\') || (*name == '/')) name++; |
| 906 | continue; |
| 907 | } |
| 908 | else if ((name[1] == '.') && IS_END_OF_NAME(name[2])) |
| 909 | { |
| 910 | name += 2; |
| 911 | while ((*name == '\\') || (*name == '/')) name++; |
| 912 | while ((p_l > root) && (*p_l != '/')) p_l--; |
| 913 | while ((p_s > full->short_name + 2) && (*p_s != '\\')) p_s--; |
| 914 | *p_l = *p_s = '\0'; /* Remove trailing separator */ |
| 915 | continue; |
| 916 | } |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 917 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 918 | |
| 919 | /* Make sure buffers are large enough */ |
| 920 | |
| 921 | if ((p_s >= full->short_name + sizeof(full->short_name) - 14) || |
| 922 | (p_l >= full->long_name + sizeof(full->long_name) - 1)) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 923 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 924 | SetLastError( ERROR_PATH_NOT_FOUND ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 925 | return FALSE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 926 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 927 | |
| 928 | /* Get the long and short name matching the file name */ |
| 929 | |
| 930 | if ((found = DOSFS_FindUnixName( full->long_name, name, p_l + 1, |
| 931 | sizeof(full->long_name) - (p_l - full->long_name) - 1, |
| 932 | p_s + 1, !(flags & DRIVE_CASE_SENSITIVE) ))) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 933 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 934 | *p_l++ = '/'; |
| 935 | p_l += strlen(p_l); |
| 936 | *p_s++ = '\\'; |
| 937 | p_s += strlen(p_s); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 938 | while (!IS_END_OF_NAME(*name)) name++; |
| 939 | } |
Alexandre Julliard | 7e56f68 | 1996-01-31 19:02:28 +0000 | [diff] [blame] | 940 | else if (!check_last) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 941 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 942 | *p_l++ = '/'; |
| 943 | *p_s++ = '\\'; |
| 944 | while (!IS_END_OF_NAME(*name) && |
| 945 | (p_s < full->short_name + sizeof(full->short_name) - 1) && |
| 946 | (p_l < full->long_name + sizeof(full->long_name) - 1)) |
| 947 | { |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 948 | *p_s++ = FILE_tolower(*name); |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 949 | /* If the drive is case-sensitive we want to create new */ |
| 950 | /* files in lower-case otherwise we can't reopen them */ |
| 951 | /* under the same short name. */ |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 952 | if (flags & DRIVE_CASE_SENSITIVE) *p_l++ = FILE_tolower(*name); |
Alexandre Julliard | 829fe32 | 1998-07-26 14:27:39 +0000 | [diff] [blame] | 953 | else *p_l++ = *name; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 954 | name++; |
| 955 | } |
Dave Hawkes | bb9e66e | 2000-06-25 12:46:40 +0000 | [diff] [blame] | 956 | /* Ignore trailing dots and spaces */ |
| 957 | while(p_l[-1] == '.' || p_l[-1] == ' ') { |
| 958 | --p_l; |
| 959 | --p_s; |
| 960 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 961 | *p_l = *p_s = '\0'; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 962 | } |
| 963 | while ((*name == '\\') || (*name == '/')) name++; |
| 964 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 965 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 966 | if (!found) |
| 967 | { |
Alexander Larsson | a8745ea | 1998-12-02 10:04:52 +0000 | [diff] [blame] | 968 | if (check_last) |
| 969 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 970 | SetLastError( ERROR_FILE_NOT_FOUND ); |
Alexander Larsson | a8745ea | 1998-12-02 10:04:52 +0000 | [diff] [blame] | 971 | return FALSE; |
| 972 | } |
Alexander Larsson | 2772a67 | 1998-12-07 16:23:42 +0000 | [diff] [blame] | 973 | if (*name) /* Not last */ |
| 974 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 975 | SetLastError( ERROR_PATH_NOT_FOUND ); |
Alexander Larsson | 2772a67 | 1998-12-07 16:23:42 +0000 | [diff] [blame] | 976 | return FALSE; |
| 977 | } |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 978 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 979 | if (!full->long_name[0]) strcpy( full->long_name, "/" ); |
| 980 | if (!full->short_name[2]) strcpy( full->short_name + 2, "\\" ); |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 981 | TRACE("returning %s = %s\n", full->long_name, full->short_name ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 982 | return TRUE; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 983 | } |
| 984 | |
| 985 | |
| 986 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 987 | * GetShortPathNameA (KERNEL32.@) |
Juergen Schmied | 4658e4d | 1998-11-22 12:21:05 +0000 | [diff] [blame] | 988 | * |
| 989 | * NOTES |
| 990 | * observed: |
| 991 | * longpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0 |
Francois Gouget | 60a83ef | 2001-09-14 00:59:58 +0000 | [diff] [blame] | 992 | * longpath="" or invalid: LastError=ERROR_BAD_PATHNAME, ret=0 |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 993 | * |
| 994 | * more observations ( with NT 3.51 (WinDD) ): |
| 995 | * longpath <= 8.3 -> just copy longpath to shortpath |
| 996 | * longpath > 8.3 -> |
| 997 | * a) file does not exist -> return 0, LastError = ERROR_FILE_NOT_FOUND |
| 998 | * b) file does exist -> set the short filename. |
| 999 | * - trailing slashes are reproduced in the short name, even if the |
| 1000 | * file is not a directory |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1001 | * - the absolute/relative path of the short name is reproduced like found |
| 1002 | * in the long name |
Francois Gouget | 60a83ef | 2001-09-14 00:59:58 +0000 | [diff] [blame] | 1003 | * - longpath and shortpath may have the same address |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1004 | * Peter Ganten, 1999 |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1005 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1006 | DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 1007 | DWORD shortlen ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1008 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1009 | DOS_FULL_NAME full_name; |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1010 | LPSTR tmpshortpath; |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1011 | DWORD sp = 0, lp = 0; |
| 1012 | int tmplen, drive; |
| 1013 | UINT flags; |
| 1014 | |
Patrik Stridvall | 422a10a | 2000-02-26 13:15:51 +0000 | [diff] [blame] | 1015 | TRACE("%s\n", debugstr_a(longpath)); |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1016 | |
| 1017 | if (!longpath) { |
| 1018 | SetLastError(ERROR_INVALID_PARAMETER); |
| 1019 | return 0; |
| 1020 | } |
| 1021 | if (!longpath[0]) { |
| 1022 | SetLastError(ERROR_BAD_PATHNAME); |
| 1023 | return 0; |
| 1024 | } |
| 1025 | |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1026 | if ( ( tmpshortpath = HeapAlloc ( GetProcessHeap(), 0, MAX_PATHNAME_LEN ) ) == NULL ) { |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1027 | SetLastError ( ERROR_NOT_ENOUGH_MEMORY ); |
| 1028 | return 0; |
| 1029 | } |
| 1030 | |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1031 | /* check for drive letter */ |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1032 | if ( longpath[1] == ':' ) { |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1033 | tmpshortpath[0] = longpath[0]; |
| 1034 | tmpshortpath[1] = ':'; |
| 1035 | sp = 2; |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1036 | } |
| 1037 | |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1038 | if ( ( drive = DOSFS_GetPathDrive ( &longpath )) == -1 ) return 0; |
| 1039 | flags = DRIVE_GetFlags ( drive ); |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1040 | |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1041 | while ( longpath[lp] ) { |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1042 | |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1043 | /* check for path delimiters and reproduce them */ |
| 1044 | if ( longpath[lp] == '\\' || longpath[lp] == '/' ) { |
Uwe Bonnes | 61f572a | 2000-04-06 19:31:11 +0000 | [diff] [blame] | 1045 | if (!sp || tmpshortpath[sp-1]!= '\\') |
| 1046 | { |
| 1047 | /* strip double "\\" */ |
| 1048 | tmpshortpath[sp] = '\\'; |
| 1049 | sp++; |
| 1050 | } |
Uwe Bonnes | 40249c6 | 2000-05-12 21:45:52 +0000 | [diff] [blame] | 1051 | tmpshortpath[sp]=0;/*terminate string*/ |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1052 | lp++; |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1053 | continue; |
| 1054 | } |
| 1055 | |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1056 | tmplen = strcspn ( longpath + lp, "\\/" ); |
| 1057 | lstrcpynA ( tmpshortpath+sp, longpath + lp, tmplen+1 ); |
| 1058 | |
| 1059 | /* Check, if the current element is a valid dos name */ |
| 1060 | if ( DOSFS_ValidDOSName ( longpath + lp, !(flags & DRIVE_CASE_SENSITIVE) ) ) { |
| 1061 | sp += tmplen; |
| 1062 | lp += tmplen; |
| 1063 | continue; |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1064 | } |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1065 | |
| 1066 | /* Check if the file exists and use the existing file name */ |
| 1067 | if ( DOSFS_GetFullName ( tmpshortpath, TRUE, &full_name ) ) { |
Alexandre Julliard | e101f6d | 2000-08-14 14:42:41 +0000 | [diff] [blame] | 1068 | strcpy( tmpshortpath+sp, strrchr ( full_name.short_name, '\\' ) + 1 ); |
Alexandre Julliard | cb10fda | 2000-08-06 02:41:16 +0000 | [diff] [blame] | 1069 | sp += strlen ( tmpshortpath+sp ); |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1070 | lp += tmplen; |
| 1071 | continue; |
| 1072 | } |
| 1073 | |
| 1074 | TRACE("not found!\n" ); |
| 1075 | SetLastError ( ERROR_FILE_NOT_FOUND ); |
| 1076 | return 0; |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1077 | } |
Uwe Bonnes | 61f572a | 2000-04-06 19:31:11 +0000 | [diff] [blame] | 1078 | tmpshortpath[sp] = 0; |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1079 | |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1080 | lstrcpynA ( shortpath, tmpshortpath, shortlen ); |
Patrik Stridvall | 422a10a | 2000-02-26 13:15:51 +0000 | [diff] [blame] | 1081 | TRACE("returning %s\n", debugstr_a(shortpath) ); |
Alexandre Julliard | cb10fda | 2000-08-06 02:41:16 +0000 | [diff] [blame] | 1082 | tmplen = strlen ( tmpshortpath ); |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1083 | HeapFree ( GetProcessHeap(), 0, tmpshortpath ); |
| 1084 | |
Peter Ganten | d580b83 | 1999-12-12 20:44:07 +0000 | [diff] [blame] | 1085 | return tmplen; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1086 | } |
| 1087 | |
| 1088 | |
| 1089 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 1090 | * GetShortPathNameW (KERNEL32.@) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1091 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1092 | DWORD WINAPI GetShortPathNameW( LPCWSTR longpath, LPWSTR shortpath, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 1093 | DWORD shortlen ) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1094 | { |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1095 | LPSTR longpathA, shortpathA; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1096 | DWORD ret = 0; |
Juergen Schmied | 4658e4d | 1998-11-22 12:21:05 +0000 | [diff] [blame] | 1097 | |
Juergen Schmied | 4658e4d | 1998-11-22 12:21:05 +0000 | [diff] [blame] | 1098 | longpathA = HEAP_strdupWtoA( GetProcessHeap(), 0, longpath ); |
Dimitrie O. Paun | abdbced | 2000-04-29 14:20:28 +0000 | [diff] [blame] | 1099 | shortpathA = HeapAlloc ( GetProcessHeap(), 0, shortlen ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1100 | |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1101 | ret = GetShortPathNameA ( longpathA, shortpathA, shortlen ); |
Alexandre Julliard | 24a62ab | 2000-11-28 22:40:56 +0000 | [diff] [blame] | 1102 | if (shortlen > 0 && !MultiByteToWideChar( CP_ACP, 0, shortpathA, -1, shortpath, shortlen )) |
| 1103 | shortpath[shortlen-1] = 0; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1104 | HeapFree( GetProcessHeap(), 0, longpathA ); |
Peter Ganten | f22bea0 | 1999-03-14 15:15:14 +0000 | [diff] [blame] | 1105 | HeapFree( GetProcessHeap(), 0, shortpathA ); |
| 1106 | |
| 1107 | return ret; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1108 | } |
| 1109 | |
| 1110 | |
| 1111 | /*********************************************************************** |
Patrik Stridvall | 3ca9823 | 2001-06-20 23:03:14 +0000 | [diff] [blame] | 1112 | * GetLongPathNameA (KERNEL32.@) |
Francois Gouget | 60a83ef | 2001-09-14 00:59:58 +0000 | [diff] [blame] | 1113 | * |
| 1114 | * NOTES |
| 1115 | * observed (Win2000): |
| 1116 | * shortpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0 |
| 1117 | * shortpath="": LastError=ERROR_PATH_NOT_FOUND, ret=0 |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1118 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1119 | DWORD WINAPI GetLongPathNameA( LPCSTR shortpath, LPSTR longpath, |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1120 | DWORD longlen ) |
| 1121 | { |
| 1122 | DOS_FULL_NAME full_name; |
Petr Tomasek | 788a9f7 | 2000-02-20 19:14:17 +0000 | [diff] [blame] | 1123 | char *p, *r, *ll, *ss; |
Francois Gouget | 60a83ef | 2001-09-14 00:59:58 +0000 | [diff] [blame] | 1124 | |
| 1125 | if (!shortpath) { |
| 1126 | SetLastError(ERROR_INVALID_PARAMETER); |
| 1127 | return 0; |
| 1128 | } |
| 1129 | if (!shortpath[0]) { |
| 1130 | SetLastError(ERROR_PATH_NOT_FOUND); |
| 1131 | return 0; |
| 1132 | } |
| 1133 | |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1134 | if (!DOSFS_GetFullName( shortpath, TRUE, &full_name )) return 0; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1135 | lstrcpynA( longpath, full_name.short_name, longlen ); |
Petr Tomasek | 788a9f7 | 2000-02-20 19:14:17 +0000 | [diff] [blame] | 1136 | |
| 1137 | /* Do some hackery to get the long filename. */ |
| 1138 | |
| 1139 | if (longpath) { |
| 1140 | ss=longpath+strlen(longpath); |
| 1141 | ll=full_name.long_name+strlen(full_name.long_name); |
| 1142 | p=NULL; |
| 1143 | while (ss>=longpath) |
| 1144 | { |
| 1145 | /* FIXME: aren't we more paranoid, than needed? */ |
| 1146 | while ((ss[0]=='\\') && (ss>=longpath)) ss--; |
| 1147 | p=ss; |
| 1148 | while ((ss[0]!='\\') && (ss>=longpath)) ss--; |
| 1149 | if (ss>=longpath) |
| 1150 | { |
| 1151 | /* FIXME: aren't we more paranoid, than needed? */ |
| 1152 | while ((ll[0]=='/') && (ll>=full_name.long_name)) ll--; |
| 1153 | while ((ll[0]!='/') && (ll>=full_name.long_name)) ll--; |
| 1154 | if (ll<full_name.long_name) |
| 1155 | { |
| 1156 | ERR("Bad longname! (ss=%s ll=%s)\n This should never happen !\n" |
| 1157 | ,ss ,ll ); |
| 1158 | return 0; |
| 1159 | } |
| 1160 | } |
| 1161 | } |
| 1162 | |
| 1163 | /* FIXME: fix for names like "C:\\" (ie. with more '\'s) */ |
| 1164 | if (p && p[2]) |
| 1165 | { |
| 1166 | p+=1; |
| 1167 | if ((p-longpath)>0) longlen -= (p-longpath); |
| 1168 | lstrcpynA( p, ll , longlen); |
| 1169 | |
| 1170 | /* Now, change all '/' to '\' */ |
| 1171 | for (r=p; r<(p+longlen); r++ ) |
| 1172 | if (r[0]=='/') r[0]='\\'; |
| 1173 | return strlen(longpath) - strlen(p) + longlen; |
| 1174 | } |
Alexander Larsson | c1190fe | 1998-10-11 13:57:09 +0000 | [diff] [blame] | 1175 | } |
Petr Tomasek | 788a9f7 | 2000-02-20 19:14:17 +0000 | [diff] [blame] | 1176 | |
| 1177 | return strlen(longpath); |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1178 | } |
| 1179 | |
| 1180 | |
| 1181 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 1182 | * GetLongPathNameW (KERNEL32.@) |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1183 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1184 | DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath, |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1185 | DWORD longlen ) |
| 1186 | { |
| 1187 | DOS_FULL_NAME full_name; |
| 1188 | DWORD ret = 0; |
| 1189 | LPSTR shortpathA = HEAP_strdupWtoA( GetProcessHeap(), 0, shortpath ); |
| 1190 | |
| 1191 | /* FIXME: is it correct to always return a fully qualified short path? */ |
| 1192 | if (DOSFS_GetFullName( shortpathA, TRUE, &full_name )) |
| 1193 | { |
| 1194 | ret = strlen( full_name.short_name ); |
Alexandre Julliard | 24a62ab | 2000-11-28 22:40:56 +0000 | [diff] [blame] | 1195 | if (longlen > 0 && !MultiByteToWideChar( CP_ACP, 0, full_name.long_name, -1, |
| 1196 | longpath, longlen )) |
| 1197 | longpath[longlen-1] = 0; |
Alexandre Julliard | e658d82 | 1997-11-30 17:45:40 +0000 | [diff] [blame] | 1198 | } |
| 1199 | HeapFree( GetProcessHeap(), 0, shortpathA ); |
| 1200 | return ret; |
| 1201 | } |
| 1202 | |
| 1203 | |
| 1204 | /*********************************************************************** |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1205 | * DOSFS_DoGetFullPathName |
| 1206 | * |
Patrik Stridvall | 2d6457c | 2000-03-28 20:22:59 +0000 | [diff] [blame] | 1207 | * Implementation of GetFullPathNameA/W. |
Uwe Bonnes | 59b5f78 | 2000-02-27 13:58:12 +0000 | [diff] [blame] | 1208 | * |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1209 | * bon@elektron 000331: |
Huw D M Davies | d0f8bfd | 2000-12-15 20:54:01 +0000 | [diff] [blame] | 1210 | * A test for GetFullPathName with many pathological cases |
| 1211 | * now gives identical output for Wine and OSR2 |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1212 | */ |
| 1213 | static DWORD DOSFS_DoGetFullPathName( LPCSTR name, DWORD len, LPSTR result, |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1214 | BOOL unicode ) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1215 | { |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1216 | DWORD ret; |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1217 | DOS_FULL_NAME full_name; |
| 1218 | char *p,*q; |
| 1219 | const char * root; |
| 1220 | char drivecur[]="c:."; |
| 1221 | char driveletter=0; |
| 1222 | int namelen,drive=0; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1223 | |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1224 | if ((strlen(name) >1)&& (name[1]==':')) |
| 1225 | /*drive letter given */ |
Uwe Bonnes | 59b5f78 | 2000-02-27 13:58:12 +0000 | [diff] [blame] | 1226 | { |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1227 | driveletter = name[0]; |
| 1228 | } |
| 1229 | if ((strlen(name) >2)&& (name[1]==':') && |
| 1230 | ((name[2]=='\\') || (name[2]=='/'))) |
Uwe Bonnes | 594a0dc | 2000-06-15 00:30:26 +0000 | [diff] [blame] | 1231 | /*absolute path given */ |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1232 | { |
| 1233 | lstrcpynA(full_name.short_name,name,MAX_PATHNAME_LEN); |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 1234 | drive = (int)FILE_toupper(name[0]) - 'A'; |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1235 | } |
| 1236 | else |
| 1237 | { |
| 1238 | if (driveletter) |
| 1239 | drivecur[0]=driveletter; |
| 1240 | else |
| 1241 | strcpy(drivecur,"."); |
| 1242 | if (!DOSFS_GetFullName( drivecur, FALSE, &full_name )) |
| 1243 | { |
| 1244 | FIXME("internal: error getting drive/path\n"); |
| 1245 | return 0; |
| 1246 | } |
| 1247 | /* find path that drive letter substitutes*/ |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 1248 | drive = (int)FILE_toupper(full_name.short_name[0]) -0x41; |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1249 | root= DRIVE_GetRoot(drive); |
Uwe Bonnes | 594a0dc | 2000-06-15 00:30:26 +0000 | [diff] [blame] | 1250 | if (!root) |
| 1251 | { |
| 1252 | FIXME("internal: error getting DOS Drive Root\n"); |
| 1253 | return 0; |
| 1254 | } |
Marcus Meissner | 7f0490e | 2000-10-23 00:37:06 +0000 | [diff] [blame] | 1255 | if (!strcmp(root,"/")) |
| 1256 | { |
| 1257 | /* we have just the last / and we need it. */ |
| 1258 | p= full_name.long_name; |
| 1259 | } |
| 1260 | else |
| 1261 | { |
| 1262 | p= full_name.long_name +strlen(root); |
| 1263 | } |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1264 | /* append long name (= unix name) to drive */ |
| 1265 | lstrcpynA(full_name.short_name+2,p,MAX_PATHNAME_LEN-3); |
| 1266 | /* append name to treat */ |
| 1267 | namelen= strlen(full_name.short_name); |
| 1268 | p = (char*)name; |
| 1269 | if (driveletter) |
| 1270 | p += +2; /* skip drive name when appending */ |
| 1271 | if (namelen +2 + strlen(p) > MAX_PATHNAME_LEN) |
| 1272 | { |
| 1273 | FIXME("internal error: buffer too small\n"); |
| 1274 | return 0; |
| 1275 | } |
| 1276 | full_name.short_name[namelen++] ='\\'; |
| 1277 | full_name.short_name[namelen] = 0; |
| 1278 | lstrcpynA(full_name.short_name +namelen,p,MAX_PATHNAME_LEN-namelen); |
| 1279 | } |
| 1280 | /* reverse all slashes */ |
| 1281 | for (p=full_name.short_name; |
| 1282 | p < full_name.short_name+strlen(full_name.short_name); |
| 1283 | p++) |
| 1284 | { |
| 1285 | if ( *p == '/' ) |
| 1286 | *p = '\\'; |
| 1287 | } |
| 1288 | /* Use memmove, as areas overlap*/ |
| 1289 | /* Delete .. */ |
| 1290 | while ((p = strstr(full_name.short_name,"\\..\\"))) |
| 1291 | { |
| 1292 | if (p > full_name.short_name+2) |
| 1293 | { |
| 1294 | *p = 0; |
| 1295 | q = strrchr(full_name.short_name,'\\'); |
| 1296 | memmove(q+1,p+4,strlen(p+4)+1); |
| 1297 | } |
| 1298 | else |
| 1299 | { |
| 1300 | memmove(full_name.short_name+3,p+4,strlen(p+4)+1); |
| 1301 | } |
| 1302 | } |
| 1303 | if ((full_name.short_name[2]=='.')&&(full_name.short_name[3]=='.')) |
| 1304 | { |
| 1305 | /* This case istn't treated yet : c:..\test */ |
| 1306 | memmove(full_name.short_name+2,full_name.short_name+4, |
| 1307 | strlen(full_name.short_name+4)+1); |
| 1308 | } |
| 1309 | /* Delete . */ |
| 1310 | while ((p = strstr(full_name.short_name,"\\.\\"))) |
| 1311 | { |
| 1312 | *(p+1) = 0; |
Uwe Bonnes | ed343a2 | 2000-05-19 03:37:53 +0000 | [diff] [blame] | 1313 | memmove(p+1,p+3,strlen(p+3)+1); |
Uwe Bonnes | 59b5f78 | 2000-02-27 13:58:12 +0000 | [diff] [blame] | 1314 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1315 | if (!(DRIVE_GetFlags(drive) & DRIVE_CASE_PRESERVING)) |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 1316 | for (p = full_name.short_name; *p; p++) *p = FILE_toupper(*p); |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1317 | namelen=strlen(full_name.short_name); |
| 1318 | if (!strcmp(full_name.short_name+namelen-3,"\\..")) |
| 1319 | { |
| 1320 | /* one more starnge case: "c:\test\test1\.." |
| 1321 | return "c:\test"*/ |
| 1322 | *(full_name.short_name+namelen-3)=0; |
| 1323 | q = strrchr(full_name.short_name,'\\'); |
| 1324 | *q =0; |
| 1325 | } |
| 1326 | if (full_name.short_name[namelen-1]=='.') |
| 1327 | full_name.short_name[(namelen--)-1] =0; |
| 1328 | if (!driveletter) |
| 1329 | if (full_name.short_name[namelen-1]=='\\') |
| 1330 | full_name.short_name[(namelen--)-1] =0; |
| 1331 | TRACE("got %s\n",full_name.short_name); |
| 1332 | |
Uwe Bonnes | 59b5f78 | 2000-02-27 13:58:12 +0000 | [diff] [blame] | 1333 | /* If the lpBuffer buffer is too small, the return value is the |
| 1334 | size of the buffer, in characters, required to hold the path |
| 1335 | plus the terminating \0 (tested against win95osr, bon 001118) |
| 1336 | . */ |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1337 | ret = strlen(full_name.short_name); |
Uwe Bonnes | 59b5f78 | 2000-02-27 13:58:12 +0000 | [diff] [blame] | 1338 | if (ret >= len ) |
| 1339 | { |
| 1340 | /* don't touch anything when the buffer is not large enough */ |
| 1341 | SetLastError( ERROR_INSUFFICIENT_BUFFER ); |
| 1342 | return ret+1; |
| 1343 | } |
Alexandre Julliard | 08b9b4f | 1999-06-06 17:09:21 +0000 | [diff] [blame] | 1344 | if (result) |
| 1345 | { |
| 1346 | if (unicode) |
Alexandre Julliard | 24a62ab | 2000-11-28 22:40:56 +0000 | [diff] [blame] | 1347 | MultiByteToWideChar( CP_ACP, 0, full_name.short_name, -1, (LPWSTR)result, len ); |
Alexandre Julliard | 08b9b4f | 1999-06-06 17:09:21 +0000 | [diff] [blame] | 1348 | else |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1349 | lstrcpynA( result, full_name.short_name, len ); |
Alexandre Julliard | 08b9b4f | 1999-06-06 17:09:21 +0000 | [diff] [blame] | 1350 | } |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1351 | |
Uwe Bonnes | d3b890f | 2000-04-28 20:48:54 +0000 | [diff] [blame] | 1352 | TRACE("returning '%s'\n", full_name.short_name ); |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1353 | return ret; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1354 | } |
| 1355 | |
| 1356 | |
| 1357 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 1358 | * GetFullPathNameA (KERNEL32.@) |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1359 | * NOTES |
| 1360 | * if the path closed with '\', *lastpart is 0 |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1361 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1362 | DWORD WINAPI GetFullPathNameA( LPCSTR name, DWORD len, LPSTR buffer, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 1363 | LPSTR *lastpart ) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1364 | { |
| 1365 | DWORD ret = DOSFS_DoGetFullPathName( name, len, buffer, FALSE ); |
Uwe Bonnes | 59b5f78 | 2000-02-27 13:58:12 +0000 | [diff] [blame] | 1366 | if (ret && (ret<=len) && buffer && lastpart) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1367 | { |
| 1368 | LPSTR p = buffer + strlen(buffer); |
Juergen Schmied | 30f503f | 1998-12-15 17:28:26 +0000 | [diff] [blame] | 1369 | |
Juergen Schmied | 30f503f | 1998-12-15 17:28:26 +0000 | [diff] [blame] | 1370 | if (*p != '\\') |
| 1371 | { |
| 1372 | while ((p > buffer + 2) && (*p != '\\')) p--; |
| 1373 | *lastpart = p + 1; |
| 1374 | } |
| 1375 | else *lastpart = NULL; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1376 | } |
| 1377 | return ret; |
| 1378 | } |
| 1379 | |
| 1380 | |
| 1381 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 1382 | * GetFullPathNameW (KERNEL32.@) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1383 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1384 | DWORD WINAPI GetFullPathNameW( LPCWSTR name, DWORD len, LPWSTR buffer, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 1385 | LPWSTR *lastpart ) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1386 | { |
| 1387 | LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name ); |
| 1388 | DWORD ret = DOSFS_DoGetFullPathName( nameA, len, (LPSTR)buffer, TRUE ); |
| 1389 | HeapFree( GetProcessHeap(), 0, nameA ); |
Uwe Bonnes | 59b5f78 | 2000-02-27 13:58:12 +0000 | [diff] [blame] | 1390 | if (ret && (ret<=len) && buffer && lastpart) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1391 | { |
Alexandre Julliard | e101f6d | 2000-08-14 14:42:41 +0000 | [diff] [blame] | 1392 | LPWSTR p = buffer + strlenW(buffer); |
Juergen Schmied | 8640716 | 1999-01-03 16:12:01 +0000 | [diff] [blame] | 1393 | if (*p != (WCHAR)'\\') |
| 1394 | { |
| 1395 | while ((p > buffer + 2) && (*p != (WCHAR)'\\')) p--; |
| 1396 | *lastpart = p + 1; |
| 1397 | } |
| 1398 | else *lastpart = NULL; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1399 | } |
| 1400 | return ret; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1401 | } |
| 1402 | |
Alexandre Julliard | 3a0f8b7 | 2000-12-01 20:48:41 +0000 | [diff] [blame] | 1403 | |
| 1404 | /*********************************************************************** |
Patrik Stridvall | 044855c | 2001-07-11 18:56:41 +0000 | [diff] [blame] | 1405 | * wine_get_unix_file_name (KERNEL32.@) Not a Windows API |
Alexandre Julliard | 3a0f8b7 | 2000-12-01 20:48:41 +0000 | [diff] [blame] | 1406 | * |
| 1407 | * Return the full Unix file name for a given path. |
| 1408 | */ |
| 1409 | BOOL WINAPI wine_get_unix_file_name( LPCSTR dos, LPSTR buffer, DWORD len ) |
| 1410 | { |
| 1411 | BOOL ret; |
| 1412 | DOS_FULL_NAME path; |
Alexandre Julliard | 3879b19 | 2001-01-17 01:55:04 +0000 | [diff] [blame] | 1413 | if ((ret = DOSFS_GetFullName( dos, FALSE, &path ))) lstrcpynA( buffer, path.long_name, len ); |
Alexandre Julliard | 3a0f8b7 | 2000-12-01 20:48:41 +0000 | [diff] [blame] | 1414 | return ret; |
| 1415 | } |
| 1416 | |
| 1417 | |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1418 | /*********************************************************************** |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1419 | * DOSFS_FindNextEx |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1420 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1421 | static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAA *entry ) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1422 | { |
Andreas Mohr | 220312e | 2000-10-19 20:38:38 +0000 | [diff] [blame] | 1423 | DWORD attr = info->attr | FA_UNUSED | FA_ARCHIVE | FA_RDONLY | FILE_ATTRIBUTE_SYMLINK; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1424 | UINT flags = DRIVE_GetFlags( info->drive ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1425 | char *p, buffer[MAX_PATHNAME_LEN]; |
| 1426 | const char *drive_path; |
| 1427 | int drive_root; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1428 | LPCSTR long_name, short_name; |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1429 | BY_HANDLE_FILE_INFORMATION fileinfo; |
| 1430 | char dos_name[13]; |
Alexandre Julliard | 1e37a18 | 1996-08-18 16:21:52 +0000 | [diff] [blame] | 1431 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1432 | if ((info->attr & ~(FA_UNUSED | FA_ARCHIVE | FA_RDONLY)) == FA_LABEL) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1433 | { |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1434 | if (info->cur_pos) return 0; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1435 | entry->dwFileAttributes = FILE_ATTRIBUTE_LABEL; |
Alexandre Julliard | e101f6d | 2000-08-14 14:42:41 +0000 | [diff] [blame] | 1436 | RtlSecondsSince1970ToTime( (time_t)0, &entry->ftCreationTime ); |
| 1437 | RtlSecondsSince1970ToTime( (time_t)0, &entry->ftLastAccessTime ); |
| 1438 | RtlSecondsSince1970ToTime( (time_t)0, &entry->ftLastWriteTime ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1439 | entry->nFileSizeHigh = 0; |
| 1440 | entry->nFileSizeLow = 0; |
| 1441 | entry->dwReserved0 = 0; |
| 1442 | entry->dwReserved1 = 0; |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1443 | DOSFS_ToDosDTAFormat( DRIVE_GetLabel( info->drive ), entry->cFileName ); |
| 1444 | strcpy( entry->cAlternateFileName, entry->cFileName ); |
| 1445 | info->cur_pos++; |
Stefan Leichter | eb0ab1b | 2000-08-18 23:45:46 +0000 | [diff] [blame] | 1446 | TRACE("returning %s (%s) as label\n", |
| 1447 | entry->cFileName, entry->cAlternateFileName); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1448 | return 1; |
| 1449 | } |
| 1450 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1451 | drive_path = info->path + strlen(DRIVE_GetRoot( info->drive )); |
| 1452 | while ((*drive_path == '/') || (*drive_path == '\\')) drive_path++; |
| 1453 | drive_root = !*drive_path; |
| 1454 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1455 | lstrcpynA( buffer, info->path, sizeof(buffer) - 1 ); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1456 | strcat( buffer, "/" ); |
| 1457 | p = buffer + strlen(buffer); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1458 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1459 | while (DOSFS_ReadDir( info->dir, &long_name, &short_name )) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1460 | { |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1461 | info->cur_pos++; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1462 | |
Alexandre Julliard | 0c126c7 | 1996-02-18 18:44:41 +0000 | [diff] [blame] | 1463 | /* Don't return '.' and '..' in the root of the drive */ |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1464 | if (drive_root && (long_name[0] == '.') && |
| 1465 | (!long_name[1] || ((long_name[1] == '.') && !long_name[2]))) |
| 1466 | continue; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1467 | |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1468 | /* Check the long mask */ |
| 1469 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1470 | if (info->long_mask) |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1471 | { |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1472 | if (!DOSFS_MatchLong( info->long_mask, long_name, |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1473 | flags & DRIVE_CASE_SENSITIVE )) continue; |
| 1474 | } |
| 1475 | |
| 1476 | /* Check the short mask */ |
| 1477 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1478 | if (info->short_mask) |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1479 | { |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1480 | if (!short_name) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1481 | { |
| 1482 | DOSFS_Hash( long_name, dos_name, TRUE, |
| 1483 | !(flags & DRIVE_CASE_SENSITIVE) ); |
| 1484 | short_name = dos_name; |
| 1485 | } |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1486 | if (!DOSFS_MatchShort( info->short_mask, short_name )) continue; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1487 | } |
| 1488 | |
| 1489 | /* Check the file attributes */ |
| 1490 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1491 | lstrcpynA( p, long_name, sizeof(buffer) - (int)(p - buffer) ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1492 | if (!FILE_Stat( buffer, &fileinfo )) |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1493 | { |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 1494 | WARN("can't stat %s\n", buffer); |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1495 | continue; |
| 1496 | } |
Andreas Mohr | 220312e | 2000-10-19 20:38:38 +0000 | [diff] [blame] | 1497 | if ((fileinfo.dwFileAttributes & FILE_ATTRIBUTE_SYMLINK) && |
| 1498 | (fileinfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) |
| 1499 | { |
| 1500 | static int show_dir_symlinks = -1; |
| 1501 | if (show_dir_symlinks == -1) |
| 1502 | show_dir_symlinks = PROFILE_GetWineIniBool("wine", "ShowDirSymlinks", 0); |
| 1503 | if (!show_dir_symlinks) continue; |
| 1504 | } |
| 1505 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1506 | if (fileinfo.dwFileAttributes & ~attr) continue; |
Alexandre Julliard | 139a4b1 | 1996-11-02 14:24:07 +0000 | [diff] [blame] | 1507 | |
| 1508 | /* We now have a matching entry; fill the result and return */ |
| 1509 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1510 | entry->dwFileAttributes = fileinfo.dwFileAttributes; |
| 1511 | entry->ftCreationTime = fileinfo.ftCreationTime; |
| 1512 | entry->ftLastAccessTime = fileinfo.ftLastAccessTime; |
| 1513 | entry->ftLastWriteTime = fileinfo.ftLastWriteTime; |
| 1514 | entry->nFileSizeHigh = fileinfo.nFileSizeHigh; |
| 1515 | entry->nFileSizeLow = fileinfo.nFileSizeLow; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1516 | |
| 1517 | if (short_name) |
| 1518 | DOSFS_ToDosDTAFormat( short_name, entry->cAlternateFileName ); |
| 1519 | else |
| 1520 | DOSFS_Hash( long_name, entry->cAlternateFileName, FALSE, |
| 1521 | !(flags & DRIVE_CASE_SENSITIVE) ); |
| 1522 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1523 | lstrcpynA( entry->cFileName, long_name, sizeof(entry->cFileName) ); |
Alexandre Julliard | dcd247e | 2000-08-14 17:39:15 +0000 | [diff] [blame] | 1524 | if (!(flags & DRIVE_CASE_PRESERVING)) _strlwr( entry->cFileName ); |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 1525 | TRACE("returning %s (%s) %02lx %ld\n", |
| 1526 | entry->cFileName, entry->cAlternateFileName, |
| 1527 | entry->dwFileAttributes, entry->nFileSizeLow ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1528 | return 1; |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1529 | } |
Alexandre Julliard | 4f8c37b | 1996-01-14 18:12:01 +0000 | [diff] [blame] | 1530 | return 0; /* End of directory */ |
| 1531 | } |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1532 | |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1533 | /*********************************************************************** |
| 1534 | * DOSFS_FindNext |
| 1535 | * |
| 1536 | * Find the next matching file. Return the number of entries read to find |
| 1537 | * the matching one, or 0 if no more entries. |
| 1538 | * 'short_mask' is the 8.3 mask (in FCB format), 'long_mask' is the long |
| 1539 | * file name mask. Either or both can be NULL. |
| 1540 | * |
| 1541 | * NOTE: This is supposed to be only called by the int21 emulation |
| 1542 | * routines. Thus, we should own the Win16Mutex anyway. |
| 1543 | * Nevertheless, we explicitly enter it to ensure the static |
| 1544 | * directory cache is protected. |
| 1545 | */ |
| 1546 | int DOSFS_FindNext( const char *path, const char *short_mask, |
| 1547 | const char *long_mask, int drive, BYTE attr, |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1548 | int skip, WIN32_FIND_DATAA *entry ) |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1549 | { |
Joerg Mayer | 959d73e | 2000-10-22 23:56:32 +0000 | [diff] [blame] | 1550 | static FIND_FIRST_INFO info; |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1551 | LPCSTR short_name, long_name; |
| 1552 | int count; |
| 1553 | |
Alexandre Julliard | ab68797 | 2000-11-15 23:41:46 +0000 | [diff] [blame] | 1554 | _EnterWin16Lock(); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1555 | |
| 1556 | /* Check the cached directory */ |
| 1557 | if (!(info.dir && info.path == path && info.short_mask == short_mask |
| 1558 | && info.long_mask == long_mask && info.drive == drive |
| 1559 | && info.attr == attr && info.cur_pos <= skip)) |
| 1560 | { |
| 1561 | /* Not in the cache, open it anew */ |
| 1562 | if (info.dir) DOSFS_CloseDir( info.dir ); |
| 1563 | |
| 1564 | info.path = (LPSTR)path; |
| 1565 | info.long_mask = (LPSTR)long_mask; |
| 1566 | info.short_mask = (LPSTR)short_mask; |
| 1567 | info.attr = attr; |
| 1568 | info.drive = drive; |
| 1569 | info.cur_pos = 0; |
| 1570 | info.dir = DOSFS_OpenDir( info.path ); |
| 1571 | } |
| 1572 | |
| 1573 | /* Skip to desired position */ |
| 1574 | while (info.cur_pos < skip) |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 1575 | if (info.dir && DOSFS_ReadDir( info.dir, &long_name, &short_name )) |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1576 | info.cur_pos++; |
| 1577 | else |
| 1578 | break; |
| 1579 | |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 1580 | if (info.dir && info.cur_pos == skip && DOSFS_FindNextEx( &info, entry )) |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1581 | count = info.cur_pos - skip; |
| 1582 | else |
| 1583 | count = 0; |
| 1584 | |
| 1585 | if (!count) |
| 1586 | { |
Alexandre Julliard | a0d7731 | 1998-09-13 16:32:00 +0000 | [diff] [blame] | 1587 | if (info.dir) DOSFS_CloseDir( info.dir ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1588 | memset( &info, '\0', sizeof(info) ); |
| 1589 | } |
| 1590 | |
Alexandre Julliard | ab68797 | 2000-11-15 23:41:46 +0000 | [diff] [blame] | 1591 | _LeaveWin16Lock(); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1592 | |
| 1593 | return count; |
| 1594 | } |
| 1595 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1596 | /************************************************************************* |
Patrik Stridvall | 3ca9823 | 2001-06-20 23:03:14 +0000 | [diff] [blame] | 1597 | * FindFirstFileExA (KERNEL32.@) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1598 | */ |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1599 | HANDLE WINAPI FindFirstFileExA( |
| 1600 | LPCSTR lpFileName, |
| 1601 | FINDEX_INFO_LEVELS fInfoLevelId, |
| 1602 | LPVOID lpFindFileData, |
| 1603 | FINDEX_SEARCH_OPS fSearchOp, |
| 1604 | LPVOID lpSearchFilter, |
| 1605 | DWORD dwAdditionalFlags) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1606 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1607 | DOS_FULL_NAME full_name; |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1608 | HGLOBAL handle; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1609 | FIND_FIRST_INFO *info; |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1610 | |
| 1611 | if ((fSearchOp != FindExSearchNameMatch) || (dwAdditionalFlags != 0)) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1612 | { |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1613 | FIXME("options not implemented 0x%08x 0x%08lx\n", fSearchOp, dwAdditionalFlags ); |
| 1614 | return INVALID_HANDLE_VALUE; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1615 | } |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1616 | |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1617 | switch(fInfoLevelId) |
| 1618 | { |
| 1619 | case FindExInfoStandard: |
| 1620 | { |
| 1621 | WIN32_FIND_DATAA * data = (WIN32_FIND_DATAA *) lpFindFileData; |
| 1622 | data->dwReserved0 = data->dwReserved1 = 0x0; |
| 1623 | if (!lpFileName) return 0; |
| 1624 | if (!DOSFS_GetFullName( lpFileName, FALSE, &full_name )) break; |
| 1625 | if (!(handle = GlobalAlloc(GMEM_MOVEABLE, sizeof(FIND_FIRST_INFO)))) break; |
| 1626 | info = (FIND_FIRST_INFO *)GlobalLock( handle ); |
Alexandre Julliard | 5f728ca | 2001-07-24 21:45:22 +0000 | [diff] [blame] | 1627 | info->path = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 ); |
| 1628 | strcpy( info->path, full_name.long_name ); |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1629 | info->long_mask = strrchr( info->path, '/' ); |
| 1630 | *(info->long_mask++) = '\0'; |
| 1631 | info->short_mask = NULL; |
| 1632 | info->attr = 0xff; |
| 1633 | if (lpFileName[0] && (lpFileName[1] == ':')) |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 1634 | info->drive = FILE_toupper(*lpFileName) - 'A'; |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1635 | else info->drive = DRIVE_GetCurrentDrive(); |
| 1636 | info->cur_pos = 0; |
| 1637 | |
| 1638 | info->dir = DOSFS_OpenDir( info->path ); |
| 1639 | |
| 1640 | GlobalUnlock( handle ); |
| 1641 | if (!FindNextFileA( handle, data )) |
| 1642 | { |
| 1643 | FindClose( handle ); |
| 1644 | SetLastError( ERROR_NO_MORE_FILES ); |
| 1645 | break; |
| 1646 | } |
| 1647 | return handle; |
| 1648 | } |
| 1649 | break; |
| 1650 | default: |
| 1651 | FIXME("fInfoLevelId 0x%08x not implemented\n", fInfoLevelId ); |
| 1652 | } |
| 1653 | return INVALID_HANDLE_VALUE; |
| 1654 | } |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1655 | |
| 1656 | /************************************************************************* |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 1657 | * FindFirstFileA (KERNEL32.@) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1658 | */ |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1659 | HANDLE WINAPI FindFirstFileA( |
| 1660 | LPCSTR lpFileName, |
| 1661 | WIN32_FIND_DATAA *lpFindData ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1662 | { |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1663 | return FindFirstFileExA(lpFileName, FindExInfoStandard, lpFindData, |
| 1664 | FindExSearchNameMatch, NULL, 0); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1665 | } |
| 1666 | |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1667 | /************************************************************************* |
Patrik Stridvall | 3ca9823 | 2001-06-20 23:03:14 +0000 | [diff] [blame] | 1668 | * FindFirstFileExW (KERNEL32.@) |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1669 | */ |
| 1670 | HANDLE WINAPI FindFirstFileExW( |
| 1671 | LPCWSTR lpFileName, |
| 1672 | FINDEX_INFO_LEVELS fInfoLevelId, |
| 1673 | LPVOID lpFindFileData, |
| 1674 | FINDEX_SEARCH_OPS fSearchOp, |
| 1675 | LPVOID lpSearchFilter, |
| 1676 | DWORD dwAdditionalFlags) |
| 1677 | { |
| 1678 | HANDLE handle; |
| 1679 | WIN32_FIND_DATAA dataA; |
| 1680 | LPVOID _lpFindFileData; |
| 1681 | LPSTR pathA; |
| 1682 | |
| 1683 | switch(fInfoLevelId) |
| 1684 | { |
| 1685 | case FindExInfoStandard: |
| 1686 | { |
| 1687 | _lpFindFileData = &dataA; |
| 1688 | } |
| 1689 | break; |
| 1690 | default: |
| 1691 | FIXME("fInfoLevelId 0x%08x not implemented\n", fInfoLevelId ); |
| 1692 | return INVALID_HANDLE_VALUE; |
| 1693 | } |
| 1694 | |
| 1695 | pathA = HEAP_strdupWtoA( GetProcessHeap(), 0, lpFileName ); |
| 1696 | handle = FindFirstFileExA(pathA, fInfoLevelId, _lpFindFileData, fSearchOp, lpSearchFilter, dwAdditionalFlags); |
| 1697 | HeapFree( GetProcessHeap(), 0, pathA ); |
| 1698 | if (handle == INVALID_HANDLE_VALUE) return handle; |
| 1699 | |
| 1700 | switch(fInfoLevelId) |
| 1701 | { |
| 1702 | case FindExInfoStandard: |
| 1703 | { |
| 1704 | WIN32_FIND_DATAW *dataW = (WIN32_FIND_DATAW*) lpFindFileData; |
| 1705 | dataW->dwFileAttributes = dataA.dwFileAttributes; |
| 1706 | dataW->ftCreationTime = dataA.ftCreationTime; |
| 1707 | dataW->ftLastAccessTime = dataA.ftLastAccessTime; |
| 1708 | dataW->ftLastWriteTime = dataA.ftLastWriteTime; |
| 1709 | dataW->nFileSizeHigh = dataA.nFileSizeHigh; |
| 1710 | dataW->nFileSizeLow = dataA.nFileSizeLow; |
Alexandre Julliard | 072dfb5 | 2000-09-25 23:30:56 +0000 | [diff] [blame] | 1711 | MultiByteToWideChar( CP_ACP, 0, dataA.cFileName, -1, |
| 1712 | dataW->cFileName, sizeof(dataW->cFileName)/sizeof(WCHAR) ); |
| 1713 | MultiByteToWideChar( CP_ACP, 0, dataA.cAlternateFileName, -1, |
| 1714 | dataW->cAlternateFileName, |
| 1715 | sizeof(dataW->cAlternateFileName)/sizeof(WCHAR) ); |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1716 | } |
| 1717 | break; |
| 1718 | default: |
| 1719 | FIXME("fInfoLevelId 0x%08x not implemented\n", fInfoLevelId ); |
| 1720 | return INVALID_HANDLE_VALUE; |
| 1721 | } |
| 1722 | return handle; |
| 1723 | } |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1724 | |
| 1725 | /************************************************************************* |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 1726 | * FindFirstFileW (KERNEL32.@) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1727 | */ |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1728 | HANDLE WINAPI FindFirstFileW( LPCWSTR lpFileName, WIN32_FIND_DATAW *lpFindData ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1729 | { |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1730 | return FindFirstFileExW(lpFileName, FindExInfoStandard, lpFindData, |
| 1731 | FindExSearchNameMatch, NULL, 0); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1732 | } |
| 1733 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1734 | /************************************************************************* |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 1735 | * FindNextFileA (KERNEL32.@) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1736 | */ |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1737 | BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1738 | { |
| 1739 | FIND_FIRST_INFO *info; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1740 | |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1741 | if ((handle == INVALID_HANDLE_VALUE) || |
| 1742 | !(info = (FIND_FIRST_INFO *)GlobalLock( handle ))) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1743 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 1744 | SetLastError( ERROR_INVALID_HANDLE ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1745 | return FALSE; |
| 1746 | } |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1747 | GlobalUnlock( handle ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1748 | if (!info->path || !info->dir) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1749 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 1750 | SetLastError( ERROR_NO_MORE_FILES ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1751 | return FALSE; |
| 1752 | } |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1753 | if (!DOSFS_FindNextEx( info, data )) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1754 | { |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1755 | DOSFS_CloseDir( info->dir ); info->dir = NULL; |
Alexandre Julliard | 90476d6 | 2000-02-16 22:47:24 +0000 | [diff] [blame] | 1756 | HeapFree( GetProcessHeap(), 0, info->path ); |
Alexandre Julliard | 85ed45e | 1998-08-22 19:03:56 +0000 | [diff] [blame] | 1757 | info->path = info->long_mask = NULL; |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 1758 | SetLastError( ERROR_NO_MORE_FILES ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1759 | return FALSE; |
| 1760 | } |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1761 | return TRUE; |
| 1762 | } |
| 1763 | |
| 1764 | |
| 1765 | /************************************************************************* |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 1766 | * FindNextFileW (KERNEL32.@) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1767 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1768 | BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1769 | { |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1770 | WIN32_FIND_DATAA dataA; |
| 1771 | if (!FindNextFileA( handle, &dataA )) return FALSE; |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1772 | data->dwFileAttributes = dataA.dwFileAttributes; |
| 1773 | data->ftCreationTime = dataA.ftCreationTime; |
| 1774 | data->ftLastAccessTime = dataA.ftLastAccessTime; |
| 1775 | data->ftLastWriteTime = dataA.ftLastWriteTime; |
| 1776 | data->nFileSizeHigh = dataA.nFileSizeHigh; |
| 1777 | data->nFileSizeLow = dataA.nFileSizeLow; |
Alexandre Julliard | 072dfb5 | 2000-09-25 23:30:56 +0000 | [diff] [blame] | 1778 | MultiByteToWideChar( CP_ACP, 0, dataA.cFileName, -1, |
| 1779 | data->cFileName, sizeof(data->cFileName)/sizeof(WCHAR) ); |
| 1780 | MultiByteToWideChar( CP_ACP, 0, dataA.cAlternateFileName, -1, |
| 1781 | data->cAlternateFileName, |
| 1782 | sizeof(data->cAlternateFileName)/sizeof(WCHAR) ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1783 | return TRUE; |
| 1784 | } |
| 1785 | |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1786 | /************************************************************************* |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 1787 | * FindClose (KERNEL32.@) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1788 | */ |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1789 | BOOL WINAPI FindClose( HANDLE handle ) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1790 | { |
| 1791 | FIND_FIRST_INFO *info; |
| 1792 | |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1793 | if ((handle == INVALID_HANDLE_VALUE) || |
| 1794 | !(info = (FIND_FIRST_INFO *)GlobalLock( handle ))) |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1795 | { |
Alexandre Julliard | 4ff2a27 | 1999-01-31 15:23:45 +0000 | [diff] [blame] | 1796 | SetLastError( ERROR_INVALID_HANDLE ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1797 | return FALSE; |
| 1798 | } |
Dominik Strasser | 4f46b5d | 2001-04-20 18:38:41 +0000 | [diff] [blame] | 1799 | __TRY |
| 1800 | { |
| 1801 | if (info->dir) DOSFS_CloseDir( info->dir ); |
| 1802 | if (info->path) HeapFree( GetProcessHeap(), 0, info->path ); |
| 1803 | } |
| 1804 | __EXCEPT(page_fault) |
| 1805 | { |
| 1806 | WARN("Illegal handle %x\n", handle); |
| 1807 | SetLastError( ERROR_INVALID_HANDLE ); |
| 1808 | return FALSE; |
| 1809 | } |
| 1810 | __ENDTRY |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 1811 | GlobalUnlock( handle ); |
| 1812 | GlobalFree( handle ); |
Alexandre Julliard | 9ea19e5 | 1997-01-01 17:29:55 +0000 | [diff] [blame] | 1813 | return TRUE; |
| 1814 | } |
| 1815 | |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1816 | /*********************************************************************** |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1817 | * DOSFS_UnixTimeToFileTime |
| 1818 | * |
| 1819 | * Convert a Unix time to FILETIME format. |
| 1820 | * The FILETIME structure is a 64-bit value representing the number of |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1821 | * 100-nanosecond intervals since January 1, 1601, 0:00. |
| 1822 | * 'remainder' is the nonnegative number of 100-ns intervals |
| 1823 | * corresponding to the time fraction smaller than 1 second that |
| 1824 | * couldn't be stored in the time_t value. |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1825 | */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1826 | void DOSFS_UnixTimeToFileTime( time_t unix_time, FILETIME *filetime, |
| 1827 | DWORD remainder ) |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1828 | { |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1829 | /* NOTES: |
| 1830 | |
| 1831 | CONSTANTS: |
| 1832 | The time difference between 1 January 1601, 00:00:00 and |
| 1833 | 1 January 1970, 00:00:00 is 369 years, plus the leap years |
| 1834 | from 1604 to 1968, excluding 1700, 1800, 1900. |
| 1835 | This makes (1968 - 1600) / 4 - 3 = 89 leap days, and a total |
| 1836 | of 134774 days. |
| 1837 | |
| 1838 | Any day in that period had 24 * 60 * 60 = 86400 seconds. |
| 1839 | |
| 1840 | The time difference is 134774 * 86400 * 10000000, which can be written |
| 1841 | 116444736000000000 |
| 1842 | 27111902 * 2^32 + 3577643008 |
| 1843 | 413 * 2^48 + 45534 * 2^32 + 54590 * 2^16 + 32768 |
| 1844 | |
| 1845 | If you find that these constants are buggy, please change them in all |
| 1846 | instances in both conversion functions. |
| 1847 | |
| 1848 | VERSIONS: |
| 1849 | There are two versions, one of them uses long long variables and |
| 1850 | is presumably faster but not ISO C. The other one uses standard C |
| 1851 | data types and operations but relies on the assumption that negative |
| 1852 | numbers are stored as 2's complement (-1 is 0xffff....). If this |
| 1853 | assumption is violated, dates before 1970 will not convert correctly. |
| 1854 | This should however work on any reasonable architecture where WINE |
| 1855 | will run. |
| 1856 | |
| 1857 | DETAILS: |
| 1858 | |
| 1859 | Take care not to remove the casts. I have tested these functions |
| 1860 | (in both versions) for a lot of numbers. I would be interested in |
| 1861 | results on other compilers than GCC. |
| 1862 | |
| 1863 | The operations have been designed to account for the possibility |
| 1864 | of 64-bit time_t in future UNICES. Even the versions without |
| 1865 | internal long long numbers will work if time_t only is 64 bit. |
| 1866 | A 32-bit shift, which was necessary for that operation, turned out |
| 1867 | not to work correctly in GCC, besides giving the warning. So I |
| 1868 | used a double 16-bit shift instead. Numbers are in the ISO version |
| 1869 | represented by three limbs, the most significant with 32 bit, the |
| 1870 | other two with 16 bit each. |
| 1871 | |
| 1872 | As the modulo-operator % is not well-defined for negative numbers, |
| 1873 | negative divisors have been avoided in DOSFS_FileTimeToUnixTime. |
| 1874 | |
| 1875 | There might be quicker ways to do this in C. Certainly so in |
| 1876 | assembler. |
| 1877 | |
| 1878 | Claus Fischer, fischer@iue.tuwien.ac.at |
| 1879 | */ |
| 1880 | |
Patrik Stridvall | 9633632 | 1999-10-24 22:13:47 +0000 | [diff] [blame] | 1881 | #if SIZEOF_LONG_LONG >= 8 |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1882 | # define USE_LONG_LONG 1 |
| 1883 | #else |
| 1884 | # define USE_LONG_LONG 0 |
| 1885 | #endif |
| 1886 | |
| 1887 | #if USE_LONG_LONG /* gcc supports long long type */ |
| 1888 | |
| 1889 | long long int t = unix_time; |
| 1890 | t *= 10000000; |
| 1891 | t += 116444736000000000LL; |
| 1892 | t += remainder; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1893 | filetime->dwLowDateTime = (UINT)t; |
| 1894 | filetime->dwHighDateTime = (UINT)(t >> 32); |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1895 | |
| 1896 | #else /* ISO version */ |
| 1897 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1898 | UINT a0; /* 16 bit, low bits */ |
| 1899 | UINT a1; /* 16 bit, medium bits */ |
| 1900 | UINT a2; /* 32 bit, high bits */ |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1901 | |
| 1902 | /* Copy the unix time to a2/a1/a0 */ |
| 1903 | a0 = unix_time & 0xffff; |
| 1904 | a1 = (unix_time >> 16) & 0xffff; |
| 1905 | /* This is obsolete if unix_time is only 32 bits, but it does not hurt. |
| 1906 | Do not replace this by >> 32, it gives a compiler warning and it does |
| 1907 | not work. */ |
| 1908 | a2 = (unix_time >= 0 ? (unix_time >> 16) >> 16 : |
| 1909 | ~((~unix_time >> 16) >> 16)); |
| 1910 | |
| 1911 | /* Multiply a by 10000000 (a = a2/a1/a0) |
| 1912 | Split the factor into 10000 * 1000 which are both less than 0xffff. */ |
| 1913 | a0 *= 10000; |
| 1914 | a1 = a1 * 10000 + (a0 >> 16); |
| 1915 | a2 = a2 * 10000 + (a1 >> 16); |
| 1916 | a0 &= 0xffff; |
| 1917 | a1 &= 0xffff; |
| 1918 | |
| 1919 | a0 *= 1000; |
| 1920 | a1 = a1 * 1000 + (a0 >> 16); |
| 1921 | a2 = a2 * 1000 + (a1 >> 16); |
| 1922 | a0 &= 0xffff; |
| 1923 | a1 &= 0xffff; |
| 1924 | |
| 1925 | /* Add the time difference and the remainder */ |
| 1926 | a0 += 32768 + (remainder & 0xffff); |
| 1927 | a1 += 54590 + (remainder >> 16 ) + (a0 >> 16); |
| 1928 | a2 += 27111902 + (a1 >> 16); |
| 1929 | a0 &= 0xffff; |
| 1930 | a1 &= 0xffff; |
| 1931 | |
| 1932 | /* Set filetime */ |
| 1933 | filetime->dwLowDateTime = (a1 << 16) + a0; |
| 1934 | filetime->dwHighDateTime = a2; |
| 1935 | #endif |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1936 | } |
| 1937 | |
| 1938 | |
| 1939 | /*********************************************************************** |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1940 | * DOSFS_FileTimeToUnixTime |
| 1941 | * |
| 1942 | * Convert a FILETIME format to Unix time. |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1943 | * If not NULL, 'remainder' contains the fractional part of the filetime, |
| 1944 | * in the range of [0..9999999] (even if time_t is negative). |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1945 | */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 1946 | time_t DOSFS_FileTimeToUnixTime( const FILETIME *filetime, DWORD *remainder ) |
Alexandre Julliard | ca22b33 | 1996-07-12 19:02:39 +0000 | [diff] [blame] | 1947 | { |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1948 | /* Read the comment in the function DOSFS_UnixTimeToFileTime. */ |
| 1949 | #if USE_LONG_LONG |
| 1950 | |
| 1951 | long long int t = filetime->dwHighDateTime; |
| 1952 | t <<= 32; |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1953 | t += (UINT)filetime->dwLowDateTime; |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1954 | t -= 116444736000000000LL; |
| 1955 | if (t < 0) |
| 1956 | { |
| 1957 | if (remainder) *remainder = 9999999 - (-t - 1) % 10000000; |
| 1958 | return -1 - ((-t - 1) / 10000000); |
| 1959 | } |
| 1960 | else |
| 1961 | { |
| 1962 | if (remainder) *remainder = t % 10000000; |
| 1963 | return t / 10000000; |
| 1964 | } |
| 1965 | |
| 1966 | #else /* ISO version */ |
| 1967 | |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1968 | UINT a0; /* 16 bit, low bits */ |
| 1969 | UINT a1; /* 16 bit, medium bits */ |
| 1970 | UINT a2; /* 32 bit, high bits */ |
| 1971 | UINT r; /* remainder of division */ |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1972 | unsigned int carry; /* carry bit for subtraction */ |
| 1973 | int negative; /* whether a represents a negative value */ |
| 1974 | |
| 1975 | /* Copy the time values to a2/a1/a0 */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1976 | a2 = (UINT)filetime->dwHighDateTime; |
| 1977 | a1 = ((UINT)filetime->dwLowDateTime ) >> 16; |
| 1978 | a0 = ((UINT)filetime->dwLowDateTime ) & 0xffff; |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1979 | |
| 1980 | /* Subtract the time difference */ |
| 1981 | if (a0 >= 32768 ) a0 -= 32768 , carry = 0; |
| 1982 | else a0 += (1 << 16) - 32768 , carry = 1; |
| 1983 | |
| 1984 | if (a1 >= 54590 + carry) a1 -= 54590 + carry, carry = 0; |
| 1985 | else a1 += (1 << 16) - 54590 - carry, carry = 1; |
| 1986 | |
| 1987 | a2 -= 27111902 + carry; |
| 1988 | |
| 1989 | /* If a is negative, replace a by (-1-a) */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 1990 | negative = (a2 >= ((UINT)1) << 31); |
Alexandre Julliard | d37eb36 | 1997-07-20 16:23:21 +0000 | [diff] [blame] | 1991 | if (negative) |
| 1992 | { |
| 1993 | /* Set a to -a - 1 (a is a2/a1/a0) */ |
| 1994 | a0 = 0xffff - a0; |
| 1995 | a1 = 0xffff - a1; |
| 1996 | a2 = ~a2; |
| 1997 | } |
| 1998 | |
| 1999 | /* Divide a by 10000000 (a = a2/a1/a0), put the rest into r. |
| 2000 | Split the divisor into 10000 * 1000 which are both less than 0xffff. */ |
| 2001 | a1 += (a2 % 10000) << 16; |
| 2002 | a2 /= 10000; |
| 2003 | a0 += (a1 % 10000) << 16; |
| 2004 | a1 /= 10000; |
| 2005 | r = a0 % 10000; |
| 2006 | a0 /= 10000; |
| 2007 | |
| 2008 | a1 += (a2 % 1000) << 16; |
| 2009 | a2 /= 1000; |
| 2010 | a0 += (a1 % 1000) << 16; |
| 2011 | a1 /= 1000; |
| 2012 | r += (a0 % 1000) * 10000; |
| 2013 | a0 /= 1000; |
| 2014 | |
| 2015 | /* If a was negative, replace a by (-1-a) and r by (9999999 - r) */ |
| 2016 | if (negative) |
| 2017 | { |
| 2018 | /* Set a to -a - 1 (a is a2/a1/a0) */ |
| 2019 | a0 = 0xffff - a0; |
| 2020 | a1 = 0xffff - a1; |
| 2021 | a2 = ~a2; |
| 2022 | |
| 2023 | r = 9999999 - r; |
| 2024 | } |
| 2025 | |
| 2026 | if (remainder) *remainder = r; |
| 2027 | |
| 2028 | /* Do not replace this by << 32, it gives a compiler warning and it does |
| 2029 | not work. */ |
| 2030 | return ((((time_t)a2) << 16) << 16) + (a1 << 16) + a0; |
| 2031 | #endif |
Alexandre Julliard | b1bac32 | 1996-12-15 19:45:59 +0000 | [diff] [blame] | 2032 | } |
| 2033 | |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2034 | |
| 2035 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2036 | * MulDiv (KERNEL32.@) |
Alexandre Julliard | 15467bf | 2000-08-01 22:03:18 +0000 | [diff] [blame] | 2037 | * RETURNS |
| 2038 | * Result of multiplication and division |
| 2039 | * -1: Overflow occurred or Divisor was 0 |
| 2040 | */ |
| 2041 | INT WINAPI MulDiv( |
| 2042 | INT nMultiplicand, |
| 2043 | INT nMultiplier, |
| 2044 | INT nDivisor) |
| 2045 | { |
| 2046 | #if SIZEOF_LONG_LONG >= 8 |
| 2047 | long long ret; |
| 2048 | |
| 2049 | if (!nDivisor) return -1; |
| 2050 | |
| 2051 | /* We want to deal with a positive divisor to simplify the logic. */ |
| 2052 | if (nDivisor < 0) |
| 2053 | { |
| 2054 | nMultiplicand = - nMultiplicand; |
| 2055 | nDivisor = -nDivisor; |
| 2056 | } |
| 2057 | |
| 2058 | /* If the result is positive, we "add" to round. else, we subtract to round. */ |
| 2059 | if ( ( (nMultiplicand < 0) && (nMultiplier < 0) ) || |
| 2060 | ( (nMultiplicand >= 0) && (nMultiplier >= 0) ) ) |
| 2061 | ret = (((long long)nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor; |
| 2062 | else |
| 2063 | ret = (((long long)nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor; |
| 2064 | |
| 2065 | if ((ret > 2147483647) || (ret < -2147483647)) return -1; |
| 2066 | return ret; |
| 2067 | #else |
| 2068 | if (!nDivisor) return -1; |
| 2069 | |
| 2070 | /* We want to deal with a positive divisor to simplify the logic. */ |
| 2071 | if (nDivisor < 0) |
| 2072 | { |
| 2073 | nMultiplicand = - nMultiplicand; |
| 2074 | nDivisor = -nDivisor; |
| 2075 | } |
| 2076 | |
| 2077 | /* If the result is positive, we "add" to round. else, we subtract to round. */ |
| 2078 | if ( ( (nMultiplicand < 0) && (nMultiplier < 0) ) || |
| 2079 | ( (nMultiplicand >= 0) && (nMultiplier >= 0) ) ) |
| 2080 | return ((nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor; |
| 2081 | |
| 2082 | return ((nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor; |
| 2083 | |
| 2084 | #endif |
| 2085 | } |
| 2086 | |
| 2087 | |
| 2088 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2089 | * DosDateTimeToFileTime (KERNEL32.@) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2090 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2091 | BOOL WINAPI DosDateTimeToFileTime( WORD fatdate, WORD fattime, LPFILETIME ft) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2092 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2093 | struct tm newtm; |
| 2094 | |
| 2095 | newtm.tm_sec = (fattime & 0x1f) * 2; |
| 2096 | newtm.tm_min = (fattime >> 5) & 0x3f; |
| 2097 | newtm.tm_hour = (fattime >> 11); |
| 2098 | newtm.tm_mday = (fatdate & 0x1f); |
| 2099 | newtm.tm_mon = ((fatdate >> 5) & 0x0f) - 1; |
| 2100 | newtm.tm_year = (fatdate >> 9) + 80; |
Alexandre Julliard | e101f6d | 2000-08-14 14:42:41 +0000 | [diff] [blame] | 2101 | RtlSecondsSince1970ToTime( mktime( &newtm ), ft ); |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2102 | return TRUE; |
| 2103 | } |
| 2104 | |
| 2105 | |
| 2106 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2107 | * FileTimeToDosDateTime (KERNEL32.@) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2108 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2109 | BOOL WINAPI FileTimeToDosDateTime( const FILETIME *ft, LPWORD fatdate, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 2110 | LPWORD fattime ) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2111 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2112 | time_t unixtime = DOSFS_FileTimeToUnixTime( ft, NULL ); |
| 2113 | struct tm *tm = localtime( &unixtime ); |
| 2114 | if (fattime) |
| 2115 | *fattime = (tm->tm_hour << 11) + (tm->tm_min << 5) + (tm->tm_sec / 2); |
| 2116 | if (fatdate) |
| 2117 | *fatdate = ((tm->tm_year - 80) << 9) + ((tm->tm_mon + 1) << 5) |
| 2118 | + tm->tm_mday; |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2119 | return TRUE; |
| 2120 | } |
| 2121 | |
| 2122 | |
| 2123 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2124 | * LocalFileTimeToFileTime (KERNEL32.@) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2125 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2126 | BOOL WINAPI LocalFileTimeToFileTime( const FILETIME *localft, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 2127 | LPFILETIME utcft ) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2128 | { |
| 2129 | struct tm *xtm; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2130 | DWORD remainder; |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2131 | |
| 2132 | /* convert from local to UTC. Perhaps not correct. FIXME */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2133 | time_t unixtime = DOSFS_FileTimeToUnixTime( localft, &remainder ); |
| 2134 | xtm = gmtime( &unixtime ); |
| 2135 | DOSFS_UnixTimeToFileTime( mktime(xtm), utcft, remainder ); |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2136 | return TRUE; |
| 2137 | } |
| 2138 | |
| 2139 | |
| 2140 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2141 | * FileTimeToLocalFileTime (KERNEL32.@) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2142 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2143 | BOOL WINAPI FileTimeToLocalFileTime( const FILETIME *utcft, |
Alexandre Julliard | 670cdc4 | 1997-08-24 16:00:30 +0000 | [diff] [blame] | 2144 | LPFILETIME localft ) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2145 | { |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2146 | DWORD remainder; |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2147 | /* convert from UTC to local. Perhaps not correct. FIXME */ |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2148 | time_t unixtime = DOSFS_FileTimeToUnixTime( utcft, &remainder ); |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2149 | #ifdef HAVE_TIMEGM |
| 2150 | struct tm *xtm = localtime( &unixtime ); |
| 2151 | time_t localtime; |
| 2152 | |
| 2153 | localtime = timegm(xtm); |
| 2154 | DOSFS_UnixTimeToFileTime( localtime, localft, remainder ); |
| 2155 | |
| 2156 | #else |
| 2157 | struct tm *xtm,*gtm; |
| 2158 | time_t time1,time2; |
| 2159 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2160 | xtm = localtime( &unixtime ); |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2161 | gtm = gmtime( &unixtime ); |
| 2162 | time1 = mktime(xtm); |
| 2163 | time2 = mktime(gtm); |
| 2164 | DOSFS_UnixTimeToFileTime( 2*time1-time2, localft, remainder ); |
| 2165 | #endif |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2166 | return TRUE; |
| 2167 | } |
| 2168 | |
| 2169 | |
| 2170 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2171 | * FileTimeToSystemTime (KERNEL32.@) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2172 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2173 | BOOL WINAPI FileTimeToSystemTime( const FILETIME *ft, LPSYSTEMTIME syst ) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2174 | { |
| 2175 | struct tm *xtm; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2176 | DWORD remainder; |
| 2177 | time_t xtime = DOSFS_FileTimeToUnixTime( ft, &remainder ); |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2178 | xtm = gmtime(&xtime); |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2179 | syst->wYear = xtm->tm_year+1900; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 2180 | syst->wMonth = xtm->tm_mon + 1; |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2181 | syst->wDayOfWeek = xtm->tm_wday; |
| 2182 | syst->wDay = xtm->tm_mday; |
| 2183 | syst->wHour = xtm->tm_hour; |
| 2184 | syst->wMinute = xtm->tm_min; |
| 2185 | syst->wSecond = xtm->tm_sec; |
| 2186 | syst->wMilliseconds = remainder / 10000; |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2187 | return TRUE; |
| 2188 | } |
| 2189 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2190 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2191 | * QueryDosDeviceA (KERNEL32.@) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2192 | * |
| 2193 | * returns array of strings terminated by \0, terminated by \0 |
| 2194 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2195 | DWORD WINAPI QueryDosDeviceA(LPCSTR devname,LPSTR target,DWORD bufsize) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2196 | { |
| 2197 | LPSTR s; |
| 2198 | char buffer[200]; |
| 2199 | |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 2200 | TRACE("(%s,...)\n", devname ? devname : "<null>"); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2201 | if (!devname) { |
| 2202 | /* return known MSDOS devices */ |
Alexandre Julliard | 24a62ab | 2000-11-28 22:40:56 +0000 | [diff] [blame] | 2203 | static const char devices[24] = "CON\0COM1\0COM2\0LPT1\0NUL\0\0"; |
| 2204 | memcpy( target, devices, min(bufsize,sizeof(devices)) ); |
| 2205 | return min(bufsize,sizeof(devices)); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2206 | } |
Marcus Meissner | 04d5efd | 2001-05-25 20:39:45 +0000 | [diff] [blame] | 2207 | /* In theory all that are possible and have been defined. |
| 2208 | * Now just those below, since mirc uses it to check for special files. |
| 2209 | * |
| 2210 | * (It is more complex, and supports netmounted stuff, and \\.\ stuff, |
| 2211 | * but currently we just ignore that.) |
| 2212 | */ |
| 2213 | #define CHECK(x) (strstr(devname,#x)==devname) |
| 2214 | if (CHECK(con) || CHECK(com) || CHECK(lpt) || CHECK(nul)) { |
| 2215 | strcpy(buffer,"\\DEV\\"); |
| 2216 | strcat(buffer,devname); |
| 2217 | if ((s=strchr(buffer,':'))) *s='\0'; |
| 2218 | lstrcpynA(target,buffer,bufsize); |
| 2219 | return strlen(buffer)+1; |
| 2220 | } else { |
| 2221 | if (strchr(devname,':') || devname[0]=='\\') { |
| 2222 | /* This might be a DOS device we do not handle yet ... */ |
| 2223 | FIXME("(%s) not detected as DOS device!\n",devname); |
| 2224 | } |
| 2225 | SetLastError(ERROR_DEV_NOT_EXIST); |
| 2226 | return 0; |
| 2227 | } |
| 2228 | |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2229 | } |
| 2230 | |
| 2231 | |
| 2232 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2233 | * QueryDosDeviceW (KERNEL32.@) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2234 | * |
| 2235 | * returns array of strings terminated by \0, terminated by \0 |
| 2236 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2237 | DWORD WINAPI QueryDosDeviceW(LPCWSTR devname,LPWSTR target,DWORD bufsize) |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2238 | { |
| 2239 | LPSTR devnameA = devname?HEAP_strdupWtoA(GetProcessHeap(),0,devname):NULL; |
Dimitrie O. Paun | abdbced | 2000-04-29 14:20:28 +0000 | [diff] [blame] | 2240 | LPSTR targetA = (LPSTR)HeapAlloc(GetProcessHeap(),0,bufsize); |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2241 | DWORD ret = QueryDosDeviceA(devnameA,targetA,bufsize); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2242 | |
Alexandre Julliard | 24a62ab | 2000-11-28 22:40:56 +0000 | [diff] [blame] | 2243 | ret = MultiByteToWideChar( CP_ACP, 0, targetA, ret, target, bufsize ); |
Alexandre Julliard | c6c0944 | 1997-01-12 18:32:19 +0000 | [diff] [blame] | 2244 | if (devnameA) HeapFree(GetProcessHeap(),0,devnameA); |
| 2245 | if (targetA) HeapFree(GetProcessHeap(),0,targetA); |
| 2246 | return ret; |
| 2247 | } |
| 2248 | |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2249 | |
| 2250 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2251 | * SystemTimeToFileTime (KERNEL32.@) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2252 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2253 | BOOL WINAPI SystemTimeToFileTime( const SYSTEMTIME *syst, LPFILETIME ft ) |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2254 | { |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2255 | #ifdef HAVE_TIMEGM |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2256 | struct tm xtm; |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2257 | time_t utctime; |
| 2258 | #else |
| 2259 | struct tm xtm,*local_tm,*utc_tm; |
| 2260 | time_t localtim,utctime; |
| 2261 | #endif |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2262 | |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2263 | xtm.tm_year = syst->wYear-1900; |
Alexandre Julliard | a11d7b1 | 1998-03-01 20:05:02 +0000 | [diff] [blame] | 2264 | xtm.tm_mon = syst->wMonth - 1; |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2265 | xtm.tm_wday = syst->wDayOfWeek; |
| 2266 | xtm.tm_mday = syst->wDay; |
| 2267 | xtm.tm_hour = syst->wHour; |
| 2268 | xtm.tm_min = syst->wMinute; |
Alexandre Julliard | a69b88b | 1998-03-15 20:29:56 +0000 | [diff] [blame] | 2269 | xtm.tm_sec = syst->wSecond; /* this is UTC */ |
| 2270 | xtm.tm_isdst = -1; |
| 2271 | #ifdef HAVE_TIMEGM |
| 2272 | utctime = timegm(&xtm); |
| 2273 | DOSFS_UnixTimeToFileTime( utctime, ft, |
| 2274 | syst->wMilliseconds * 10000 ); |
| 2275 | #else |
| 2276 | localtim = mktime(&xtm); /* now we've got local time */ |
| 2277 | local_tm = localtime(&localtim); |
| 2278 | utc_tm = gmtime(&localtim); |
| 2279 | utctime = mktime(utc_tm); |
| 2280 | DOSFS_UnixTimeToFileTime( 2*localtim -utctime, ft, |
| 2281 | syst->wMilliseconds * 10000 ); |
| 2282 | #endif |
Alexandre Julliard | 75d86e1 | 1996-11-17 18:59:11 +0000 | [diff] [blame] | 2283 | return TRUE; |
| 2284 | } |
Marcus Meissner | 575a165 | 1998-10-21 16:47:29 +0000 | [diff] [blame] | 2285 | |
Patrik Stridvall | 3a9c476 | 1999-10-31 02:07:05 +0000 | [diff] [blame] | 2286 | /*********************************************************************** |
Patrik Stridvall | dae8de6 | 2001-06-13 20:13:18 +0000 | [diff] [blame] | 2287 | * DefineDosDeviceA (KERNEL32.@) |
Patrik Stridvall | 3a9c476 | 1999-10-31 02:07:05 +0000 | [diff] [blame] | 2288 | */ |
Alexandre Julliard | a396029 | 1999-02-26 11:11:13 +0000 | [diff] [blame] | 2289 | BOOL WINAPI DefineDosDeviceA(DWORD flags,LPCSTR devname,LPCSTR targetpath) { |
Dimitrie O. Paun | dd03cc1 | 1999-12-08 03:56:23 +0000 | [diff] [blame] | 2290 | FIXME("(0x%08lx,%s,%s),stub!\n",flags,devname,targetpath); |
Marcus Meissner | 575a165 | 1998-10-21 16:47:29 +0000 | [diff] [blame] | 2291 | SetLastError(ERROR_CALL_NOT_IMPLEMENTED); |
| 2292 | return FALSE; |
| 2293 | } |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2294 | |
| 2295 | /* |
| 2296 | --- 16 bit functions --- |
| 2297 | */ |
| 2298 | |
| 2299 | /************************************************************************* |
Patrik Stridvall | 01d5e5b | 2001-07-02 19:59:40 +0000 | [diff] [blame] | 2300 | * FindFirstFile (KERNEL.413) |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2301 | */ |
| 2302 | HANDLE16 WINAPI FindFirstFile16( LPCSTR path, WIN32_FIND_DATAA *data ) |
| 2303 | { |
| 2304 | DOS_FULL_NAME full_name; |
| 2305 | HGLOBAL16 handle; |
| 2306 | FIND_FIRST_INFO *info; |
| 2307 | |
| 2308 | data->dwReserved0 = data->dwReserved1 = 0x0; |
| 2309 | if (!path) return 0; |
| 2310 | if (!DOSFS_GetFullName( path, FALSE, &full_name )) |
| 2311 | return INVALID_HANDLE_VALUE16; |
| 2312 | if (!(handle = GlobalAlloc16( GMEM_MOVEABLE, sizeof(FIND_FIRST_INFO) ))) |
| 2313 | return INVALID_HANDLE_VALUE16; |
| 2314 | info = (FIND_FIRST_INFO *)GlobalLock16( handle ); |
Alexandre Julliard | 5f728ca | 2001-07-24 21:45:22 +0000 | [diff] [blame] | 2315 | info->path = HeapAlloc( GetProcessHeap(), 0, strlen(full_name.long_name)+1 ); |
| 2316 | strcpy( info->path, full_name.long_name ); |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2317 | info->long_mask = strrchr( info->path, '/' ); |
| 2318 | if (info->long_mask ) |
| 2319 | *(info->long_mask++) = '\0'; |
| 2320 | info->short_mask = NULL; |
| 2321 | info->attr = 0xff; |
Aric Stewart | e4d0932 | 2000-12-03 03:14:29 +0000 | [diff] [blame] | 2322 | if (path[0] && (path[1] == ':')) info->drive = FILE_toupper(*path) - 'A'; |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2323 | else info->drive = DRIVE_GetCurrentDrive(); |
| 2324 | info->cur_pos = 0; |
| 2325 | |
| 2326 | info->dir = DOSFS_OpenDir( info->path ); |
| 2327 | |
| 2328 | GlobalUnlock16( handle ); |
| 2329 | if (!FindNextFile16( handle, data )) |
| 2330 | { |
| 2331 | FindClose16( handle ); |
| 2332 | SetLastError( ERROR_NO_MORE_FILES ); |
| 2333 | return INVALID_HANDLE_VALUE16; |
| 2334 | } |
| 2335 | return handle; |
| 2336 | } |
| 2337 | |
| 2338 | /************************************************************************* |
Patrik Stridvall | 01d5e5b | 2001-07-02 19:59:40 +0000 | [diff] [blame] | 2339 | * FindNextFile (KERNEL.414) |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2340 | */ |
| 2341 | BOOL16 WINAPI FindNextFile16( HANDLE16 handle, WIN32_FIND_DATAA *data ) |
| 2342 | { |
| 2343 | FIND_FIRST_INFO *info; |
| 2344 | |
| 2345 | if ((handle == INVALID_HANDLE_VALUE16) || |
| 2346 | !(info = (FIND_FIRST_INFO *)GlobalLock16( handle ))) |
| 2347 | { |
| 2348 | SetLastError( ERROR_INVALID_HANDLE ); |
| 2349 | return FALSE; |
| 2350 | } |
| 2351 | GlobalUnlock16( handle ); |
| 2352 | if (!info->path || !info->dir) |
| 2353 | { |
| 2354 | SetLastError( ERROR_NO_MORE_FILES ); |
| 2355 | return FALSE; |
| 2356 | } |
| 2357 | if (!DOSFS_FindNextEx( info, data )) |
| 2358 | { |
| 2359 | DOSFS_CloseDir( info->dir ); info->dir = NULL; |
Alexandre Julliard | 61d32b4 | 2001-02-23 01:35:36 +0000 | [diff] [blame] | 2360 | HeapFree( GetProcessHeap(), 0, info->path ); |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2361 | info->path = info->long_mask = NULL; |
| 2362 | SetLastError( ERROR_NO_MORE_FILES ); |
| 2363 | return FALSE; |
| 2364 | } |
| 2365 | return TRUE; |
| 2366 | } |
| 2367 | |
| 2368 | /************************************************************************* |
Patrik Stridvall | 01d5e5b | 2001-07-02 19:59:40 +0000 | [diff] [blame] | 2369 | * FindClose (KERNEL.415) |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2370 | */ |
| 2371 | BOOL16 WINAPI FindClose16( HANDLE16 handle ) |
| 2372 | { |
| 2373 | FIND_FIRST_INFO *info; |
| 2374 | |
| 2375 | if ((handle == INVALID_HANDLE_VALUE16) || |
| 2376 | !(info = (FIND_FIRST_INFO *)GlobalLock16( handle ))) |
| 2377 | { |
| 2378 | SetLastError( ERROR_INVALID_HANDLE ); |
| 2379 | return FALSE; |
| 2380 | } |
| 2381 | if (info->dir) DOSFS_CloseDir( info->dir ); |
Alexandre Julliard | 61d32b4 | 2001-02-23 01:35:36 +0000 | [diff] [blame] | 2382 | if (info->path) HeapFree( GetProcessHeap(), 0, info->path ); |
Juergen Schmied | 2250f12 | 2000-06-01 23:17:42 +0000 | [diff] [blame] | 2383 | GlobalUnlock16( handle ); |
| 2384 | GlobalFree16( handle ); |
| 2385 | return TRUE; |
| 2386 | } |
| 2387 | |