2 * DOS file system functions
4 * Copyright 1993 Erik Bos
5 * Copyright 1996 Alexandre Julliard
16 #if defined(__svr4__) || defined(_SCO_DS)
17 #include <sys/statfs.h>
30 /* Chars we don't want to see in DOS file names */
31 #define INVALID_DOS_CHARS "*?<>|\"+=,;[] \345"
33 static const char *DOSFS_Devices
[][2] =
37 { "NUL", "/dev/null" },
49 #define GET_DRIVE(path) \
50 (((path)[1] == ':') ? toupper((path)[0]) - 'A' : DOSFS_CurDrive)
52 /* DOS extended error status */
53 WORD DOS_ExtendedError
;
59 /***********************************************************************
62 * Return 1 if Unix file 'name' is also a valid MS-DOS name
63 * (i.e. contains only valid DOS chars, lower-case only, fits in 8.3 format).
64 * File name can be terminated by '\0', '\\' or '/'.
66 static int DOSFS_ValidDOSName( const char *name
, int ignore_case
)
68 static const char invalid_chars
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" INVALID_DOS_CHARS
;
70 const char *invalid
= ignore_case
? (invalid_chars
+ 26) : invalid_chars
;
75 /* Check for "." and ".." */
78 /* All other names beginning with '.' are invalid */
79 return (IS_END_OF_NAME(*p
));
81 while (!IS_END_OF_NAME(*p
))
83 if (strchr( invalid
, *p
)) return 0; /* Invalid char */
84 if (*p
== '.') break; /* Start of the extension */
85 if (++len
> 8) return 0; /* Name too long */
88 if (*p
!= '.') return 1; /* End of name */
90 if (IS_END_OF_NAME(*p
)) return 0; /* Empty extension not allowed */
92 while (!IS_END_OF_NAME(*p
))
94 if (strchr( invalid
, *p
)) return 0; /* Invalid char */
95 if (*p
== '.') return 0; /* Second extension not allowed */
96 if (++len
> 3) return 0; /* Extension too long */
103 /***********************************************************************
106 * Remove all '.' and '..' at the beginning of 'name'.
108 static const char * DOSFS_CheckDotDot( const char *name
, char *buffer
,
109 char sep
, int *len
)
111 char *p
= buffer
+ strlen(buffer
);
115 if (IS_END_OF_NAME(name
[1]))
118 while ((*name
== '\\') || (*name
== '/')) name
++;
120 else if ((name
[1] == '.') && IS_END_OF_NAME(name
[2]))
123 while ((*name
== '\\') || (*name
== '/')) name
++;
124 while ((p
> buffer
) && (*p
!= sep
)) { p
--; (*len
)++; }
125 *p
= '\0'; /* Remove trailing separator */
133 /***********************************************************************
134 * DOSFS_ToDosFCBFormat
136 * Convert a file name to DOS FCB format (8+3 chars, padded with blanks),
137 * expanding wild cards and converting to upper-case in the process.
138 * File name can be terminated by '\0', '\\' or '/'.
139 * Return NULL if the name is not a valid DOS name.
141 const char *DOSFS_ToDosFCBFormat( const char *name
)
143 static const char invalid_chars
[] = INVALID_DOS_CHARS
;
144 static char buffer
[12];
145 const char *p
= name
;
148 /* Check for "." and ".." */
152 strcpy( buffer
, ". " );
154 return (!*p
|| (*p
== '/') || (*p
== '\\')) ? buffer
: NULL
;
157 for (i
= 0; i
< 8; i
++)
174 if (strchr( invalid_chars
, *p
)) return NULL
;
175 buffer
[i
] = toupper(*p
);
183 /* Skip all chars after wildcard up to first dot */
184 while (*p
&& (*p
!= '/') && (*p
!= '\\') && (*p
!= '.')) p
++;
188 /* Check if name too long */
189 if (*p
&& (*p
!= '/') && (*p
!= '\\') && (*p
!= '.')) return NULL
;
191 if (*p
== '.') p
++; /* Skip dot */
193 for (i
= 8; i
< 11; i
++)
203 return NULL
; /* Second extension not allowed */
211 if (strchr( invalid_chars
, *p
)) return NULL
;
212 buffer
[i
] = toupper(*p
);
222 /***********************************************************************
223 * DOSFS_ToDosDTAFormat
225 * Convert a file name from FCB to DTA format (name.ext, null-terminated)
226 * converting to upper-case in the process.
227 * File name can be terminated by '\0', '\\' or '/'.
228 * Return NULL if the name is not a valid DOS name.
230 const char *DOSFS_ToDosDTAFormat( const char *name
)
232 static char buffer
[13];
235 memcpy( buffer
, name
, 8 );
236 for (p
= buffer
+ 8; (p
> buffer
) && (p
[-1] == ' '); p
--);
238 memcpy( p
, name
+ 8, 3 );
239 for (p
+= 3; p
[-1] == ' '; p
--);
240 if (p
[-1] == '.') p
--;
246 /***********************************************************************
249 * Check a DOS file name against a mask (both in FCB format).
251 static int DOSFS_MatchShort( const char *mask
, const char *name
)
254 for (i
= 11; i
> 0; i
--, mask
++, name
++)
255 if ((*mask
!= '?') && (*mask
!= *name
)) return 0;
260 /***********************************************************************
263 * Check a long file name against a mask.
265 static int DOSFS_MatchLong( const char *mask
, const char *name
,
268 while (*name
&& *mask
)
273 while (*mask
== '*') mask
++; /* Skip consecutive '*' */
274 if (!*mask
) return 1;
275 if (case_sensitive
) while (*name
&& (*name
!= *mask
)) name
++;
276 else while (*name
&& (toupper(*name
) != toupper(*mask
))) name
++;
277 if (!*name
) return 0;
279 else if (*mask
!= '?')
283 if (*mask
!= *name
) return 0;
285 else if (toupper(*mask
) != toupper(*name
)) return 0;
290 return (!*name
&& !*mask
);
294 /***********************************************************************
295 * DOSFS_ToDosDateTime
297 * Convert a Unix time in the DOS date/time format.
299 void DOSFS_ToDosDateTime( time_t unixtime
, WORD
*pDate
, WORD
*pTime
)
301 struct tm
*tm
= localtime( &unixtime
);
303 *pTime
= (tm
->tm_hour
<< 11) + (tm
->tm_min
<< 5) + (tm
->tm_sec
/ 2);
305 *pDate
= ((tm
->tm_year
- 80) << 9) + ((tm
->tm_mon
+ 1) << 5)
309 /***********************************************************************
310 * DOSFS_DosDateTimeToUnixTime
312 * Convert from the DOS (FAT) date/time format into Unix time
313 * (borrowed from files/file.c)
315 time_t DOSFS_DosDateTimeToUnixTime( WORD date
, WORD time
)
319 newtm
.tm_sec
= (time
& 0x1f) * 2;
320 newtm
.tm_min
= (time
>> 5) & 0x3f;
321 newtm
.tm_hour
= (time
>> 11);
322 newtm
.tm_mday
= (date
& 0x1f);
323 newtm
.tm_mon
= ((date
>> 5) & 0x0f) - 1;
324 newtm
.tm_year
= (date
>> 9) + 80;
325 return mktime( &newtm
);
329 /***********************************************************************
330 * DOSFS_UnixTimeToFileTime
332 * Convert a Unix time to FILETIME format.
334 void DOSFS_UnixTimeToFileTime( time_t unixtime
, FILETIME
*filetime
)
337 filetime
->dwLowDateTime
= unixtime
;
338 filetime
->dwHighDateTime
= 0;
342 /***********************************************************************
343 * DOSFS_FileTimeToUnixTime
345 * Convert a FILETIME format to Unix time.
347 time_t DOSFS_FileTimeToUnixTime( FILETIME
*filetime
)
350 return filetime
->dwLowDateTime
;
354 /***********************************************************************
357 * Transform a Unix file name into a hashed DOS name. If the name is a valid
358 * DOS name, it is converted to upper-case; otherwise it is replaced by a
359 * hashed version that fits in 8.3 format.
360 * File name can be terminated by '\0', '\\' or '/'.
362 const char *DOSFS_Hash( const char *name
, int dir_format
, int ignore_case
)
364 static const char invalid_chars
[] = INVALID_DOS_CHARS
"~.";
365 static const char hash_chars
[32] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
367 static char buffer
[13];
373 if (dir_format
) strcpy( buffer
, " " );
375 if (DOSFS_ValidDOSName( name
, ignore_case
))
377 /* Check for '.' and '..' */
381 if (!dir_format
) buffer
[1] = buffer
[2] = '\0';
382 if (name
[1] == '.') buffer
[1] = '.';
386 /* Simply copy the name, converting to uppercase */
388 for (dst
= buffer
; !IS_END_OF_NAME(*name
) && (*name
!= '.'); name
++)
389 *dst
++ = toupper(*name
);
392 if (dir_format
) dst
= buffer
+ 8;
394 for (name
++; !IS_END_OF_NAME(*name
); name
++)
395 *dst
++ = toupper(*name
);
397 if (!dir_format
) *dst
= '\0';
401 /* Compute the hash code of the file name */
402 /* If you know something about hash functions, feel free to */
403 /* insert a better algorithm here... */
406 for (p
= name
, hash
= 0xbeef; !IS_END_OF_NAME(p
[1]); p
++)
407 hash
= (hash
<< 3) ^ (hash
>> 5) ^ tolower(*p
) ^ (tolower(p
[1]) << 8);
408 hash
= (hash
<< 3) ^ (hash
>> 5) ^ tolower(*p
); /* Last character*/
412 for (p
= name
, hash
= 0xbeef; !IS_END_OF_NAME(p
[1]); p
++)
413 hash
= (hash
<< 3) ^ (hash
>> 5) ^ *p
^ (p
[1] << 8);
414 hash
= (hash
<< 3) ^ (hash
>> 5) ^ *p
; /* Last character */
417 /* Find last dot for start of the extension */
418 for (p
= name
+1, ext
= NULL
; !IS_END_OF_NAME(*p
); p
++)
419 if (*p
== '.') ext
= p
;
420 if (ext
&& IS_END_OF_NAME(ext
[1]))
421 ext
= NULL
; /* Empty extension ignored */
423 /* Copy first 4 chars, replacing invalid chars with '_' */
424 for (i
= 4, p
= name
, dst
= buffer
; i
> 0; i
--, p
++)
426 if (IS_END_OF_NAME(*p
) || (p
== ext
)) break;
427 *dst
++ = strchr( invalid_chars
, *p
) ? '_' : toupper(*p
);
429 /* Pad to 5 chars with '~' */
430 while (i
-- >= 0) *dst
++ = '~';
432 /* Insert hash code converted to 3 ASCII chars */
433 *dst
++ = hash_chars
[(hash
>> 10) & 0x1f];
434 *dst
++ = hash_chars
[(hash
>> 5) & 0x1f];
435 *dst
++ = hash_chars
[hash
& 0x1f];
437 /* Copy the first 3 chars of the extension (if any) */
440 if (!dir_format
) *dst
++ = '.';
441 for (i
= 3, ext
++; (i
> 0) && !IS_END_OF_NAME(*ext
); i
--, ext
++)
442 *dst
++ = toupper(*ext
);
444 if (!dir_format
) *dst
= '\0';
450 /***********************************************************************
453 * Find the Unix file name in a given directory that corresponds to
454 * a file name (either in Unix or DOS format).
455 * File name can be terminated by '\0', '\\' or '/'.
456 * Return 1 if OK, 0 if no file name matches.
458 static int DOSFS_FindUnixName( const char *path
, const char *name
,
459 char *buffer
, int maxlen
, UINT32 drive_flags
)
462 struct dirent
*dirent
;
464 const char *dos_name
= DOSFS_ToDosFCBFormat( name
);
465 const char *p
= strchr( name
, '/' );
466 int len
= p
? (int)(p
- name
) : strlen(name
);
468 dprintf_dosfs( stddeb
, "DOSFS_FindUnixName: %s %s\n", path
, name
);
470 if ((p
= strchr( name
, '\\' ))) len
= MIN( (int)(p
- name
), len
);
472 if (!(dir
= opendir( path
)))
474 dprintf_dosfs( stddeb
, "DOSFS_FindUnixName(%s,%s): can't open dir\n",
478 while ((dirent
= readdir( dir
)) != NULL
)
480 /* Check against Unix name */
481 if (len
== strlen(dirent
->d_name
))
483 if (drive_flags
& DRIVE_CASE_SENSITIVE
)
485 if (!lstrncmp32A( dirent
->d_name
, name
, len
)) break;
489 if (!lstrncmpi32A( dirent
->d_name
, name
, len
)) break;
494 /* Check against hashed DOS name */
495 const char *hash_name
= DOSFS_Hash( dirent
->d_name
, TRUE
,
496 !(drive_flags
& DRIVE_CASE_SENSITIVE
) );
497 if (!strcmp( dos_name
, hash_name
)) break;
500 if (dirent
) lstrcpyn32A( buffer
, dirent
->d_name
, maxlen
);
502 dprintf_dosfs( stddeb
, "DOSFS_FindUnixName(%s,%s) -> %s\n",
503 path
, name
, dirent
? buffer
: "** Not found **" );
504 return (dirent
!= NULL
);
508 /***********************************************************************
511 * Check if a DOS file name represents a DOS device. Returns the name
512 * of the associated Unix device, or NULL if not found.
514 const char *DOSFS_IsDevice( const char *name
)
519 if (name
[0] && (name
[1] == ':')) name
+= 2;
520 if ((p
= strrchr( name
, '/' ))) name
= p
+ 1;
521 if ((p
= strrchr( name
, '\\' ))) name
= p
+ 1;
522 for (i
= 0; i
< sizeof(DOSFS_Devices
)/sizeof(DOSFS_Devices
[0]); i
++)
524 const char *dev
= DOSFS_Devices
[i
][0];
525 if (!lstrncmpi32A( dev
, name
, strlen(dev
) ))
527 p
= name
+ strlen( dev
);
528 if (!*p
|| (*p
== '.')) return DOSFS_Devices
[i
][1];
535 /***********************************************************************
536 * DOSFS_GetUnixFileName
538 * Convert a file name (DOS or mixed DOS/Unix format) to a valid Unix name.
539 * Return NULL if one of the path components does not exist. The last path
540 * component is only checked if 'check_last' is non-zero.
542 const char * DOSFS_GetUnixFileName( const char * name
, int check_last
)
544 static char buffer
[MAX_PATHNAME_LEN
];
545 int drive
, len
, found
;
549 dprintf_dosfs( stddeb
, "DOSFS_GetUnixFileName: %s\n", name
);
550 if (name
[0] && (name
[1] == ':'))
552 drive
= toupper(name
[0]) - 'A';
555 else if (name
[0] == '/') /* Absolute Unix path? */
557 if ((drive
= DRIVE_FindDriveRoot( &name
)) == -1)
559 fprintf( stderr
, "Warning: %s not accessible from a DOS drive\n",
561 /* Assume it really was a DOS name */
562 drive
= DRIVE_GetCurrentDrive();
565 else drive
= DRIVE_GetCurrentDrive();
567 if (!DRIVE_IsValid(drive
))
569 DOS_ERROR( ER_InvalidDrive
, EC_MediaError
, SA_Abort
, EL_Disk
);
572 flags
= DRIVE_GetFlags(drive
);
573 lstrcpyn32A( buffer
, DRIVE_GetRoot(drive
), MAX_PATHNAME_LEN
);
574 if (buffer
[1]) root
= buffer
+ strlen(buffer
);
575 else root
= buffer
; /* root directory */
577 if ((*name
== '\\') || (*name
== '/'))
579 while ((*name
== '\\') || (*name
== '/')) name
++;
583 lstrcpyn32A( root
+ 1, DRIVE_GetUnixCwd(drive
),
584 MAX_PATHNAME_LEN
- (int)(root
- buffer
) - 1 );
585 if (root
[1]) *root
= '/';
588 p
= buffer
[1] ? buffer
+ strlen(buffer
) : buffer
;
589 len
= MAX_PATHNAME_LEN
- strlen(buffer
);
591 while (*name
&& found
)
593 const char *newname
= DOSFS_CheckDotDot( name
, root
, '/', &len
);
596 p
= root
+ strlen(root
);
602 DOS_ERROR( ER_PathNotFound
, EC_NotFound
, SA_Abort
, EL_Disk
);
605 if ((found
= DOSFS_FindUnixName( buffer
, name
, p
+1, len
-1, flags
)))
610 while (!IS_END_OF_NAME(*name
)) name
++;
612 else if (!check_last
)
615 for (len
--; !IS_END_OF_NAME(*name
) && (len
> 1); name
++, len
--)
616 *p
++ = tolower(*name
);
619 while ((*name
== '\\') || (*name
== '/')) name
++;
625 DOS_ERROR( ER_FileNotFound
, EC_NotFound
, SA_Abort
, EL_Disk
);
628 if (*name
) /* Not last */
630 DOS_ERROR( ER_PathNotFound
, EC_NotFound
, SA_Abort
, EL_Disk
);
634 if (!buffer
[0]) strcpy( buffer
, "/" );
635 dprintf_dosfs( stddeb
, "DOSFS_GetUnixFileName: returning %s\n", buffer
);
640 /***********************************************************************
641 * DOSFS_GetDosTrueName
643 * Convert a file name (DOS or Unix format) to a complete DOS name.
644 * Return NULL if the path name is invalid or too long.
645 * The unix_format flag is a hint that the file name is in Unix format.
647 const char * DOSFS_GetDosTrueName( const char *name
, int unix_format
)
649 static char buffer
[MAX_PATHNAME_LEN
];
654 dprintf_dosfs( stddeb
, "DOSFS_GetDosTrueName(%s,%d)\n", name
, unix_format
);
655 if (name
[0] && (name
[1] == ':'))
657 drive
= toupper(name
[0]) - 'A';
660 else if (name
[0] == '/') /* Absolute Unix path? */
662 if ((drive
= DRIVE_FindDriveRoot( &name
)) == -1)
664 fprintf( stderr
, "Warning: %s not accessible from a DOS drive\n",
666 /* Assume it really was a DOS name */
667 drive
= DRIVE_GetCurrentDrive();
670 else drive
= DRIVE_GetCurrentDrive();
672 if (!DRIVE_IsValid(drive
))
674 DOS_ERROR( ER_InvalidDrive
, EC_MediaError
, SA_Abort
, EL_Disk
);
681 if (IS_END_OF_NAME(*name
))
683 while ((*name
== '\\') || (*name
== '/')) name
++;
688 lstrcpyn32A( p
, DRIVE_GetDosCwd(drive
), sizeof(buffer
) - 3 );
689 if (*p
) p
+= strlen(p
); else p
--;
692 len
= MAX_PATHNAME_LEN
- (int)(p
- buffer
);
693 flags
= DRIVE_GetFlags(drive
);
697 const char *newname
= DOSFS_CheckDotDot( name
, buffer
+2, '\\', &len
);
700 p
= buffer
+ strlen(buffer
);
706 DOS_ERROR( ER_PathNotFound
, EC_NotFound
, SA_Abort
, EL_Disk
);
710 if (unix_format
) /* Hash it into a DOS name */
712 lstrcpyn32A( p
, DOSFS_Hash( name
, FALSE
,
713 !(flags
& DRIVE_CASE_SENSITIVE
) ),
717 while (!IS_END_OF_NAME(*name
)) name
++;
719 else /* Already DOS format, simply upper-case it */
721 while (!IS_END_OF_NAME(*name
) && (len
> 1))
723 *p
++ = toupper(*name
);
729 while ((*name
== '\\') || (*name
== '/')) name
++;
736 dprintf_dosfs( stddeb
, "DOSFS_GetDosTrueName: returning %s\n", buffer
);
741 /***********************************************************************
744 * Find the next matching file. Return the number of entries read to find
745 * the matching one, or 0 if no more entries.
746 * 'short_mask' is the 8.3 mask (in FCB format), 'long_mask' is the long
747 * file name mask. Either or both can be NULL.
749 int DOSFS_FindNext( const char *path
, const char *short_mask
,
750 const char *long_mask
, int drive
, BYTE attr
,
751 int skip
, DOS_DIRENT
*entry
)
753 static DIR *dir
= NULL
;
754 struct dirent
*dirent
;
756 static char buffer
[MAX_PATHNAME_LEN
];
757 static int cur_pos
= 0;
758 static int drive_root
= 0;
760 const char *hash_name
;
763 if ((attr
& ~(FA_UNUSED
| FA_ARCHIVE
| FA_RDONLY
)) == FA_LABEL
)
766 strcpy( entry
->name
, DRIVE_GetLabel( drive
) );
767 entry
->attr
= FA_LABEL
;
769 DOSFS_ToDosDateTime( time(NULL
), &entry
->date
, &entry
->time
);
773 /* Check the cached directory */
774 if (dir
&& !strcmp( buffer
, path
) && (cur_pos
<= skip
)) skip
-= cur_pos
;
775 else /* Not in the cache, open it anew */
777 const char *drive_path
;
778 dprintf_dosfs( stddeb
, "DOSFS_FindNext: cache miss, path=%s skip=%d buf=%s cur=%d\n",
779 path
, skip
, buffer
, cur_pos
);
781 if (dir
) closedir(dir
);
782 if (!*path
) path
= "/";
783 if (!(dir
= opendir(path
))) return 0;
786 if (DRIVE_FindDriveRoot( &drive_path
) != -1)
788 while ((*drive_path
== '/') || (*drive_path
== '\\')) drive_path
++;
789 if (!*drive_path
) drive_root
= 1;
791 dprintf_dosfs(stddeb
, "DOSFS_FindNext: drive_root = %d\n", drive_root
);
792 lstrcpyn32A( buffer
, path
, sizeof(buffer
) - 1 );
795 strcat( buffer
, "/" );
796 p
= buffer
+ strlen(buffer
);
797 attr
|= FA_UNUSED
| FA_ARCHIVE
| FA_RDONLY
;
798 flags
= DRIVE_GetFlags( drive
);
801 while ((dirent
= readdir( dir
)) != NULL
)
803 if (skip
-- > 0) continue;
806 /* Don't return '.' and '..' in the root of the drive */
807 if (drive_root
&& (dirent
->d_name
[0] == '.') &&
808 (!dirent
->d_name
[1] ||
809 ((dirent
->d_name
[1] == '.') && !dirent
->d_name
[2]))) continue;
811 /* Check the long mask */
815 if (!DOSFS_MatchLong( long_mask
, dirent
->d_name
,
816 flags
& DRIVE_CASE_SENSITIVE
)) continue;
819 /* Check the short mask */
823 hash_name
= DOSFS_Hash( dirent
->d_name
, TRUE
,
824 !(flags
& DRIVE_CASE_SENSITIVE
) );
825 if (!DOSFS_MatchShort( short_mask
, hash_name
)) continue;
828 /* Check the file attributes */
830 lstrcpyn32A( p
, dirent
->d_name
, sizeof(buffer
) - (int)(p
- buffer
) );
831 if (!FILE_Stat( buffer
, &entry
->attr
, &entry
->size
,
832 &entry
->date
, &entry
->time
))
834 fprintf( stderr
, "DOSFS_FindNext: can't stat %s\n", buffer
);
837 if (entry
->attr
& ~attr
) continue;
839 /* We now have a matching entry; fill the result and return */
842 hash_name
= DOSFS_Hash( dirent
->d_name
, TRUE
,
843 !(flags
& DRIVE_CASE_SENSITIVE
) );
844 strcpy( entry
->name
, hash_name
);
845 lstrcpyn32A( entry
->unixname
, dirent
->d_name
, sizeof(entry
->unixname
));
846 if (!(flags
& DRIVE_CASE_PRESERVING
)) AnsiLower( entry
->unixname
);
847 dprintf_dosfs( stddeb
, "DOSFS_FindNext: returning %s %02x %ld\n",
848 entry
->name
, entry
->attr
, entry
->size
);
850 p
[-1] = '\0'; /* Remove trailing slash in buffer */
855 return 0; /* End of directory */
859 /***********************************************************************
860 * GetShortPathNameA (KERNEL32.271)
862 DWORD
GetShortPathName32A( LPCSTR longpath
, LPSTR shortpath
, DWORD shortlen
)
866 dprintf_dosfs( stddeb
, "GetShortPathName32A(%s,%p,%ld)\n",
867 longpath
, shortpath
, shortlen
);
869 dostruename
= DOSFS_GetDosTrueName( longpath
, TRUE
);
870 lstrcpyn32A( shortpath
, dostruename
, shortlen
);
871 return strlen(dostruename
);
875 /***********************************************************************
876 * GetShortPathNameW (KERNEL32.272)
878 DWORD
GetShortPathName32W( LPCWSTR longpath
, LPWSTR shortpath
, DWORD shortlen
)
880 LPSTR longpatha
= HEAP_strdupWtoA( GetProcessHeap(), 0, longpath
);
881 LPCSTR dostruename
= DOSFS_GetDosTrueName( longpatha
, TRUE
);
882 HeapFree( GetProcessHeap(), 0, longpatha
);
883 lstrcpynAtoW( shortpath
, dostruename
, shortlen
);
884 return strlen(dostruename
);
888 /***********************************************************************
889 * GetFullPathNameA (KERNEL32.272)
891 DWORD
GetFullPathName32A( LPCSTR fn
, DWORD buflen
, LPSTR buf
, LPSTR
*lastpart
)
893 dprintf_file(stddeb
,"GetFullPathNameA(%s)\n",fn
);
896 lstrcpyn32A(buf
,fn
,buflen
);
898 *lastpart
= strrchr(buf
,'\\');
899 if (!*lastpart
) *lastpart
=buf
;
905 /***********************************************************************
906 * GetFullPathName32W (KERNEL32.273)
908 DWORD
GetFullPathName32W(LPCWSTR fn
,DWORD buflen
,LPWSTR buf
,LPWSTR
*lastpart
) {
911 dprintf_file(stddeb
,"GetFullPathNameW(%p)\n",fn
);
914 lstrcpyn32W(buf
,fn
,buflen
);
916 x
= buf
+lstrlen32W(buf
)-1;
917 while (x
>=buf
&& *x
!='\\')
925 return lstrlen32W(fn
);
929 /***********************************************************************
930 * DosDateTimeToFileTime (KERNEL32.76)
932 BOOL32
DosDateTimeToFileTime( WORD fatdate
, WORD fattime
, LPFILETIME ft
)
934 time_t unixtime
= DOSFS_DosDateTimeToUnixTime(fatdate
,fattime
);
935 DOSFS_UnixTimeToFileTime(unixtime
,ft
);
940 /***********************************************************************
941 * FileTimeToDosDateTime (KERNEL32.111)
943 BOOL32
FileTimeToDosDateTime( LPFILETIME ft
, LPWORD fatdate
, LPWORD fattime
)
945 time_t unixtime
= DOSFS_FileTimeToUnixTime(ft
);
946 DOSFS_ToDosDateTime(unixtime
,fatdate
,fattime
);
951 /***********************************************************************
952 * LocalFileTimeToFileTime (KERNEL32.373)
954 BOOL32
LocalFileTimeToFileTime( LPFILETIME localft
, LPFILETIME utcft
)
958 /* convert from local to UTC. Perhaps not correct. FIXME */
959 xtm
= gmtime((time_t*)&(localft
->dwLowDateTime
));
960 utcft
->dwLowDateTime
= mktime(xtm
);
961 utcft
->dwHighDateTime
= 0;
966 /***********************************************************************
967 * FileTimeToLocalFileTime (KERNEL32.112)
969 BOOL32
FileTimeToLocalFileTime( LPFILETIME utcft
, LPFILETIME localft
)
973 /* convert from UTC to local. Perhaps not correct. FIXME */
974 xtm
= localtime((time_t*)&(utcft
->dwLowDateTime
));
975 localft
->dwLowDateTime
= mktime(xtm
);
976 localft
->dwHighDateTime
= 0;
981 /***********************************************************************
982 * FileTimeToSystemTime (KERNEL32.113)
984 BOOL32
FileTimeToSystemTime( LPFILETIME ft
, LPSYSTEMTIME syst
)
987 time_t xtime
= DOSFS_FileTimeToUnixTime(ft
);
988 xtm
= gmtime(&xtime
);
989 syst
->wYear
= xtm
->tm_year
;
990 syst
->wMonth
= xtm
->tm_mon
;
991 syst
->wDayOfWeek
= xtm
->tm_wday
;
992 syst
->wDay
= xtm
->tm_mday
;
993 syst
->wHour
= xtm
->tm_hour
;
994 syst
->wMinute
= xtm
->tm_min
;
995 syst
->wSecond
= xtm
->tm_sec
;
996 syst
->wMilliseconds
= 0; /* FIXME */
1001 /***********************************************************************
1002 * SystemTimeToFileTime (KERNEL32.526)
1004 BOOL32
SystemTimeToFileTime( LPSYSTEMTIME syst
, LPFILETIME ft
)
1008 xtm
.tm_year
= syst
->wYear
;
1009 xtm
.tm_mon
= syst
->wMonth
;
1010 xtm
.tm_wday
= syst
->wDayOfWeek
;
1011 xtm
.tm_mday
= syst
->wDay
;
1012 xtm
.tm_hour
= syst
->wHour
;
1013 xtm
.tm_min
= syst
->wMinute
;
1014 xtm
.tm_sec
= syst
->wSecond
;
1015 DOSFS_UnixTimeToFileTime(mktime(&xtm
),ft
);