source: trunk/src/msvcrt/dir.c@ 21542

Last change on this file since 21542 was 21542, checked in by dmik, 15 years ago

minivcrt: Fixed _fullpath() which could implicitly change the current drive (LIBC bug).

File size: 20.6 KB
Line 
1/*
2 * msvcrt.dll drive/directory functions
3 *
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
8 *
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.
13 *
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.
18 *
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
22 */
23#ifdef __WIN32OS2__
24#include <emxheader.h>
25#include <stdlib.h>
26#include <string.h>
27#include <ctype.h>
28#include <winbase.h>
29#else
30#include "config.h"
31#endif
32
33#ifndef __MINIVCRT__
34
35#include "wine/port.h"
36
37#include <time.h>
38#include "winternl.h"
39#include "wine/unicode.h"
40#include "msvcrt.h"
41#include "msvcrt/errno.h"
42
43#include "wine/unicode.h"
44#include "msvcrt/direct.h"
45#include "msvcrt/dos.h"
46#include "msvcrt/io.h"
47#include "msvcrt/stdlib.h"
48#include "msvcrt/string.h"
49
50#include "wine/debug.h"
51
52WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
53
54#else /* !__MINIVCRT__ */
55
56#include "minivcrt.h"
57#include "minivcrt_internal.h"
58
59#include "winternl.h"
60#include "wine/unicode.h"
61
62#include <errno.h>
63#include <stdlib.h>
64#include <limits.h>
65
66#ifdef __EMX__
67// restore the EMX version of _fullpath
68#undef _fullpath
69#endif
70
71#endif /* !__MINIVCRT__ */
72
73#ifndef __MINIVCRT__
74
75/* INTERNAL: Translate finddata_t to PWIN32_FIND_DATAA */
76static void msvcrt_fttofd(LPWIN32_FIND_DATAA fd, struct _finddata_t* ft)
77{
78 DWORD dw;
79
80 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
81 ft->attrib = 0;
82 else
83 ft->attrib = fd->dwFileAttributes;
84
85 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
86 ft->time_create = dw;
87 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
88 ft->time_access = dw;
89 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
90 ft->time_write = dw;
91 ft->size = fd->nFileSizeLow;
92 strcpy(ft->name, fd->cFileName);
93}
94
95#endif /* !__MINIVCRT__ */
96
97/* INTERNAL: Translate wfinddata_t to PWIN32_FIND_DATAA */
98static void msvcrt_wfttofd(LPWIN32_FIND_DATAW fd, struct _wfinddata_t* ft)
99{
100 DWORD dw;
101
102 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
103 ft->attrib = 0;
104 else
105 ft->attrib = fd->dwFileAttributes;
106
107 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftCreationTime, &dw );
108 ft->time_create = dw;
109 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
110 ft->time_access = dw;
111 RtlTimeToSecondsSince1970( (LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
112 ft->time_write = dw;
113 ft->size = fd->nFileSizeLow;
114 strcpyW(ft->name, fd->cFileName);
115}
116
117#ifndef __MINIVCRT__
118
119/*********************************************************************
120 * _chdir (MSVCRT.@)
121 */
122int MSVCRT__chdir(const char * newdir)
123{
124 if (!SetCurrentDirectoryA(newdir))
125 {
126 MSVCRT__set_errno(newdir?GetLastError():0);
127 return -1;
128 }
129 return 0;
130}
131
132#endif /* !__MINIVCRT__ */
133
134/*********************************************************************
135 * _wchdir (MSVCRT.@)
136 */
137int _wchdir(const MSVCRT_wchar_t * newdir)
138{
139 if (!SetCurrentDirectoryW(newdir))
140 {
141 MSVCRT__set_errno(newdir?GetLastError():0);
142 return -1;
143 }
144 return 0;
145}
146
147#ifndef __MINIVCRT__
148
149/*********************************************************************
150 * _chdrive (MSVCRT.@)
151 */
152int MSVCRT__chdrive(int newdrive)
153{
154 char buffer[3] = "A:";
155 buffer[0] += newdrive - 1;
156 if (!SetCurrentDirectoryA( buffer ))
157 {
158 MSVCRT__set_errno(GetLastError());
159 if (newdrive <= 0)
160 *MSVCRT__errno() = MSVCRT_EACCES;
161 return -1;
162 }
163 return 0;
164}
165
166/*********************************************************************
167 * _findclose (MSVCRT.@)
168 */
169int _findclose(long hand)
170{
171 TRACE(":handle %ld\n",hand);
172 if (!FindClose((HANDLE)hand))
173 {
174 MSVCRT__set_errno(GetLastError());
175 return -1;
176 }
177 return 0;
178}
179
180/*********************************************************************
181 * _findfirst (MSVCRT.@)
182 */
183long _findfirst(const char * fspec, struct _finddata_t* ft)
184{
185 WIN32_FIND_DATAA find_data;
186 HANDLE hfind;
187
188 hfind = FindFirstFileA(fspec, &find_data);
189 if (hfind == INVALID_HANDLE_VALUE)
190 {
191 MSVCRT__set_errno(GetLastError());
192 return -1;
193 }
194 msvcrt_fttofd(&find_data,ft);
195 TRACE(":got handle %p\n",hfind);
196 return (long)hfind;
197}
198
199#endif /* !__MINIVCRT__ */
200
201/*********************************************************************
202 * _wfindfirst (MSVCRT.@)
203 */
204long _wfindfirst(const MSVCRT_wchar_t * fspec, struct _wfinddata_t* ft)
205{
206 WIN32_FIND_DATAW find_data;
207 HANDLE hfind;
208
209 hfind = FindFirstFileW(fspec, &find_data);
210 if (hfind == INVALID_HANDLE_VALUE)
211 {
212 MSVCRT__set_errno(GetLastError());
213 return -1;
214 }
215 msvcrt_wfttofd(&find_data,ft);
216 TRACE(":got handle %p\n",hfind);
217 return (long)hfind;
218}
219
220#ifndef __MINIVCRT__
221
222/*********************************************************************
223 * _findnext (MSVCRT.@)
224 */
225int _findnext(long hand, struct _finddata_t * ft)
226{
227 WIN32_FIND_DATAA find_data;
228
229 if (!FindNextFileA((HANDLE)hand, &find_data))
230 {
231 *MSVCRT__errno() = MSVCRT(ENOENT);
232 return -1;
233 }
234
235 msvcrt_fttofd(&find_data,ft);
236 return 0;
237}
238
239#endif /* !__MINIVCRT__ */
240
241/*********************************************************************
242 * _wfindnext (MSVCRT.@)
243 */
244int _wfindnext(long hand, struct _wfinddata_t * ft)
245{
246 WIN32_FIND_DATAW find_data;
247
248 if (!FindNextFileW((HANDLE)hand, &find_data))
249 {
250 *MSVCRT__errno() = MSVCRT(ENOENT);
251 return -1;
252 }
253
254 msvcrt_wfttofd(&find_data,ft);
255 return 0;
256}
257
258#ifndef __MINIVCRT__
259
260/*********************************************************************
261 * _getcwd (MSVCRT.@)
262 */
263char* MSVCRT__getcwd(char * buf, int size)
264{
265 char dir[MAX_PATH];
266 int dir_len = GetCurrentDirectoryA(MAX_PATH,dir);
267
268 if (dir_len < 1)
269 return NULL; /* FIXME: Real return value untested */
270
271 if (!buf)
272 {
273 if (size < 0)
274 return MSVCRT__strdup(dir);
275 return msvcrt_strndup(dir,size);
276 }
277 if (dir_len >= size)
278 {
279 *MSVCRT__errno() = MSVCRT_ERANGE;
280 return NULL; /* buf too small */
281 }
282 strcpy(buf,dir);
283 return buf;
284}
285
286#endif /* !__MINIVCRT__ */
287
288/*********************************************************************
289 * _wgetcwd (MSVCRT.@)
290 */
291MSVCRT_wchar_t* _wgetcwd(MSVCRT_wchar_t * buf, int size)
292{
293 MSVCRT_wchar_t dir[MAX_PATH];
294 int dir_len = GetCurrentDirectoryW(MAX_PATH,dir);
295
296 if (dir_len < 1)
297 return NULL; /* FIXME: Real return value untested */
298
299 if (!buf)
300 {
301 if (size < 0)
302 return _wcsdup(dir);
303 return msvcrt_wstrndup(dir,size);
304 }
305 if (dir_len >= size)
306 {
307 *MSVCRT__errno() = MSVCRT(ERANGE);
308 return NULL; /* buf too small */
309 }
310 strcpyW(buf,dir);
311 return buf;
312}
313
314#ifndef __MINIVCRT__
315
316/*********************************************************************
317 * _getdrive (MSVCRT.@)
318 */
319int MSVCRT__getdrive(void)
320{
321 char buffer[MAX_PATH];
322 if (!GetCurrentDirectoryA( sizeof(buffer), buffer )) return 0;
323 if (buffer[1] != ':') return 0;
324 return toupper(buffer[0]) - 'A' + 1;
325}
326
327/*********************************************************************
328 * _getdcwd (MSVCRT.@)
329 */
330char* MSVCRT__getdcwd(int drive, char * buf, int size)
331{
332 static char* dummy;
333
334 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
335
336 if (!drive || drive == MSVCRT__getdrive())
337 return MSVCRT__getcwd(buf,size); /* current */
338 else
339 {
340 char dir[MAX_PATH];
341 char drivespec[4] = {'A', ':', '\\', 0};
342 int dir_len;
343
344 drivespec[0] += drive - 1;
345 if (GetDriveTypeA(drivespec) < DRIVE_REMOVABLE)
346 {
347 *MSVCRT__errno() = MSVCRT_EACCES;
348 return NULL;
349 }
350
351 dir_len = GetFullPathNameA(drivespec,MAX_PATH,dir,&dummy);
352 if (dir_len >= size || dir_len < 1)
353 {
354 *MSVCRT__errno() = MSVCRT_ERANGE;
355 return NULL; /* buf too small */
356 }
357
358 TRACE(":returning '%s'\n", dir);
359 if (!buf)
360 return MSVCRT__strdup(dir); /* allocate */
361
362 strcpy(buf,dir);
363 }
364 return buf;
365}
366
367#endif /* !__MINIVCRT__ */
368
369/*********************************************************************
370 * _wgetdcwd (MSVCRT.@)
371 */
372MSVCRT_wchar_t* _wgetdcwd(int drive, MSVCRT_wchar_t * buf, int size)
373{
374 static MSVCRT_wchar_t* dummy;
375
376 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
377
378 if (!drive || drive == MSVCRT__getdrive())
379 return _wgetcwd(buf,size); /* current */
380 else
381 {
382 MSVCRT_wchar_t dir[MAX_PATH];
383 MSVCRT_wchar_t drivespec[4] = {'A', ':', '\\', 0};
384 int dir_len;
385
386 drivespec[0] += drive - 1;
387 if (GetDriveTypeW(drivespec) < DRIVE_REMOVABLE)
388 {
389 *MSVCRT__errno() = MSVCRT(EACCES);
390 return NULL;
391 }
392
393 dir_len = GetFullPathNameW(drivespec,MAX_PATH,dir,&dummy);
394 if (dir_len >= size || dir_len < 1)
395 {
396 *MSVCRT__errno() = MSVCRT(ERANGE);
397 return NULL; /* buf too small */
398 }
399
400 TRACE(":returning %s\n", debugstr_w(dir));
401 if (!buf)
402 return _wcsdup(dir); /* allocate */
403 strcpyW(buf,dir);
404 }
405 return buf;
406}
407
408#ifndef __MINIVCRT__
409
410/*********************************************************************
411 * _getdiskfree (MSVCRT.@)
412 */
413unsigned int _getdiskfree(unsigned int disk, struct _diskfree_t* d)
414{
415 char drivespec[4] = {'@', ':', '\\', 0};
416 DWORD ret[4];
417 unsigned int err;
418
419 if (disk > 26)
420 return ERROR_INVALID_PARAMETER; /* MSVCRT doesn't set errno here */
421
422 drivespec[0] += disk; /* make a drive letter */
423
424 if (GetDiskFreeSpaceA(disk==0?NULL:drivespec,ret,ret+1,ret+2,ret+3))
425 {
426 d->sectors_per_cluster = (unsigned)ret[0];
427 d->bytes_per_sector = (unsigned)ret[1];
428 d->avail_clusters = (unsigned)ret[2];
429 d->total_clusters = (unsigned)ret[3];
430 return 0;
431 }
432 err = GetLastError();
433 MSVCRT__set_errno(err);
434 return err;
435}
436
437/*********************************************************************
438 * _mkdir (MSVCRT.@)
439 */
440int MSVCRT__mkdir(const char * newdir)
441{
442 if (CreateDirectoryA(newdir,NULL))
443 return 0;
444 MSVCRT__set_errno(GetLastError());
445 return -1;
446}
447
448#endif /* !__MINIVCRT__ */
449
450/*********************************************************************
451 * _wmkdir (MSVCRT.@)
452 */
453int _wmkdir(const MSVCRT_wchar_t* newdir)
454{
455 if (CreateDirectoryW(newdir,NULL))
456 return 0;
457 MSVCRT__set_errno(GetLastError());
458 return -1;
459}
460
461#ifndef __MINIVCRT__
462
463/*********************************************************************
464 * _rmdir (MSVCRT.@)
465 */
466int MSVCRT__rmdir(const char * dir)
467{
468 if (RemoveDirectoryA(dir))
469 return 0;
470 MSVCRT__set_errno(GetLastError());
471 return -1;
472}
473
474#endif /* !__MINIVCRT__ */
475
476/*********************************************************************
477 * _wrmdir (MSVCRT.@)
478 */
479int _wrmdir(const MSVCRT_wchar_t * dir)
480{
481 if (RemoveDirectoryW(dir))
482 return 0;
483 MSVCRT__set_errno(GetLastError());
484 return -1;
485}
486
487/*********************************************************************
488 * _wsplitpath (MSVCRT.@)
489 */
490void _wsplitpath(const MSVCRT_wchar_t *inpath, MSVCRT_wchar_t *drv, MSVCRT_wchar_t *dir,
491 MSVCRT_wchar_t *fname, MSVCRT_wchar_t *ext )
492{
493 /* Modified PD code from 'snippets' collection. */
494 MSVCRT_wchar_t ch, *ptr, *p;
495 MSVCRT_wchar_t pathbuff[MAX_PATH],*path=pathbuff;
496
497 TRACE("MSVCRT: _wsplitpath %s\n",debugstr_w(path));
498 /* FIXME: Should be an strncpyW or something */
499 strcpyW(pathbuff, inpath);
500
501 /* convert slashes to backslashes for searching */
502 for (ptr = (MSVCRT_wchar_t*)path; *ptr; ++ptr)
503 if (*ptr == '/')
504 *ptr = '\\';
505
506 /* look for drive spec */
507 if ((ptr = strchrW(path, ':')) != 0)
508 {
509 ++ptr;
510 if (drv)
511 {
512 strncpyW(drv, path, ptr - path);
513 drv[ptr - path] = 0;
514 }
515 path = ptr;
516 }
517 else if (drv)
518 *drv = 0;
519
520 /* find rightmost backslash or leftmost colon */
521 if ((ptr = strrchrW(path, '\\')) == NULL)
522 ptr = (strchrW(path, ':'));
523
524 if (!ptr)
525 {
526 ptr = (MSVCRT_wchar_t *)path; /* no path */
527 if (dir)
528 *dir = 0;
529 }
530 else
531 {
532 ++ptr; /* skip the delimiter */
533 if (dir)
534 {
535 ch = *ptr;
536 *ptr = 0;
537 strcpyW(dir, path);
538 *ptr = ch;
539 }
540 }
541
542 if ((p = strrchrW(ptr, '.')) == NULL)
543 {
544 if (fname)
545 strcpyW(fname, ptr);
546 if (ext)
547 *ext = 0;
548 }
549 else
550 {
551 *p = 0;
552 if (fname)
553 strcpyW(fname, ptr);
554 *p = '.';
555 if (ext)
556 strcpyW(ext, p);
557 }
558
559 /* Fix pathological case - Win returns ':' as part of the
560 * directory when no drive letter is given.
561 */
562 if (drv && drv[0] == ':')
563 {
564 *drv = 0;
565 if (dir)
566 {
567 pathbuff[0] = ':';
568 pathbuff[1] = 0;
569 strcatW(pathbuff,dir);
570 strcpyW(dir, pathbuff);
571 }
572 }
573}
574
575#ifndef __MINIVCRT__
576
577/* INTERNAL: Helper for _fullpath. Modified PD code from 'snippets'. */
578static void msvcrt_fln_fix(char *path)
579{
580 int dir_flag = 0, root_flag = 0;
581 char *r, *p, *q, *s;
582
583 /* Skip drive */
584 if (NULL == (r = strrchr(path, ':')))
585 r = path;
586 else
587 ++r;
588
589 /* Ignore leading slashes */
590 while ('\\' == *r)
591 if ('\\' == r[1])
592 strcpy(r, &r[1]);
593 else
594 {
595 root_flag = 1;
596 ++r;
597 }
598
599 p = r; /* Change "\\" to "\" */
600 while (NULL != (p = strchr(p, '\\')))
601 if ('\\' == p[1])
602 strcpy(p, &p[1]);
603 else
604 ++p;
605
606 while ('.' == *r) /* Scrunch leading ".\" */
607 {
608 if ('.' == r[1])
609 {
610 /* Ignore leading ".." */
611 for (p = (r += 2); *p && (*p != '\\'); ++p)
612 ;
613 }
614 else
615 {
616 for (p = r + 1 ;*p && (*p != '\\'); ++p)
617 ;
618 }
619 strcpy(r, p + ((*p) ? 1 : 0));
620 }
621
622 while ('\\' == path[strlen(path)-1]) /* Strip last '\\' */
623 {
624 dir_flag = 1;
625 path[strlen(path)-1] = '\0';
626 }
627
628 s = r;
629
630 /* Look for "\." in path */
631
632 while (NULL != (p = strstr(s, "\\.")))
633 {
634 if ('.' == p[2])
635 {
636 /* Execute this section if ".." found */
637 q = p - 1;
638 while (q > r) /* Backup one level */
639 {
640 if (*q == '\\')
641 break;
642 --q;
643 }
644 if (q > r)
645 {
646 strcpy(q, p + 3);
647 s = q;
648 }
649 else if ('.' != *q)
650 {
651 strcpy(q + ((*q == '\\') ? 1 : 0),
652 p + 3 + ((*(p + 3)) ? 1 : 0));
653 s = q;
654 }
655 else s = ++p;
656 }
657 else
658 {
659 /* Execute this section if "." found */
660 q = p + 2;
661 for ( ;*q && (*q != '\\'); ++q)
662 ;
663 strcpy (p, q);
664 }
665 }
666
667 if (root_flag) /* Embedded ".." could have bubbled up to root */
668 {
669 for (p = r; *p && ('.' == *p || '\\' == *p); ++p)
670 ;
671 if (r != p)
672 strcpy(r, p);
673 }
674
675 if (dir_flag)
676 strcat(path, "\\");
677}
678
679/*********************************************************************
680 * _fullpath (MSVCRT.@)
681 */
682char *MSVCRT__fullpath(char * absPath, const char* relPath, unsigned int size)
683{
684 char drive[5],dir[MAX_PATH],file[MAX_PATH],ext[MAX_PATH];
685 char res[MAX_PATH];
686 size_t len;
687
688 res[0] = '\0';
689
690 if (!relPath || !*relPath)
691 return MSVCRT__getcwd(absPath, size);
692
693 if (size < 4)
694 {
695 *MSVCRT__errno() = MSVCRT_ERANGE;
696 return NULL;
697 }
698
699 TRACE("MSVCRT: _fullpath '%s'\n",relPath);
700
701 _splitpath(relPath, drive, dir, file, ext);
702
703 /* Get Directory and drive into 'res' */
704 if (!dir[0] || (dir[0] != '/' && dir[0] != '\\'))
705 {
706 /* Relative or no directory given */
707 _getdcwd(drive[0] ? toupper(drive[0]) - 'A' + 1 : 0, res, MAX_PATH);
708 strcat(res,"\\");
709 if (dir[0])
710 strcat(res,dir);
711 if (drive[0])
712 res[0] = drive[0]; /* If given a drive, preserve the letter case */
713 }
714 else
715 {
716 strcpy(res,drive);
717 strcat(res,dir);
718 }
719
720 strcat(res,"\\");
721 strcat(res, file);
722 strcat(res, ext);
723 msvcrt_fln_fix(res);
724
725 len = strlen(res);
726 if (len >= MAX_PATH || len >= (size_t)size)
727 return NULL; /* FIXME: errno? */
728
729 if (!absPath)
730 return MSVCRT__strdup(res);
731 strcpy(absPath,res);
732 return absPath;
733}
734
735/*********************************************************************
736 * _makepath (MSVCRT.@)
737 */
738VOID MSVCRT__makepath(char * path, const char * drive,
739 const char *directory, const char * filename,
740 const char * extension )
741{
742 char ch;
743 TRACE("got %s %s %s %s\n", drive, directory,
744 filename, extension);
745
746 if ( !path )
747 return;
748
749 path[0] = 0;
750 if (drive && drive[0])
751 {
752 path[0] = drive[0];
753 path[1] = ':';
754 path[2] = 0;
755 }
756 if (directory && directory[0])
757 {
758 strcat(path, directory);
759 ch = path[strlen(path)-1];
760 if (ch != '/' && ch != '\\')
761 strcat(path,"\\");
762 }
763 if (filename && filename[0])
764 {
765 strcat(path, filename);
766 if (extension && extension[0])
767 {
768 if ( extension[0] != '.' )
769 strcat(path,".");
770 strcat(path,extension);
771 }
772 }
773
774 TRACE("returning %s\n",path);
775}
776
777#else /* !__MINIVCRT__ */
778
779#ifdef __EMX__
780
781// The EMX version of _fullpath() returns int instead of char* and implicitly
782// changes the current drive. It also doesn't expect absPath to be NULL and
783// allocate a buffer in this case. Provide a wrapper to fix these issues.
784char *MSVCRT__fullpath(char * absPath, const char* relPath, unsigned int size)
785{
786 char *buf = NULL;
787 if (absPath == NULL)
788 {
789 size = PATH_MAX;
790 absPath = buf = (char *)MSVCRT_malloc(size);
791 if (buf == NULL)
792 {
793 *MSVCRT__errno() = ENOMEM;
794 return NULL;
795 }
796 }
797
798 int d = _getdrive();
799 char *result = _fullpath(absPath, relPath, size) == 0 ? absPath : NULL;
800 _chdrive(d);
801
802 if (result == NULL && buf != NULL)
803 MSVCRT_free(buf);
804
805 return result;
806}
807
808#endif /* EMX */
809
810#endif /* !__MINIVCRT__ */
811
812/*********************************************************************
813 * _wmakepath (MSVCRT.@)
814 */
815VOID _wmakepath(MSVCRT_wchar_t *path, const MSVCRT_wchar_t *drive, const MSVCRT_wchar_t *directory,
816 const MSVCRT_wchar_t *filename, const MSVCRT_wchar_t *extension)
817{
818 MSVCRT_wchar_t ch;
819 TRACE("%s %s %s %s\n", debugstr_w(drive), debugstr_w(directory),
820 debugstr_w(filename), debugstr_w(extension));
821
822 if ( !path )
823 return;
824
825 path[0] = 0;
826 if (drive && drive[0])
827 {
828 path[0] = drive[0];
829 path[1] = ':';
830 path[2] = 0;
831 }
832 if (directory && directory[0])
833 {
834 strcatW(path, directory);
835 ch = path[strlenW(path) - 1];
836 if (ch != '/' && ch != '\\')
837 {
838 static const MSVCRT_wchar_t backslashW[] = {'\\',0};
839 strcatW(path, backslashW);
840 }
841 }
842 if (filename && filename[0])
843 {
844 strcatW(path, filename);
845 if (extension && extension[0])
846 {
847 if ( extension[0] != '.' )
848 {
849 static const MSVCRT_wchar_t dotW[] = {'.',0};
850 strcatW(path, dotW);
851 }
852 strcatW(path, extension);
853 }
854 }
855
856 TRACE("returning %s\n", debugstr_w(path));
857}
858
859#ifndef __MINIVCRT__
860
861/*********************************************************************
862 * _searchenv (MSVCRT.@)
863 */
864void MSVCRT__searchenv(const char* file, const char* env, char *buf)
865{
866 char*envVal, *penv;
867 char curPath[MAX_PATH];
868
869 *buf = '\0';
870
871 /* Try CWD first */
872 if (GetFileAttributesA( file ) != 0xFFFFFFFF)
873 {
874 GetFullPathNameA( file, MAX_PATH, buf, NULL );
875 /* Sigh. This error is *always* set, regardless of success */
876 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
877 return;
878 }
879
880 /* Search given environment variable */
881 envVal = MSVCRT_getenv(env);
882 if (!envVal)
883 {
884 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
885 return;
886 }
887
888 penv = envVal;
889 TRACE(":searching for %s in paths %s\n", file, envVal);
890
891 do
892 {
893 char *end = penv;
894
895 while(*end && *end != ';') end++; /* Find end of next path */
896 if (penv == end || !*penv)
897 {
898 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
899 return;
900 }
901 strncpy(curPath, penv, end - penv);
902 if (curPath[end - penv] != '/' || curPath[end - penv] != '\\')
903 {
904 curPath[end - penv] = '\\';
905 curPath[end - penv + 1] = '\0';
906 }
907 else
908 curPath[end - penv] = '\0';
909
910 strcat(curPath, file);
911 TRACE("Checking for file %s\n", curPath);
912 if (GetFileAttributesA( curPath ) != 0xFFFFFFFF)
913 {
914 strcpy(buf, curPath);
915 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND);
916 return; /* Found */
917 }
918 penv = *end ? end + 1 : end;
919 } while(1);
920}
921
922#endif /* !__MINIVCRT__ */
923
924MSVCRT_wchar_t* _wfullpath(MSVCRT_wchar_t* absPath,const MSVCRT_wchar_t* relPath,MSVCRT(size_t) size)
925{
926 char asciiabsPath[280], asciirelPath[280];
927
928 TRACE("MSVCRT: _wfullpath %s %d\n", debugstr_w(relPath),size);
929
930 WideCharToMultiByte(CP_ACP, 0, relPath, -1, (LPSTR)asciirelPath, 280, NULL, NULL);
931
932 MSVCRT__fullpath(asciiabsPath, asciirelPath, size);
933
934 MultiByteToWideChar(CP_ACP, 0, asciiabsPath, -1, absPath, size);
935
936 return absPath;
937}
Note: See TracBrowser for help on using the repository browser.