Update types checked by winapi_check.
[wine/dcerpc.git] / dlls / msvcrt / dir.c
blob827ba7336d88320696a540036ef830437111bacc
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 "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
40 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata_t */
41 static void msvcrt_fttofd( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata_t* ft)
43 DWORD dw;
45 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
46 ft->attrib = 0;
47 else
48 ft->attrib = fd->dwFileAttributes;
50 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
51 ft->time_create = dw;
52 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
53 ft->time_access = dw;
54 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
55 ft->time_write = dw;
56 ft->size = fd->nFileSizeLow;
57 strcpy(ft->name, fd->cFileName);
60 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata_t */
61 static void msvcrt_wfttofd( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata_t* ft)
63 DWORD dw;
65 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
66 ft->attrib = 0;
67 else
68 ft->attrib = fd->dwFileAttributes;
70 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
71 ft->time_create = dw;
72 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
73 ft->time_access = dw;
74 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
75 ft->time_write = dw;
76 ft->size = fd->nFileSizeLow;
77 strcpyW(ft->name, fd->cFileName);
80 /* INTERNAL: Translate WIN32_FIND_DATAA to finddatai64_t */
81 static void msvcrt_fttofdi64( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddatai64_t* ft)
83 DWORD dw;
85 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
86 ft->attrib = 0;
87 else
88 ft->attrib = fd->dwFileAttributes;
90 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
91 ft->time_create = dw;
92 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
93 ft->time_access = dw;
94 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
95 ft->time_write = dw;
96 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
97 strcpy(ft->name, fd->cFileName);
100 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddatai64_t */
101 static void msvcrt_wfttofdi64( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddatai64_t* ft)
103 DWORD dw;
105 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
106 ft->attrib = 0;
107 else
108 ft->attrib = fd->dwFileAttributes;
110 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
111 ft->time_create = dw;
112 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
113 ft->time_access = dw;
114 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
115 ft->time_write = dw;
116 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
117 strcpyW(ft->name, fd->cFileName);
120 /*********************************************************************
121 * _chdir (MSVCRT.@)
123 * Change the current working directory.
125 * PARAMS
126 * newdir [I] Directory to change to
128 * RETURNS
129 * Success: 0. The current working directory is set to newdir.
130 * Failure: -1. errno indicates the error.
132 * NOTES
133 * See SetCurrentDirectoryA.
135 int _chdir(const char * newdir)
137 if (!SetCurrentDirectoryA(newdir))
139 msvcrt_set_errno(newdir?GetLastError():0);
140 return -1;
142 return 0;
145 /*********************************************************************
146 * _wchdir (MSVCRT.@)
148 * Unicode version of _chdir.
150 int _wchdir(const MSVCRT_wchar_t * newdir)
152 if (!SetCurrentDirectoryW(newdir))
154 msvcrt_set_errno(newdir?GetLastError():0);
155 return -1;
157 return 0;
160 /*********************************************************************
161 * _chdrive (MSVCRT.@)
163 * Change the current drive.
165 * PARAMS
166 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
168 * RETURNS
169 * Success: 0. The current drive is set to newdrive.
170 * Failure: -1. errno indicates the error.
172 * NOTES
173 * See SetCurrentDirectoryA.
175 int _chdrive(int newdrive)
177 WCHAR buffer[3] = {'A', ':', 0};
179 buffer[0] += newdrive - 1;
180 if (!SetCurrentDirectoryW( buffer ))
182 msvcrt_set_errno(GetLastError());
183 if (newdrive <= 0)
184 *MSVCRT__errno() = MSVCRT_EACCES;
185 return -1;
187 return 0;
190 /*********************************************************************
191 * _findclose (MSVCRT.@)
193 * Close a handle returned by _findfirst().
195 * PARAMS
196 * hand [I] Handle to close
198 * RETURNS
199 * Success: 0. All resources associated with hand are freed.
200 * Failure: -1. errno indicates the error.
202 * NOTES
203 * See FindClose.
205 int _findclose(long hand)
207 TRACE(":handle %ld\n",hand);
208 if (!FindClose((HANDLE)hand))
210 msvcrt_set_errno(GetLastError());
211 return -1;
213 return 0;
216 /*********************************************************************
217 * _findfirst (MSVCRT.@)
219 * Open a handle for iterating through a directory.
221 * PARAMS
222 * fspec [I] File specification of files to iterate.
223 * ft [O] Information for the first file found.
225 * RETURNS
226 * Success: A handle suitable for passing to _findnext() and _findclose().
227 * ft is populated with the details of the found file.
228 * Failure: -1. errno indicates the error.
230 * NOTES
231 * See FindFirstFileA.
233 long MSVCRT__findfirst(const char * fspec, struct MSVCRT__finddata_t* ft)
235 WIN32_FIND_DATAA find_data;
236 HANDLE hfind;
238 hfind = FindFirstFileA(fspec, &find_data);
239 if (hfind == INVALID_HANDLE_VALUE)
241 msvcrt_set_errno(GetLastError());
242 return -1;
244 msvcrt_fttofd(&find_data,ft);
245 TRACE(":got handle %p\n",hfind);
246 return (long)hfind;
249 /*********************************************************************
250 * _wfindfirst (MSVCRT.@)
252 * Unicode version of _findfirst.
254 long MSVCRT__wfindfirst(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddata_t* ft)
256 WIN32_FIND_DATAW find_data;
257 HANDLE hfind;
259 hfind = FindFirstFileW(fspec, &find_data);
260 if (hfind == INVALID_HANDLE_VALUE)
262 msvcrt_set_errno(GetLastError());
263 return -1;
265 msvcrt_wfttofd(&find_data,ft);
266 TRACE(":got handle %p\n",hfind);
267 return (long)hfind;
270 /*********************************************************************
271 * _findfirsti64 (MSVCRT.@)
273 * 64-bit version of _findfirst.
275 long MSVCRT__findfirsti64(const char * fspec, struct MSVCRT__finddatai64_t* ft)
277 WIN32_FIND_DATAA find_data;
278 HANDLE hfind;
280 hfind = FindFirstFileA(fspec, &find_data);
281 if (hfind == INVALID_HANDLE_VALUE)
283 msvcrt_set_errno(GetLastError());
284 return -1;
286 msvcrt_fttofdi64(&find_data,ft);
287 TRACE(":got handle %p\n",hfind);
288 return (long)hfind;
291 /*********************************************************************
292 * _wfindfirsti64 (MSVCRT.@)
294 * Unicode version of _findfirsti64.
296 long MSVCRT__wfindfirsti64(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddatai64_t* ft)
298 WIN32_FIND_DATAW find_data;
299 HANDLE hfind;
301 hfind = FindFirstFileW(fspec, &find_data);
302 if (hfind == INVALID_HANDLE_VALUE)
304 msvcrt_set_errno(GetLastError());
305 return -1;
307 msvcrt_wfttofdi64(&find_data,ft);
308 TRACE(":got handle %p\n",hfind);
309 return (long)hfind;
312 /*********************************************************************
313 * _findnext (MSVCRT.@)
315 * Find the next file from a file search handle.
317 * PARAMS
318 * hand [I] Handle to the search returned from _findfirst().
319 * ft [O] Information for the file found.
321 * RETURNS
322 * Success: 0. ft is populated with the details of the found file.
323 * Failure: -1. errno indicates the error.
325 * NOTES
326 * See FindNextFileA.
328 int MSVCRT__findnext(long hand, struct MSVCRT__finddata_t * ft)
330 WIN32_FIND_DATAA find_data;
332 if (!FindNextFileA((HANDLE)hand, &find_data))
334 *MSVCRT__errno() = MSVCRT_ENOENT;
335 return -1;
338 msvcrt_fttofd(&find_data,ft);
339 return 0;
342 /*********************************************************************
343 * _wfindnext (MSVCRT.@)
345 * Unicode version of _findnext.
347 int MSVCRT__wfindnext(long hand, struct MSVCRT__wfinddata_t * ft)
349 WIN32_FIND_DATAW find_data;
351 if (!FindNextFileW((HANDLE)hand, &find_data))
353 *MSVCRT__errno() = MSVCRT_ENOENT;
354 return -1;
357 msvcrt_wfttofd(&find_data,ft);
358 return 0;
361 /*********************************************************************
362 * _findnexti64 (MSVCRT.@)
364 * 64-bit version of _findnext.
366 int MSVCRT__findnexti64(long hand, struct MSVCRT__finddatai64_t * ft)
368 WIN32_FIND_DATAA find_data;
370 if (!FindNextFileA((HANDLE)hand, &find_data))
372 *MSVCRT__errno() = MSVCRT_ENOENT;
373 return -1;
376 msvcrt_fttofdi64(&find_data,ft);
377 return 0;
380 /*********************************************************************
381 * _wfindnexti64 (MSVCRT.@)
383 * Unicode version of _findnexti64.
385 int MSVCRT__wfindnexti64(long hand, struct MSVCRT__wfinddatai64_t * ft)
387 WIN32_FIND_DATAW find_data;
389 if (!FindNextFileW((HANDLE)hand, &find_data))
391 *MSVCRT__errno() = MSVCRT_ENOENT;
392 return -1;
395 msvcrt_wfttofdi64(&find_data,ft);
396 return 0;
399 /*********************************************************************
400 * _getcwd (MSVCRT.@)
402 * Get the current working directory.
404 * PARAMS
405 * buf [O] Destination for current working directory.
406 * size [I] Size of buf in characters
408 * RETURNS
409 * Success: If buf is NULL, returns an allocated string containing the path.
410 * Otherwise populates buf with the path and returns it.
411 * Failure: NULL. errno indicates the error.
413 char* _getcwd(char * buf, int size)
415 char dir[MAX_PATH];
416 int dir_len = GetCurrentDirectoryA(MAX_PATH,dir);
418 if (dir_len < 1)
419 return NULL; /* FIXME: Real return value untested */
421 if (!buf)
423 if (size < 0)
424 return _strdup(dir);
425 return msvcrt_strndup(dir,size);
427 if (dir_len >= size)
429 *MSVCRT__errno() = MSVCRT_ERANGE;
430 return NULL; /* buf too small */
432 strcpy(buf,dir);
433 return buf;
436 /*********************************************************************
437 * _wgetcwd (MSVCRT.@)
439 * Unicode version of _getcwd.
441 MSVCRT_wchar_t* _wgetcwd(MSVCRT_wchar_t * buf, int size)
443 MSVCRT_wchar_t dir[MAX_PATH];
444 int dir_len = GetCurrentDirectoryW(MAX_PATH,dir);
446 if (dir_len < 1)
447 return NULL; /* FIXME: Real return value untested */
449 if (!buf)
451 if (size < 0)
452 return _wcsdup(dir);
453 return msvcrt_wstrndup(dir,size);
455 if (dir_len >= size)
457 *MSVCRT__errno() = MSVCRT_ERANGE;
458 return NULL; /* buf too small */
460 strcpyW(buf,dir);
461 return buf;
464 /*********************************************************************
465 * _getdrive (MSVCRT.@)
467 * Get the current drive number.
469 * PARAMS
470 * None.
472 * RETURNS
473 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
474 * Failure: 0.
476 int _getdrive(void)
478 WCHAR buffer[MAX_PATH];
479 if (GetCurrentDirectoryW( MAX_PATH, buffer ) &&
480 buffer[0] >= 'A' && buffer[0] <= 'z' && buffer[1] == ':')
481 return toupperW(buffer[0]) - 'A' + 1;
482 return 0;
485 /*********************************************************************
486 * _getdcwd (MSVCRT.@)
488 * Get the current working directory on a given disk.
490 * PARAMS
491 * drive [I] Drive letter to get the current working directory from.
492 * buf [O] Destination for the current working directory.
493 * size [I] Length of drive in characters.
495 * RETURNS
496 * Success: If drive is NULL, returns an allocated string containing the path.
497 * Otherwise populates drive with the path and returns it.
498 * Failure: NULL. errno indicates the error.
500 char* _getdcwd(int drive, char * buf, int size)
502 static char* dummy;
504 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
506 if (!drive || drive == _getdrive())
507 return _getcwd(buf,size); /* current */
508 else
510 char dir[MAX_PATH];
511 char drivespec[4] = {'A', ':', '\\', 0};
512 int dir_len;
514 drivespec[0] += drive - 1;
515 if (GetDriveTypeA(drivespec) < DRIVE_REMOVABLE)
517 *MSVCRT__errno() = MSVCRT_EACCES;
518 return NULL;
521 dir_len = GetFullPathNameA(drivespec,MAX_PATH,dir,&dummy);
522 if (dir_len >= size || dir_len < 1)
524 *MSVCRT__errno() = MSVCRT_ERANGE;
525 return NULL; /* buf too small */
528 TRACE(":returning '%s'\n", dir);
529 if (!buf)
530 return _strdup(dir); /* allocate */
532 strcpy(buf,dir);
534 return buf;
537 /*********************************************************************
538 * _wgetdcwd (MSVCRT.@)
540 * Unicode version of _wgetdcwd.
542 MSVCRT_wchar_t* _wgetdcwd(int drive, MSVCRT_wchar_t * buf, int size)
544 static MSVCRT_wchar_t* dummy;
546 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
548 if (!drive || drive == _getdrive())
549 return _wgetcwd(buf,size); /* current */
550 else
552 MSVCRT_wchar_t dir[MAX_PATH];
553 MSVCRT_wchar_t drivespec[4] = {'A', ':', '\\', 0};
554 int dir_len;
556 drivespec[0] += drive - 1;
557 if (GetDriveTypeW(drivespec) < DRIVE_REMOVABLE)
559 *MSVCRT__errno() = MSVCRT_EACCES;
560 return NULL;
563 dir_len = GetFullPathNameW(drivespec,MAX_PATH,dir,&dummy);
564 if (dir_len >= size || dir_len < 1)
566 *MSVCRT__errno() = MSVCRT_ERANGE;
567 return NULL; /* buf too small */
570 TRACE(":returning %s\n", debugstr_w(dir));
571 if (!buf)
572 return _wcsdup(dir); /* allocate */
573 strcpyW(buf,dir);
575 return buf;
578 /*********************************************************************
579 * _getdiskfree (MSVCRT.@)
581 * Get information about the free space on a drive.
583 * PARAMS
584 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
585 * info [O] Destination for the resulting information.
587 * RETURNS
588 * Success: 0. info is updated with the free space information.
589 * Failure: An error code from GetLastError().
591 * NOTES
592 * See GetLastError().
594 unsigned int MSVCRT__getdiskfree(unsigned int disk, struct MSVCRT__diskfree_t * d)
596 WCHAR drivespec[4] = {'@', ':', '\\', 0};
597 DWORD ret[4];
598 unsigned int err;
600 if (disk > 26)
601 return ERROR_INVALID_PARAMETER; /* MSVCRT doesn't set errno here */
603 drivespec[0] += disk; /* make a drive letter */
605 if (GetDiskFreeSpaceW(disk==0?NULL:drivespec,ret,ret+1,ret+2,ret+3))
607 d->sectors_per_cluster = (unsigned)ret[0];
608 d->bytes_per_sector = (unsigned)ret[1];
609 d->avail_clusters = (unsigned)ret[2];
610 d->total_clusters = (unsigned)ret[3];
611 return 0;
613 err = GetLastError();
614 msvcrt_set_errno(err);
615 return err;
618 /*********************************************************************
619 * _mkdir (MSVCRT.@)
621 * Create a directory.
623 * PARAMS
624 * newdir [I] Name of directory to create.
626 * RETURNS
627 * Success: 0. The directory indicated by newdir is created.
628 * Failure: -1. errno indicates the error.
630 * NOTES
631 * See CreateDirectoryA.
633 int _mkdir(const char * newdir)
635 if (CreateDirectoryA(newdir,NULL))
636 return 0;
637 msvcrt_set_errno(GetLastError());
638 return -1;
641 /*********************************************************************
642 * _wmkdir (MSVCRT.@)
644 * Unicode version of _mkdir.
646 int _wmkdir(const MSVCRT_wchar_t* newdir)
648 if (CreateDirectoryW(newdir,NULL))
649 return 0;
650 msvcrt_set_errno(GetLastError());
651 return -1;
654 /*********************************************************************
655 * _rmdir (MSVCRT.@)
657 * Delete a directory.
659 * PARAMS
660 * dir [I] Name of directory to delete.
662 * RETURNS
663 * Success: 0. The directory indicated by newdir is deleted.
664 * Failure: -1. errno indicates the error.
666 * NOTES
667 * See RemoveDirectoryA.
669 int _rmdir(const char * dir)
671 if (RemoveDirectoryA(dir))
672 return 0;
673 msvcrt_set_errno(GetLastError());
674 return -1;
677 /*********************************************************************
678 * _wrmdir (MSVCRT.@)
680 * Unicode version of _rmdir.
682 int _wrmdir(const MSVCRT_wchar_t * dir)
684 if (RemoveDirectoryW(dir))
685 return 0;
686 msvcrt_set_errno(GetLastError());
687 return -1;
690 /*********************************************************************
691 * _wsplitpath (MSVCRT.@)
693 * Unicode version of _splitpath.
695 void _wsplitpath(const MSVCRT_wchar_t *inpath, MSVCRT_wchar_t *drv, MSVCRT_wchar_t *dir,
696 MSVCRT_wchar_t *fname, MSVCRT_wchar_t *ext )
698 const MSVCRT_wchar_t *p, *end;
700 if (inpath[0] && inpath[1] == ':')
702 if (drv)
704 drv[0] = inpath[0];
705 drv[1] = inpath[1];
706 drv[2] = 0;
708 inpath += 2;
710 else if (drv) drv[0] = 0;
712 /* look for end of directory part */
713 end = NULL;
714 for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
716 if (end) /* got a directory */
718 if (dir)
720 memcpy( dir, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
721 dir[end - inpath] = 0;
723 inpath = end;
725 else if (dir) dir[0] = 0;
727 /* look for extension: what's after the last dot */
728 end = NULL;
729 for (p = inpath; *p; p++) if (*p == '.') end = p;
731 if (!end) end = p; /* there's no extension */
733 if (fname)
735 memcpy( fname, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
736 fname[end - inpath] = 0;
738 if (ext) strcpyW( ext, end );
741 /* INTERNAL: Helper for _fullpath. Modified PD code from 'snippets'. */
742 static void wmsvcrt_fln_fix(MSVCRT_wchar_t *path)
744 int dir_flag = 0, root_flag = 0;
745 MSVCRT_wchar_t *r, *p, *q, *s;
746 MSVCRT_wchar_t szbsdot[] = { '\\', '.', 0 };
748 /* Skip drive */
749 if (NULL == (r = strrchrW(path, ':')))
750 r = path;
751 else
752 ++r;
754 /* Ignore leading slashes */
755 while ('\\' == *r)
756 if ('\\' == r[1])
757 strcpyW(r, &r[1]);
758 else
760 root_flag = 1;
761 ++r;
764 p = r; /* Change "\\" to "\" */
765 while (NULL != (p = strchrW(p, '\\')))
766 if ('\\' == p[1])
767 strcpyW(p, &p[1]);
768 else
769 ++p;
771 while ('.' == *r) /* Scrunch leading ".\" */
773 if ('.' == r[1])
775 /* Ignore leading ".." */
776 for (p = (r += 2); *p && (*p != '\\'); ++p)
779 else
781 for (p = r + 1 ;*p && (*p != '\\'); ++p)
784 strcpyW(r, p + ((*p) ? 1 : 0));
787 while ('\\' == path[strlenW(path)-1]) /* Strip last '\\' */
789 dir_flag = 1;
790 path[strlenW(path)-1] = '\0';
793 s = r;
795 /* Look for "\." in path */
797 while (NULL != (p = strstrW(s, szbsdot)))
799 if ('.' == p[2])
801 /* Execute this section if ".." found */
802 q = p - 1;
803 while (q > r) /* Backup one level */
805 if (*q == '\\')
806 break;
807 --q;
809 if (q > r)
811 strcpyW(q, p + 3);
812 s = q;
814 else if ('.' != *q)
816 strcpyW(q + ((*q == '\\') ? 1 : 0),
817 p + 3 + ((*(p + 3)) ? 1 : 0));
818 s = q;
820 else s = ++p;
822 else
824 /* Execute this section if "." found */
825 q = p + 2;
826 for ( ;*q && (*q != '\\'); ++q)
828 strcpyW (p, q);
832 if (root_flag) /* Embedded ".." could have bubbled up to root */
834 for (p = r; *p && ('.' == *p || '\\' == *p); ++p)
836 if (r != p)
837 strcpyW(r, p);
840 if (dir_flag)
842 MSVCRT_wchar_t szbs[] = { '\\', 0 };
844 strcatW(path, szbs);
848 /*********************************************************************
849 * _wfullpath (MSVCRT.@)
851 * Unicode version of _fullpath.
853 MSVCRT_wchar_t *_wfullpath(MSVCRT_wchar_t * absPath, const MSVCRT_wchar_t* relPath, MSVCRT_size_t size)
855 MSVCRT_wchar_t drive[5],dir[MAX_PATH],file[MAX_PATH],ext[MAX_PATH];
856 MSVCRT_wchar_t res[MAX_PATH];
857 size_t len;
858 MSVCRT_wchar_t szbs[] = { '\\', 0 };
861 res[0] = '\0';
863 if (!relPath || !*relPath)
864 return _wgetcwd(absPath, size);
866 if (size < 4)
868 *MSVCRT__errno() = MSVCRT_ERANGE;
869 return NULL;
872 TRACE(":resolving relative path '%s'\n",debugstr_w(relPath));
874 _wsplitpath(relPath, drive, dir, file, ext);
876 /* Get Directory and drive into 'res' */
877 if (!dir[0] || (dir[0] != '/' && dir[0] != '\\'))
879 /* Relative or no directory given */
880 _wgetdcwd(drive[0] ? toupper(drive[0]) - 'A' + 1 : 0, res, MAX_PATH);
881 strcatW(res,szbs);
882 if (dir[0])
883 strcatW(res,dir);
884 if (drive[0])
885 res[0] = drive[0]; /* If given a drive, preserve the letter case */
887 else
889 strcpyW(res,drive);
890 strcatW(res,dir);
893 strcatW(res,szbs);
894 strcatW(res, file);
895 strcatW(res, ext);
896 wmsvcrt_fln_fix(res);
898 len = strlenW(res);
899 if (len >= MAX_PATH || len >= (size_t)size)
900 return NULL; /* FIXME: errno? */
902 if (!absPath)
903 return _wcsdup(res);
904 strcpyW(absPath,res);
905 return absPath;
908 /* INTERNAL: Helper for _fullpath. Modified PD code from 'snippets'. */
909 static void msvcrt_fln_fix(char *path)
911 int dir_flag = 0, root_flag = 0;
912 char *r, *p, *q, *s;
914 /* Skip drive */
915 if (NULL == (r = strrchr(path, ':')))
916 r = path;
917 else
918 ++r;
920 /* Ignore leading slashes */
921 while ('\\' == *r)
922 if ('\\' == r[1])
923 strcpy(r, &r[1]);
924 else
926 root_flag = 1;
927 ++r;
930 p = r; /* Change "\\" to "\" */
931 while (NULL != (p = strchr(p, '\\')))
932 if ('\\' == p[1])
933 strcpy(p, &p[1]);
934 else
935 ++p;
937 while ('.' == *r) /* Scrunch leading ".\" */
939 if ('.' == r[1])
941 /* Ignore leading ".." */
942 for (p = (r += 2); *p && (*p != '\\'); ++p)
945 else
947 for (p = r + 1 ;*p && (*p != '\\'); ++p)
950 strcpy(r, p + ((*p) ? 1 : 0));
953 while ('\\' == path[strlen(path)-1]) /* Strip last '\\' */
955 dir_flag = 1;
956 path[strlen(path)-1] = '\0';
959 s = r;
961 /* Look for "\." in path */
963 while (NULL != (p = strstr(s, "\\.")))
965 if ('.' == p[2])
967 /* Execute this section if ".." found */
968 q = p - 1;
969 while (q > r) /* Backup one level */
971 if (*q == '\\')
972 break;
973 --q;
975 if (q > r)
977 strcpy(q, p + 3);
978 s = q;
980 else if ('.' != *q)
982 strcpy(q + ((*q == '\\') ? 1 : 0),
983 p + 3 + ((*(p + 3)) ? 1 : 0));
984 s = q;
986 else s = ++p;
988 else
990 /* Execute this section if "." found */
991 q = p + 2;
992 for ( ;*q && (*q != '\\'); ++q)
994 strcpy (p, q);
998 if (root_flag) /* Embedded ".." could have bubbled up to root */
1000 for (p = r; *p && ('.' == *p || '\\' == *p); ++p)
1002 if (r != p)
1003 strcpy(r, p);
1006 if (dir_flag)
1007 strcat(path, "\\");
1010 /*********************************************************************
1011 * _fullpath (MSVCRT.@)
1013 * Create an absolute path from a relative path.
1015 * PARAMS
1016 * absPath [O] Destination for absolute path
1017 * relPath [I] Relative path to convert to absolute
1018 * size [I] Length of absPath in characters.
1020 * RETURNS
1021 * Success: If absPath is NULL, returns an allocated string containing the path.
1022 * Otherwise populates absPath with the path and returns it.
1023 * Failure: NULL. errno indicates the error.
1025 char *_fullpath(char * absPath, const char* relPath, unsigned int size)
1027 char drive[5],dir[MAX_PATH],file[MAX_PATH],ext[MAX_PATH];
1028 char res[MAX_PATH];
1029 size_t len;
1031 res[0] = '\0';
1033 if (!relPath || !*relPath)
1034 return _getcwd(absPath, size);
1036 if (size < 4)
1038 *MSVCRT__errno() = MSVCRT_ERANGE;
1039 return NULL;
1042 TRACE(":resolving relative path '%s'\n",relPath);
1044 _splitpath(relPath, drive, dir, file, ext);
1046 /* Get Directory and drive into 'res' */
1047 if (!dir[0] || (dir[0] != '/' && dir[0] != '\\'))
1049 /* Relative or no directory given */
1050 _getdcwd(drive[0] ? toupper(drive[0]) - 'A' + 1 : 0, res, MAX_PATH);
1051 strcat(res,"\\");
1052 if (dir[0])
1053 strcat(res,dir);
1054 if (drive[0])
1055 res[0] = drive[0]; /* If given a drive, preserve the letter case */
1057 else
1059 strcpy(res,drive);
1060 strcat(res,dir);
1063 strcat(res,"\\");
1064 strcat(res, file);
1065 strcat(res, ext);
1066 msvcrt_fln_fix(res);
1068 len = strlen(res);
1069 if (len >= MAX_PATH || len >= (size_t)size)
1070 return NULL; /* FIXME: errno? */
1072 if (!absPath)
1073 return _strdup(res);
1074 strcpy(absPath,res);
1075 return absPath;
1078 /*********************************************************************
1079 * _makepath (MSVCRT.@)
1081 * Create a pathname.
1083 * PARAMS
1084 * path [O] Destination for created pathname
1085 * drive [I] Drive letter (e.g. "A:")
1086 * directory [I] Directory
1087 * filename [I] Name of the file, excluding extension
1088 * extension [I] File extension (e.g. ".TXT")
1090 * RETURNS
1091 * Nothing. If path is not large enough to hold the resulting pathname,
1092 * random process memory will be overwritten.
1094 VOID _makepath(char * path, const char * drive,
1095 const char *directory, const char * filename,
1096 const char * extension)
1098 char ch;
1099 char tmpPath[MAX_PATH];
1100 TRACE("got %s %s %s %s\n", debugstr_a(drive), debugstr_a(directory),
1101 debugstr_a(filename), debugstr_a(extension) );
1103 if ( !path )
1104 return;
1106 tmpPath[0] = '\0';
1107 if (drive && drive[0])
1109 tmpPath[0] = drive[0];
1110 tmpPath[1] = ':';
1111 tmpPath[2] = 0;
1113 if (directory && directory[0])
1115 strcat(tmpPath, directory);
1116 ch = tmpPath[strlen(tmpPath)-1];
1117 if (ch != '/' && ch != '\\')
1118 strcat(tmpPath,"\\");
1120 if (filename && filename[0])
1122 strcat(tmpPath, filename);
1123 if (extension && extension[0])
1125 if ( extension[0] != '.' )
1126 strcat(tmpPath,".");
1127 strcat(tmpPath,extension);
1131 strcpy( path, tmpPath );
1133 TRACE("returning %s\n",path);
1136 /*********************************************************************
1137 * _wmakepath (MSVCRT.@)
1139 * Unicode version of _wmakepath.
1141 VOID _wmakepath(MSVCRT_wchar_t *path, const MSVCRT_wchar_t *drive, const MSVCRT_wchar_t *directory,
1142 const MSVCRT_wchar_t *filename, const MSVCRT_wchar_t *extension)
1144 MSVCRT_wchar_t ch;
1145 TRACE("%s %s %s %s\n", debugstr_w(drive), debugstr_w(directory),
1146 debugstr_w(filename), debugstr_w(extension));
1148 if ( !path )
1149 return;
1151 path[0] = 0;
1152 if (drive && drive[0])
1154 path[0] = drive[0];
1155 path[1] = ':';
1156 path[2] = 0;
1158 if (directory && directory[0])
1160 strcatW(path, directory);
1161 ch = path[strlenW(path) - 1];
1162 if (ch != '/' && ch != '\\')
1164 static const MSVCRT_wchar_t backslashW[] = {'\\',0};
1165 strcatW(path, backslashW);
1168 if (filename && filename[0])
1170 strcatW(path, filename);
1171 if (extension && extension[0])
1173 if ( extension[0] != '.' )
1175 static const MSVCRT_wchar_t dotW[] = {'.',0};
1176 strcatW(path, dotW);
1178 strcatW(path, extension);
1182 TRACE("returning %s\n", debugstr_w(path));
1185 /*********************************************************************
1186 * _searchenv (MSVCRT.@)
1188 * Search for a file in a list of paths from an envronment variable.
1190 * PARAMS
1191 * file [I] Name of the file to search for.
1192 * env [I] Name of the environment variable containing a list of paths.
1193 * buf [O] Destination for the found file path.
1195 * RETURNS
1196 * Nothing. If the file is not found, buf will contain an empty string
1197 * and errno is set.
1199 void _searchenv(const char* file, const char* env, char *buf)
1201 char*envVal, *penv;
1202 char curPath[MAX_PATH];
1204 *buf = '\0';
1206 /* Try CWD first */
1207 if (GetFileAttributesA( file ) != INVALID_FILE_ATTRIBUTES)
1209 GetFullPathNameA( file, MAX_PATH, buf, NULL );
1210 /* Sigh. This error is *always* set, regardless of success */
1211 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1212 return;
1215 /* Search given environment variable */
1216 envVal = MSVCRT_getenv(env);
1217 if (!envVal)
1219 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1220 return;
1223 penv = envVal;
1224 TRACE(":searching for %s in paths %s\n", file, envVal);
1228 char *end = penv;
1230 while(*end && *end != ';') end++; /* Find end of next path */
1231 if (penv == end || !*penv)
1233 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1234 return;
1236 strncpy(curPath, penv, end - penv);
1237 if (curPath[end - penv] != '/' || curPath[end - penv] != '\\')
1239 curPath[end - penv] = '\\';
1240 curPath[end - penv + 1] = '\0';
1242 else
1243 curPath[end - penv] = '\0';
1245 strcat(curPath, file);
1246 TRACE("Checking for file %s\n", curPath);
1247 if (GetFileAttributesA( curPath ) != INVALID_FILE_ATTRIBUTES)
1249 strcpy(buf, curPath);
1250 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1251 return; /* Found */
1253 penv = *end ? end + 1 : end;
1254 } while(1);