blob: 734c5eaaa06f4f0fd8a30361e9a182675bceda97 [file] [log] [blame]
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001/*
2 * DOS file system functions
3 *
4 * Copyright 1993 Erik Bos
5 * Copyright 1996 Alexandre Julliard
6 */
7
Alexandre Julliardc7c217b1998-04-13 12:21:30 +00008#include "config.h"
Alexandre Julliard0c126c71996-02-18 18:44:41 +00009#include <sys/types.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000010#include <ctype.h>
11#include <dirent.h>
Alexandre Julliard44ed71f1997-12-21 19:17:50 +000012#include <errno.h>
Howard Abrams13277481999-07-10 13:16:29 +000013#ifdef HAVE_SYS_ERRNO_H
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000014#include <sys/errno.h>
Howard Abrams13277481999-07-10 13:16:29 +000015#endif
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000016#include <fcntl.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000017#include <string.h>
18#include <stdlib.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000019#include <sys/stat.h>
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000020#include <sys/ioctl.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000021#include <time.h>
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000022#include <unistd.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000023
Marcus Meissner317af321999-02-17 13:51:06 +000024#include "windef.h"
25#include "winuser.h"
26#include "wine/winbase16.h"
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000027#include "winerror.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000028#include "drive.h"
29#include "file.h"
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +000030#include "heap.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000031#include "msdos.h"
Alexandre Julliard85ed45e1998-08-22 19:03:56 +000032#include "syslevel.h"
Alexandre Julliard62a8b431999-01-19 17:48:23 +000033#include "server.h"
34#include "process.h"
Marcus Meissner6b9dd2e1999-03-18 17:39:57 +000035#include "options.h"
Alexandre Julliard06c275a1999-05-02 14:32:27 +000036#include "debugtools.h"
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000037
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000038DECLARE_DEBUG_CHANNEL(dosfs)
39DECLARE_DEBUG_CHANNEL(file)
40
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000041/* Define the VFAT ioctl to get both short and long file names */
Alexandre Julliardc6c09441997-01-12 18:32:19 +000042/* FIXME: is it possible to get this to work on other systems? */
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000043#ifdef linux
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000044/* We want the real kernel dirent structure, not the libc one */
45typedef struct
46{
47 long d_ino;
48 long d_off;
49 unsigned short d_reclen;
50 char d_name[256];
51} KERNEL_DIRENT;
52
Peter Ganten0bac5e91999-09-27 11:46:27 +000053#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, KERNEL_DIRENT [2] )
54
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000055#else /* linux */
56#undef VFAT_IOCTL_READDIR_BOTH /* just in case... */
57#endif /* linux */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000058
59/* Chars we don't want to see in DOS file names */
Alexandre Julliard7e56f681996-01-31 19:02:28 +000060#define INVALID_DOS_CHARS "*?<>|\"+=,;[] \345"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000061
Alexandre Julliard829fe321998-07-26 14:27:39 +000062static const DOS_DEVICE DOSFS_Devices[] =
63/* name, device flags (see Int 21/AX=0x4400) */
64{
65 { "CON", 0xc0d3 },
66 { "PRN", 0xa0c0 },
67 { "NUL", 0x80c4 },
68 { "AUX", 0x80c0 },
69 { "LPT1", 0xa0c0 },
70 { "LPT2", 0xa0c0 },
71 { "LPT3", 0xa0c0 },
72 { "LPT4", 0xc0d3 },
73 { "COM1", 0x80c0 },
74 { "COM2", 0x80c0 },
75 { "COM3", 0x80c0 },
76 { "COM4", 0x80c0 },
77 { "SCSIMGR$", 0xc0c0 },
78 { "HPSCAN", 0xc0c0 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000079};
80
81#define GET_DRIVE(path) \
82 (((path)[1] == ':') ? toupper((path)[0]) - 'A' : DOSFS_CurDrive)
83
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000084/* Directory info for DOSFS_ReadDir */
85typedef struct
86{
87 DIR *dir;
88#ifdef VFAT_IOCTL_READDIR_BOTH
89 int fd;
90 char short_name[12];
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000091 KERNEL_DIRENT dirent[2];
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000092#endif
93} DOS_DIR;
94
Alexandre Julliard85ed45e1998-08-22 19:03:56 +000095/* Info structure for FindFirstFile handle */
96typedef struct
97{
98 LPSTR path;
99 LPSTR long_mask;
100 LPSTR short_mask;
101 BYTE attr;
102 int drive;
103 int cur_pos;
104 DOS_DIR *dir;
105} FIND_FIRST_INFO;
106
107
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000108
109/***********************************************************************
110 * DOSFS_ValidDOSName
111 *
112 * Return 1 if Unix file 'name' is also a valid MS-DOS name
113 * (i.e. contains only valid DOS chars, lower-case only, fits in 8.3 format).
114 * File name can be terminated by '\0', '\\' or '/'.
115 */
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000116static int DOSFS_ValidDOSName( const char *name, int ignore_case )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000117{
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000118 static const char invalid_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" INVALID_DOS_CHARS;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000119 const char *p = name;
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000120 const char *invalid = ignore_case ? (invalid_chars + 26) : invalid_chars;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000121 int len = 0;
122
123 if (*p == '.')
124 {
125 /* Check for "." and ".." */
126 p++;
127 if (*p == '.') p++;
128 /* All other names beginning with '.' are invalid */
129 return (IS_END_OF_NAME(*p));
130 }
131 while (!IS_END_OF_NAME(*p))
132 {
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000133 if (strchr( invalid, *p )) return 0; /* Invalid char */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000134 if (*p == '.') break; /* Start of the extension */
135 if (++len > 8) return 0; /* Name too long */
136 p++;
137 }
138 if (*p != '.') return 1; /* End of name */
139 p++;
140 if (IS_END_OF_NAME(*p)) return 0; /* Empty extension not allowed */
141 len = 0;
142 while (!IS_END_OF_NAME(*p))
143 {
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000144 if (strchr( invalid, *p )) return 0; /* Invalid char */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000145 if (*p == '.') return 0; /* Second extension not allowed */
146 if (++len > 3) return 0; /* Extension too long */
147 p++;
148 }
149 return 1;
150}
151
152
153/***********************************************************************
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000154 * DOSFS_ToDosFCBFormat
155 *
156 * Convert a file name to DOS FCB format (8+3 chars, padded with blanks),
157 * expanding wild cards and converting to upper-case in the process.
158 * File name can be terminated by '\0', '\\' or '/'.
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000159 * Return FALSE if the name is not a valid DOS name.
160 * 'buffer' must be at least 12 characters long.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000161 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000162BOOL DOSFS_ToDosFCBFormat( LPCSTR name, LPSTR buffer )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000163{
164 static const char invalid_chars[] = INVALID_DOS_CHARS;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000165 const char *p = name;
166 int i;
167
168 /* Check for "." and ".." */
169 if (*p == '.')
170 {
171 p++;
172 strcpy( buffer, ". " );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000173 if (*p == '.')
174 {
175 buffer[1] = '.';
176 p++;
177 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000178 return (!*p || (*p == '/') || (*p == '\\'));
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000179 }
180
181 for (i = 0; i < 8; i++)
182 {
183 switch(*p)
184 {
185 case '\0':
186 case '\\':
187 case '/':
188 case '.':
189 buffer[i] = ' ';
190 break;
191 case '?':
192 p++;
193 /* fall through */
194 case '*':
195 buffer[i] = '?';
196 break;
197 default:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000198 if (strchr( invalid_chars, *p )) return FALSE;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000199 buffer[i] = toupper(*p);
200 p++;
201 break;
202 }
203 }
204
205 if (*p == '*')
206 {
207 /* Skip all chars after wildcard up to first dot */
208 while (*p && (*p != '/') && (*p != '\\') && (*p != '.')) p++;
209 }
210 else
211 {
212 /* Check if name too long */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000213 if (*p && (*p != '/') && (*p != '\\') && (*p != '.')) return FALSE;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000214 }
215 if (*p == '.') p++; /* Skip dot */
216
217 for (i = 8; i < 11; i++)
218 {
219 switch(*p)
220 {
221 case '\0':
222 case '\\':
223 case '/':
224 buffer[i] = ' ';
225 break;
226 case '.':
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000227 return FALSE; /* Second extension not allowed */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000228 case '?':
229 p++;
230 /* fall through */
231 case '*':
232 buffer[i] = '?';
233 break;
234 default:
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000235 if (strchr( invalid_chars, *p )) return FALSE;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000236 buffer[i] = toupper(*p);
237 p++;
238 break;
239 }
240 }
241 buffer[11] = '\0';
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000242 return TRUE;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000243}
244
245
246/***********************************************************************
247 * DOSFS_ToDosDTAFormat
248 *
249 * Convert a file name from FCB to DTA format (name.ext, null-terminated)
250 * converting to upper-case in the process.
251 * File name can be terminated by '\0', '\\' or '/'.
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000252 * 'buffer' must be at least 13 characters long.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000253 */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000254static void DOSFS_ToDosDTAFormat( LPCSTR name, LPSTR buffer )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000255{
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000256 char *p;
257
258 memcpy( buffer, name, 8 );
259 for (p = buffer + 8; (p > buffer) && (p[-1] == ' '); p--);
260 *p++ = '.';
261 memcpy( p, name + 8, 3 );
262 for (p += 3; p[-1] == ' '; p--);
263 if (p[-1] == '.') p--;
264 *p = '\0';
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000265}
266
267
268/***********************************************************************
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000269 * DOSFS_MatchShort
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000270 *
271 * Check a DOS file name against a mask (both in FCB format).
272 */
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000273static int DOSFS_MatchShort( const char *mask, const char *name )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000274{
275 int i;
276 for (i = 11; i > 0; i--, mask++, name++)
277 if ((*mask != '?') && (*mask != *name)) return 0;
278 return 1;
279}
280
281
282/***********************************************************************
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000283 * DOSFS_MatchLong
284 *
285 * Check a long file name against a mask.
286 */
287static int DOSFS_MatchLong( const char *mask, const char *name,
288 int case_sensitive )
289{
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000290 if (!strcmp( mask, "*.*" )) return 1;
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000291 while (*name && *mask)
292 {
293 if (*mask == '*')
294 {
295 mask++;
296 while (*mask == '*') mask++; /* Skip consecutive '*' */
297 if (!*mask) return 1;
298 if (case_sensitive) while (*name && (*name != *mask)) name++;
299 else while (*name && (toupper(*name) != toupper(*mask))) name++;
Robert W Hall9132a781999-04-18 14:38:17 +0000300 if (!*name) break;
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000301 }
302 else if (*mask != '?')
303 {
304 if (case_sensitive)
305 {
306 if (*mask != *name) return 0;
307 }
308 else if (toupper(*mask) != toupper(*name)) return 0;
309 }
310 mask++;
311 name++;
312 }
Robert W Hall9132a781999-04-18 14:38:17 +0000313 if (*mask == '.') mask++; /* Ignore trailing '.' in mask */
Alexandre Julliard139a4b11996-11-02 14:24:07 +0000314 return (!*name && !*mask);
315}
316
317
318/***********************************************************************
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000319 * DOSFS_OpenDir
320 */
321static DOS_DIR *DOSFS_OpenDir( LPCSTR path )
322{
323 DOS_DIR *dir = HeapAlloc( SystemHeap, 0, sizeof(*dir) );
324 if (!dir)
325 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000326 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000327 return NULL;
328 }
329
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000330 /* Treat empty path as root directory. This simplifies path split into
331 directory and mask in several other places */
332 if (!*path) path = "/";
333
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000334#ifdef VFAT_IOCTL_READDIR_BOTH
335
336 /* Check if the VFAT ioctl is supported on this directory */
337
338 if ((dir->fd = open( path, O_RDONLY )) != -1)
339 {
340 if (ioctl( dir->fd, VFAT_IOCTL_READDIR_BOTH, (long)dir->dirent ) == -1)
341 {
342 close( dir->fd );
343 dir->fd = -1;
344 }
345 else
346 {
347 /* Set the file pointer back at the start of the directory */
348 lseek( dir->fd, 0, SEEK_SET );
349 dir->dir = NULL;
350 return dir;
351 }
352 }
353#endif /* VFAT_IOCTL_READDIR_BOTH */
354
355 /* Now use the standard opendir/readdir interface */
356
357 if (!(dir->dir = opendir( path )))
358 {
359 HeapFree( SystemHeap, 0, dir );
360 return NULL;
361 }
362 return dir;
363}
364
365
366/***********************************************************************
367 * DOSFS_CloseDir
368 */
369static void DOSFS_CloseDir( DOS_DIR *dir )
370{
371#ifdef VFAT_IOCTL_READDIR_BOTH
372 if (dir->fd != -1) close( dir->fd );
373#endif /* VFAT_IOCTL_READDIR_BOTH */
374 if (dir->dir) closedir( dir->dir );
375 HeapFree( SystemHeap, 0, dir );
376}
377
378
379/***********************************************************************
380 * DOSFS_ReadDir
381 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000382static BOOL DOSFS_ReadDir( DOS_DIR *dir, LPCSTR *long_name,
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000383 LPCSTR *short_name )
384{
385 struct dirent *dirent;
386
387#ifdef VFAT_IOCTL_READDIR_BOTH
388 if (dir->fd != -1)
389 {
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000390 if (ioctl( dir->fd, VFAT_IOCTL_READDIR_BOTH, (long)dir->dirent ) != -1) {
391 if (!dir->dirent[0].d_reclen) return FALSE;
392 if (!DOSFS_ToDosFCBFormat( dir->dirent[0].d_name, dir->short_name ))
393 dir->short_name[0] = '\0';
394 *short_name = dir->short_name;
395 if (dir->dirent[1].d_name[0]) *long_name = dir->dirent[1].d_name;
396 else *long_name = dir->dirent[0].d_name;
397 return TRUE;
398 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000399 }
400#endif /* VFAT_IOCTL_READDIR_BOTH */
401
402 if (!(dirent = readdir( dir->dir ))) return FALSE;
403 *long_name = dirent->d_name;
404 *short_name = NULL;
405 return TRUE;
406}
407
408
409/***********************************************************************
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000410 * DOSFS_Hash
411 *
412 * Transform a Unix file name into a hashed DOS name. If the name is a valid
413 * DOS name, it is converted to upper-case; otherwise it is replaced by a
414 * hashed version that fits in 8.3 format.
415 * File name can be terminated by '\0', '\\' or '/'.
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000416 * 'buffer' must be at least 13 characters long.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000417 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000418static void DOSFS_Hash( LPCSTR name, LPSTR buffer, BOOL dir_format,
419 BOOL ignore_case )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000420{
421 static const char invalid_chars[] = INVALID_DOS_CHARS "~.";
422 static const char hash_chars[32] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
423
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000424 const char *p, *ext;
425 char *dst;
426 unsigned short hash;
427 int i;
428
429 if (dir_format) strcpy( buffer, " " );
430
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000431 if (DOSFS_ValidDOSName( name, ignore_case ))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000432 {
433 /* Check for '.' and '..' */
434 if (*name == '.')
435 {
436 buffer[0] = '.';
437 if (!dir_format) buffer[1] = buffer[2] = '\0';
438 if (name[1] == '.') buffer[1] = '.';
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000439 return;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000440 }
441
442 /* Simply copy the name, converting to uppercase */
443
444 for (dst = buffer; !IS_END_OF_NAME(*name) && (*name != '.'); name++)
445 *dst++ = toupper(*name);
446 if (*name == '.')
447 {
448 if (dir_format) dst = buffer + 8;
449 else *dst++ = '.';
450 for (name++; !IS_END_OF_NAME(*name); name++)
451 *dst++ = toupper(*name);
452 }
453 if (!dir_format) *dst = '\0';
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000454 return;
455 }
456
457 /* Compute the hash code of the file name */
458 /* If you know something about hash functions, feel free to */
459 /* insert a better algorithm here... */
460 if (ignore_case)
461 {
462 for (p = name, hash = 0xbeef; !IS_END_OF_NAME(p[1]); p++)
463 hash = (hash<<3) ^ (hash>>5) ^ tolower(*p) ^ (tolower(p[1]) << 8);
464 hash = (hash<<3) ^ (hash>>5) ^ tolower(*p); /* Last character*/
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000465 }
466 else
467 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000468 for (p = name, hash = 0xbeef; !IS_END_OF_NAME(p[1]); p++)
469 hash = (hash << 3) ^ (hash >> 5) ^ *p ^ (p[1] << 8);
470 hash = (hash << 3) ^ (hash >> 5) ^ *p; /* Last character */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000471 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000472
473 /* Find last dot for start of the extension */
474 for (p = name+1, ext = NULL; !IS_END_OF_NAME(*p); p++)
475 if (*p == '.') ext = p;
476 if (ext && IS_END_OF_NAME(ext[1]))
477 ext = NULL; /* Empty extension ignored */
478
479 /* Copy first 4 chars, replacing invalid chars with '_' */
480 for (i = 4, p = name, dst = buffer; i > 0; i--, p++)
481 {
482 if (IS_END_OF_NAME(*p) || (p == ext)) break;
483 *dst++ = strchr( invalid_chars, *p ) ? '_' : toupper(*p);
484 }
485 /* Pad to 5 chars with '~' */
486 while (i-- >= 0) *dst++ = '~';
487
488 /* Insert hash code converted to 3 ASCII chars */
489 *dst++ = hash_chars[(hash >> 10) & 0x1f];
490 *dst++ = hash_chars[(hash >> 5) & 0x1f];
491 *dst++ = hash_chars[hash & 0x1f];
492
493 /* Copy the first 3 chars of the extension (if any) */
494 if (ext)
495 {
496 if (!dir_format) *dst++ = '.';
497 for (i = 3, ext++; (i > 0) && !IS_END_OF_NAME(*ext); i--, ext++)
498 *dst++ = strchr( invalid_chars, *ext ) ? '_' : toupper(*ext);
499 }
500 if (!dir_format) *dst = '\0';
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000501}
502
503
504/***********************************************************************
505 * DOSFS_FindUnixName
506 *
507 * Find the Unix file name in a given directory that corresponds to
508 * a file name (either in Unix or DOS format).
509 * File name can be terminated by '\0', '\\' or '/'.
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000510 * Return TRUE if OK, FALSE if no file name matches.
511 *
512 * 'long_buf' must be at least 'long_len' characters long. If the long name
513 * turns out to be larger than that, the function returns FALSE.
514 * 'short_buf' must be at least 13 characters long.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000515 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000516BOOL DOSFS_FindUnixName( LPCSTR path, LPCSTR name, LPSTR long_buf,
517 INT long_len, LPSTR short_buf, BOOL ignore_case)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000518{
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000519 DOS_DIR *dir;
520 LPCSTR long_name, short_name;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000521 char dos_name[12], tmp_buf[13];
Alexandre Julliarda3960291999-02-26 11:11:13 +0000522 BOOL ret;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000523
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000524 const char *p = strchr( name, '/' );
525 int len = p ? (int)(p - name) : strlen(name);
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000526 if ((p = strchr( name, '\\' ))) len = MIN( (int)(p - name), len );
Andreas Mohr0c3f70d1999-04-25 12:27:58 +0000527 /* Ignore trailing dots */
528 while (len > 1 && name[len-1] == '.') len--;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000529 if (long_len < len + 1) return FALSE;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000530
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000531 TRACE_(dosfs)("%s,%s\n", path, name );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000532
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000533 if (!DOSFS_ToDosFCBFormat( name, dos_name )) dos_name[0] = '\0';
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000534
535 if (!(dir = DOSFS_OpenDir( path )))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000536 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000537 WARN_(dosfs)("(%s,%s): can't open dir: %s\n",
Alexandre Julliard44ed71f1997-12-21 19:17:50 +0000538 path, name, strerror(errno) );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000539 return FALSE;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000540 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000541
542 while ((ret = DOSFS_ReadDir( dir, &long_name, &short_name )))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000543 {
544 /* Check against Unix name */
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000545 if (len == strlen(long_name))
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000546 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000547 if (!ignore_case)
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000548 {
Alexandre Julliard89f079b1999-08-08 18:54:47 +0000549 if (!strncmp( long_name, name, len )) break;
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000550 }
551 else
552 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000553 if (!lstrncmpiA( long_name, name, len )) break;
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000554 }
555 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000556 if (dos_name[0])
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000557 {
558 /* Check against hashed DOS name */
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000559 if (!short_name)
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000560 {
561 DOSFS_Hash( long_name, tmp_buf, TRUE, ignore_case );
562 short_name = tmp_buf;
563 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000564 if (!strcmp( dos_name, short_name )) break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000565 }
566 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000567 if (ret)
568 {
569 if (long_buf) strcpy( long_buf, long_name );
570 if (short_buf)
571 {
572 if (short_name)
573 DOSFS_ToDosDTAFormat( short_name, short_buf );
574 else
575 DOSFS_Hash( long_name, short_buf, FALSE, ignore_case );
576 }
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000577 TRACE_(dosfs)("(%s,%s) -> %s (%s)\n",
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000578 path, name, long_name, short_buf ? short_buf : "***");
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000579 }
580 else
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000581 WARN_(dosfs)("'%s' not found in '%s'\n", name, path);
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000582 DOSFS_CloseDir( dir );
583 return ret;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000584}
585
586
587/***********************************************************************
Alexandre Julliard829fe321998-07-26 14:27:39 +0000588 * DOSFS_GetDevice
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000589 *
Alexandre Julliard829fe321998-07-26 14:27:39 +0000590 * Check if a DOS file name represents a DOS device and return the device.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000591 */
Alexandre Julliard829fe321998-07-26 14:27:39 +0000592const DOS_DEVICE *DOSFS_GetDevice( const char *name )
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000593{
594 int i;
595 const char *p;
596
Alexandre Julliard767e6f61998-08-09 12:47:43 +0000597 if (!name) return NULL; /* if FILE_DupUnixHandle was used */
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000598 if (name[0] && (name[1] == ':')) name += 2;
599 if ((p = strrchr( name, '/' ))) name = p + 1;
600 if ((p = strrchr( name, '\\' ))) name = p + 1;
601 for (i = 0; i < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]); i++)
602 {
Alexandre Julliard829fe321998-07-26 14:27:39 +0000603 const char *dev = DOSFS_Devices[i].name;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000604 if (!lstrncmpiA( dev, name, strlen(dev) ))
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000605 {
606 p = name + strlen( dev );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000607 if (!*p || (*p == '.')) return &DOSFS_Devices[i];
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000608 }
609 }
Alexandre Julliard829fe321998-07-26 14:27:39 +0000610 return NULL;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000611}
612
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000613
614/***********************************************************************
615 * DOSFS_GetDeviceByHandle
616 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000617const DOS_DEVICE *DOSFS_GetDeviceByHandle( HFILE hFile )
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000618{
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000619 struct get_file_info_request *req = get_req_buffer();
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000620
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000621 req->handle = hFile;
622 if (!server_call( REQ_GET_FILE_INFO ) && (req->type == FILE_TYPE_UNKNOWN))
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000623 {
Alexandre Julliardebe29ef1999-06-26 08:43:26 +0000624 if ((req->attr >= 0) &&
625 (req->attr < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0])))
626 return &DOSFS_Devices[req->attr];
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000627 }
628 return NULL;
629}
630
631
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000632/***********************************************************************
633 * DOSFS_OpenDevice
634 *
635 * Open a DOS device. This might not map 1:1 into the UNIX device concept.
636 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000637HFILE DOSFS_OpenDevice( const char *name, DWORD access )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000638{
639 int i;
640 const char *p;
641
Alexandre Julliarda3960291999-02-26 11:11:13 +0000642 if (!name) return (HFILE)NULL; /* if FILE_DupUnixHandle was used */
Alexandre Julliard0c126c71996-02-18 18:44:41 +0000643 if (name[0] && (name[1] == ':')) name += 2;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000644 if ((p = strrchr( name, '/' ))) name = p + 1;
645 if ((p = strrchr( name, '\\' ))) name = p + 1;
646 for (i = 0; i < sizeof(DOSFS_Devices)/sizeof(DOSFS_Devices[0]); i++)
647 {
Alexandre Julliard829fe321998-07-26 14:27:39 +0000648 const char *dev = DOSFS_Devices[i].name;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000649 if (!lstrncmpiA( dev, name, strlen(dev) ))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000650 {
651 p = name + strlen( dev );
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000652 if (!*p || (*p == '.')) {
653 /* got it */
Alexandre Julliard829fe321998-07-26 14:27:39 +0000654 if (!strcmp(DOSFS_Devices[i].name,"NUL"))
Alexandre Julliard05625391999-01-03 11:55:56 +0000655 return FILE_CreateFile( "/dev/null", access,
656 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
657 OPEN_EXISTING, 0, -1 );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000658 if (!strcmp(DOSFS_Devices[i].name,"CON")) {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000659 HFILE to_dup;
660 HFILE handle;
Alexandre Julliard05625391999-01-03 11:55:56 +0000661 switch (access & (GENERIC_READ|GENERIC_WRITE)) {
662 case GENERIC_READ:
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000663 to_dup = GetStdHandle( STD_INPUT_HANDLE );
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000664 break;
Alexandre Julliard05625391999-01-03 11:55:56 +0000665 case GENERIC_WRITE:
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000666 to_dup = GetStdHandle( STD_OUTPUT_HANDLE );
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000667 break;
668 default:
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000669 FIXME_(dosfs)("can't open CON read/write\n");
Alexandre Julliarda3960291999-02-26 11:11:13 +0000670 return HFILE_ERROR;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000671 break;
672 }
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000673 if (!DuplicateHandle( GetCurrentProcess(), to_dup, GetCurrentProcess(),
674 &handle, 0, FALSE, DUPLICATE_SAME_ACCESS ))
Alexandre Julliarda3960291999-02-26 11:11:13 +0000675 handle = HFILE_ERROR;
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000676 return handle;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000677 }
Alexandre Julliardfbe63ad1998-12-30 12:10:06 +0000678 if (!strcmp(DOSFS_Devices[i].name,"SCSIMGR$") ||
679 !strcmp(DOSFS_Devices[i].name,"HPSCAN"))
680 {
Alexandre Julliard62a8b431999-01-19 17:48:23 +0000681 return FILE_CreateDevice( i, access, NULL );
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000682 }
Michael McCormacka8486071999-03-14 12:25:36 +0000683 {
684 HFILE r;
685 char devname[40];
686 PROFILE_GetWineIniString("serialports",name,"",devname,sizeof devname);
687
688 if(devname[0])
689 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000690 TRACE_(file)("DOSFS_OpenDevice %s is %s\n",
Michael McCormacka8486071999-03-14 12:25:36 +0000691 DOSFS_Devices[i].name,devname);
692 r = FILE_CreateFile( devname, access,
693 FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
694 OPEN_EXISTING, 0, -1 );
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000695 TRACE_(file)("Create_File return %08X\n",r);
Michael McCormacka8486071999-03-14 12:25:36 +0000696 return r;
697 }
698 }
699
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000700 FIXME_(dosfs)("device open %s not supported (yet)\n",DOSFS_Devices[i].name);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000701 return HFILE_ERROR;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000702 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000703 }
704 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000705 return HFILE_ERROR;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000706}
707
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000708
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000709/***********************************************************************
710 * DOSFS_GetPathDrive
711 *
712 * Get the drive specified by a given path name (DOS or Unix format).
713 */
714static int DOSFS_GetPathDrive( const char **name )
715{
716 int drive;
717 const char *p = *name;
718
719 if (*p && (p[1] == ':'))
720 {
721 drive = toupper(*p) - 'A';
722 *name += 2;
723 }
724 else if (*p == '/') /* Absolute Unix path? */
725 {
726 if ((drive = DRIVE_FindDriveRoot( name )) == -1)
727 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000728 MESSAGE("Warning: %s not accessible from a DOS drive\n", *name );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000729 /* Assume it really was a DOS name */
730 drive = DRIVE_GetCurrentDrive();
731 }
732 }
733 else drive = DRIVE_GetCurrentDrive();
734
735 if (!DRIVE_IsValid(drive))
736 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000737 SetLastError( ERROR_INVALID_DRIVE );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000738 return -1;
739 }
740 return drive;
741}
742
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000743
744/***********************************************************************
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000745 * DOSFS_GetFullName
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000746 *
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000747 * Convert a file name (DOS or mixed DOS/Unix format) to a valid
748 * Unix name / short DOS name pair.
749 * Return FALSE if one of the path components does not exist. The last path
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000750 * component is only checked if 'check_last' is non-zero.
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000751 * The buffers pointed to by 'long_buf' and 'short_buf' must be
752 * at least MAX_PATHNAME_LEN long.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000753 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000754BOOL DOSFS_GetFullName( LPCSTR name, BOOL check_last, DOS_FULL_NAME *full )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000755{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000756 BOOL found;
757 UINT flags;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000758 char *p_l, *p_s, *root;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000759
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000760 TRACE_(dosfs)("%s (last=%d)\n",
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000761 name, check_last );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000762
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000763 if ((full->drive = DOSFS_GetPathDrive( &name )) == -1) return FALSE;
764 flags = DRIVE_GetFlags( full->drive );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000765
Alexandre Julliarda3960291999-02-26 11:11:13 +0000766 lstrcpynA( full->long_name, DRIVE_GetRoot( full->drive ),
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000767 sizeof(full->long_name) );
768 if (full->long_name[1]) root = full->long_name + strlen(full->long_name);
769 else root = full->long_name; /* root directory */
770
771 strcpy( full->short_name, "A:\\" );
772 full->short_name[0] += full->drive;
773
774 if ((*name == '\\') || (*name == '/')) /* Absolute path */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000775 {
776 while ((*name == '\\') || (*name == '/')) name++;
777 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000778 else /* Relative path */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000779 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000780 lstrcpynA( root + 1, DRIVE_GetUnixCwd( full->drive ),
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000781 sizeof(full->long_name) - (root - full->long_name) - 1 );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000782 if (root[1]) *root = '/';
Alexandre Julliarda3960291999-02-26 11:11:13 +0000783 lstrcpynA( full->short_name + 3, DRIVE_GetDosCwd( full->drive ),
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000784 sizeof(full->short_name) - 3 );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000785 }
786
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000787 p_l = full->long_name[1] ? full->long_name + strlen(full->long_name)
788 : full->long_name;
789 p_s = full->short_name[3] ? full->short_name + strlen(full->short_name)
790 : full->short_name + 2;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000791 found = TRUE;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000792
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000793 while (*name && found)
794 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000795 /* Check for '.' and '..' */
796
797 if (*name == '.')
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000798 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000799 if (IS_END_OF_NAME(name[1]))
800 {
801 name++;
802 while ((*name == '\\') || (*name == '/')) name++;
803 continue;
804 }
805 else if ((name[1] == '.') && IS_END_OF_NAME(name[2]))
806 {
807 name += 2;
808 while ((*name == '\\') || (*name == '/')) name++;
809 while ((p_l > root) && (*p_l != '/')) p_l--;
810 while ((p_s > full->short_name + 2) && (*p_s != '\\')) p_s--;
811 *p_l = *p_s = '\0'; /* Remove trailing separator */
812 continue;
813 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000814 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000815
816 /* Make sure buffers are large enough */
817
818 if ((p_s >= full->short_name + sizeof(full->short_name) - 14) ||
819 (p_l >= full->long_name + sizeof(full->long_name) - 1))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000820 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000821 SetLastError( ERROR_PATH_NOT_FOUND );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000822 return FALSE;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000823 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000824
825 /* Get the long and short name matching the file name */
826
827 if ((found = DOSFS_FindUnixName( full->long_name, name, p_l + 1,
828 sizeof(full->long_name) - (p_l - full->long_name) - 1,
829 p_s + 1, !(flags & DRIVE_CASE_SENSITIVE) )))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000830 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000831 *p_l++ = '/';
832 p_l += strlen(p_l);
833 *p_s++ = '\\';
834 p_s += strlen(p_s);
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000835 while (!IS_END_OF_NAME(*name)) name++;
836 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000837 else if (!check_last)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000838 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000839 *p_l++ = '/';
840 *p_s++ = '\\';
841 while (!IS_END_OF_NAME(*name) &&
842 (p_s < full->short_name + sizeof(full->short_name) - 1) &&
843 (p_l < full->long_name + sizeof(full->long_name) - 1))
844 {
Alexandre Julliard829fe321998-07-26 14:27:39 +0000845 *p_s++ = tolower(*name);
846 /* If the drive is case-sensitive we want to create new */
847 /* files in lower-case otherwise we can't reopen them */
848 /* under the same short name. */
849 if (flags & DRIVE_CASE_SENSITIVE) *p_l++ = tolower(*name);
850 else *p_l++ = *name;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000851 name++;
852 }
853 *p_l = *p_s = '\0';
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000854 }
855 while ((*name == '\\') || (*name == '/')) name++;
856 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000857
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000858 if (!found)
859 {
Alexander Larssona8745ea1998-12-02 10:04:52 +0000860 if (check_last)
861 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000862 SetLastError( ERROR_FILE_NOT_FOUND );
Alexander Larssona8745ea1998-12-02 10:04:52 +0000863 return FALSE;
864 }
Alexander Larsson2772a671998-12-07 16:23:42 +0000865 if (*name) /* Not last */
866 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000867 SetLastError( ERROR_PATH_NOT_FOUND );
Alexander Larsson2772a671998-12-07 16:23:42 +0000868 return FALSE;
869 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000870 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000871 if (!full->long_name[0]) strcpy( full->long_name, "/" );
872 if (!full->short_name[2]) strcpy( full->short_name + 2, "\\" );
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000873 TRACE_(dosfs)("returning %s = %s\n",
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000874 full->long_name, full->short_name );
875 return TRUE;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000876}
877
878
879/***********************************************************************
Peter Gantenf22bea01999-03-14 15:15:14 +0000880 * GetShortPathNameA (KERNEL32.271)
Juergen Schmied4658e4d1998-11-22 12:21:05 +0000881 *
882 * NOTES
883 * observed:
884 * longpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0
885 * *longpath="" or invalid: LastError=ERROR_BAD_PATHNAME, ret=0
Peter Gantenf22bea01999-03-14 15:15:14 +0000886 *
887 * more observations ( with NT 3.51 (WinDD) ):
888 * longpath <= 8.3 -> just copy longpath to shortpath
889 * longpath > 8.3 ->
890 * a) file does not exist -> return 0, LastError = ERROR_FILE_NOT_FOUND
891 * b) file does exist -> set the short filename.
892 * - trailing slashes are reproduced in the short name, even if the
893 * file is not a directory
894 * - the absolute/relative path of the short name is reproduced in the
895 * same way, like the long name
896 * - longpath and shortpath may have the same adress
897 * Peter Ganten, 1999
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000898 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000899DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath,
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000900 DWORD shortlen )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000901{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000902 DOS_FULL_NAME full_name;
Peter Gantenf22bea01999-03-14 15:15:14 +0000903 LPSTR tmpshortpath;
904 DWORD length = 0, pos = 0;
905 INT start=-1, end=-1, tmplen;
906
907 if (!longpath) {
908 SetLastError(ERROR_INVALID_PARAMETER);
909 return 0;
910 }
911 if (!longpath[0]) {
912 SetLastError(ERROR_BAD_PATHNAME);
913 return 0;
914 }
915
916 tmpshortpath = HeapAlloc( GetProcessHeap(), 0, MAX_PATHNAME_LEN );
917 if ( !tmpshortpath ) {
918 SetLastError ( ERROR_NOT_ENOUGH_MEMORY );
919 return 0;
920 }
921
922 /* Check for Drive-Letter */
923 if ( longpath[1] == ':' ) {
924 lstrcpynA ( tmpshortpath, longpath, 3 );
925 length = 2;
926 pos = 2;
927 }
928
929 /* loop over each part of the name */
930 while ( longpath[pos] ) {
931
932 if (( longpath[pos] == '\\' ) ||
933 ( longpath[pos+1] == '\0' ) ||
934 ( longpath[pos] == '/')) {
935
936 if ( start != -1 ) {
937 if ( DOSFS_ValidDOSName ( longpath + start, TRUE )) {
938 tmplen = end - start + ( (( longpath[pos] == '\\' ) || ( longpath[pos] == '/' )) ? 1 : 2 );
939 lstrcpynA ( tmpshortpath+length, longpath+start, tmplen );
940 length += tmplen - 1;
941 }
942 else {
943 DOSFS_Hash ( longpath + start, tmpshortpath+length, FALSE, FALSE );
944 length = lstrlenA ( tmpshortpath );
945
946 /* Check if the path, up to this point exists */
947 if ( !DOSFS_GetFullName ( tmpshortpath, TRUE, &full_name ) ) {
948 SetLastError ( ERROR_FILE_NOT_FOUND );
949 return 0;
950 }
951
952 }
953 }
954
955 if (( longpath[pos] == '\\' ) || ( longpath[pos] == '/' )) {
956 tmpshortpath[length] = '\\';
957 tmpshortpath[length+1]='\0';
958 length++;
959 }
960 pos++;
961
962 start = -1;
963 end = -1;
964 continue;
965 }
966
967 if ( start == -1 ) {
968 start = pos;
969 }
970 pos++;
971 end = pos;
972 }
Juergen Schmied4658e4d1998-11-22 12:21:05 +0000973
Peter Gantenf22bea01999-03-14 15:15:14 +0000974 lstrcpynA ( shortpath, tmpshortpath, shortlen );
975 length = lstrlenA ( tmpshortpath );
976 HeapFree ( GetProcessHeap(), 0, tmpshortpath );
977
978 return length;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000979}
980
981
982/***********************************************************************
983 * GetShortPathName32W (KERNEL32.272)
984 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000985DWORD WINAPI GetShortPathNameW( LPCWSTR longpath, LPWSTR shortpath,
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000986 DWORD shortlen )
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000987{
Peter Gantenf22bea01999-03-14 15:15:14 +0000988 LPSTR longpathA, shortpathA;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000989 DWORD ret = 0;
Juergen Schmied4658e4d1998-11-22 12:21:05 +0000990
Juergen Schmied4658e4d1998-11-22 12:21:05 +0000991 longpathA = HEAP_strdupWtoA( GetProcessHeap(), 0, longpath );
Peter Gantenf22bea01999-03-14 15:15:14 +0000992 shortpathA = HEAP_xalloc ( GetProcessHeap(), 0, shortlen );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000993
Peter Gantenf22bea01999-03-14 15:15:14 +0000994 ret = GetShortPathNameA ( longpathA, shortpathA, shortlen );
995 lstrcpynAtoW ( shortpath, shortpathA, shortlen );
Juergen Schmied4658e4d1998-11-22 12:21:05 +0000996
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000997 HeapFree( GetProcessHeap(), 0, longpathA );
Peter Gantenf22bea01999-03-14 15:15:14 +0000998 HeapFree( GetProcessHeap(), 0, shortpathA );
999
1000 return ret;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001001}
1002
1003
1004/***********************************************************************
Alexandre Julliarde658d821997-11-30 17:45:40 +00001005 * GetLongPathName32A (KERNEL32.xxx)
1006 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001007DWORD WINAPI GetLongPathNameA( LPCSTR shortpath, LPSTR longpath,
Alexandre Julliarde658d821997-11-30 17:45:40 +00001008 DWORD longlen )
1009{
1010 DOS_FULL_NAME full_name;
Alexander Larssonc1190fe1998-10-11 13:57:09 +00001011 char *p;
1012 char *longfilename;
1013 DWORD shortpathlen;
1014
Alexandre Julliarde658d821997-11-30 17:45:40 +00001015 if (!DOSFS_GetFullName( shortpath, TRUE, &full_name )) return 0;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001016 lstrcpynA( longpath, full_name.short_name, longlen );
Alexander Larssonc1190fe1998-10-11 13:57:09 +00001017 /* Do some hackery to get the long filename.
1018 * FIXME: Would be better if it returned the
1019 * long version of the directories too
1020 */
1021 longfilename = strrchr(full_name.long_name, '/')+1;
1022 if (longpath != NULL) {
1023 if ((p = strrchr( longpath, '\\' )) != NULL) {
1024 p++;
1025 longlen -= (p-longpath);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001026 lstrcpynA( p, longfilename , longlen);
Alexander Larssonc1190fe1998-10-11 13:57:09 +00001027 }
1028 }
1029 shortpathlen =
1030 ((strrchr( full_name.short_name, '\\' ) - full_name.short_name) + 1);
1031 return shortpathlen + strlen( longfilename );
Alexandre Julliarde658d821997-11-30 17:45:40 +00001032}
1033
1034
1035/***********************************************************************
1036 * GetLongPathName32W (KERNEL32.269)
1037 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001038DWORD WINAPI GetLongPathNameW( LPCWSTR shortpath, LPWSTR longpath,
Alexandre Julliarde658d821997-11-30 17:45:40 +00001039 DWORD longlen )
1040{
1041 DOS_FULL_NAME full_name;
1042 DWORD ret = 0;
1043 LPSTR shortpathA = HEAP_strdupWtoA( GetProcessHeap(), 0, shortpath );
1044
1045 /* FIXME: is it correct to always return a fully qualified short path? */
1046 if (DOSFS_GetFullName( shortpathA, TRUE, &full_name ))
1047 {
1048 ret = strlen( full_name.short_name );
1049 lstrcpynAtoW( longpath, full_name.long_name, longlen );
1050 }
1051 HeapFree( GetProcessHeap(), 0, shortpathA );
1052 return ret;
1053}
1054
1055
1056/***********************************************************************
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001057 * DOSFS_DoGetFullPathName
1058 *
1059 * Implementation of GetFullPathName32A/W.
1060 */
1061static DWORD DOSFS_DoGetFullPathName( LPCSTR name, DWORD len, LPSTR result,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001062 BOOL unicode )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001063{
1064 char buffer[MAX_PATHNAME_LEN];
1065 int drive;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001066 char *p;
Juergen Schmied86407161999-01-03 16:12:01 +00001067 DWORD ret;
1068
1069 /* last possible position for a char != 0 */
1070 char *endchar = buffer + sizeof(buffer) - 2;
1071 *endchar = '\0';
1072
Alexandre Julliard06c275a1999-05-02 14:32:27 +00001073 TRACE_(dosfs)("converting '%s'\n", name );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001074
Alexandre Julliard08b9b4f1999-06-06 17:09:21 +00001075 if (!name || ((drive = DOSFS_GetPathDrive( &name )) == -1) )
Juergen Schmied86407161999-01-03 16:12:01 +00001076 { SetLastError( ERROR_INVALID_PARAMETER );
1077 return 0;
1078 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001079
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001080 p = buffer;
1081 *p++ = 'A' + drive;
1082 *p++ = ':';
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001083 if (IS_END_OF_NAME(*name) && (*name)) /* Absolute path */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001084 {
Juergen Schmied86407161999-01-03 16:12:01 +00001085 while (((*name == '\\') || (*name == '/')) && (!*endchar) )
1086 *p++ = *name++;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001087 }
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001088 else /* Relative path or empty path */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001089 {
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001090 *p++ = '\\';
Alexandre Julliarda3960291999-02-26 11:11:13 +00001091 lstrcpynA( p, DRIVE_GetDosCwd(drive), sizeof(buffer) - 4 );
Juergen Schmied86407161999-01-03 16:12:01 +00001092 if ( *p )
1093 {
1094 p += strlen(p);
1095 *p++ = '\\';
1096 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001097 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001098 *p = '\0';
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001099
1100 while (*name)
1101 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001102 if (*name == '.')
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001103 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001104 if (IS_END_OF_NAME(name[1]))
1105 {
1106 name++;
1107 while ((*name == '\\') || (*name == '/')) name++;
1108 continue;
1109 }
1110 else if ((name[1] == '.') && IS_END_OF_NAME(name[2]))
1111 {
1112 name += 2;
1113 while ((*name == '\\') || (*name == '/')) name++;
Juergen Schmied86407161999-01-03 16:12:01 +00001114
1115 if (p < buffer + 3) /* no previous dir component */
1116 continue;
1117 p--; /* skip previously added '\\' */
1118 while ((*p == '\\') || (*p == '/')) p--;
1119 /* skip previous dir component */
1120 while ((*p != '\\') && (*p != '/')) p--;
1121 p++;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001122 continue;
1123 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001124 }
Juergen Schmied86407161999-01-03 16:12:01 +00001125 if ( *endchar )
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001126 { SetLastError( ERROR_PATH_NOT_FOUND );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001127 return 0;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001128 }
Juergen Schmied86407161999-01-03 16:12:01 +00001129 while (!IS_END_OF_NAME(*name) && (!*endchar) )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001130 *p++ = *name++;
Juergen Schmied86407161999-01-03 16:12:01 +00001131 while (((*name == '\\') || (*name == '/')) && (!*endchar) )
1132 *p++ = *name++;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001133 }
Juergen Schmied86407161999-01-03 16:12:01 +00001134 *p = '\0';
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001135
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001136 if (!(DRIVE_GetFlags(drive) & DRIVE_CASE_PRESERVING))
Alexandre Julliarda3960291999-02-26 11:11:13 +00001137 CharUpperA( buffer );
Juergen Schmied86407161999-01-03 16:12:01 +00001138
Alexandre Julliard08b9b4f1999-06-06 17:09:21 +00001139 if (result)
1140 {
1141 if (unicode)
1142 lstrcpynAtoW( (LPWSTR)result, buffer, len );
1143 else
1144 lstrcpynA( result, buffer, len );
1145 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001146
Alexandre Julliard06c275a1999-05-02 14:32:27 +00001147 TRACE_(dosfs)("returning '%s'\n", buffer );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001148
Juergen Schmied86407161999-01-03 16:12:01 +00001149 /* If the lpBuffer buffer is too small, the return value is the
1150 size of the buffer, in characters, required to hold the path. */
1151
1152 ret = strlen(buffer);
1153
1154 if (ret >= len )
1155 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1156
1157 return ret;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001158}
1159
1160
1161/***********************************************************************
1162 * GetFullPathName32A (KERNEL32.272)
Juergen Schmied86407161999-01-03 16:12:01 +00001163 * NOTES
1164 * if the path closed with '\', *lastpart is 0
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001165 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001166DWORD WINAPI GetFullPathNameA( LPCSTR name, DWORD len, LPSTR buffer,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001167 LPSTR *lastpart )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001168{
1169 DWORD ret = DOSFS_DoGetFullPathName( name, len, buffer, FALSE );
Alexandre Julliard08b9b4f1999-06-06 17:09:21 +00001170 if (ret && buffer && lastpart)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001171 {
1172 LPSTR p = buffer + strlen(buffer);
Juergen Schmied30f503f1998-12-15 17:28:26 +00001173
Juergen Schmied30f503f1998-12-15 17:28:26 +00001174 if (*p != '\\')
1175 {
1176 while ((p > buffer + 2) && (*p != '\\')) p--;
1177 *lastpart = p + 1;
1178 }
1179 else *lastpart = NULL;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001180 }
1181 return ret;
1182}
1183
1184
1185/***********************************************************************
1186 * GetFullPathName32W (KERNEL32.273)
1187 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001188DWORD WINAPI GetFullPathNameW( LPCWSTR name, DWORD len, LPWSTR buffer,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001189 LPWSTR *lastpart )
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001190{
1191 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
1192 DWORD ret = DOSFS_DoGetFullPathName( nameA, len, (LPSTR)buffer, TRUE );
1193 HeapFree( GetProcessHeap(), 0, nameA );
Alexandre Julliard08b9b4f1999-06-06 17:09:21 +00001194 if (ret && buffer && lastpart)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001195 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001196 LPWSTR p = buffer + lstrlenW(buffer);
Juergen Schmied86407161999-01-03 16:12:01 +00001197 if (*p != (WCHAR)'\\')
1198 {
1199 while ((p > buffer + 2) && (*p != (WCHAR)'\\')) p--;
1200 *lastpart = p + 1;
1201 }
1202 else *lastpart = NULL;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001203 }
1204 return ret;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001205}
1206
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001207/***********************************************************************
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001208 * DOSFS_FindNextEx
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001209 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001210static int DOSFS_FindNextEx( FIND_FIRST_INFO *info, WIN32_FIND_DATAA *entry )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001211{
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001212 BYTE attr = info->attr | FA_UNUSED | FA_ARCHIVE | FA_RDONLY;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001213 UINT flags = DRIVE_GetFlags( info->drive );
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001214 char *p, buffer[MAX_PATHNAME_LEN];
1215 const char *drive_path;
1216 int drive_root;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001217 LPCSTR long_name, short_name;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001218 BY_HANDLE_FILE_INFORMATION fileinfo;
1219 char dos_name[13];
Alexandre Julliard1e37a181996-08-18 16:21:52 +00001220
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001221 if ((info->attr & ~(FA_UNUSED | FA_ARCHIVE | FA_RDONLY)) == FA_LABEL)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001222 {
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001223 if (info->cur_pos) return 0;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001224 entry->dwFileAttributes = FILE_ATTRIBUTE_LABEL;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001225 DOSFS_UnixTimeToFileTime( (time_t)0, &entry->ftCreationTime, 0 );
1226 DOSFS_UnixTimeToFileTime( (time_t)0, &entry->ftLastAccessTime, 0 );
1227 DOSFS_UnixTimeToFileTime( (time_t)0, &entry->ftLastWriteTime, 0 );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001228 entry->nFileSizeHigh = 0;
1229 entry->nFileSizeLow = 0;
1230 entry->dwReserved0 = 0;
1231 entry->dwReserved1 = 0;
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001232 DOSFS_ToDosDTAFormat( DRIVE_GetLabel( info->drive ), entry->cFileName );
1233 strcpy( entry->cAlternateFileName, entry->cFileName );
1234 info->cur_pos++;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001235 return 1;
1236 }
1237
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001238 drive_path = info->path + strlen(DRIVE_GetRoot( info->drive ));
1239 while ((*drive_path == '/') || (*drive_path == '\\')) drive_path++;
1240 drive_root = !*drive_path;
1241
Alexandre Julliarda3960291999-02-26 11:11:13 +00001242 lstrcpynA( buffer, info->path, sizeof(buffer) - 1 );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001243 strcat( buffer, "/" );
1244 p = buffer + strlen(buffer);
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001245
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001246 while (DOSFS_ReadDir( info->dir, &long_name, &short_name ))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001247 {
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001248 info->cur_pos++;
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001249
Alexandre Julliard0c126c71996-02-18 18:44:41 +00001250 /* Don't return '.' and '..' in the root of the drive */
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001251 if (drive_root && (long_name[0] == '.') &&
1252 (!long_name[1] || ((long_name[1] == '.') && !long_name[2])))
1253 continue;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001254
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001255 /* Check the long mask */
1256
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001257 if (info->long_mask)
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001258 {
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001259 if (!DOSFS_MatchLong( info->long_mask, long_name,
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001260 flags & DRIVE_CASE_SENSITIVE )) continue;
1261 }
1262
1263 /* Check the short mask */
1264
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001265 if (info->short_mask)
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001266 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001267 if (!short_name)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001268 {
1269 DOSFS_Hash( long_name, dos_name, TRUE,
1270 !(flags & DRIVE_CASE_SENSITIVE) );
1271 short_name = dos_name;
1272 }
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001273 if (!DOSFS_MatchShort( info->short_mask, short_name )) continue;
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001274 }
1275
1276 /* Check the file attributes */
1277
Alexandre Julliarda3960291999-02-26 11:11:13 +00001278 lstrcpynA( p, long_name, sizeof(buffer) - (int)(p - buffer) );
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001279 if (!FILE_Stat( buffer, &fileinfo ))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001280 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +00001281 WARN_(dosfs)("can't stat %s\n", buffer);
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001282 continue;
1283 }
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001284 if (fileinfo.dwFileAttributes & ~attr) continue;
Alexandre Julliard139a4b11996-11-02 14:24:07 +00001285
1286 /* We now have a matching entry; fill the result and return */
1287
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001288 entry->dwFileAttributes = fileinfo.dwFileAttributes;
1289 entry->ftCreationTime = fileinfo.ftCreationTime;
1290 entry->ftLastAccessTime = fileinfo.ftLastAccessTime;
1291 entry->ftLastWriteTime = fileinfo.ftLastWriteTime;
1292 entry->nFileSizeHigh = fileinfo.nFileSizeHigh;
1293 entry->nFileSizeLow = fileinfo.nFileSizeLow;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001294
1295 if (short_name)
1296 DOSFS_ToDosDTAFormat( short_name, entry->cAlternateFileName );
1297 else
1298 DOSFS_Hash( long_name, entry->cAlternateFileName, FALSE,
1299 !(flags & DRIVE_CASE_SENSITIVE) );
1300
Alexandre Julliarda3960291999-02-26 11:11:13 +00001301 lstrcpynA( entry->cFileName, long_name, sizeof(entry->cFileName) );
1302 if (!(flags & DRIVE_CASE_PRESERVING)) CharLowerA( entry->cFileName );
Alexandre Julliard06c275a1999-05-02 14:32:27 +00001303 TRACE_(dosfs)("returning %s (%s) %02lx %ld\n",
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001304 entry->cFileName, entry->cAlternateFileName,
1305 entry->dwFileAttributes, entry->nFileSizeLow );
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001306 return 1;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001307 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001308 return 0; /* End of directory */
1309}
Alexandre Julliardca22b331996-07-12 19:02:39 +00001310
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001311/***********************************************************************
1312 * DOSFS_FindNext
1313 *
1314 * Find the next matching file. Return the number of entries read to find
1315 * the matching one, or 0 if no more entries.
1316 * 'short_mask' is the 8.3 mask (in FCB format), 'long_mask' is the long
1317 * file name mask. Either or both can be NULL.
1318 *
1319 * NOTE: This is supposed to be only called by the int21 emulation
1320 * routines. Thus, we should own the Win16Mutex anyway.
1321 * Nevertheless, we explicitly enter it to ensure the static
1322 * directory cache is protected.
1323 */
1324int DOSFS_FindNext( const char *path, const char *short_mask,
1325 const char *long_mask, int drive, BYTE attr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001326 int skip, WIN32_FIND_DATAA *entry )
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001327{
1328 static FIND_FIRST_INFO info = { NULL };
1329 LPCSTR short_name, long_name;
1330 int count;
1331
1332 SYSLEVEL_EnterWin16Lock();
1333
1334 /* Check the cached directory */
1335 if (!(info.dir && info.path == path && info.short_mask == short_mask
1336 && info.long_mask == long_mask && info.drive == drive
1337 && info.attr == attr && info.cur_pos <= skip))
1338 {
1339 /* Not in the cache, open it anew */
1340 if (info.dir) DOSFS_CloseDir( info.dir );
1341
1342 info.path = (LPSTR)path;
1343 info.long_mask = (LPSTR)long_mask;
1344 info.short_mask = (LPSTR)short_mask;
1345 info.attr = attr;
1346 info.drive = drive;
1347 info.cur_pos = 0;
1348 info.dir = DOSFS_OpenDir( info.path );
1349 }
1350
1351 /* Skip to desired position */
1352 while (info.cur_pos < skip)
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001353 if (info.dir && DOSFS_ReadDir( info.dir, &long_name, &short_name ))
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001354 info.cur_pos++;
1355 else
1356 break;
1357
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001358 if (info.dir && info.cur_pos == skip && DOSFS_FindNextEx( &info, entry ))
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001359 count = info.cur_pos - skip;
1360 else
1361 count = 0;
1362
1363 if (!count)
1364 {
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001365 if (info.dir) DOSFS_CloseDir( info.dir );
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001366 memset( &info, '\0', sizeof(info) );
1367 }
1368
1369 SYSLEVEL_LeaveWin16Lock();
1370
1371 return count;
1372}
1373
1374
Alexandre Julliardca22b331996-07-12 19:02:39 +00001375
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001376/*************************************************************************
1377 * FindFirstFile16 (KERNEL.413)
1378 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001379HANDLE16 WINAPI FindFirstFile16( LPCSTR path, WIN32_FIND_DATAA *data )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001380{
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001381 DOS_FULL_NAME full_name;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001382 HGLOBAL16 handle;
1383 FIND_FIRST_INFO *info;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001384
Andreas Mohrc21650e1998-10-11 17:37:53 +00001385 data->dwReserved0 = data->dwReserved1 = 0x0;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001386 if (!path) return 0;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001387 if (!DOSFS_GetFullName( path, FALSE, &full_name ))
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001388 return INVALID_HANDLE_VALUE16;
1389 if (!(handle = GlobalAlloc16( GMEM_MOVEABLE, sizeof(FIND_FIRST_INFO) )))
1390 return INVALID_HANDLE_VALUE16;
1391 info = (FIND_FIRST_INFO *)GlobalLock16( handle );
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001392 info->path = HEAP_strdupA( SystemHeap, 0, full_name.long_name );
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001393 info->long_mask = strrchr( info->path, '/' );
1394 *(info->long_mask++) = '\0';
1395 info->short_mask = NULL;
1396 info->attr = 0xff;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001397 if (path[0] && (path[1] == ':')) info->drive = toupper(*path) - 'A';
1398 else info->drive = DRIVE_GetCurrentDrive();
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001399 info->cur_pos = 0;
1400
1401 info->dir = DOSFS_OpenDir( info->path );
1402
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001403 GlobalUnlock16( handle );
1404 if (!FindNextFile16( handle, data ))
1405 {
1406 FindClose16( handle );
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001407 SetLastError( ERROR_NO_MORE_FILES );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001408 return INVALID_HANDLE_VALUE16;
1409 }
1410 return handle;
1411}
1412
1413
1414/*************************************************************************
1415 * FindFirstFile32A (KERNEL32.123)
1416 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001417HANDLE WINAPI FindFirstFileA( LPCSTR path, WIN32_FIND_DATAA *data )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001418{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001419 HANDLE handle = FindFirstFile16( path, data );
1420 if (handle == INVALID_HANDLE_VALUE16) return INVALID_HANDLE_VALUE;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001421 return handle;
1422}
1423
1424
1425/*************************************************************************
1426 * FindFirstFile32W (KERNEL32.124)
1427 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001428HANDLE WINAPI FindFirstFileW( LPCWSTR path, WIN32_FIND_DATAW *data )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001429{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001430 WIN32_FIND_DATAA dataA;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001431 LPSTR pathA = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001432 HANDLE handle = FindFirstFileA( pathA, &dataA );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001433 HeapFree( GetProcessHeap(), 0, pathA );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001434 if (handle != INVALID_HANDLE_VALUE)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001435 {
1436 data->dwFileAttributes = dataA.dwFileAttributes;
1437 data->ftCreationTime = dataA.ftCreationTime;
1438 data->ftLastAccessTime = dataA.ftLastAccessTime;
1439 data->ftLastWriteTime = dataA.ftLastWriteTime;
1440 data->nFileSizeHigh = dataA.nFileSizeHigh;
1441 data->nFileSizeLow = dataA.nFileSizeLow;
1442 lstrcpyAtoW( data->cFileName, dataA.cFileName );
1443 lstrcpyAtoW( data->cAlternateFileName, dataA.cAlternateFileName );
1444 }
1445 return handle;
1446}
1447
1448
1449/*************************************************************************
1450 * FindNextFile16 (KERNEL.414)
1451 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001452BOOL16 WINAPI FindNextFile16( HANDLE16 handle, WIN32_FIND_DATAA *data )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001453{
1454 FIND_FIRST_INFO *info;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001455
1456 if (!(info = (FIND_FIRST_INFO *)GlobalLock16( handle )))
1457 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001458 SetLastError( ERROR_INVALID_HANDLE );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001459 return FALSE;
1460 }
1461 GlobalUnlock16( handle );
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001462 if (!info->path || !info->dir)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001463 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001464 SetLastError( ERROR_NO_MORE_FILES );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001465 return FALSE;
1466 }
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001467 if (!DOSFS_FindNextEx( info, data ))
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001468 {
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001469 DOSFS_CloseDir( info->dir ); info->dir = NULL;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001470 HeapFree( SystemHeap, 0, info->path );
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001471 info->path = info->long_mask = NULL;
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001472 SetLastError( ERROR_NO_MORE_FILES );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001473 return FALSE;
1474 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001475 return TRUE;
1476}
1477
1478
1479/*************************************************************************
1480 * FindNextFile32A (KERNEL32.126)
1481 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001482BOOL WINAPI FindNextFileA( HANDLE handle, WIN32_FIND_DATAA *data )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001483{
1484 return FindNextFile16( handle, data );
1485}
1486
1487
1488/*************************************************************************
1489 * FindNextFile32W (KERNEL32.127)
1490 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001491BOOL WINAPI FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *data )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001492{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001493 WIN32_FIND_DATAA dataA;
1494 if (!FindNextFileA( handle, &dataA )) return FALSE;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001495 data->dwFileAttributes = dataA.dwFileAttributes;
1496 data->ftCreationTime = dataA.ftCreationTime;
1497 data->ftLastAccessTime = dataA.ftLastAccessTime;
1498 data->ftLastWriteTime = dataA.ftLastWriteTime;
1499 data->nFileSizeHigh = dataA.nFileSizeHigh;
1500 data->nFileSizeLow = dataA.nFileSizeLow;
1501 lstrcpyAtoW( data->cFileName, dataA.cFileName );
1502 lstrcpyAtoW( data->cAlternateFileName, dataA.cAlternateFileName );
1503 return TRUE;
1504}
1505
1506
1507/*************************************************************************
1508 * FindClose16 (KERNEL.415)
1509 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001510BOOL16 WINAPI FindClose16( HANDLE16 handle )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001511{
1512 FIND_FIRST_INFO *info;
1513
1514 if ((handle == INVALID_HANDLE_VALUE16) ||
1515 !(info = (FIND_FIRST_INFO *)GlobalLock16( handle )))
1516 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +00001517 SetLastError( ERROR_INVALID_HANDLE );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001518 return FALSE;
1519 }
Alexandre Julliard85ed45e1998-08-22 19:03:56 +00001520 if (info->dir) DOSFS_CloseDir( info->dir );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001521 if (info->path) HeapFree( SystemHeap, 0, info->path );
1522 GlobalUnlock16( handle );
1523 GlobalFree16( handle );
1524 return TRUE;
1525}
1526
1527
1528/*************************************************************************
1529 * FindClose32 (KERNEL32.119)
1530 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001531BOOL WINAPI FindClose( HANDLE handle )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001532{
1533 return FindClose16( (HANDLE16)handle );
1534}
1535
1536
Alexandre Julliardca22b331996-07-12 19:02:39 +00001537/***********************************************************************
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001538 * DOSFS_UnixTimeToFileTime
1539 *
1540 * Convert a Unix time to FILETIME format.
1541 * The FILETIME structure is a 64-bit value representing the number of
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001542 * 100-nanosecond intervals since January 1, 1601, 0:00.
1543 * 'remainder' is the nonnegative number of 100-ns intervals
1544 * corresponding to the time fraction smaller than 1 second that
1545 * couldn't be stored in the time_t value.
Alexandre Julliardca22b331996-07-12 19:02:39 +00001546 */
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001547void DOSFS_UnixTimeToFileTime( time_t unix_time, FILETIME *filetime,
1548 DWORD remainder )
Alexandre Julliardca22b331996-07-12 19:02:39 +00001549{
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001550 /* NOTES:
1551
1552 CONSTANTS:
1553 The time difference between 1 January 1601, 00:00:00 and
1554 1 January 1970, 00:00:00 is 369 years, plus the leap years
1555 from 1604 to 1968, excluding 1700, 1800, 1900.
1556 This makes (1968 - 1600) / 4 - 3 = 89 leap days, and a total
1557 of 134774 days.
1558
1559 Any day in that period had 24 * 60 * 60 = 86400 seconds.
1560
1561 The time difference is 134774 * 86400 * 10000000, which can be written
1562 116444736000000000
1563 27111902 * 2^32 + 3577643008
1564 413 * 2^48 + 45534 * 2^32 + 54590 * 2^16 + 32768
1565
1566 If you find that these constants are buggy, please change them in all
1567 instances in both conversion functions.
1568
1569 VERSIONS:
1570 There are two versions, one of them uses long long variables and
1571 is presumably faster but not ISO C. The other one uses standard C
1572 data types and operations but relies on the assumption that negative
1573 numbers are stored as 2's complement (-1 is 0xffff....). If this
1574 assumption is violated, dates before 1970 will not convert correctly.
1575 This should however work on any reasonable architecture where WINE
1576 will run.
1577
1578 DETAILS:
1579
1580 Take care not to remove the casts. I have tested these functions
1581 (in both versions) for a lot of numbers. I would be interested in
1582 results on other compilers than GCC.
1583
1584 The operations have been designed to account for the possibility
1585 of 64-bit time_t in future UNICES. Even the versions without
1586 internal long long numbers will work if time_t only is 64 bit.
1587 A 32-bit shift, which was necessary for that operation, turned out
1588 not to work correctly in GCC, besides giving the warning. So I
1589 used a double 16-bit shift instead. Numbers are in the ISO version
1590 represented by three limbs, the most significant with 32 bit, the
1591 other two with 16 bit each.
1592
1593 As the modulo-operator % is not well-defined for negative numbers,
1594 negative divisors have been avoided in DOSFS_FileTimeToUnixTime.
1595
1596 There might be quicker ways to do this in C. Certainly so in
1597 assembler.
1598
1599 Claus Fischer, fischer@iue.tuwien.ac.at
1600 */
1601
Patrik Stridvall96336321999-10-24 22:13:47 +00001602#if SIZEOF_LONG_LONG >= 8
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001603# define USE_LONG_LONG 1
1604#else
1605# define USE_LONG_LONG 0
1606#endif
1607
1608#if USE_LONG_LONG /* gcc supports long long type */
1609
1610 long long int t = unix_time;
1611 t *= 10000000;
1612 t += 116444736000000000LL;
1613 t += remainder;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001614 filetime->dwLowDateTime = (UINT)t;
1615 filetime->dwHighDateTime = (UINT)(t >> 32);
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001616
1617#else /* ISO version */
1618
Alexandre Julliarda3960291999-02-26 11:11:13 +00001619 UINT a0; /* 16 bit, low bits */
1620 UINT a1; /* 16 bit, medium bits */
1621 UINT a2; /* 32 bit, high bits */
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001622
1623 /* Copy the unix time to a2/a1/a0 */
1624 a0 = unix_time & 0xffff;
1625 a1 = (unix_time >> 16) & 0xffff;
1626 /* This is obsolete if unix_time is only 32 bits, but it does not hurt.
1627 Do not replace this by >> 32, it gives a compiler warning and it does
1628 not work. */
1629 a2 = (unix_time >= 0 ? (unix_time >> 16) >> 16 :
1630 ~((~unix_time >> 16) >> 16));
1631
1632 /* Multiply a by 10000000 (a = a2/a1/a0)
1633 Split the factor into 10000 * 1000 which are both less than 0xffff. */
1634 a0 *= 10000;
1635 a1 = a1 * 10000 + (a0 >> 16);
1636 a2 = a2 * 10000 + (a1 >> 16);
1637 a0 &= 0xffff;
1638 a1 &= 0xffff;
1639
1640 a0 *= 1000;
1641 a1 = a1 * 1000 + (a0 >> 16);
1642 a2 = a2 * 1000 + (a1 >> 16);
1643 a0 &= 0xffff;
1644 a1 &= 0xffff;
1645
1646 /* Add the time difference and the remainder */
1647 a0 += 32768 + (remainder & 0xffff);
1648 a1 += 54590 + (remainder >> 16 ) + (a0 >> 16);
1649 a2 += 27111902 + (a1 >> 16);
1650 a0 &= 0xffff;
1651 a1 &= 0xffff;
1652
1653 /* Set filetime */
1654 filetime->dwLowDateTime = (a1 << 16) + a0;
1655 filetime->dwHighDateTime = a2;
1656#endif
Alexandre Julliardca22b331996-07-12 19:02:39 +00001657}
1658
1659
1660/***********************************************************************
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001661 * DOSFS_FileTimeToUnixTime
1662 *
1663 * Convert a FILETIME format to Unix time.
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001664 * If not NULL, 'remainder' contains the fractional part of the filetime,
1665 * in the range of [0..9999999] (even if time_t is negative).
Alexandre Julliardca22b331996-07-12 19:02:39 +00001666 */
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001667time_t DOSFS_FileTimeToUnixTime( const FILETIME *filetime, DWORD *remainder )
Alexandre Julliardca22b331996-07-12 19:02:39 +00001668{
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001669 /* Read the comment in the function DOSFS_UnixTimeToFileTime. */
1670#if USE_LONG_LONG
1671
1672 long long int t = filetime->dwHighDateTime;
1673 t <<= 32;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001674 t += (UINT)filetime->dwLowDateTime;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001675 t -= 116444736000000000LL;
1676 if (t < 0)
1677 {
1678 if (remainder) *remainder = 9999999 - (-t - 1) % 10000000;
1679 return -1 - ((-t - 1) / 10000000);
1680 }
1681 else
1682 {
1683 if (remainder) *remainder = t % 10000000;
1684 return t / 10000000;
1685 }
1686
1687#else /* ISO version */
1688
Alexandre Julliarda3960291999-02-26 11:11:13 +00001689 UINT a0; /* 16 bit, low bits */
1690 UINT a1; /* 16 bit, medium bits */
1691 UINT a2; /* 32 bit, high bits */
1692 UINT r; /* remainder of division */
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001693 unsigned int carry; /* carry bit for subtraction */
1694 int negative; /* whether a represents a negative value */
1695
1696 /* Copy the time values to a2/a1/a0 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001697 a2 = (UINT)filetime->dwHighDateTime;
1698 a1 = ((UINT)filetime->dwLowDateTime ) >> 16;
1699 a0 = ((UINT)filetime->dwLowDateTime ) & 0xffff;
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001700
1701 /* Subtract the time difference */
1702 if (a0 >= 32768 ) a0 -= 32768 , carry = 0;
1703 else a0 += (1 << 16) - 32768 , carry = 1;
1704
1705 if (a1 >= 54590 + carry) a1 -= 54590 + carry, carry = 0;
1706 else a1 += (1 << 16) - 54590 - carry, carry = 1;
1707
1708 a2 -= 27111902 + carry;
1709
1710 /* If a is negative, replace a by (-1-a) */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001711 negative = (a2 >= ((UINT)1) << 31);
Alexandre Julliardd37eb361997-07-20 16:23:21 +00001712 if (negative)
1713 {
1714 /* Set a to -a - 1 (a is a2/a1/a0) */
1715 a0 = 0xffff - a0;
1716 a1 = 0xffff - a1;
1717 a2 = ~a2;
1718 }
1719
1720 /* Divide a by 10000000 (a = a2/a1/a0), put the rest into r.
1721 Split the divisor into 10000 * 1000 which are both less than 0xffff. */
1722 a1 += (a2 % 10000) << 16;
1723 a2 /= 10000;
1724 a0 += (a1 % 10000) << 16;
1725 a1 /= 10000;
1726 r = a0 % 10000;
1727 a0 /= 10000;
1728
1729 a1 += (a2 % 1000) << 16;
1730 a2 /= 1000;
1731 a0 += (a1 % 1000) << 16;
1732 a1 /= 1000;
1733 r += (a0 % 1000) * 10000;
1734 a0 /= 1000;
1735
1736 /* If a was negative, replace a by (-1-a) and r by (9999999 - r) */
1737 if (negative)
1738 {
1739 /* Set a to -a - 1 (a is a2/a1/a0) */
1740 a0 = 0xffff - a0;
1741 a1 = 0xffff - a1;
1742 a2 = ~a2;
1743
1744 r = 9999999 - r;
1745 }
1746
1747 if (remainder) *remainder = r;
1748
1749 /* Do not replace this by << 32, it gives a compiler warning and it does
1750 not work. */
1751 return ((((time_t)a2) << 16) << 16) + (a1 << 16) + a0;
1752#endif
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001753}
1754
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001755
1756/***********************************************************************
1757 * DosDateTimeToFileTime (KERNEL32.76)
1758 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001759BOOL WINAPI DosDateTimeToFileTime( WORD fatdate, WORD fattime, LPFILETIME ft)
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001760{
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001761 struct tm newtm;
1762
1763 newtm.tm_sec = (fattime & 0x1f) * 2;
1764 newtm.tm_min = (fattime >> 5) & 0x3f;
1765 newtm.tm_hour = (fattime >> 11);
1766 newtm.tm_mday = (fatdate & 0x1f);
1767 newtm.tm_mon = ((fatdate >> 5) & 0x0f) - 1;
1768 newtm.tm_year = (fatdate >> 9) + 80;
1769 DOSFS_UnixTimeToFileTime( mktime( &newtm ), ft, 0 );
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001770 return TRUE;
1771}
1772
1773
1774/***********************************************************************
1775 * FileTimeToDosDateTime (KERNEL32.111)
1776 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001777BOOL WINAPI FileTimeToDosDateTime( const FILETIME *ft, LPWORD fatdate,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001778 LPWORD fattime )
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001779{
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001780 time_t unixtime = DOSFS_FileTimeToUnixTime( ft, NULL );
1781 struct tm *tm = localtime( &unixtime );
1782 if (fattime)
1783 *fattime = (tm->tm_hour << 11) + (tm->tm_min << 5) + (tm->tm_sec / 2);
1784 if (fatdate)
1785 *fatdate = ((tm->tm_year - 80) << 9) + ((tm->tm_mon + 1) << 5)
1786 + tm->tm_mday;
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001787 return TRUE;
1788}
1789
1790
1791/***********************************************************************
1792 * LocalFileTimeToFileTime (KERNEL32.373)
1793 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001794BOOL WINAPI LocalFileTimeToFileTime( const FILETIME *localft,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001795 LPFILETIME utcft )
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001796{
1797 struct tm *xtm;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001798 DWORD remainder;
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001799
1800 /* convert from local to UTC. Perhaps not correct. FIXME */
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001801 time_t unixtime = DOSFS_FileTimeToUnixTime( localft, &remainder );
1802 xtm = gmtime( &unixtime );
1803 DOSFS_UnixTimeToFileTime( mktime(xtm), utcft, remainder );
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001804 return TRUE;
1805}
1806
1807
1808/***********************************************************************
1809 * FileTimeToLocalFileTime (KERNEL32.112)
1810 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001811BOOL WINAPI FileTimeToLocalFileTime( const FILETIME *utcft,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001812 LPFILETIME localft )
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001813{
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001814 DWORD remainder;
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001815 /* convert from UTC to local. Perhaps not correct. FIXME */
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001816 time_t unixtime = DOSFS_FileTimeToUnixTime( utcft, &remainder );
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001817#ifdef HAVE_TIMEGM
1818 struct tm *xtm = localtime( &unixtime );
1819 time_t localtime;
1820
1821 localtime = timegm(xtm);
1822 DOSFS_UnixTimeToFileTime( localtime, localft, remainder );
1823
1824#else
1825 struct tm *xtm,*gtm;
1826 time_t time1,time2;
1827
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001828 xtm = localtime( &unixtime );
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001829 gtm = gmtime( &unixtime );
1830 time1 = mktime(xtm);
1831 time2 = mktime(gtm);
1832 DOSFS_UnixTimeToFileTime( 2*time1-time2, localft, remainder );
1833#endif
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001834 return TRUE;
1835}
1836
1837
1838/***********************************************************************
1839 * FileTimeToSystemTime (KERNEL32.113)
1840 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001841BOOL WINAPI FileTimeToSystemTime( const FILETIME *ft, LPSYSTEMTIME syst )
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001842{
1843 struct tm *xtm;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001844 DWORD remainder;
1845 time_t xtime = DOSFS_FileTimeToUnixTime( ft, &remainder );
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001846 xtm = gmtime(&xtime);
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001847 syst->wYear = xtm->tm_year+1900;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +00001848 syst->wMonth = xtm->tm_mon + 1;
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001849 syst->wDayOfWeek = xtm->tm_wday;
1850 syst->wDay = xtm->tm_mday;
1851 syst->wHour = xtm->tm_hour;
1852 syst->wMinute = xtm->tm_min;
1853 syst->wSecond = xtm->tm_sec;
1854 syst->wMilliseconds = remainder / 10000;
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001855 return TRUE;
1856}
1857
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001858/***********************************************************************
1859 * QueryDosDeviceA (KERNEL32.413)
1860 *
1861 * returns array of strings terminated by \0, terminated by \0
1862 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001863DWORD WINAPI QueryDosDeviceA(LPCSTR devname,LPSTR target,DWORD bufsize)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001864{
1865 LPSTR s;
1866 char buffer[200];
1867
Alexandre Julliard06c275a1999-05-02 14:32:27 +00001868 TRACE_(dosfs)("(%s,...)\n",devname?devname:"<null>");
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001869 if (!devname) {
1870 /* return known MSDOS devices */
Alexandre Julliard89f079b1999-08-08 18:54:47 +00001871 strcpy(buffer,"CON COM1 COM2 LPT1 NUL ");
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001872 while ((s=strchr(buffer,' ')))
1873 *s='\0';
1874
Alexandre Julliarda3960291999-02-26 11:11:13 +00001875 lstrcpynA(target,buffer,bufsize);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001876 return strlen(buffer);
1877 }
Alexandre Julliard89f079b1999-08-08 18:54:47 +00001878 strcpy(buffer,"\\DEV\\");
1879 strcat(buffer,devname);
Alexandre Julliard01d63461997-01-20 19:43:45 +00001880 if ((s=strchr(buffer,':'))) *s='\0';
Alexandre Julliarda3960291999-02-26 11:11:13 +00001881 lstrcpynA(target,buffer,bufsize);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001882 return strlen(buffer);
1883}
1884
1885
1886/***********************************************************************
1887 * QueryDosDeviceW (KERNEL32.414)
1888 *
1889 * returns array of strings terminated by \0, terminated by \0
1890 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001891DWORD WINAPI QueryDosDeviceW(LPCWSTR devname,LPWSTR target,DWORD bufsize)
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001892{
1893 LPSTR devnameA = devname?HEAP_strdupWtoA(GetProcessHeap(),0,devname):NULL;
1894 LPSTR targetA = (LPSTR)HEAP_xalloc(GetProcessHeap(),0,bufsize);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001895 DWORD ret = QueryDosDeviceA(devnameA,targetA,bufsize);
Alexandre Julliardc6c09441997-01-12 18:32:19 +00001896
1897 lstrcpynAtoW(target,targetA,bufsize);
1898 if (devnameA) HeapFree(GetProcessHeap(),0,devnameA);
1899 if (targetA) HeapFree(GetProcessHeap(),0,targetA);
1900 return ret;
1901}
1902
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001903
1904/***********************************************************************
1905 * SystemTimeToFileTime (KERNEL32.526)
1906 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001907BOOL WINAPI SystemTimeToFileTime( const SYSTEMTIME *syst, LPFILETIME ft )
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001908{
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001909#ifdef HAVE_TIMEGM
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001910 struct tm xtm;
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001911 time_t utctime;
1912#else
1913 struct tm xtm,*local_tm,*utc_tm;
1914 time_t localtim,utctime;
1915#endif
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001916
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001917 xtm.tm_year = syst->wYear-1900;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +00001918 xtm.tm_mon = syst->wMonth - 1;
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001919 xtm.tm_wday = syst->wDayOfWeek;
1920 xtm.tm_mday = syst->wDay;
1921 xtm.tm_hour = syst->wHour;
1922 xtm.tm_min = syst->wMinute;
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001923 xtm.tm_sec = syst->wSecond; /* this is UTC */
1924 xtm.tm_isdst = -1;
1925#ifdef HAVE_TIMEGM
1926 utctime = timegm(&xtm);
1927 DOSFS_UnixTimeToFileTime( utctime, ft,
1928 syst->wMilliseconds * 10000 );
1929#else
1930 localtim = mktime(&xtm); /* now we've got local time */
1931 local_tm = localtime(&localtim);
1932 utc_tm = gmtime(&localtim);
1933 utctime = mktime(utc_tm);
1934 DOSFS_UnixTimeToFileTime( 2*localtim -utctime, ft,
1935 syst->wMilliseconds * 10000 );
1936#endif
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001937 return TRUE;
1938}
Marcus Meissner575a1651998-10-21 16:47:29 +00001939
Patrik Stridvall3a9c4761999-10-31 02:07:05 +00001940/***********************************************************************
1941 * DefineDosDeviceA (KERNEL32.182)
1942 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001943BOOL WINAPI DefineDosDeviceA(DWORD flags,LPCSTR devname,LPCSTR targetpath) {
Alexandre Julliard06c275a1999-05-02 14:32:27 +00001944 FIXME_(dosfs)("(0x%08lx,%s,%s),stub!\n",flags,devname,targetpath);
Marcus Meissner575a1651998-10-21 16:47:29 +00001945 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1946 return FALSE;
1947}