2 * DOS file system functions
4 * Copyright 1993 Erik Bos
5 * Copyright 1996 Alexandre Julliard
17 #include <sys/ioctl.h>
20 #if defined(__svr4__) || defined(_SCO_DS)
21 #include <sys/statfs.h>
32 /* Define the VFAT ioctl to get both short and long file names */
33 /* FIXME: is it possible to get this to work on other systems? */
35 #define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, long)
36 /* We want the real kernel dirent structure, not the libc one */
41 unsigned short d_reclen
;
46 #undef VFAT_IOCTL_READDIR_BOTH /* just in case... */
49 /* Chars we don't want to see in DOS file names */
50 #define INVALID_DOS_CHARS "*?<>|\"+=,;[] \345"
52 static const char *DOSFS_Devices
[] = {
53 "CON","PRN","NUL","AUX","LPT1","LPT2","LPT3","LPT4","COM1","COM2","COM3","COM4",
57 #define GET_DRIVE(path) \
58 (((path)[1] == ':') ? toupper((path)[0]) - 'A' : DOSFS_CurDrive)
60 /* DOS extended error status */
61 WORD DOS_ExtendedError
;
66 /* Info structure for FindFirstFile handle */
76 /* Directory info for DOSFS_ReadDir */
80 #ifdef VFAT_IOCTL_READDIR_BOTH
83 KERNEL_DIRENT dirent
[2];
88 /***********************************************************************
91 * Return 1 if Unix file 'name' is also a valid MS-DOS name
92 * (i.e. contains only valid DOS chars, lower-case only, fits in 8.3 format).
93 * File name can be terminated by '\0', '\\' or '/'.
95 static int DOSFS_ValidDOSName( const char *name
, int ignore_case
)
97 static const char invalid_chars
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" INVALID_DOS_CHARS
;
99 const char *invalid
= ignore_case
? (invalid_chars
+ 26) : invalid_chars
;
104 /* Check for "." and ".." */
107 /* All other names beginning with '.' are invalid */
108 return (IS_END_OF_NAME(*p
));
110 while (!IS_END_OF_NAME(*p
))
112 if (strchr( invalid
, *p
)) return 0; /* Invalid char */
113 if (*p
== '.') break; /* Start of the extension */
114 if (++len
> 8) return 0; /* Name too long */
117 if (*p
!= '.') return 1; /* End of name */
119 if (IS_END_OF_NAME(*p
)) return 0; /* Empty extension not allowed */
121 while (!IS_END_OF_NAME(*p
))
123 if (strchr( invalid
, *p
)) return 0; /* Invalid char */
124 if (*p
== '.') return 0; /* Second extension not allowed */
125 if (++len
> 3) return 0; /* Extension too long */
132 /***********************************************************************
133 * DOSFS_ToDosFCBFormat
135 * Convert a file name to DOS FCB format (8+3 chars, padded with blanks),
136 * expanding wild cards and converting to upper-case in the process.
137 * File name can be terminated by '\0', '\\' or '/'.
138 * Return FALSE if the name is not a valid DOS name.
139 * 'buffer' must be at least 12 characters long.
141 BOOL32
DOSFS_ToDosFCBFormat( LPCSTR name
, LPSTR buffer
)
143 static const char invalid_chars
[] = INVALID_DOS_CHARS
;
144 const char *p
= name
;
147 /* Check for "." and ".." */
151 strcpy( buffer
, ". " );
157 return (!*p
|| (*p
== '/') || (*p
== '\\'));
160 for (i
= 0; i
< 8; i
++)
177 if (strchr( invalid_chars
, *p
)) return FALSE
;
178 buffer
[i
] = toupper(*p
);
186 /* Skip all chars after wildcard up to first dot */
187 while (*p
&& (*p
!= '/') && (*p
!= '\\') && (*p
!= '.')) p
++;
191 /* Check if name too long */
192 if (*p
&& (*p
!= '/') && (*p
!= '\\') && (*p
!= '.')) return FALSE
;
194 if (*p
== '.') p
++; /* Skip dot */
196 for (i
= 8; i
< 11; i
++)
206 return FALSE
; /* Second extension not allowed */
214 if (strchr( invalid_chars
, *p
)) return FALSE
;
215 buffer
[i
] = toupper(*p
);
225 /***********************************************************************
226 * DOSFS_ToDosDTAFormat
228 * Convert a file name from FCB to DTA format (name.ext, null-terminated)
229 * converting to upper-case in the process.
230 * File name can be terminated by '\0', '\\' or '/'.
231 * 'buffer' must be at least 13 characters long.
233 static void DOSFS_ToDosDTAFormat( LPCSTR name
, LPSTR buffer
)
237 memcpy( buffer
, name
, 8 );
238 for (p
= buffer
+ 8; (p
> buffer
) && (p
[-1] == ' '); p
--);
240 memcpy( p
, name
+ 8, 3 );
241 for (p
+= 3; p
[-1] == ' '; p
--);
242 if (p
[-1] == '.') p
--;
247 /***********************************************************************
250 * Check a DOS file name against a mask (both in FCB format).
252 static int DOSFS_MatchShort( const char *mask
, const char *name
)
255 for (i
= 11; i
> 0; i
--, mask
++, name
++)
256 if ((*mask
!= '?') && (*mask
!= *name
)) return 0;
261 /***********************************************************************
264 * Check a long file name against a mask.
266 static int DOSFS_MatchLong( const char *mask
, const char *name
,
269 if (!strcmp( mask
, "*.*" )) return 1;
270 while (*name
&& *mask
)
275 while (*mask
== '*') mask
++; /* Skip consecutive '*' */
276 if (!*mask
) return 1;
277 if (case_sensitive
) while (*name
&& (*name
!= *mask
)) name
++;
278 else while (*name
&& (toupper(*name
) != toupper(*mask
))) name
++;
279 if (!*name
) return 0;
281 else if (*mask
!= '?')
285 if (*mask
!= *name
) return 0;
287 else if (toupper(*mask
) != toupper(*name
)) return 0;
292 return (!*name
&& !*mask
);
296 /***********************************************************************
299 static DOS_DIR
*DOSFS_OpenDir( LPCSTR path
)
301 DOS_DIR
*dir
= HeapAlloc( SystemHeap
, 0, sizeof(*dir
) );
304 DOS_ERROR( ER_OutOfMemory
, EC_OutOfResource
, SA_Abort
, EL_Memory
);
308 #ifdef VFAT_IOCTL_READDIR_BOTH
310 /* Check if the VFAT ioctl is supported on this directory */
312 if ((dir
->fd
= open( path
, O_RDONLY
)) != -1)
314 if (ioctl( dir
->fd
, VFAT_IOCTL_READDIR_BOTH
, (long)dir
->dirent
) == -1)
321 /* Set the file pointer back at the start of the directory */
322 lseek( dir
->fd
, 0, SEEK_SET
);
327 #endif /* VFAT_IOCTL_READDIR_BOTH */
329 /* Now use the standard opendir/readdir interface */
331 if (!(dir
->dir
= opendir( path
)))
333 HeapFree( SystemHeap
, 0, dir
);
340 /***********************************************************************
343 static void DOSFS_CloseDir( DOS_DIR
*dir
)
345 #ifdef VFAT_IOCTL_READDIR_BOTH
346 if (dir
->fd
!= -1) close( dir
->fd
);
347 #endif /* VFAT_IOCTL_READDIR_BOTH */
348 if (dir
->dir
) closedir( dir
->dir
);
349 HeapFree( SystemHeap
, 0, dir
);
353 /***********************************************************************
356 static BOOL32
DOSFS_ReadDir( DOS_DIR
*dir
, LPCSTR
*long_name
,
359 struct dirent
*dirent
;
361 #ifdef VFAT_IOCTL_READDIR_BOTH
364 if (ioctl( dir
->fd
, VFAT_IOCTL_READDIR_BOTH
, (long)dir
->dirent
) != -1) {
365 if (!dir
->dirent
[0].d_reclen
) return FALSE
;
366 if (!DOSFS_ToDosFCBFormat( dir
->dirent
[0].d_name
, dir
->short_name
))
367 dir
->short_name
[0] = '\0';
368 *short_name
= dir
->short_name
;
369 if (dir
->dirent
[1].d_name
[0]) *long_name
= dir
->dirent
[1].d_name
;
370 else *long_name
= dir
->dirent
[0].d_name
;
374 #endif /* VFAT_IOCTL_READDIR_BOTH */
376 if (!(dirent
= readdir( dir
->dir
))) return FALSE
;
377 *long_name
= dirent
->d_name
;
383 /***********************************************************************
386 * Transform a Unix file name into a hashed DOS name. If the name is a valid
387 * DOS name, it is converted to upper-case; otherwise it is replaced by a
388 * hashed version that fits in 8.3 format.
389 * File name can be terminated by '\0', '\\' or '/'.
390 * 'buffer' must be at least 13 characters long.
392 static void DOSFS_Hash( LPCSTR name
, LPSTR buffer
, BOOL32 dir_format
,
395 static const char invalid_chars
[] = INVALID_DOS_CHARS
"~.";
396 static const char hash_chars
[32] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
403 if (dir_format
) strcpy( buffer
, " " );
405 if (DOSFS_ValidDOSName( name
, ignore_case
))
407 /* Check for '.' and '..' */
411 if (!dir_format
) buffer
[1] = buffer
[2] = '\0';
412 if (name
[1] == '.') buffer
[1] = '.';
416 /* Simply copy the name, converting to uppercase */
418 for (dst
= buffer
; !IS_END_OF_NAME(*name
) && (*name
!= '.'); name
++)
419 *dst
++ = toupper(*name
);
422 if (dir_format
) dst
= buffer
+ 8;
424 for (name
++; !IS_END_OF_NAME(*name
); name
++)
425 *dst
++ = toupper(*name
);
427 if (!dir_format
) *dst
= '\0';
431 /* Compute the hash code of the file name */
432 /* If you know something about hash functions, feel free to */
433 /* insert a better algorithm here... */
436 for (p
= name
, hash
= 0xbeef; !IS_END_OF_NAME(p
[1]); p
++)
437 hash
= (hash
<<3) ^ (hash
>>5) ^ tolower(*p
) ^ (tolower(p
[1]) << 8);
438 hash
= (hash
<<3) ^ (hash
>>5) ^ tolower(*p
); /* Last character*/
442 for (p
= name
, hash
= 0xbeef; !IS_END_OF_NAME(p
[1]); p
++)
443 hash
= (hash
<< 3) ^ (hash
>> 5) ^ *p
^ (p
[1] << 8);
444 hash
= (hash
<< 3) ^ (hash
>> 5) ^ *p
; /* Last character */
447 /* Find last dot for start of the extension */
448 for (p
= name
+1, ext
= NULL
; !IS_END_OF_NAME(*p
); p
++)
449 if (*p
== '.') ext
= p
;
450 if (ext
&& IS_END_OF_NAME(ext
[1]))
451 ext
= NULL
; /* Empty extension ignored */
453 /* Copy first 4 chars, replacing invalid chars with '_' */
454 for (i
= 4, p
= name
, dst
= buffer
; i
> 0; i
--, p
++)
456 if (IS_END_OF_NAME(*p
) || (p
== ext
)) break;
457 *dst
++ = strchr( invalid_chars
, *p
) ? '_' : toupper(*p
);
459 /* Pad to 5 chars with '~' */
460 while (i
-- >= 0) *dst
++ = '~';
462 /* Insert hash code converted to 3 ASCII chars */
463 *dst
++ = hash_chars
[(hash
>> 10) & 0x1f];
464 *dst
++ = hash_chars
[(hash
>> 5) & 0x1f];
465 *dst
++ = hash_chars
[hash
& 0x1f];
467 /* Copy the first 3 chars of the extension (if any) */
470 if (!dir_format
) *dst
++ = '.';
471 for (i
= 3, ext
++; (i
> 0) && !IS_END_OF_NAME(*ext
); i
--, ext
++)
472 *dst
++ = strchr( invalid_chars
, *ext
) ? '_' : toupper(*ext
);
474 if (!dir_format
) *dst
= '\0';
478 /***********************************************************************
481 * Find the Unix file name in a given directory that corresponds to
482 * a file name (either in Unix or DOS format).
483 * File name can be terminated by '\0', '\\' or '/'.
484 * Return TRUE if OK, FALSE if no file name matches.
486 * 'long_buf' must be at least 'long_len' characters long. If the long name
487 * turns out to be larger than that, the function returns FALSE.
488 * 'short_buf' must be at least 13 characters long.
490 BOOL32
DOSFS_FindUnixName( LPCSTR path
, LPCSTR name
, LPSTR long_buf
,
491 INT32 long_len
, LPSTR short_buf
, BOOL32 ignore_case
)
494 LPCSTR long_name
, short_name
;
495 char dos_name
[12], tmp_buf
[13];
498 const char *p
= strchr( name
, '/' );
499 int len
= p
? (int)(p
- name
) : strlen(name
);
500 if ((p
= strchr( name
, '\\' ))) len
= MIN( (int)(p
- name
), len
);
501 if (long_len
< len
+ 1) return FALSE
;
503 TRACE(dosfs
, "%s,%s\n", path
, name
);
505 if (!DOSFS_ToDosFCBFormat( name
, dos_name
)) dos_name
[0] = '\0';
507 if (!(dir
= DOSFS_OpenDir( path
)))
509 WARN(dosfs
, "(%s,%s): can't open dir: %s\n",
510 path
, name
, strerror(errno
) );
514 while ((ret
= DOSFS_ReadDir( dir
, &long_name
, &short_name
)))
516 /* Check against Unix name */
517 if (len
== strlen(long_name
))
521 if (!lstrncmp32A( long_name
, name
, len
)) break;
525 if (!lstrncmpi32A( long_name
, name
, len
)) break;
530 /* Check against hashed DOS name */
533 DOSFS_Hash( long_name
, tmp_buf
, TRUE
, ignore_case
);
534 short_name
= tmp_buf
;
536 if (!strcmp( dos_name
, short_name
)) break;
541 if (long_buf
) strcpy( long_buf
, long_name
);
545 DOSFS_ToDosDTAFormat( short_name
, short_buf
);
547 DOSFS_Hash( long_name
, short_buf
, FALSE
, ignore_case
);
549 TRACE(dosfs
, "(%s,%s) -> %s (%s)\n",
550 path
, name
, long_name
, short_buf
? short_buf
: "***");
553 WARN(dosfs
, "'%s' not found in '%s'\n", name
, path
);
554 DOSFS_CloseDir( dir
);
559 /***********************************************************************
562 * Check if a DOS file name represents a DOS device.
564 BOOL32
DOSFS_IsDevice( const char *name
)
569 if (name
[0] && (name
[1] == ':')) name
+= 2;
570 if ((p
= strrchr( name
, '/' ))) name
= p
+ 1;
571 if ((p
= strrchr( name
, '\\' ))) name
= p
+ 1;
572 for (i
= 0; i
< sizeof(DOSFS_Devices
)/sizeof(DOSFS_Devices
[0]); i
++)
574 const char *dev
= DOSFS_Devices
[i
];
575 if (!lstrncmpi32A( dev
, name
, strlen(dev
) ))
577 p
= name
+ strlen( dev
);
578 if (!*p
|| (*p
== '.')) return TRUE
;
584 /***********************************************************************
587 * Open a DOS device. This might not map 1:1 into the UNIX device concept.
589 HFILE32
DOSFS_OpenDevice( const char *name
, int unixmode
)
594 if (name
[0] && (name
[1] == ':')) name
+= 2;
595 if ((p
= strrchr( name
, '/' ))) name
= p
+ 1;
596 if ((p
= strrchr( name
, '\\' ))) name
= p
+ 1;
597 for (i
= 0; i
< sizeof(DOSFS_Devices
)/sizeof(DOSFS_Devices
[0]); i
++)
599 const char *dev
= DOSFS_Devices
[i
];
600 if (!lstrncmpi32A( dev
, name
, strlen(dev
) ))
602 p
= name
+ strlen( dev
);
603 if (!*p
|| (*p
== '.')) {
605 if (!strcmp(DOSFS_Devices
[i
],"NUL"))
606 return FILE_OpenUnixFile("/dev/null",unixmode
);
607 if (!strcmp(DOSFS_Devices
[i
],"CON")) {
610 return GetStdHandle( STD_INPUT_HANDLE
);
613 return GetStdHandle( STD_OUTPUT_HANDLE
);
616 FIXME(dosfs
,"can't open CON read/write\n");
617 return HFILE_ERROR32
;
621 /* FIXME: the rest of the devices ... lptX, comX et.al. */
622 return HFILE_ERROR32
;
626 return HFILE_ERROR32
;
630 /***********************************************************************
633 * Get the drive specified by a given path name (DOS or Unix format).
635 static int DOSFS_GetPathDrive( const char **name
)
638 const char *p
= *name
;
640 if (*p
&& (p
[1] == ':'))
642 drive
= toupper(*p
) - 'A';
645 else if (*p
== '/') /* Absolute Unix path? */
647 if ((drive
= DRIVE_FindDriveRoot( name
)) == -1)
649 fprintf( stderr
, "Warning: %s not accessible from a DOS drive\n",
651 /* Assume it really was a DOS name */
652 drive
= DRIVE_GetCurrentDrive();
655 else drive
= DRIVE_GetCurrentDrive();
657 if (!DRIVE_IsValid(drive
))
659 DOS_ERROR( ER_InvalidDrive
, EC_MediaError
, SA_Abort
, EL_Disk
);
666 /***********************************************************************
669 * Convert a file name (DOS or mixed DOS/Unix format) to a valid
670 * Unix name / short DOS name pair.
671 * Return FALSE if one of the path components does not exist. The last path
672 * component is only checked if 'check_last' is non-zero.
673 * The buffers pointed to by 'long_buf' and 'short_buf' must be
674 * at least MAX_PATHNAME_LEN long.
676 BOOL32
DOSFS_GetFullName( LPCSTR name
, BOOL32 check_last
, DOS_FULL_NAME
*full
)
680 char *p_l
, *p_s
, *root
;
682 TRACE(dosfs
, "%s (last=%d)\n",
685 if ((full
->drive
= DOSFS_GetPathDrive( &name
)) == -1) return FALSE
;
686 flags
= DRIVE_GetFlags( full
->drive
);
688 lstrcpyn32A( full
->long_name
, DRIVE_GetRoot( full
->drive
),
689 sizeof(full
->long_name
) );
690 if (full
->long_name
[1]) root
= full
->long_name
+ strlen(full
->long_name
);
691 else root
= full
->long_name
; /* root directory */
693 strcpy( full
->short_name
, "A:\\" );
694 full
->short_name
[0] += full
->drive
;
696 if ((*name
== '\\') || (*name
== '/')) /* Absolute path */
698 while ((*name
== '\\') || (*name
== '/')) name
++;
700 else /* Relative path */
702 lstrcpyn32A( root
+ 1, DRIVE_GetUnixCwd( full
->drive
),
703 sizeof(full
->long_name
) - (root
- full
->long_name
) - 1 );
704 if (root
[1]) *root
= '/';
705 lstrcpyn32A( full
->short_name
+ 3, DRIVE_GetDosCwd( full
->drive
),
706 sizeof(full
->short_name
) - 3 );
709 p_l
= full
->long_name
[1] ? full
->long_name
+ strlen(full
->long_name
)
711 p_s
= full
->short_name
[3] ? full
->short_name
+ strlen(full
->short_name
)
712 : full
->short_name
+ 2;
715 while (*name
&& found
)
717 /* Check for '.' and '..' */
721 if (IS_END_OF_NAME(name
[1]))
724 while ((*name
== '\\') || (*name
== '/')) name
++;
727 else if ((name
[1] == '.') && IS_END_OF_NAME(name
[2]))
730 while ((*name
== '\\') || (*name
== '/')) name
++;
731 while ((p_l
> root
) && (*p_l
!= '/')) p_l
--;
732 while ((p_s
> full
->short_name
+ 2) && (*p_s
!= '\\')) p_s
--;
733 *p_l
= *p_s
= '\0'; /* Remove trailing separator */
738 /* Make sure buffers are large enough */
740 if ((p_s
>= full
->short_name
+ sizeof(full
->short_name
) - 14) ||
741 (p_l
>= full
->long_name
+ sizeof(full
->long_name
) - 1))
743 DOS_ERROR( ER_PathNotFound
, EC_NotFound
, SA_Abort
, EL_Disk
);
747 /* Get the long and short name matching the file name */
749 if ((found
= DOSFS_FindUnixName( full
->long_name
, name
, p_l
+ 1,
750 sizeof(full
->long_name
) - (p_l
- full
->long_name
) - 1,
751 p_s
+ 1, !(flags
& DRIVE_CASE_SENSITIVE
) )))
757 while (!IS_END_OF_NAME(*name
)) name
++;
759 else if (!check_last
)
763 while (!IS_END_OF_NAME(*name
) &&
764 (p_s
< full
->short_name
+ sizeof(full
->short_name
) - 1) &&
765 (p_l
< full
->long_name
+ sizeof(full
->long_name
) - 1))
767 *p_l
++ = *p_s
++ = tolower(*name
);
772 while ((*name
== '\\') || (*name
== '/')) name
++;
779 DOS_ERROR( ER_FileNotFound
, EC_NotFound
, SA_Abort
, EL_Disk
);
782 if (*name
) /* Not last */
784 DOS_ERROR( ER_PathNotFound
, EC_NotFound
, SA_Abort
, EL_Disk
);
788 if (!full
->long_name
[0]) strcpy( full
->long_name
, "/" );
789 if (!full
->short_name
[2]) strcpy( full
->short_name
+ 2, "\\" );
790 TRACE(dosfs
, "returning %s = %s\n",
791 full
->long_name
, full
->short_name
);
796 /***********************************************************************
797 * GetShortPathName32A (KERNEL32.271)
799 DWORD WINAPI
GetShortPathName32A( LPCSTR longpath
, LPSTR shortpath
,
802 DOS_FULL_NAME full_name
;
804 /* FIXME: is it correct to always return a fully qualified short path? */
805 if (!DOSFS_GetFullName( longpath
, TRUE
, &full_name
)) return 0;
806 lstrcpyn32A( shortpath
, full_name
.short_name
, shortlen
);
807 return strlen( full_name
.short_name
);
811 /***********************************************************************
812 * GetShortPathName32W (KERNEL32.272)
814 DWORD WINAPI
GetShortPathName32W( LPCWSTR longpath
, LPWSTR shortpath
,
817 DOS_FULL_NAME full_name
;
819 LPSTR longpathA
= HEAP_strdupWtoA( GetProcessHeap(), 0, longpath
);
821 /* FIXME: is it correct to always return a fully qualified short path? */
822 if (DOSFS_GetFullName( longpathA
, TRUE
, &full_name
))
824 ret
= strlen( full_name
.short_name
);
825 lstrcpynAtoW( shortpath
, full_name
.short_name
, shortlen
);
827 HeapFree( GetProcessHeap(), 0, longpathA
);
832 /***********************************************************************
833 * GetLongPathName32A (KERNEL32.xxx)
835 DWORD WINAPI
GetLongPathName32A( LPCSTR shortpath
, LPSTR longpath
,
838 DOS_FULL_NAME full_name
;
840 /* FIXME: is it correct to always return a fully qualified short path? */
841 if (!DOSFS_GetFullName( shortpath
, TRUE
, &full_name
)) return 0;
842 lstrcpyn32A( longpath
, full_name
.long_name
, longlen
);
843 return strlen( full_name
.long_name
);
847 /***********************************************************************
848 * GetLongPathName32W (KERNEL32.269)
850 DWORD WINAPI
GetLongPathName32W( LPCWSTR shortpath
, LPWSTR longpath
,
853 DOS_FULL_NAME full_name
;
855 LPSTR shortpathA
= HEAP_strdupWtoA( GetProcessHeap(), 0, shortpath
);
857 /* FIXME: is it correct to always return a fully qualified short path? */
858 if (DOSFS_GetFullName( shortpathA
, TRUE
, &full_name
))
860 ret
= strlen( full_name
.short_name
);
861 lstrcpynAtoW( longpath
, full_name
.long_name
, longlen
);
863 HeapFree( GetProcessHeap(), 0, shortpathA
);
868 /***********************************************************************
869 * DOSFS_DoGetFullPathName
871 * Implementation of GetFullPathName32A/W.
873 static DWORD
DOSFS_DoGetFullPathName( LPCSTR name
, DWORD len
, LPSTR result
,
876 char buffer
[MAX_PATHNAME_LEN
];
880 TRACE(dosfs
, "converting %s\n", name
);
882 if (!name
|| !result
) return 0;
884 if ((drive
= DOSFS_GetPathDrive( &name
)) == -1) return 0;
888 if (IS_END_OF_NAME(*name
) && (*name
)) /* Absolute path */
890 while ((*name
== '\\') || (*name
== '/')) name
++;
892 else /* Relative path or empty path */
895 lstrcpyn32A( p
, DRIVE_GetDosCwd(drive
), sizeof(buffer
) - 3 );
896 if (*p
) p
+= strlen(p
); else p
--;
898 if (!*name
) /* empty path */
906 if (IS_END_OF_NAME(name
[1]))
909 while ((*name
== '\\') || (*name
== '/')) name
++;
912 else if ((name
[1] == '.') && IS_END_OF_NAME(name
[2]))
915 while ((*name
== '\\') || (*name
== '/')) name
++;
916 while ((p
> buffer
+ 2) && (*p
!= '\\')) p
--;
917 *p
= '\0'; /* Remove trailing separator */
921 if (p
>= buffer
+ sizeof(buffer
) - 1)
923 DOS_ERROR( ER_PathNotFound
, EC_NotFound
, SA_Abort
, EL_Disk
);
927 while (!IS_END_OF_NAME(*name
) && (p
< buffer
+ sizeof(buffer
) - 1))
930 while ((*name
== '\\') || (*name
== '/')) name
++;
938 if (!(DRIVE_GetFlags(drive
) & DRIVE_CASE_PRESERVING
))
939 CharUpper32A( buffer
);
941 if (unicode
) lstrcpynAtoW( (LPWSTR
)result
, buffer
, len
);
942 else lstrcpyn32A( result
, buffer
, len
);
944 TRACE(dosfs
, "returning %s\n", buffer
);
945 return strlen(buffer
);
949 /***********************************************************************
950 * GetFullPathName32A (KERNEL32.272)
952 DWORD WINAPI
GetFullPathName32A( LPCSTR name
, DWORD len
, LPSTR buffer
,
955 DWORD ret
= DOSFS_DoGetFullPathName( name
, len
, buffer
, FALSE
);
958 LPSTR p
= buffer
+ strlen(buffer
);
959 while ((p
> buffer
+ 2) && (*p
!= '\\')) p
--;
966 /***********************************************************************
967 * GetFullPathName32W (KERNEL32.273)
969 DWORD WINAPI
GetFullPathName32W( LPCWSTR name
, DWORD len
, LPWSTR buffer
,
972 LPSTR nameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, name
);
973 DWORD ret
= DOSFS_DoGetFullPathName( nameA
, len
, (LPSTR
)buffer
, TRUE
);
974 HeapFree( GetProcessHeap(), 0, nameA
);
977 LPWSTR p
= buffer
+ lstrlen32W(buffer
);
978 while ((p
> buffer
+ 2) && (*p
!= '\\')) p
--;
985 /***********************************************************************
988 * Find the next matching file. Return the number of entries read to find
989 * the matching one, or 0 if no more entries.
990 * 'short_mask' is the 8.3 mask (in FCB format), 'long_mask' is the long
991 * file name mask. Either or both can be NULL.
993 int DOSFS_FindNext( const char *path
, const char *short_mask
,
994 const char *long_mask
, int drive
, BYTE attr
,
995 int skip
, WIN32_FIND_DATA32A
*entry
)
997 static DOS_DIR
*dir
= NULL
;
999 static char buffer
[MAX_PATHNAME_LEN
];
1000 static int cur_pos
= 0;
1001 static int drive_root
= 0;
1004 LPCSTR long_name
, short_name
;
1006 BY_HANDLE_FILE_INFORMATION info
;
1008 if ((attr
& ~(FA_UNUSED
| FA_ARCHIVE
| FA_RDONLY
)) == FA_LABEL
)
1011 entry
->dwFileAttributes
= FILE_ATTRIBUTE_LABEL
;
1012 DOSFS_UnixTimeToFileTime( (time_t)0, &entry
->ftCreationTime
, 0 );
1013 DOSFS_UnixTimeToFileTime( (time_t)0, &entry
->ftLastAccessTime
, 0 );
1014 DOSFS_UnixTimeToFileTime( (time_t)0, &entry
->ftLastWriteTime
, 0 );
1015 entry
->nFileSizeHigh
= 0;
1016 entry
->nFileSizeLow
= 0;
1017 entry
->dwReserved0
= 0;
1018 entry
->dwReserved1
= 0;
1019 DOSFS_ToDosDTAFormat( DRIVE_GetLabel( drive
), entry
->cFileName
);
1020 strcpy( entry
->cAlternateFileName
, entry
->cFileName
);
1024 /* Check the cached directory */
1025 if (dir
&& !strcmp( buffer
, path
) && (cur_pos
<= skip
)) skip
-= cur_pos
;
1026 else /* Not in the cache, open it anew */
1028 const char *drive_path
;
1029 TRACE(dosfs
, "cache miss, path=%s skip=%d buf=%s cur=%d\n",
1030 path
, skip
, buffer
, cur_pos
);
1032 if (dir
) DOSFS_CloseDir(dir
);
1033 if (!*path
) path
= "/";
1034 if (!(dir
= DOSFS_OpenDir(path
))) return 0;
1035 drive_path
= path
+ strlen(DRIVE_GetRoot(drive
));
1036 while ((*drive_path
== '/') || (*drive_path
== '\\')) drive_path
++;
1037 drive_root
= !*drive_path
;
1038 TRACE(dosfs
, "drive_root = %d\n", drive_root
);
1039 lstrcpyn32A( buffer
, path
, sizeof(buffer
) - 1 );
1041 strcat( buffer
, "/" );
1042 p
= buffer
+ strlen(buffer
);
1043 attr
|= FA_UNUSED
| FA_ARCHIVE
| FA_RDONLY
;
1044 flags
= DRIVE_GetFlags( drive
);
1046 while (DOSFS_ReadDir( dir
, &long_name
, &short_name
))
1048 if (skip
-- > 0) continue;
1051 /* Don't return '.' and '..' in the root of the drive */
1052 if (drive_root
&& (long_name
[0] == '.') &&
1053 (!long_name
[1] || ((long_name
[1] == '.') && !long_name
[2])))
1056 /* Check the long mask */
1060 if (!DOSFS_MatchLong( long_mask
, long_name
,
1061 flags
& DRIVE_CASE_SENSITIVE
)) continue;
1064 /* Check the short mask */
1070 DOSFS_Hash( long_name
, dos_name
, TRUE
,
1071 !(flags
& DRIVE_CASE_SENSITIVE
) );
1072 short_name
= dos_name
;
1074 if (!DOSFS_MatchShort( short_mask
, short_name
)) continue;
1077 /* Check the file attributes */
1079 lstrcpyn32A( p
, long_name
, sizeof(buffer
) - (int)(p
- buffer
) );
1080 if (!FILE_Stat( buffer
, &info
))
1082 WARN(dosfs
, "can't stat %s\n", buffer
);
1085 if (info
.dwFileAttributes
& ~attr
) continue;
1087 /* We now have a matching entry; fill the result and return */
1089 entry
->dwFileAttributes
= info
.dwFileAttributes
;
1090 entry
->ftCreationTime
= info
.ftCreationTime
;
1091 entry
->ftLastAccessTime
= info
.ftLastAccessTime
;
1092 entry
->ftLastWriteTime
= info
.ftLastWriteTime
;
1093 entry
->nFileSizeHigh
= info
.nFileSizeHigh
;
1094 entry
->nFileSizeLow
= info
.nFileSizeLow
;
1097 DOSFS_ToDosDTAFormat( short_name
, entry
->cAlternateFileName
);
1099 DOSFS_Hash( long_name
, entry
->cAlternateFileName
, FALSE
,
1100 !(flags
& DRIVE_CASE_SENSITIVE
) );
1102 lstrcpyn32A( entry
->cFileName
, long_name
, sizeof(entry
->cFileName
) );
1103 if (!(flags
& DRIVE_CASE_PRESERVING
)) CharLower32A( entry
->cFileName
);
1104 TRACE(dosfs
, "returning %s (%s) %02lx %ld\n",
1105 entry
->cFileName
, entry
->cAlternateFileName
,
1106 entry
->dwFileAttributes
, entry
->nFileSizeLow
);
1108 p
[-1] = '\0'; /* Remove trailing slash in buffer */
1111 DOSFS_CloseDir( dir
);
1113 return 0; /* End of directory */
1117 /*************************************************************************
1118 * FindFirstFile16 (KERNEL.413)
1120 HANDLE16 WINAPI
FindFirstFile16( LPCSTR path
, WIN32_FIND_DATA32A
*data
)
1122 DOS_FULL_NAME full_name
;
1124 FIND_FIRST_INFO
*info
;
1126 if (!path
) return 0;
1127 if (!DOSFS_GetFullName( path
, FALSE
, &full_name
))
1128 return INVALID_HANDLE_VALUE16
;
1129 if (!(handle
= GlobalAlloc16( GMEM_MOVEABLE
, sizeof(FIND_FIRST_INFO
) )))
1130 return INVALID_HANDLE_VALUE16
;
1131 info
= (FIND_FIRST_INFO
*)GlobalLock16( handle
);
1132 info
->path
= HEAP_strdupA( SystemHeap
, 0, full_name
.long_name
);
1133 info
->mask
= strrchr( info
->path
, '/' );
1134 *(info
->mask
++) = '\0';
1135 if (path
[0] && (path
[1] == ':')) info
->drive
= toupper(*path
) - 'A';
1136 else info
->drive
= DRIVE_GetCurrentDrive();
1138 GlobalUnlock16( handle
);
1139 if (!FindNextFile16( handle
, data
))
1141 FindClose16( handle
);
1142 DOS_ERROR( ER_NoMoreFiles
, EC_MediaError
, SA_Abort
, EL_Disk
);
1143 return INVALID_HANDLE_VALUE16
;
1149 /*************************************************************************
1150 * FindFirstFile32A (KERNEL32.123)
1152 HANDLE32 WINAPI
FindFirstFile32A( LPCSTR path
, WIN32_FIND_DATA32A
*data
)
1154 HANDLE32 handle
= FindFirstFile16( path
, data
);
1155 if (handle
== INVALID_HANDLE_VALUE16
) return INVALID_HANDLE_VALUE32
;
1160 /*************************************************************************
1161 * FindFirstFile32W (KERNEL32.124)
1163 HANDLE32 WINAPI
FindFirstFile32W( LPCWSTR path
, WIN32_FIND_DATA32W
*data
)
1165 WIN32_FIND_DATA32A dataA
;
1166 LPSTR pathA
= HEAP_strdupWtoA( GetProcessHeap(), 0, path
);
1167 HANDLE32 handle
= FindFirstFile32A( pathA
, &dataA
);
1168 HeapFree( GetProcessHeap(), 0, pathA
);
1169 if (handle
!= INVALID_HANDLE_VALUE32
)
1171 data
->dwFileAttributes
= dataA
.dwFileAttributes
;
1172 data
->ftCreationTime
= dataA
.ftCreationTime
;
1173 data
->ftLastAccessTime
= dataA
.ftLastAccessTime
;
1174 data
->ftLastWriteTime
= dataA
.ftLastWriteTime
;
1175 data
->nFileSizeHigh
= dataA
.nFileSizeHigh
;
1176 data
->nFileSizeLow
= dataA
.nFileSizeLow
;
1177 lstrcpyAtoW( data
->cFileName
, dataA
.cFileName
);
1178 lstrcpyAtoW( data
->cAlternateFileName
, dataA
.cAlternateFileName
);
1184 /*************************************************************************
1185 * FindNextFile16 (KERNEL.414)
1187 BOOL16 WINAPI
FindNextFile16( HANDLE16 handle
, WIN32_FIND_DATA32A
*data
)
1189 FIND_FIRST_INFO
*info
;
1192 if (!(info
= (FIND_FIRST_INFO
*)GlobalLock16( handle
)))
1194 DOS_ERROR( ER_InvalidHandle
, EC_ProgramError
, SA_Abort
, EL_Disk
);
1197 GlobalUnlock16( handle
);
1200 DOS_ERROR( ER_NoMoreFiles
, EC_MediaError
, SA_Abort
, EL_Disk
);
1203 if (!(count
= DOSFS_FindNext( info
->path
, NULL
, info
->mask
, info
->drive
,
1204 0xff, info
->skip
, data
)))
1206 HeapFree( SystemHeap
, 0, info
->path
);
1207 info
->path
= info
->mask
= NULL
;
1208 DOS_ERROR( ER_NoMoreFiles
, EC_MediaError
, SA_Abort
, EL_Disk
);
1211 info
->skip
+= count
;
1216 /*************************************************************************
1217 * FindNextFile32A (KERNEL32.126)
1219 BOOL32 WINAPI
FindNextFile32A( HANDLE32 handle
, WIN32_FIND_DATA32A
*data
)
1221 return FindNextFile16( handle
, data
);
1225 /*************************************************************************
1226 * FindNextFile32W (KERNEL32.127)
1228 BOOL32 WINAPI
FindNextFile32W( HANDLE32 handle
, WIN32_FIND_DATA32W
*data
)
1230 WIN32_FIND_DATA32A dataA
;
1231 if (!FindNextFile32A( handle
, &dataA
)) return FALSE
;
1232 data
->dwFileAttributes
= dataA
.dwFileAttributes
;
1233 data
->ftCreationTime
= dataA
.ftCreationTime
;
1234 data
->ftLastAccessTime
= dataA
.ftLastAccessTime
;
1235 data
->ftLastWriteTime
= dataA
.ftLastWriteTime
;
1236 data
->nFileSizeHigh
= dataA
.nFileSizeHigh
;
1237 data
->nFileSizeLow
= dataA
.nFileSizeLow
;
1238 lstrcpyAtoW( data
->cFileName
, dataA
.cFileName
);
1239 lstrcpyAtoW( data
->cAlternateFileName
, dataA
.cAlternateFileName
);
1244 /*************************************************************************
1245 * FindClose16 (KERNEL.415)
1247 BOOL16 WINAPI
FindClose16( HANDLE16 handle
)
1249 FIND_FIRST_INFO
*info
;
1251 if ((handle
== INVALID_HANDLE_VALUE16
) ||
1252 !(info
= (FIND_FIRST_INFO
*)GlobalLock16( handle
)))
1254 DOS_ERROR( ER_InvalidHandle
, EC_ProgramError
, SA_Abort
, EL_Disk
);
1257 if (info
->path
) HeapFree( SystemHeap
, 0, info
->path
);
1258 GlobalUnlock16( handle
);
1259 GlobalFree16( handle
);
1264 /*************************************************************************
1265 * FindClose32 (KERNEL32.119)
1267 BOOL32 WINAPI
FindClose32( HANDLE32 handle
)
1269 return FindClose16( (HANDLE16
)handle
);
1273 /***********************************************************************
1274 * DOSFS_UnixTimeToFileTime
1276 * Convert a Unix time to FILETIME format.
1277 * The FILETIME structure is a 64-bit value representing the number of
1278 * 100-nanosecond intervals since January 1, 1601, 0:00.
1279 * 'remainder' is the nonnegative number of 100-ns intervals
1280 * corresponding to the time fraction smaller than 1 second that
1281 * couldn't be stored in the time_t value.
1283 void DOSFS_UnixTimeToFileTime( time_t unix_time
, FILETIME
*filetime
,
1289 The time difference between 1 January 1601, 00:00:00 and
1290 1 January 1970, 00:00:00 is 369 years, plus the leap years
1291 from 1604 to 1968, excluding 1700, 1800, 1900.
1292 This makes (1968 - 1600) / 4 - 3 = 89 leap days, and a total
1295 Any day in that period had 24 * 60 * 60 = 86400 seconds.
1297 The time difference is 134774 * 86400 * 10000000, which can be written
1299 27111902 * 2^32 + 3577643008
1300 413 * 2^48 + 45534 * 2^32 + 54590 * 2^16 + 32768
1302 If you find that these constants are buggy, please change them in all
1303 instances in both conversion functions.
1306 There are two versions, one of them uses long long variables and
1307 is presumably faster but not ISO C. The other one uses standard C
1308 data types and operations but relies on the assumption that negative
1309 numbers are stored as 2's complement (-1 is 0xffff....). If this
1310 assumption is violated, dates before 1970 will not convert correctly.
1311 This should however work on any reasonable architecture where WINE
1316 Take care not to remove the casts. I have tested these functions
1317 (in both versions) for a lot of numbers. I would be interested in
1318 results on other compilers than GCC.
1320 The operations have been designed to account for the possibility
1321 of 64-bit time_t in future UNICES. Even the versions without
1322 internal long long numbers will work if time_t only is 64 bit.
1323 A 32-bit shift, which was necessary for that operation, turned out
1324 not to work correctly in GCC, besides giving the warning. So I
1325 used a double 16-bit shift instead. Numbers are in the ISO version
1326 represented by three limbs, the most significant with 32 bit, the
1327 other two with 16 bit each.
1329 As the modulo-operator % is not well-defined for negative numbers,
1330 negative divisors have been avoided in DOSFS_FileTimeToUnixTime.
1332 There might be quicker ways to do this in C. Certainly so in
1335 Claus Fischer, fischer@iue.tuwien.ac.at
1339 # define USE_LONG_LONG 1
1341 # define USE_LONG_LONG 0
1344 #if USE_LONG_LONG /* gcc supports long long type */
1346 long long int t
= unix_time
;
1348 t
+= 116444736000000000LL;
1350 filetime
->dwLowDateTime
= (UINT32
)t
;
1351 filetime
->dwHighDateTime
= (UINT32
)(t
>> 32);
1353 #else /* ISO version */
1355 UINT32 a0
; /* 16 bit, low bits */
1356 UINT32 a1
; /* 16 bit, medium bits */
1357 UINT32 a2
; /* 32 bit, high bits */
1359 /* Copy the unix time to a2/a1/a0 */
1360 a0
= unix_time
& 0xffff;
1361 a1
= (unix_time
>> 16) & 0xffff;
1362 /* This is obsolete if unix_time is only 32 bits, but it does not hurt.
1363 Do not replace this by >> 32, it gives a compiler warning and it does
1365 a2
= (unix_time
>= 0 ? (unix_time
>> 16) >> 16 :
1366 ~((~unix_time
>> 16) >> 16));
1368 /* Multiply a by 10000000 (a = a2/a1/a0)
1369 Split the factor into 10000 * 1000 which are both less than 0xffff. */
1371 a1
= a1
* 10000 + (a0
>> 16);
1372 a2
= a2
* 10000 + (a1
>> 16);
1377 a1
= a1
* 1000 + (a0
>> 16);
1378 a2
= a2
* 1000 + (a1
>> 16);
1382 /* Add the time difference and the remainder */
1383 a0
+= 32768 + (remainder
& 0xffff);
1384 a1
+= 54590 + (remainder
>> 16 ) + (a0
>> 16);
1385 a2
+= 27111902 + (a1
>> 16);
1390 filetime
->dwLowDateTime
= (a1
<< 16) + a0
;
1391 filetime
->dwHighDateTime
= a2
;
1396 /***********************************************************************
1397 * DOSFS_FileTimeToUnixTime
1399 * Convert a FILETIME format to Unix time.
1400 * If not NULL, 'remainder' contains the fractional part of the filetime,
1401 * in the range of [0..9999999] (even if time_t is negative).
1403 time_t DOSFS_FileTimeToUnixTime( const FILETIME
*filetime
, DWORD
*remainder
)
1405 /* Read the comment in the function DOSFS_UnixTimeToFileTime. */
1408 long long int t
= filetime
->dwHighDateTime
;
1410 t
+= (UINT32
)filetime
->dwLowDateTime
;
1411 t
-= 116444736000000000LL;
1414 if (remainder
) *remainder
= 9999999 - (-t
- 1) % 10000000;
1415 return -1 - ((-t
- 1) / 10000000);
1419 if (remainder
) *remainder
= t
% 10000000;
1420 return t
/ 10000000;
1423 #else /* ISO version */
1425 UINT32 a0
; /* 16 bit, low bits */
1426 UINT32 a1
; /* 16 bit, medium bits */
1427 UINT32 a2
; /* 32 bit, high bits */
1428 UINT32 r
; /* remainder of division */
1429 unsigned int carry
; /* carry bit for subtraction */
1430 int negative
; /* whether a represents a negative value */
1432 /* Copy the time values to a2/a1/a0 */
1433 a2
= (UINT32
)filetime
->dwHighDateTime
;
1434 a1
= ((UINT32
)filetime
->dwLowDateTime
) >> 16;
1435 a0
= ((UINT32
)filetime
->dwLowDateTime
) & 0xffff;
1437 /* Subtract the time difference */
1438 if (a0
>= 32768 ) a0
-= 32768 , carry
= 0;
1439 else a0
+= (1 << 16) - 32768 , carry
= 1;
1441 if (a1
>= 54590 + carry
) a1
-= 54590 + carry
, carry
= 0;
1442 else a1
+= (1 << 16) - 54590 - carry
, carry
= 1;
1444 a2
-= 27111902 + carry
;
1446 /* If a is negative, replace a by (-1-a) */
1447 negative
= (a2
>= ((UINT32
)1) << 31);
1450 /* Set a to -a - 1 (a is a2/a1/a0) */
1456 /* Divide a by 10000000 (a = a2/a1/a0), put the rest into r.
1457 Split the divisor into 10000 * 1000 which are both less than 0xffff. */
1458 a1
+= (a2
% 10000) << 16;
1460 a0
+= (a1
% 10000) << 16;
1465 a1
+= (a2
% 1000) << 16;
1467 a0
+= (a1
% 1000) << 16;
1469 r
+= (a0
% 1000) * 10000;
1472 /* If a was negative, replace a by (-1-a) and r by (9999999 - r) */
1475 /* Set a to -a - 1 (a is a2/a1/a0) */
1483 if (remainder
) *remainder
= r
;
1485 /* Do not replace this by << 32, it gives a compiler warning and it does
1487 return ((((time_t)a2
) << 16) << 16) + (a1
<< 16) + a0
;
1492 /***********************************************************************
1493 * DosDateTimeToFileTime (KERNEL32.76)
1495 BOOL32 WINAPI
DosDateTimeToFileTime( WORD fatdate
, WORD fattime
, LPFILETIME ft
)
1499 newtm
.tm_sec
= (fattime
& 0x1f) * 2;
1500 newtm
.tm_min
= (fattime
>> 5) & 0x3f;
1501 newtm
.tm_hour
= (fattime
>> 11);
1502 newtm
.tm_mday
= (fatdate
& 0x1f);
1503 newtm
.tm_mon
= ((fatdate
>> 5) & 0x0f) - 1;
1504 newtm
.tm_year
= (fatdate
>> 9) + 80;
1505 DOSFS_UnixTimeToFileTime( mktime( &newtm
), ft
, 0 );
1510 /***********************************************************************
1511 * FileTimeToDosDateTime (KERNEL32.111)
1513 BOOL32 WINAPI
FileTimeToDosDateTime( const FILETIME
*ft
, LPWORD fatdate
,
1516 time_t unixtime
= DOSFS_FileTimeToUnixTime( ft
, NULL
);
1517 struct tm
*tm
= localtime( &unixtime
);
1519 *fattime
= (tm
->tm_hour
<< 11) + (tm
->tm_min
<< 5) + (tm
->tm_sec
/ 2);
1521 *fatdate
= ((tm
->tm_year
- 80) << 9) + ((tm
->tm_mon
+ 1) << 5)
1527 /***********************************************************************
1528 * LocalFileTimeToFileTime (KERNEL32.373)
1530 BOOL32 WINAPI
LocalFileTimeToFileTime( const FILETIME
*localft
,
1536 /* convert from local to UTC. Perhaps not correct. FIXME */
1537 time_t unixtime
= DOSFS_FileTimeToUnixTime( localft
, &remainder
);
1538 xtm
= gmtime( &unixtime
);
1539 DOSFS_UnixTimeToFileTime( mktime(xtm
), utcft
, remainder
);
1544 /***********************************************************************
1545 * FileTimeToLocalFileTime (KERNEL32.112)
1547 BOOL32 WINAPI
FileTimeToLocalFileTime( const FILETIME
*utcft
,
1548 LPFILETIME localft
)
1551 /* convert from UTC to local. Perhaps not correct. FIXME */
1552 time_t unixtime
= DOSFS_FileTimeToUnixTime( utcft
, &remainder
);
1554 struct tm
*xtm
= localtime( &unixtime
);
1557 localtime
= timegm(xtm
);
1558 DOSFS_UnixTimeToFileTime( localtime
, localft
, remainder
);
1561 struct tm
*xtm
,*gtm
;
1564 xtm
= localtime( &unixtime
);
1565 gtm
= gmtime( &unixtime
);
1566 time1
= mktime(xtm
);
1567 time2
= mktime(gtm
);
1568 DOSFS_UnixTimeToFileTime( 2*time1
-time2
, localft
, remainder
);
1574 /***********************************************************************
1575 * FileTimeToSystemTime (KERNEL32.113)
1577 BOOL32 WINAPI
FileTimeToSystemTime( const FILETIME
*ft
, LPSYSTEMTIME syst
)
1581 time_t xtime
= DOSFS_FileTimeToUnixTime( ft
, &remainder
);
1582 xtm
= gmtime(&xtime
);
1583 syst
->wYear
= xtm
->tm_year
+1900;
1584 syst
->wMonth
= xtm
->tm_mon
+ 1;
1585 syst
->wDayOfWeek
= xtm
->tm_wday
;
1586 syst
->wDay
= xtm
->tm_mday
;
1587 syst
->wHour
= xtm
->tm_hour
;
1588 syst
->wMinute
= xtm
->tm_min
;
1589 syst
->wSecond
= xtm
->tm_sec
;
1590 syst
->wMilliseconds
= remainder
/ 10000;
1594 /***********************************************************************
1595 * QueryDosDeviceA (KERNEL32.413)
1597 * returns array of strings terminated by \0, terminated by \0
1599 DWORD WINAPI
QueryDosDevice32A(LPCSTR devname
,LPSTR target
,DWORD bufsize
)
1604 TRACE(dosfs
,"(%s,...)\n",devname
?devname
:"<null>");
1606 /* return known MSDOS devices */
1607 lstrcpy32A(buffer
,"CON COM1 COM2 LPT1 NUL ");
1608 while ((s
=strchr(buffer
,' ')))
1611 lstrcpyn32A(target
,buffer
,bufsize
);
1612 return strlen(buffer
);
1614 lstrcpy32A(buffer
,"\\DEV\\");
1615 lstrcat32A(buffer
,devname
);
1616 if ((s
=strchr(buffer
,':'))) *s
='\0';
1617 lstrcpyn32A(target
,buffer
,bufsize
);
1618 return strlen(buffer
);
1622 /***********************************************************************
1623 * QueryDosDeviceW (KERNEL32.414)
1625 * returns array of strings terminated by \0, terminated by \0
1627 DWORD WINAPI
QueryDosDevice32W(LPCWSTR devname
,LPWSTR target
,DWORD bufsize
)
1629 LPSTR devnameA
= devname
?HEAP_strdupWtoA(GetProcessHeap(),0,devname
):NULL
;
1630 LPSTR targetA
= (LPSTR
)HEAP_xalloc(GetProcessHeap(),0,bufsize
);
1631 DWORD ret
= QueryDosDevice32A(devnameA
,targetA
,bufsize
);
1633 lstrcpynAtoW(target
,targetA
,bufsize
);
1634 if (devnameA
) HeapFree(GetProcessHeap(),0,devnameA
);
1635 if (targetA
) HeapFree(GetProcessHeap(),0,targetA
);
1640 /***********************************************************************
1641 * SystemTimeToFileTime (KERNEL32.526)
1643 BOOL32 WINAPI
SystemTimeToFileTime( const SYSTEMTIME
*syst
, LPFILETIME ft
)
1649 struct tm xtm
,*local_tm
,*utc_tm
;
1650 time_t localtim
,utctime
;
1653 xtm
.tm_year
= syst
->wYear
-1900;
1654 xtm
.tm_mon
= syst
->wMonth
- 1;
1655 xtm
.tm_wday
= syst
->wDayOfWeek
;
1656 xtm
.tm_mday
= syst
->wDay
;
1657 xtm
.tm_hour
= syst
->wHour
;
1658 xtm
.tm_min
= syst
->wMinute
;
1659 xtm
.tm_sec
= syst
->wSecond
; /* this is UTC */
1662 utctime
= timegm(&xtm
);
1663 DOSFS_UnixTimeToFileTime( utctime
, ft
,
1664 syst
->wMilliseconds
* 10000 );
1666 localtim
= mktime(&xtm
); /* now we've got local time */
1667 local_tm
= localtime(&localtim
);
1668 utc_tm
= gmtime(&localtim
);
1669 utctime
= mktime(utc_tm
);
1670 DOSFS_UnixTimeToFileTime( 2*localtim
-utctime
, ft
,
1671 syst
->wMilliseconds
* 10000 );