Store the windows and system directories as long path names.
[wine.git] / dlls / msvcrt / dir.c
blobc789d725d98452f354252f9320ea4f612bf6aae8
1 /*
2 * msvcrt.dll drive/directory functions
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
28 #include <time.h>
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winreg.h"
33 #include "winternl.h"
34 #include "wine/unicode.h"
35 #include "msvcrt.h"
36 #include "msvcrt/errno.h"
38 #include "wine/unicode.h"
39 #include "msvcrt/io.h"
40 #include "msvcrt/stdlib.h"
41 #include "msvcrt/string.h"
42 #include "msvcrt/dos.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
48 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata_t */
49 static void msvcrt_fttofd( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata_t* ft)
51 DWORD dw;
53 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
54 ft->attrib = 0;
55 else
56 ft->attrib = fd->dwFileAttributes;
58 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
59 ft->time_create = dw;
60 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
61 ft->time_access = dw;
62 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
63 ft->time_write = dw;
64 ft->size = fd->nFileSizeLow;
65 strcpy(ft->name, fd->cFileName);
68 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata_t */
69 static void msvcrt_wfttofd( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata_t* ft)
71 DWORD dw;
73 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
74 ft->attrib = 0;
75 else
76 ft->attrib = fd->dwFileAttributes;
78 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
79 ft->time_create = dw;
80 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
81 ft->time_access = dw;
82 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
83 ft->time_write = dw;
84 ft->size = fd->nFileSizeLow;
85 strcpyW(ft->name, fd->cFileName);
88 /* INTERNAL: Translate WIN32_FIND_DATAA to finddatai64_t */
89 static void msvcrt_fttofdi64( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddatai64_t* ft)
91 DWORD dw;
93 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
94 ft->attrib = 0;
95 else
96 ft->attrib = fd->dwFileAttributes;
98 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
99 ft->time_create = dw;
100 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
101 ft->time_access = dw;
102 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
103 ft->time_write = dw;
104 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
105 strcpy(ft->name, fd->cFileName);
108 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddatai64_t */
109 static void msvcrt_wfttofdi64( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddatai64_t* ft)
111 DWORD dw;
113 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
114 ft->attrib = 0;
115 else
116 ft->attrib = fd->dwFileAttributes;
118 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
119 ft->time_create = dw;
120 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
121 ft->time_access = dw;
122 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
123 ft->time_write = dw;
124 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
125 strcpyW(ft->name, fd->cFileName);
128 /*********************************************************************
129 * _chdir (MSVCRT.@)
131 * Change the current working directory.
133 * PARAMS
134 * newdir [I] Directory to change to
136 * RETURNS
137 * Success: 0. The current working directory is set to newdir.
138 * Failure: -1. errno indicates the error.
140 * NOTES
141 * See SetCurrentDirectoryA.
143 int _chdir(const char * newdir)
145 if (!SetCurrentDirectoryA(newdir))
147 MSVCRT__set_errno(newdir?GetLastError():0);
148 return -1;
150 return 0;
153 /*********************************************************************
154 * _wchdir (MSVCRT.@)
156 * Unicode version of _chdir.
158 int _wchdir(const MSVCRT_wchar_t * newdir)
160 if (!SetCurrentDirectoryW(newdir))
162 MSVCRT__set_errno(newdir?GetLastError():0);
163 return -1;
165 return 0;
168 /*********************************************************************
169 * _chdrive (MSVCRT.@)
171 * Change the current drive.
173 * PARAMS
174 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
176 * RETURNS
177 * Success: 0. The current drive is set to newdrive.
178 * Failure: -1. errno indicates the error.
180 * NOTES
181 * See SetCurrentDirectoryA.
183 int _chdrive(int newdrive)
185 WCHAR buffer[3] = {'A', ':', 0};
187 buffer[0] += newdrive - 1;
188 if (!SetCurrentDirectoryW( buffer ))
190 MSVCRT__set_errno(GetLastError());
191 if (newdrive <= 0)
192 *MSVCRT__errno() = MSVCRT_EACCES;
193 return -1;
195 return 0;
198 /*********************************************************************
199 * _findclose (MSVCRT.@)
201 * Close a handle returned by _findfirst().
203 * PARAMS
204 * hand [I] Handle to close
206 * RETURNS
207 * Success: 0. All resources associated with hand are freed.
208 * Failure: -1. errno indicates the error.
210 * NOTES
211 * See FindClose.
213 int _findclose(long hand)
215 TRACE(":handle %ld\n",hand);
216 if (!FindClose((HANDLE)hand))
218 MSVCRT__set_errno(GetLastError());
219 return -1;
221 return 0;
224 /*********************************************************************
225 * _findfirst (MSVCRT.@)
227 * Open a handle for iterating through a directory.
229 * PARAMS
230 * fspec [I] File specification of files to iterate.
231 * ft [O] Information for the first file found.
233 * RETURNS
234 * Success: A handle suitable for passing to _findnext() and _findclose().
235 * ft is populated with the details of the found file.
236 * Failure: -1. errno indicates the error.
238 * NOTES
239 * See FindFirstFileA.
241 long MSVCRT__findfirst(const char * fspec, struct MSVCRT__finddata_t* ft)
243 WIN32_FIND_DATAA find_data;
244 HANDLE hfind;
246 hfind = FindFirstFileA(fspec, &find_data);
247 if (hfind == INVALID_HANDLE_VALUE)
249 MSVCRT__set_errno(GetLastError());
250 return -1;
252 msvcrt_fttofd(&find_data,ft);
253 TRACE(":got handle %p\n",hfind);
254 return (long)hfind;
257 /*********************************************************************
258 * _wfindfirst (MSVCRT.@)
260 * Unicode version of _findfirst.
262 long MSVCRT__wfindfirst(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddata_t* ft)
264 WIN32_FIND_DATAW find_data;
265 HANDLE hfind;
267 hfind = FindFirstFileW(fspec, &find_data);
268 if (hfind == INVALID_HANDLE_VALUE)
270 MSVCRT__set_errno(GetLastError());
271 return -1;
273 msvcrt_wfttofd(&find_data,ft);
274 TRACE(":got handle %p\n",hfind);
275 return (long)hfind;
278 /*********************************************************************
279 * _findfirsti64 (MSVCRT.@)
281 * 64-bit version of _findfirst.
283 long MSVCRT__findfirsti64(const char * fspec, struct MSVCRT__finddatai64_t* ft)
285 WIN32_FIND_DATAA find_data;
286 HANDLE hfind;
288 hfind = FindFirstFileA(fspec, &find_data);
289 if (hfind == INVALID_HANDLE_VALUE)
291 MSVCRT__set_errno(GetLastError());
292 return -1;
294 msvcrt_fttofdi64(&find_data,ft);
295 TRACE(":got handle %p\n",hfind);
296 return (long)hfind;
299 /*********************************************************************
300 * _wfindfirsti64 (MSVCRT.@)
302 * Unicode version of _findfirsti64.
304 long MSVCRT__wfindfirsti64(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddatai64_t* ft)
306 WIN32_FIND_DATAW find_data;
307 HANDLE hfind;
309 hfind = FindFirstFileW(fspec, &find_data);
310 if (hfind == INVALID_HANDLE_VALUE)
312 MSVCRT__set_errno(GetLastError());
313 return -1;
315 msvcrt_wfttofdi64(&find_data,ft);
316 TRACE(":got handle %p\n",hfind);
317 return (long)hfind;
320 /*********************************************************************
321 * _findnext (MSVCRT.@)
323 * Find the next file from a file search handle.
325 * PARAMS
326 * hand [I] Handle to the search returned from _findfirst().
327 * ft [O] Information for the file found.
329 * RETURNS
330 * Success: 0. ft is populated with the details of the found file.
331 * Failure: -1. errno indicates the error.
333 * NOTES
334 * See FindNextFileA.
336 int MSVCRT__findnext(long hand, struct MSVCRT__finddata_t * ft)
338 WIN32_FIND_DATAA find_data;
340 if (!FindNextFileA((HANDLE)hand, &find_data))
342 *MSVCRT__errno() = MSVCRT_ENOENT;
343 return -1;
346 msvcrt_fttofd(&find_data,ft);
347 return 0;
350 /*********************************************************************
351 * _wfindnext (MSVCRT.@)
353 * Unicode version of _findnext.
355 int MSVCRT__wfindnext(long hand, struct MSVCRT__wfinddata_t * ft)
357 WIN32_FIND_DATAW find_data;
359 if (!FindNextFileW((HANDLE)hand, &find_data))
361 *MSVCRT__errno() = MSVCRT_ENOENT;
362 return -1;
365 msvcrt_wfttofd(&find_data,ft);
366 return 0;
369 /*********************************************************************
370 * _findnexti64 (MSVCRT.@)
372 * 64-bit version of _findnext.
374 int MSVCRT__findnexti64(long hand, struct MSVCRT__finddatai64_t * ft)
376 WIN32_FIND_DATAA find_data;
378 if (!FindNextFileA((HANDLE)hand, &find_data))
380 *MSVCRT__errno() = MSVCRT_ENOENT;
381 return -1;
384 msvcrt_fttofdi64(&find_data,ft);
385 return 0;
388 /*********************************************************************
389 * _wfindnexti64 (MSVCRT.@)
391 * Unicode version of _findnexti64.
393 int MSVCRT__wfindnexti64(long hand, struct MSVCRT__wfinddatai64_t * ft)
395 WIN32_FIND_DATAW find_data;
397 if (!FindNextFileW((HANDLE)hand, &find_data))
399 *MSVCRT__errno() = MSVCRT_ENOENT;
400 return -1;
403 msvcrt_wfttofdi64(&find_data,ft);
404 return 0;
407 /*********************************************************************
408 * _getcwd (MSVCRT.@)
410 * Get the current working directory.
412 * PARAMS
413 * buf [O] Destination for current working directory.
414 * size [I] Size of buf in characters
416 * RETURNS
417 * Success: If buf is NULL, returns an allocated string containing the path.
418 * Otherwise populates buf with the path and returns it.
419 * Failure: NULL. errno indicates the error.
421 char* _getcwd(char * buf, int size)
423 char dir[MAX_PATH];
424 int dir_len = GetCurrentDirectoryA(MAX_PATH,dir);
426 if (dir_len < 1)
427 return NULL; /* FIXME: Real return value untested */
429 if (!buf)
431 if (size < 0)
432 return _strdup(dir);
433 return msvcrt_strndup(dir,size);
435 if (dir_len >= size)
437 *MSVCRT__errno() = MSVCRT_ERANGE;
438 return NULL; /* buf too small */
440 strcpy(buf,dir);
441 return buf;
444 /*********************************************************************
445 * _wgetcwd (MSVCRT.@)
447 * Unicode version of _getcwd.
449 MSVCRT_wchar_t* _wgetcwd(MSVCRT_wchar_t * buf, int size)
451 MSVCRT_wchar_t dir[MAX_PATH];
452 int dir_len = GetCurrentDirectoryW(MAX_PATH,dir);
454 if (dir_len < 1)
455 return NULL; /* FIXME: Real return value untested */
457 if (!buf)
459 if (size < 0)
460 return _wcsdup(dir);
461 return msvcrt_wstrndup(dir,size);
463 if (dir_len >= size)
465 *MSVCRT__errno() = MSVCRT_ERANGE;
466 return NULL; /* buf too small */
468 strcpyW(buf,dir);
469 return buf;
472 /*********************************************************************
473 * _getdrive (MSVCRT.@)
475 * Get the current drive number.
477 * PARAMS
478 * None.
480 * RETURNS
481 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
482 * Failure: 0.
484 int _getdrive(void)
486 WCHAR buffer[MAX_PATH];
487 if (GetCurrentDirectoryW( MAX_PATH, buffer ) &&
488 buffer[0] >= 'A' && buffer[0] <= 'z' && buffer[1] == ':')
489 return toupperW(buffer[0]) - 'A' + 1;
490 return 0;
493 /*********************************************************************
494 * _getdcwd (MSVCRT.@)
496 * Get the current working directory on a given disk.
498 * PARAMS
499 * drive [I] Drive letter to get the current working directory from.
500 * buf [O] Destination for the current working directory.
501 * size [I] Length of drive in characters.
503 * RETURNS
504 * Success: If drive is NULL, returns an allocated string containing the path.
505 * Otherwise populates drive with the path and returns it.
506 * Failure: NULL. errno indicates the error.
508 char* _getdcwd(int drive, char * buf, int size)
510 static char* dummy;
512 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
514 if (!drive || drive == _getdrive())
515 return _getcwd(buf,size); /* current */
516 else
518 char dir[MAX_PATH];
519 char drivespec[4] = {'A', ':', '\\', 0};
520 int dir_len;
522 drivespec[0] += drive - 1;
523 if (GetDriveTypeA(drivespec) < DRIVE_REMOVABLE)
525 *MSVCRT__errno() = MSVCRT_EACCES;
526 return NULL;
529 dir_len = GetFullPathNameA(drivespec,MAX_PATH,dir,&dummy);
530 if (dir_len >= size || dir_len < 1)
532 *MSVCRT__errno() = MSVCRT_ERANGE;
533 return NULL; /* buf too small */
536 TRACE(":returning '%s'\n", dir);
537 if (!buf)
538 return _strdup(dir); /* allocate */
540 strcpy(buf,dir);
542 return buf;
545 /*********************************************************************
546 * _wgetdcwd (MSVCRT.@)
548 * Unicode version of _wgetdcwd.
550 MSVCRT_wchar_t* _wgetdcwd(int drive, MSVCRT_wchar_t * buf, int size)
552 static MSVCRT_wchar_t* dummy;
554 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
556 if (!drive || drive == _getdrive())
557 return _wgetcwd(buf,size); /* current */
558 else
560 MSVCRT_wchar_t dir[MAX_PATH];
561 MSVCRT_wchar_t drivespec[4] = {'A', ':', '\\', 0};
562 int dir_len;
564 drivespec[0] += drive - 1;
565 if (GetDriveTypeW(drivespec) < DRIVE_REMOVABLE)
567 *MSVCRT__errno() = MSVCRT_EACCES;
568 return NULL;
571 dir_len = GetFullPathNameW(drivespec,MAX_PATH,dir,&dummy);
572 if (dir_len >= size || dir_len < 1)
574 *MSVCRT__errno() = MSVCRT_ERANGE;
575 return NULL; /* buf too small */
578 TRACE(":returning %s\n", debugstr_w(dir));
579 if (!buf)
580 return _wcsdup(dir); /* allocate */
581 strcpyW(buf,dir);
583 return buf;
586 /*********************************************************************
587 * _getdiskfree (MSVCRT.@)
589 * Get information about the free space on a drive.
591 * PARAMS
592 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
593 * info [O] Destination for the resulting information.
595 * RETURNS
596 * Success: 0. info is updated with the free space information.
597 * Failure: An error code from GetLastError().
599 * NOTES
600 * See GetLastError().
602 unsigned int MSVCRT__getdiskfree(unsigned int disk, struct MSVCRT(_diskfree_t)* d)
604 WCHAR drivespec[4] = {'@', ':', '\\', 0};
605 DWORD ret[4];
606 unsigned int err;
608 if (disk > 26)
609 return ERROR_INVALID_PARAMETER; /* MSVCRT doesn't set errno here */
611 drivespec[0] += disk; /* make a drive letter */
613 if (GetDiskFreeSpaceW(disk==0?NULL:drivespec,ret,ret+1,ret+2,ret+3))
615 d->sectors_per_cluster = (unsigned)ret[0];
616 d->bytes_per_sector = (unsigned)ret[1];
617 d->avail_clusters = (unsigned)ret[2];
618 d->total_clusters = (unsigned)ret[3];
619 return 0;
621 err = GetLastError();
622 MSVCRT__set_errno(err);
623 return err;
626 /*********************************************************************
627 * _mkdir (MSVCRT.@)
629 * Create a directory.
631 * PARAMS
632 * newdir [I] Name of directory to create.
634 * RETURNS
635 * Success: 0. The directory indicated by newdir is created.
636 * Failure: -1. errno indicates the error.
638 * NOTES
639 * See CreateDirectoryA.
641 int _mkdir(const char * newdir)
643 if (CreateDirectoryA(newdir,NULL))
644 return 0;
645 MSVCRT__set_errno(GetLastError());
646 return -1;
649 /*********************************************************************
650 * _wmkdir (MSVCRT.@)
652 * Unicode version of _mkdir.
654 int _wmkdir(const MSVCRT_wchar_t* newdir)
656 if (CreateDirectoryW(newdir,NULL))
657 return 0;
658 MSVCRT__set_errno(GetLastError());
659 return -1;
662 /*********************************************************************
663 * _rmdir (MSVCRT.@)
665 * Delete a directory.
667 * PARAMS
668 * dir [I] Name of directory to delete.
670 * RETURNS
671 * Success: 0. The directory indicated by newdir is deleted.
672 * Failure: -1. errno indicates the error.
674 * NOTES
675 * See RemoveDirectoryA.
677 int _rmdir(const char * dir)
679 if (RemoveDirectoryA(dir))
680 return 0;
681 MSVCRT__set_errno(GetLastError());
682 return -1;
685 /*********************************************************************
686 * _wrmdir (MSVCRT.@)
688 * Unicode version of _rmdir.
690 int _wrmdir(const MSVCRT_wchar_t * dir)
692 if (RemoveDirectoryW(dir))
693 return 0;
694 MSVCRT__set_errno(GetLastError());
695 return -1;
698 /*********************************************************************
699 * _wsplitpath (MSVCRT.@)
701 * Unicode version of _splitpath.
703 void _wsplitpath(const MSVCRT_wchar_t *inpath, MSVCRT_wchar_t *drv, MSVCRT_wchar_t *dir,
704 MSVCRT_wchar_t *fname, MSVCRT_wchar_t *ext )
706 const MSVCRT_wchar_t *p, *end;
708 if (inpath[0] && inpath[1] == ':')
710 if (drv)
712 drv[0] = inpath[0];
713 drv[1] = inpath[1];
714 drv[2] = 0;
716 inpath += 2;
718 else if (drv) drv[0] = 0;
720 /* look for end of directory part */
721 end = NULL;
722 for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
724 if (end) /* got a directory */
726 if (dir)
728 memcpy( dir, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
729 dir[end - inpath] = 0;
731 inpath = end;
733 else if (dir) dir[0] = 0;
735 /* look for extension: what's after the last dot */
736 end = NULL;
737 for (p = inpath; *p; p++) if (*p == '.') end = p;
739 if (!end) end = p; /* there's no extension */
741 if (fname)
743 memcpy( fname, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
744 fname[end - inpath] = 0;
746 if (ext) strcpyW( ext, end );
749 /* INTERNAL: Helper for _fullpath. Modified PD code from 'snippets'. */
750 static void wmsvcrt_fln_fix(MSVCRT_wchar_t *path)
752 int dir_flag = 0, root_flag = 0;
753 MSVCRT_wchar_t *r, *p, *q, *s;
754 MSVCRT_wchar_t szbsdot[] = { '\\', '.', 0 };
756 /* Skip drive */
757 if (NULL == (r = strrchrW(path, ':')))
758 r = path;
759 else
760 ++r;
762 /* Ignore leading slashes */
763 while ('\\' == *r)
764 if ('\\' == r[1])
765 strcpyW(r, &r[1]);
766 else
768 root_flag = 1;
769 ++r;
772 p = r; /* Change "\\" to "\" */
773 while (NULL != (p = strchrW(p, '\\')))
774 if ('\\' == p[1])
775 strcpyW(p, &p[1]);
776 else
777 ++p;
779 while ('.' == *r) /* Scrunch leading ".\" */
781 if ('.' == r[1])
783 /* Ignore leading ".." */
784 for (p = (r += 2); *p && (*p != '\\'); ++p)
787 else
789 for (p = r + 1 ;*p && (*p != '\\'); ++p)
792 strcpyW(r, p + ((*p) ? 1 : 0));
795 while ('\\' == path[strlenW(path)-1]) /* Strip last '\\' */
797 dir_flag = 1;
798 path[strlenW(path)-1] = '\0';
801 s = r;
803 /* Look for "\." in path */
805 while (NULL != (p = strstrW(s, szbsdot)))
807 if ('.' == p[2])
809 /* Execute this section if ".." found */
810 q = p - 1;
811 while (q > r) /* Backup one level */
813 if (*q == '\\')
814 break;
815 --q;
817 if (q > r)
819 strcpyW(q, p + 3);
820 s = q;
822 else if ('.' != *q)
824 strcpyW(q + ((*q == '\\') ? 1 : 0),
825 p + 3 + ((*(p + 3)) ? 1 : 0));
826 s = q;
828 else s = ++p;
830 else
832 /* Execute this section if "." found */
833 q = p + 2;
834 for ( ;*q && (*q != '\\'); ++q)
836 strcpyW (p, q);
840 if (root_flag) /* Embedded ".." could have bubbled up to root */
842 for (p = r; *p && ('.' == *p || '\\' == *p); ++p)
844 if (r != p)
845 strcpyW(r, p);
848 if (dir_flag)
850 MSVCRT_wchar_t szbs[] = { '\\', 0 };
852 strcatW(path, szbs);
856 /*********************************************************************
857 * _wfullpath (MSVCRT.@)
859 * Unicode version of _fullpath.
861 MSVCRT_wchar_t *_wfullpath(MSVCRT_wchar_t * absPath, const MSVCRT_wchar_t* relPath, MSVCRT_size_t size)
863 MSVCRT_wchar_t drive[5],dir[MAX_PATH],file[MAX_PATH],ext[MAX_PATH];
864 MSVCRT_wchar_t res[MAX_PATH];
865 size_t len;
866 MSVCRT_wchar_t szbs[] = { '\\', 0 };
869 res[0] = '\0';
871 if (!relPath || !*relPath)
872 return _wgetcwd(absPath, size);
874 if (size < 4)
876 *MSVCRT__errno() = MSVCRT_ERANGE;
877 return NULL;
880 TRACE(":resolving relative path '%s'\n",debugstr_w(relPath));
882 _wsplitpath(relPath, drive, dir, file, ext);
884 /* Get Directory and drive into 'res' */
885 if (!dir[0] || (dir[0] != '/' && dir[0] != '\\'))
887 /* Relative or no directory given */
888 _wgetdcwd(drive[0] ? toupper(drive[0]) - 'A' + 1 : 0, res, MAX_PATH);
889 strcatW(res,szbs);
890 if (dir[0])
891 strcatW(res,dir);
892 if (drive[0])
893 res[0] = drive[0]; /* If given a drive, preserve the letter case */
895 else
897 strcpyW(res,drive);
898 strcatW(res,dir);
901 strcatW(res,szbs);
902 strcatW(res, file);
903 strcatW(res, ext);
904 wmsvcrt_fln_fix(res);
906 len = strlenW(res);
907 if (len >= MAX_PATH || len >= (size_t)size)
908 return NULL; /* FIXME: errno? */
910 if (!absPath)
911 return _wcsdup(res);
912 strcpyW(absPath,res);
913 return absPath;
916 /* INTERNAL: Helper for _fullpath. Modified PD code from 'snippets'. */
917 static void msvcrt_fln_fix(char *path)
919 int dir_flag = 0, root_flag = 0;
920 char *r, *p, *q, *s;
922 /* Skip drive */
923 if (NULL == (r = strrchr(path, ':')))
924 r = path;
925 else
926 ++r;
928 /* Ignore leading slashes */
929 while ('\\' == *r)
930 if ('\\' == r[1])
931 strcpy(r, &r[1]);
932 else
934 root_flag = 1;
935 ++r;
938 p = r; /* Change "\\" to "\" */
939 while (NULL != (p = strchr(p, '\\')))
940 if ('\\' == p[1])
941 strcpy(p, &p[1]);
942 else
943 ++p;
945 while ('.' == *r) /* Scrunch leading ".\" */
947 if ('.' == r[1])
949 /* Ignore leading ".." */
950 for (p = (r += 2); *p && (*p != '\\'); ++p)
953 else
955 for (p = r + 1 ;*p && (*p != '\\'); ++p)
958 strcpy(r, p + ((*p) ? 1 : 0));
961 while ('\\' == path[strlen(path)-1]) /* Strip last '\\' */
963 dir_flag = 1;
964 path[strlen(path)-1] = '\0';
967 s = r;
969 /* Look for "\." in path */
971 while (NULL != (p = strstr(s, "\\.")))
973 if ('.' == p[2])
975 /* Execute this section if ".." found */
976 q = p - 1;
977 while (q > r) /* Backup one level */
979 if (*q == '\\')
980 break;
981 --q;
983 if (q > r)
985 strcpy(q, p + 3);
986 s = q;
988 else if ('.' != *q)
990 strcpy(q + ((*q == '\\') ? 1 : 0),
991 p + 3 + ((*(p + 3)) ? 1 : 0));
992 s = q;
994 else s = ++p;
996 else
998 /* Execute this section if "." found */
999 q = p + 2;
1000 for ( ;*q && (*q != '\\'); ++q)
1002 strcpy (p, q);
1006 if (root_flag) /* Embedded ".." could have bubbled up to root */
1008 for (p = r; *p && ('.' == *p || '\\' == *p); ++p)
1010 if (r != p)
1011 strcpy(r, p);
1014 if (dir_flag)
1015 strcat(path, "\\");
1018 /*********************************************************************
1019 * _fullpath (MSVCRT.@)
1021 * Create an absolute path from a relative path.
1023 * PARAMS
1024 * absPath [O] Destination for absolute path
1025 * relPath [I] Relative path to convert to absolute
1026 * size [I] Length of absPath in characters.
1028 * RETURNS
1029 * Success: If absPath is NULL, returns an allocated string containing the path.
1030 * Otherwise populates absPath with the path and returns it.
1031 * Failure: NULL. errno indicates the error.
1033 char *_fullpath(char * absPath, const char* relPath, unsigned int size)
1035 char drive[5],dir[MAX_PATH],file[MAX_PATH],ext[MAX_PATH];
1036 char res[MAX_PATH];
1037 size_t len;
1039 res[0] = '\0';
1041 if (!relPath || !*relPath)
1042 return _getcwd(absPath, size);
1044 if (size < 4)
1046 *MSVCRT__errno() = MSVCRT_ERANGE;
1047 return NULL;
1050 TRACE(":resolving relative path '%s'\n",relPath);
1052 _splitpath(relPath, drive, dir, file, ext);
1054 /* Get Directory and drive into 'res' */
1055 if (!dir[0] || (dir[0] != '/' && dir[0] != '\\'))
1057 /* Relative or no directory given */
1058 _getdcwd(drive[0] ? toupper(drive[0]) - 'A' + 1 : 0, res, MAX_PATH);
1059 strcat(res,"\\");
1060 if (dir[0])
1061 strcat(res,dir);
1062 if (drive[0])
1063 res[0] = drive[0]; /* If given a drive, preserve the letter case */
1065 else
1067 strcpy(res,drive);
1068 strcat(res,dir);
1071 strcat(res,"\\");
1072 strcat(res, file);
1073 strcat(res, ext);
1074 msvcrt_fln_fix(res);
1076 len = strlen(res);
1077 if (len >= MAX_PATH || len >= (size_t)size)
1078 return NULL; /* FIXME: errno? */
1080 if (!absPath)
1081 return _strdup(res);
1082 strcpy(absPath,res);
1083 return absPath;
1086 /*********************************************************************
1087 * _makepath (MSVCRT.@)
1089 * Create a pathname.
1091 * PARAMS
1092 * path [O] Destination for created pathname
1093 * drive [I] Drive letter (e.g. "A:")
1094 * directory [I] Directory
1095 * filename [I] Name of the file, excluding extension
1096 * extension [I] File extension (e.g. ".TXT")
1098 * RETURNS
1099 * Nothing. If path is not large enough to hold the resulting pathname,
1100 * random process memory will be overwritten.
1102 VOID _makepath(char * path, const char * drive,
1103 const char *directory, const char * filename,
1104 const char * extension)
1106 char ch;
1107 char tmpPath[MAX_PATH];
1108 TRACE("got %s %s %s %s\n", debugstr_a(drive), debugstr_a(directory),
1109 debugstr_a(filename), debugstr_a(extension) );
1111 if ( !path )
1112 return;
1114 tmpPath[0] = '\0';
1115 if (drive && drive[0])
1117 tmpPath[0] = drive[0];
1118 tmpPath[1] = ':';
1119 tmpPath[2] = 0;
1121 if (directory && directory[0])
1123 strcat(tmpPath, directory);
1124 ch = tmpPath[strlen(tmpPath)-1];
1125 if (ch != '/' && ch != '\\')
1126 strcat(tmpPath,"\\");
1128 if (filename && filename[0])
1130 strcat(tmpPath, filename);
1131 if (extension && extension[0])
1133 if ( extension[0] != '.' )
1134 strcat(tmpPath,".");
1135 strcat(tmpPath,extension);
1139 strcpy( path, tmpPath );
1141 TRACE("returning %s\n",path);
1144 /*********************************************************************
1145 * _wmakepath (MSVCRT.@)
1147 * Unicode version of _wmakepath.
1149 VOID _wmakepath(MSVCRT_wchar_t *path, const MSVCRT_wchar_t *drive, const MSVCRT_wchar_t *directory,
1150 const MSVCRT_wchar_t *filename, const MSVCRT_wchar_t *extension)
1152 MSVCRT_wchar_t ch;
1153 TRACE("%s %s %s %s\n", debugstr_w(drive), debugstr_w(directory),
1154 debugstr_w(filename), debugstr_w(extension));
1156 if ( !path )
1157 return;
1159 path[0] = 0;
1160 if (drive && drive[0])
1162 path[0] = drive[0];
1163 path[1] = ':';
1164 path[2] = 0;
1166 if (directory && directory[0])
1168 strcatW(path, directory);
1169 ch = path[strlenW(path) - 1];
1170 if (ch != '/' && ch != '\\')
1172 static const MSVCRT_wchar_t backslashW[] = {'\\',0};
1173 strcatW(path, backslashW);
1176 if (filename && filename[0])
1178 strcatW(path, filename);
1179 if (extension && extension[0])
1181 if ( extension[0] != '.' )
1183 static const MSVCRT_wchar_t dotW[] = {'.',0};
1184 strcatW(path, dotW);
1186 strcatW(path, extension);
1190 TRACE("returning %s\n", debugstr_w(path));
1193 /*********************************************************************
1194 * _searchenv (MSVCRT.@)
1196 * Search for a file in a list of paths from an envronment variable.
1198 * PARAMS
1199 * file [I] Name of the file to search for.
1200 * env [I] Name of the environment variable containing a list of paths.
1201 * buf [O] Destination for the found file path.
1203 * RETURNS
1204 * Nothing. If the file is not found, buf will contain an empty string
1205 * and errno is set.
1207 void _searchenv(const char* file, const char* env, char *buf)
1209 char*envVal, *penv;
1210 char curPath[MAX_PATH];
1212 *buf = '\0';
1214 /* Try CWD first */
1215 if (GetFileAttributesA( file ) != INVALID_FILE_ATTRIBUTES)
1217 GetFullPathNameA( file, MAX_PATH, buf, NULL );
1218 /* Sigh. This error is *always* set, regardless of success */
1219 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1220 return;
1223 /* Search given environment variable */
1224 envVal = MSVCRT_getenv(env);
1225 if (!envVal)
1227 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1228 return;
1231 penv = envVal;
1232 TRACE(":searching for %s in paths %s\n", file, envVal);
1236 char *end = penv;
1238 while(*end && *end != ';') end++; /* Find end of next path */
1239 if (penv == end || !*penv)
1241 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1242 return;
1244 strncpy(curPath, penv, end - penv);
1245 if (curPath[end - penv] != '/' || curPath[end - penv] != '\\')
1247 curPath[end - penv] = '\\';
1248 curPath[end - penv + 1] = '\0';
1250 else
1251 curPath[end - penv] = '\0';
1253 strcat(curPath, file);
1254 TRACE("Checking for file %s\n", curPath);
1255 if (GetFileAttributesA( curPath ) != INVALID_FILE_ATTRIBUTES)
1257 strcpy(buf, curPath);
1258 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1259 return; /* Found */
1261 penv = *end ? end + 1 : end;
1262 } while(1);