Implemented the remaining 64-bit file functions, and added a few other
[wine/multimedia.git] / dlls / msvcrt / dir.c
blob69a4dc55a6096b28446876db3fff7f03a56535cd
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/direct.h"
40 #include "msvcrt/dos.h"
41 #include "msvcrt/io.h"
42 #include "msvcrt/stdlib.h"
43 #include "msvcrt/string.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
49 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata_t */
50 static void msvcrt_fttofd( const WIN32_FIND_DATAA *fd, struct _finddata_t* ft)
52 DWORD dw;
54 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
55 ft->attrib = 0;
56 else
57 ft->attrib = fd->dwFileAttributes;
59 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
60 ft->time_create = dw;
61 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
62 ft->time_access = dw;
63 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
64 ft->time_write = dw;
65 ft->size = fd->nFileSizeLow;
66 strcpy(ft->name, fd->cFileName);
69 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata_t */
70 static void msvcrt_wfttofd( const WIN32_FIND_DATAW *fd, struct _wfinddata_t* ft)
72 DWORD dw;
74 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
75 ft->attrib = 0;
76 else
77 ft->attrib = fd->dwFileAttributes;
79 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
80 ft->time_create = dw;
81 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
82 ft->time_access = dw;
83 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
84 ft->time_write = dw;
85 ft->size = fd->nFileSizeLow;
86 strcpyW(ft->name, fd->cFileName);
89 /* INTERNAL: Translate WIN32_FIND_DATAA to finddatai64_t */
90 static void msvcrt_fttofdi64( const WIN32_FIND_DATAA *fd, struct _finddatai64_t* ft)
92 DWORD dw;
94 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
95 ft->attrib = 0;
96 else
97 ft->attrib = fd->dwFileAttributes;
99 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
100 ft->time_create = dw;
101 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
102 ft->time_access = dw;
103 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
104 ft->time_write = dw;
105 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
106 strcpy(ft->name, fd->cFileName);
109 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddatai64_t */
110 static void msvcrt_wfttofdi64( const WIN32_FIND_DATAW *fd, struct _wfinddatai64_t* ft)
112 DWORD dw;
114 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
115 ft->attrib = 0;
116 else
117 ft->attrib = fd->dwFileAttributes;
119 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
120 ft->time_create = dw;
121 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
122 ft->time_access = dw;
123 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
124 ft->time_write = dw;
125 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
126 strcpyW(ft->name, fd->cFileName);
129 /*********************************************************************
130 * _chdir (MSVCRT.@)
132 int _chdir(const char * newdir)
134 if (!SetCurrentDirectoryA(newdir))
136 MSVCRT__set_errno(newdir?GetLastError():0);
137 return -1;
139 return 0;
142 /*********************************************************************
143 * _wchdir (MSVCRT.@)
145 int _wchdir(const MSVCRT_wchar_t * newdir)
147 if (!SetCurrentDirectoryW(newdir))
149 MSVCRT__set_errno(newdir?GetLastError():0);
150 return -1;
152 return 0;
155 /*********************************************************************
156 * _chdrive (MSVCRT.@)
158 int _chdrive(int newdrive)
160 char buffer[3] = "A:";
161 buffer[0] += newdrive - 1;
162 if (!SetCurrentDirectoryA( buffer ))
164 MSVCRT__set_errno(GetLastError());
165 if (newdrive <= 0)
166 *MSVCRT__errno() = MSVCRT_EACCES;
167 return -1;
169 return 0;
172 /*********************************************************************
173 * _findclose (MSVCRT.@)
175 int _findclose(long hand)
177 TRACE(":handle %ld\n",hand);
178 if (!FindClose((HANDLE)hand))
180 MSVCRT__set_errno(GetLastError());
181 return -1;
183 return 0;
186 /*********************************************************************
187 * _findfirst (MSVCRT.@)
189 long _findfirst(const char * fspec, struct _finddata_t* ft)
191 WIN32_FIND_DATAA find_data;
192 HANDLE hfind;
194 hfind = FindFirstFileA(fspec, &find_data);
195 if (hfind == INVALID_HANDLE_VALUE)
197 MSVCRT__set_errno(GetLastError());
198 return -1;
200 msvcrt_fttofd(&find_data,ft);
201 TRACE(":got handle %p\n",hfind);
202 return (long)hfind;
205 /*********************************************************************
206 * _wfindfirst (MSVCRT.@)
208 long _wfindfirst(const MSVCRT_wchar_t * fspec, struct _wfinddata_t* ft)
210 WIN32_FIND_DATAW find_data;
211 HANDLE hfind;
213 hfind = FindFirstFileW(fspec, &find_data);
214 if (hfind == INVALID_HANDLE_VALUE)
216 MSVCRT__set_errno(GetLastError());
217 return -1;
219 msvcrt_wfttofd(&find_data,ft);
220 TRACE(":got handle %p\n",hfind);
221 return (long)hfind;
224 /*********************************************************************
225 * _findfirsti64 (MSVCRT.@)
227 long _findfirsti64(const char * fspec, struct _finddatai64_t* ft)
229 WIN32_FIND_DATAA find_data;
230 HANDLE hfind;
232 hfind = FindFirstFileA(fspec, &find_data);
233 if (hfind == INVALID_HANDLE_VALUE)
235 MSVCRT__set_errno(GetLastError());
236 return -1;
238 msvcrt_fttofdi64(&find_data,ft);
239 TRACE(":got handle %p\n",hfind);
240 return (long)hfind;
243 /*********************************************************************
244 * _wfindfirsti64 (MSVCRT.@)
246 long _wfindfirsti64(const MSVCRT_wchar_t * fspec, struct _wfinddatai64_t* ft)
248 WIN32_FIND_DATAW find_data;
249 HANDLE hfind;
251 hfind = FindFirstFileW(fspec, &find_data);
252 if (hfind == INVALID_HANDLE_VALUE)
254 MSVCRT__set_errno(GetLastError());
255 return -1;
257 msvcrt_wfttofdi64(&find_data,ft);
258 TRACE(":got handle %p\n",hfind);
259 return (long)hfind;
262 /*********************************************************************
263 * _findnext (MSVCRT.@)
265 int _findnext(long hand, struct _finddata_t * ft)
267 WIN32_FIND_DATAA find_data;
269 if (!FindNextFileA((HANDLE)hand, &find_data))
271 *MSVCRT__errno() = MSVCRT_ENOENT;
272 return -1;
275 msvcrt_fttofd(&find_data,ft);
276 return 0;
279 /*********************************************************************
280 * _wfindnext (MSVCRT.@)
282 int _wfindnext(long hand, struct _wfinddata_t * ft)
284 WIN32_FIND_DATAW find_data;
286 if (!FindNextFileW((HANDLE)hand, &find_data))
288 *MSVCRT__errno() = MSVCRT_ENOENT;
289 return -1;
292 msvcrt_wfttofd(&find_data,ft);
293 return 0;
296 /*********************************************************************
297 * _findnexti64 (MSVCRT.@)
299 int _findnexti64(long hand, struct _finddatai64_t * ft)
301 WIN32_FIND_DATAA find_data;
303 if (!FindNextFileA((HANDLE)hand, &find_data))
305 *MSVCRT__errno() = MSVCRT_ENOENT;
306 return -1;
309 msvcrt_fttofdi64(&find_data,ft);
310 return 0;
313 /*********************************************************************
314 * _wfindnexti64 (MSVCRT.@)
316 int _wfindnexti64(long hand, struct _wfinddatai64_t * ft)
318 WIN32_FIND_DATAW find_data;
320 if (!FindNextFileW((HANDLE)hand, &find_data))
322 *MSVCRT__errno() = MSVCRT_ENOENT;
323 return -1;
326 msvcrt_wfttofdi64(&find_data,ft);
327 return 0;
330 /*********************************************************************
331 * _getcwd (MSVCRT.@)
333 char* _getcwd(char * buf, int size)
335 char dir[MAX_PATH];
336 int dir_len = GetCurrentDirectoryA(MAX_PATH,dir);
338 if (dir_len < 1)
339 return NULL; /* FIXME: Real return value untested */
341 if (!buf)
343 if (size < 0)
344 return _strdup(dir);
345 return msvcrt_strndup(dir,size);
347 if (dir_len >= size)
349 *MSVCRT__errno() = MSVCRT_ERANGE;
350 return NULL; /* buf too small */
352 strcpy(buf,dir);
353 return buf;
356 /*********************************************************************
357 * _wgetcwd (MSVCRT.@)
359 MSVCRT_wchar_t* _wgetcwd(MSVCRT_wchar_t * buf, int size)
361 MSVCRT_wchar_t dir[MAX_PATH];
362 int dir_len = GetCurrentDirectoryW(MAX_PATH,dir);
364 if (dir_len < 1)
365 return NULL; /* FIXME: Real return value untested */
367 if (!buf)
369 if (size < 0)
370 return _wcsdup(dir);
371 return msvcrt_wstrndup(dir,size);
373 if (dir_len >= size)
375 *MSVCRT__errno() = MSVCRT_ERANGE;
376 return NULL; /* buf too small */
378 strcpyW(buf,dir);
379 return buf;
382 /*********************************************************************
383 * _getdrive (MSVCRT.@)
385 int _getdrive(void)
387 char buffer[MAX_PATH];
388 if (!GetCurrentDirectoryA( sizeof(buffer), buffer )) return 0;
389 if (buffer[1] != ':') return 0;
390 return toupper(buffer[0]) - 'A' + 1;
393 /*********************************************************************
394 * _getdcwd (MSVCRT.@)
396 char* _getdcwd(int drive, char * buf, int size)
398 static char* dummy;
400 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
402 if (!drive || drive == _getdrive())
403 return _getcwd(buf,size); /* current */
404 else
406 char dir[MAX_PATH];
407 char drivespec[4] = {'A', ':', '\\', 0};
408 int dir_len;
410 drivespec[0] += drive - 1;
411 if (GetDriveTypeA(drivespec) < DRIVE_REMOVABLE)
413 *MSVCRT__errno() = MSVCRT_EACCES;
414 return NULL;
417 dir_len = GetFullPathNameA(drivespec,MAX_PATH,dir,&dummy);
418 if (dir_len >= size || dir_len < 1)
420 *MSVCRT__errno() = MSVCRT_ERANGE;
421 return NULL; /* buf too small */
424 TRACE(":returning '%s'\n", dir);
425 if (!buf)
426 return _strdup(dir); /* allocate */
428 strcpy(buf,dir);
430 return buf;
433 /*********************************************************************
434 * _wgetdcwd (MSVCRT.@)
436 MSVCRT_wchar_t* _wgetdcwd(int drive, MSVCRT_wchar_t * buf, int size)
438 static MSVCRT_wchar_t* dummy;
440 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
442 if (!drive || drive == _getdrive())
443 return _wgetcwd(buf,size); /* current */
444 else
446 MSVCRT_wchar_t dir[MAX_PATH];
447 MSVCRT_wchar_t drivespec[4] = {'A', ':', '\\', 0};
448 int dir_len;
450 drivespec[0] += drive - 1;
451 if (GetDriveTypeW(drivespec) < DRIVE_REMOVABLE)
453 *MSVCRT__errno() = MSVCRT_EACCES;
454 return NULL;
457 dir_len = GetFullPathNameW(drivespec,MAX_PATH,dir,&dummy);
458 if (dir_len >= size || dir_len < 1)
460 *MSVCRT__errno() = MSVCRT_ERANGE;
461 return NULL; /* buf too small */
464 TRACE(":returning %s\n", debugstr_w(dir));
465 if (!buf)
466 return _wcsdup(dir); /* allocate */
467 strcpyW(buf,dir);
469 return buf;
472 /*********************************************************************
473 * _getdiskfree (MSVCRT.@)
475 unsigned int _getdiskfree(unsigned int disk, struct _diskfree_t* d)
477 char drivespec[4] = {'@', ':', '\\', 0};
478 DWORD ret[4];
479 unsigned int err;
481 if (disk > 26)
482 return ERROR_INVALID_PARAMETER; /* MSVCRT doesn't set errno here */
484 drivespec[0] += disk; /* make a drive letter */
486 if (GetDiskFreeSpaceA(disk==0?NULL:drivespec,ret,ret+1,ret+2,ret+3))
488 d->sectors_per_cluster = (unsigned)ret[0];
489 d->bytes_per_sector = (unsigned)ret[1];
490 d->avail_clusters = (unsigned)ret[2];
491 d->total_clusters = (unsigned)ret[3];
492 return 0;
494 err = GetLastError();
495 MSVCRT__set_errno(err);
496 return err;
499 /*********************************************************************
500 * _mkdir (MSVCRT.@)
502 int _mkdir(const char * newdir)
504 if (CreateDirectoryA(newdir,NULL))
505 return 0;
506 MSVCRT__set_errno(GetLastError());
507 return -1;
510 /*********************************************************************
511 * _wmkdir (MSVCRT.@)
513 int _wmkdir(const MSVCRT_wchar_t* newdir)
515 if (CreateDirectoryW(newdir,NULL))
516 return 0;
517 MSVCRT__set_errno(GetLastError());
518 return -1;
521 /*********************************************************************
522 * _rmdir (MSVCRT.@)
524 int _rmdir(const char * dir)
526 if (RemoveDirectoryA(dir))
527 return 0;
528 MSVCRT__set_errno(GetLastError());
529 return -1;
532 /*********************************************************************
533 * _wrmdir (MSVCRT.@)
535 int _wrmdir(const MSVCRT_wchar_t * dir)
537 if (RemoveDirectoryW(dir))
538 return 0;
539 MSVCRT__set_errno(GetLastError());
540 return -1;
543 /*********************************************************************
544 * _wsplitpath (MSVCRT.@)
546 void _wsplitpath(const MSVCRT_wchar_t *inpath, MSVCRT_wchar_t *drv, MSVCRT_wchar_t *dir,
547 MSVCRT_wchar_t *fname, MSVCRT_wchar_t *ext )
549 const MSVCRT_wchar_t *p, *end;
551 if (inpath[0] && inpath[1] == ':')
553 if (drv)
555 drv[0] = inpath[0];
556 drv[1] = inpath[1];
557 drv[2] = 0;
559 inpath += 2;
561 else if (drv) drv[0] = 0;
563 /* look for end of directory part */
564 end = NULL;
565 for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
567 if (end) /* got a directory */
569 if (dir)
571 memcpy( dir, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
572 dir[end - inpath] = 0;
574 inpath = end;
576 else if (dir) dir[0] = 0;
578 /* look for extension: what's after the last dot */
579 end = NULL;
580 for (p = inpath; *p; p++) if (*p == '.') end = p;
582 if (!end) end = p; /* there's no extension */
584 if (fname)
586 memcpy( fname, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
587 fname[end - inpath] = 0;
589 if (ext) strcpyW( ext, end );
592 /* INTERNAL: Helper for _fullpath. Modified PD code from 'snippets'. */
593 static void wmsvcrt_fln_fix(MSVCRT_wchar_t *path)
595 int dir_flag = 0, root_flag = 0;
596 MSVCRT_wchar_t *r, *p, *q, *s;
597 MSVCRT_wchar_t szbsdot[] = { '\\', '.', 0 };
599 /* Skip drive */
600 if (NULL == (r = strrchrW(path, ':')))
601 r = path;
602 else
603 ++r;
605 /* Ignore leading slashes */
606 while ('\\' == *r)
607 if ('\\' == r[1])
608 strcpyW(r, &r[1]);
609 else
611 root_flag = 1;
612 ++r;
615 p = r; /* Change "\\" to "\" */
616 while (NULL != (p = strchrW(p, '\\')))
617 if ('\\' == p[1])
618 strcpyW(p, &p[1]);
619 else
620 ++p;
622 while ('.' == *r) /* Scrunch leading ".\" */
624 if ('.' == r[1])
626 /* Ignore leading ".." */
627 for (p = (r += 2); *p && (*p != '\\'); ++p)
630 else
632 for (p = r + 1 ;*p && (*p != '\\'); ++p)
635 strcpyW(r, p + ((*p) ? 1 : 0));
638 while ('\\' == path[strlenW(path)-1]) /* Strip last '\\' */
640 dir_flag = 1;
641 path[strlenW(path)-1] = '\0';
644 s = r;
646 /* Look for "\." in path */
648 while (NULL != (p = strstrW(s, szbsdot)))
650 if ('.' == p[2])
652 /* Execute this section if ".." found */
653 q = p - 1;
654 while (q > r) /* Backup one level */
656 if (*q == '\\')
657 break;
658 --q;
660 if (q > r)
662 strcpyW(q, p + 3);
663 s = q;
665 else if ('.' != *q)
667 strcpyW(q + ((*q == '\\') ? 1 : 0),
668 p + 3 + ((*(p + 3)) ? 1 : 0));
669 s = q;
671 else s = ++p;
673 else
675 /* Execute this section if "." found */
676 q = p + 2;
677 for ( ;*q && (*q != '\\'); ++q)
679 strcpyW (p, q);
683 if (root_flag) /* Embedded ".." could have bubbled up to root */
685 for (p = r; *p && ('.' == *p || '\\' == *p); ++p)
687 if (r != p)
688 strcpyW(r, p);
691 if (dir_flag)
693 MSVCRT_wchar_t szbs[] = { '\\', 0 };
695 strcatW(path, szbs);
699 /*********************************************************************
700 * _wfullpath (MSVCRT.@)
702 MSVCRT_wchar_t *_wfullpath(MSVCRT_wchar_t * absPath, const MSVCRT_wchar_t* relPath, MSVCRT_size_t size)
704 MSVCRT_wchar_t drive[5],dir[MAX_PATH],file[MAX_PATH],ext[MAX_PATH];
705 MSVCRT_wchar_t res[MAX_PATH];
706 size_t len;
707 MSVCRT_wchar_t szbs[] = { '\\', 0 };
710 res[0] = '\0';
712 if (!relPath || !*relPath)
713 return _wgetcwd(absPath, size);
715 if (size < 4)
717 *MSVCRT__errno() = MSVCRT_ERANGE;
718 return NULL;
721 TRACE(":resolving relative path '%s'\n",debugstr_w(relPath));
723 _wsplitpath(relPath, drive, dir, file, ext);
725 /* Get Directory and drive into 'res' */
726 if (!dir[0] || (dir[0] != '/' && dir[0] != '\\'))
728 /* Relative or no directory given */
729 _wgetdcwd(drive[0] ? toupper(drive[0]) - 'A' + 1 : 0, res, MAX_PATH);
730 strcatW(res,szbs);
731 if (dir[0])
732 strcatW(res,dir);
733 if (drive[0])
734 res[0] = drive[0]; /* If given a drive, preserve the letter case */
736 else
738 strcpyW(res,drive);
739 strcatW(res,dir);
742 strcatW(res,szbs);
743 strcatW(res, file);
744 strcatW(res, ext);
745 wmsvcrt_fln_fix(res);
747 len = strlenW(res);
748 if (len >= MAX_PATH || len >= (size_t)size)
749 return NULL; /* FIXME: errno? */
751 if (!absPath)
752 return _wcsdup(res);
753 strcpyW(absPath,res);
754 return absPath;
757 /* INTERNAL: Helper for _fullpath. Modified PD code from 'snippets'. */
758 static void msvcrt_fln_fix(char *path)
760 int dir_flag = 0, root_flag = 0;
761 char *r, *p, *q, *s;
763 /* Skip drive */
764 if (NULL == (r = strrchr(path, ':')))
765 r = path;
766 else
767 ++r;
769 /* Ignore leading slashes */
770 while ('\\' == *r)
771 if ('\\' == r[1])
772 strcpy(r, &r[1]);
773 else
775 root_flag = 1;
776 ++r;
779 p = r; /* Change "\\" to "\" */
780 while (NULL != (p = strchr(p, '\\')))
781 if ('\\' == p[1])
782 strcpy(p, &p[1]);
783 else
784 ++p;
786 while ('.' == *r) /* Scrunch leading ".\" */
788 if ('.' == r[1])
790 /* Ignore leading ".." */
791 for (p = (r += 2); *p && (*p != '\\'); ++p)
794 else
796 for (p = r + 1 ;*p && (*p != '\\'); ++p)
799 strcpy(r, p + ((*p) ? 1 : 0));
802 while ('\\' == path[strlen(path)-1]) /* Strip last '\\' */
804 dir_flag = 1;
805 path[strlen(path)-1] = '\0';
808 s = r;
810 /* Look for "\." in path */
812 while (NULL != (p = strstr(s, "\\.")))
814 if ('.' == p[2])
816 /* Execute this section if ".." found */
817 q = p - 1;
818 while (q > r) /* Backup one level */
820 if (*q == '\\')
821 break;
822 --q;
824 if (q > r)
826 strcpy(q, p + 3);
827 s = q;
829 else if ('.' != *q)
831 strcpy(q + ((*q == '\\') ? 1 : 0),
832 p + 3 + ((*(p + 3)) ? 1 : 0));
833 s = q;
835 else s = ++p;
837 else
839 /* Execute this section if "." found */
840 q = p + 2;
841 for ( ;*q && (*q != '\\'); ++q)
843 strcpy (p, q);
847 if (root_flag) /* Embedded ".." could have bubbled up to root */
849 for (p = r; *p && ('.' == *p || '\\' == *p); ++p)
851 if (r != p)
852 strcpy(r, p);
855 if (dir_flag)
856 strcat(path, "\\");
859 /*********************************************************************
860 * _fullpath (MSVCRT.@)
862 char *_fullpath(char * absPath, const char* relPath, unsigned int size)
864 char drive[5],dir[MAX_PATH],file[MAX_PATH],ext[MAX_PATH];
865 char res[MAX_PATH];
866 size_t len;
868 res[0] = '\0';
870 if (!relPath || !*relPath)
871 return _getcwd(absPath, size);
873 if (size < 4)
875 *MSVCRT__errno() = MSVCRT_ERANGE;
876 return NULL;
879 TRACE(":resolving relative path '%s'\n",relPath);
881 _splitpath(relPath, drive, dir, file, ext);
883 /* Get Directory and drive into 'res' */
884 if (!dir[0] || (dir[0] != '/' && dir[0] != '\\'))
886 /* Relative or no directory given */
887 _getdcwd(drive[0] ? toupper(drive[0]) - 'A' + 1 : 0, res, MAX_PATH);
888 strcat(res,"\\");
889 if (dir[0])
890 strcat(res,dir);
891 if (drive[0])
892 res[0] = drive[0]; /* If given a drive, preserve the letter case */
894 else
896 strcpy(res,drive);
897 strcat(res,dir);
900 strcat(res,"\\");
901 strcat(res, file);
902 strcat(res, ext);
903 msvcrt_fln_fix(res);
905 len = strlen(res);
906 if (len >= MAX_PATH || len >= (size_t)size)
907 return NULL; /* FIXME: errno? */
909 if (!absPath)
910 return _strdup(res);
911 strcpy(absPath,res);
912 return absPath;
915 /*********************************************************************
916 * _makepath (MSVCRT.@)
918 VOID _makepath(char * path, const char * drive,
919 const char *directory, const char * filename,
920 const char * extension )
922 char ch;
923 char tmpPath[MAX_PATH];
924 TRACE("got %s %s %s %s\n", debugstr_a(drive), debugstr_a(directory),
925 debugstr_a(filename), debugstr_a(extension) );
927 if ( !path )
928 return;
930 tmpPath[0] = '\0';
931 if (drive && drive[0])
933 tmpPath[0] = drive[0];
934 tmpPath[1] = ':';
935 tmpPath[2] = 0;
937 if (directory && directory[0])
939 strcat(tmpPath, directory);
940 ch = tmpPath[strlen(tmpPath)-1];
941 if (ch != '/' && ch != '\\')
942 strcat(tmpPath,"\\");
944 if (filename && filename[0])
946 strcat(tmpPath, filename);
947 if (extension && extension[0])
949 if ( extension[0] != '.' )
950 strcat(tmpPath,".");
951 strcat(tmpPath,extension);
955 strcpy( path, tmpPath );
957 TRACE("returning %s\n",path);
960 /*********************************************************************
961 * _wmakepath (MSVCRT.@)
963 VOID _wmakepath(MSVCRT_wchar_t *path, const MSVCRT_wchar_t *drive, const MSVCRT_wchar_t *directory,
964 const MSVCRT_wchar_t *filename, const MSVCRT_wchar_t *extension)
966 MSVCRT_wchar_t ch;
967 TRACE("%s %s %s %s\n", debugstr_w(drive), debugstr_w(directory),
968 debugstr_w(filename), debugstr_w(extension));
970 if ( !path )
971 return;
973 path[0] = 0;
974 if (drive && drive[0])
976 path[0] = drive[0];
977 path[1] = ':';
978 path[2] = 0;
980 if (directory && directory[0])
982 strcatW(path, directory);
983 ch = path[strlenW(path) - 1];
984 if (ch != '/' && ch != '\\')
986 static const MSVCRT_wchar_t backslashW[] = {'\\',0};
987 strcatW(path, backslashW);
990 if (filename && filename[0])
992 strcatW(path, filename);
993 if (extension && extension[0])
995 if ( extension[0] != '.' )
997 static const MSVCRT_wchar_t dotW[] = {'.',0};
998 strcatW(path, dotW);
1000 strcatW(path, extension);
1004 TRACE("returning %s\n", debugstr_w(path));
1007 /*********************************************************************
1008 * _searchenv (MSVCRT.@)
1010 void _searchenv(const char* file, const char* env, char *buf)
1012 char*envVal, *penv;
1013 char curPath[MAX_PATH];
1015 *buf = '\0';
1017 /* Try CWD first */
1018 if (GetFileAttributesA( file ) != INVALID_FILE_ATTRIBUTES)
1020 GetFullPathNameA( file, MAX_PATH, buf, NULL );
1021 /* Sigh. This error is *always* set, regardless of success */
1022 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1023 return;
1026 /* Search given environment variable */
1027 envVal = MSVCRT_getenv(env);
1028 if (!envVal)
1030 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1031 return;
1034 penv = envVal;
1035 TRACE(":searching for %s in paths %s\n", file, envVal);
1039 char *end = penv;
1041 while(*end && *end != ';') end++; /* Find end of next path */
1042 if (penv == end || !*penv)
1044 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1045 return;
1047 strncpy(curPath, penv, end - penv);
1048 if (curPath[end - penv] != '/' || curPath[end - penv] != '\\')
1050 curPath[end - penv] = '\\';
1051 curPath[end - penv + 1] = '\0';
1053 else
1054 curPath[end - penv] = '\0';
1056 strcat(curPath, file);
1057 TRACE("Checking for file %s\n", curPath);
1058 if (GetFileAttributesA( curPath ) != INVALID_FILE_ATTRIBUTES)
1060 strcpy(buf, curPath);
1061 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
1062 return; /* Found */
1064 penv = *end ? end + 1 : end;
1065 } while(1);