d3d8: Merge vertex and index buffer implementations into a single file.
[wine] / dlls / msvcrt / dir.c
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include "config.h"
25 #include "wine/port.h"
26
27 #include <stdarg.h>
28 #include <time.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winternl.h"
33 #include "wine/unicode.h"
34 #include "msvcrt.h"
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
38
39 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata_t  */
40 static void msvcrt_fttofd( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata_t* ft)
41 {
42   DWORD dw;
43
44   if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
45     ft->attrib = 0;
46   else
47     ft->attrib = fd->dwFileAttributes;
48
49   RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
50   ft->time_create = dw;
51   RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
52   ft->time_access = dw;
53   RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
54   ft->time_write = dw;
55   ft->size = fd->nFileSizeLow;
56   strcpy(ft->name, fd->cFileName);
57 }
58
59 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata_t  */
60 static void msvcrt_wfttofd( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata_t* ft)
61 {
62   DWORD dw;
63
64   if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
65     ft->attrib = 0;
66   else
67     ft->attrib = fd->dwFileAttributes;
68
69   RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
70   ft->time_create = dw;
71   RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
72   ft->time_access = dw;
73   RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
74   ft->time_write = dw;
75   ft->size = fd->nFileSizeLow;
76   strcpyW(ft->name, fd->cFileName);
77 }
78
79 /* INTERNAL: Translate WIN32_FIND_DATAA to finddatai64_t  */
80 static void msvcrt_fttofdi64( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddatai64_t* ft)
81 {
82   DWORD dw;
83
84   if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
85     ft->attrib = 0;
86   else
87     ft->attrib = fd->dwFileAttributes;
88
89   RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
90   ft->time_create = dw;
91   RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
92   ft->time_access = dw;
93   RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
94   ft->time_write = dw;
95   ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
96   strcpy(ft->name, fd->cFileName);
97 }
98
99 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64_t  */
100 static void msvcrt_fttofd64( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata64_t* ft)
101 {
102   DWORD dw;
103
104   if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
105     ft->attrib = 0;
106   else
107     ft->attrib = fd->dwFileAttributes;
108
109   RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
110   ft->time_create = dw;
111   RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
112   ft->time_access = dw;
113   RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
114   ft->time_write = dw;
115   ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
116   strcpy(ft->name, fd->cFileName);
117 }
118
119
120 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddatai64_t  */
121 static void msvcrt_wfttofdi64( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddatai64_t* ft)
122 {
123   DWORD dw;
124
125   if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
126     ft->attrib = 0;
127   else
128     ft->attrib = fd->dwFileAttributes;
129
130   RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
131   ft->time_create = dw;
132   RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
133   ft->time_access = dw;
134   RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
135   ft->time_write = dw;
136   ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
137   strcpyW(ft->name, fd->cFileName);
138 }
139
140 /*********************************************************************
141  *              _chdir (MSVCRT.@)
142  *
143  * Change the current working directory.
144  *
145  * PARAMS
146  *  newdir [I] Directory to change to
147  *
148  * RETURNS
149  *  Success: 0. The current working directory is set to newdir.
150  *  Failure: -1. errno indicates the error.
151  *
152  * NOTES
153  *  See SetCurrentDirectoryA.
154  */
155 int CDECL MSVCRT__chdir(const char * newdir)
156 {
157   if (!SetCurrentDirectoryA(newdir))
158   {
159     msvcrt_set_errno(newdir?GetLastError():0);
160     return -1;
161   }
162   return 0;
163 }
164
165 /*********************************************************************
166  *              _wchdir (MSVCRT.@)
167  *
168  * Unicode version of _chdir.
169  */
170 int CDECL _wchdir(const MSVCRT_wchar_t * newdir)
171 {
172   if (!SetCurrentDirectoryW(newdir))
173   {
174     msvcrt_set_errno(newdir?GetLastError():0);
175     return -1;
176   }
177   return 0;
178 }
179
180 /*********************************************************************
181  *              _chdrive (MSVCRT.@)
182  *
183  * Change the current drive.
184  *
185  * PARAMS
186  *  newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
187  *
188  * RETURNS
189  *  Success: 0. The current drive is set to newdrive.
190  *  Failure: -1. errno indicates the error.
191  *
192  * NOTES
193  *  See SetCurrentDirectoryA.
194  */
195 int CDECL _chdrive(int newdrive)
196 {
197   WCHAR buffer[3] = {'A', ':', 0};
198
199   buffer[0] += newdrive - 1;
200   if (!SetCurrentDirectoryW( buffer ))
201   {
202     msvcrt_set_errno(GetLastError());
203     if (newdrive <= 0)
204       *MSVCRT__errno() = MSVCRT_EACCES;
205     return -1;
206   }
207   return 0;
208 }
209
210 /*********************************************************************
211  *              _findclose (MSVCRT.@)
212  *
213  * Close a handle returned by _findfirst().
214  *
215  * PARAMS
216  *  hand [I] Handle to close
217  *
218  * RETURNS
219  *  Success: 0. All resources associated with hand are freed.
220  *  Failure: -1. errno indicates the error.
221  *
222  * NOTES
223  *  See FindClose.
224  */
225 int CDECL MSVCRT__findclose(MSVCRT_intptr_t hand)
226 {
227   TRACE(":handle %ld\n",hand);
228   if (!FindClose((HANDLE)hand))
229   {
230     msvcrt_set_errno(GetLastError());
231     return -1;
232   }
233   return 0;
234 }
235
236 /*********************************************************************
237  *              _findfirst (MSVCRT.@)
238  *
239  * Open a handle for iterating through a directory.
240  *
241  * PARAMS
242  *  fspec [I] File specification of files to iterate.
243  *  ft    [O] Information for the first file found.
244  *
245  * RETURNS
246  *  Success: A handle suitable for passing to _findnext() and _findclose().
247  *           ft is populated with the details of the found file.
248  *  Failure: -1. errno indicates the error.
249  *
250  * NOTES
251  *  See FindFirstFileA.
252  */
253 MSVCRT_intptr_t CDECL MSVCRT__findfirst(const char * fspec, struct MSVCRT__finddata_t* ft)
254 {
255   WIN32_FIND_DATAA find_data;
256   HANDLE hfind;
257
258   hfind  = FindFirstFileA(fspec, &find_data);
259   if (hfind == INVALID_HANDLE_VALUE)
260   {
261     msvcrt_set_errno(GetLastError());
262     return -1;
263   }
264   msvcrt_fttofd(&find_data,ft);
265   TRACE(":got handle %p\n",hfind);
266   return (MSVCRT_intptr_t)hfind;
267 }
268
269 /*********************************************************************
270  *              _wfindfirst (MSVCRT.@)
271  *
272  * Unicode version of _findfirst.
273  */
274 MSVCRT_intptr_t CDECL MSVCRT__wfindfirst(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddata_t* ft)
275 {
276   WIN32_FIND_DATAW find_data;
277   HANDLE hfind;
278
279   hfind  = FindFirstFileW(fspec, &find_data);
280   if (hfind == INVALID_HANDLE_VALUE)
281   {
282     msvcrt_set_errno(GetLastError());
283     return -1;
284   }
285   msvcrt_wfttofd(&find_data,ft);
286   TRACE(":got handle %p\n",hfind);
287   return (MSVCRT_intptr_t)hfind;
288 }
289
290 /*********************************************************************
291  *              _findfirsti64 (MSVCRT.@)
292  *
293  * 64-bit version of _findfirst.
294  */
295 MSVCRT_intptr_t CDECL MSVCRT__findfirsti64(const char * fspec, struct MSVCRT__finddatai64_t* ft)
296 {
297   WIN32_FIND_DATAA find_data;
298   HANDLE hfind;
299
300   hfind  = FindFirstFileA(fspec, &find_data);
301   if (hfind == INVALID_HANDLE_VALUE)
302   {
303     msvcrt_set_errno(GetLastError());
304     return -1;
305   }
306   msvcrt_fttofdi64(&find_data,ft);
307   TRACE(":got handle %p\n",hfind);
308   return (MSVCRT_intptr_t)hfind;
309 }
310
311 /*********************************************************************
312  *              _findfirst64 (MSVCRT.@)
313  *
314  * 64-bit version of _findfirst.
315  */
316 MSVCRT_intptr_t CDECL MSVCRT__findfirst64(const char * fspec, struct MSVCRT__finddata64_t* ft)
317 {
318   WIN32_FIND_DATAA find_data;
319   HANDLE hfind;
320
321   hfind  = FindFirstFileA(fspec, &find_data);
322   if (hfind == INVALID_HANDLE_VALUE)
323   {
324     msvcrt_set_errno(GetLastError());
325     return -1;
326   }
327   msvcrt_fttofd64(&find_data,ft);
328   TRACE(":got handle %p\n",hfind);
329   return (MSVCRT_intptr_t)hfind;
330 }
331
332 /*********************************************************************
333  *              _wfindfirsti64 (MSVCRT.@)
334  *
335  * Unicode version of _findfirsti64.
336  */
337 MSVCRT_intptr_t CDECL MSVCRT__wfindfirsti64(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddatai64_t* ft)
338 {
339   WIN32_FIND_DATAW find_data;
340   HANDLE hfind;
341
342   hfind  = FindFirstFileW(fspec, &find_data);
343   if (hfind == INVALID_HANDLE_VALUE)
344   {
345     msvcrt_set_errno(GetLastError());
346     return -1;
347   }
348   msvcrt_wfttofdi64(&find_data,ft);
349   TRACE(":got handle %p\n",hfind);
350   return (MSVCRT_intptr_t)hfind;
351 }
352
353 /*********************************************************************
354  *              _findnext (MSVCRT.@)
355  *
356  * Find the next file from a file search handle.
357  *
358  * PARAMS
359  *  hand  [I] Handle to the search returned from _findfirst().
360  *  ft    [O] Information for the file found.
361  *
362  * RETURNS
363  *  Success: 0. ft is populated with the details of the found file.
364  *  Failure: -1. errno indicates the error.
365  *
366  * NOTES
367  *  See FindNextFileA.
368  */
369 int CDECL MSVCRT__findnext(MSVCRT_intptr_t hand, struct MSVCRT__finddata_t * ft)
370 {
371   WIN32_FIND_DATAA find_data;
372
373   if (!FindNextFileA((HANDLE)hand, &find_data))
374   {
375     *MSVCRT__errno() = MSVCRT_ENOENT;
376     return -1;
377   }
378
379   msvcrt_fttofd(&find_data,ft);
380   return 0;
381 }
382
383 /*********************************************************************
384  *              _wfindnext (MSVCRT.@)
385  *
386  * Unicode version of _findnext.
387  */
388 int CDECL MSVCRT__wfindnext(MSVCRT_intptr_t hand, struct MSVCRT__wfinddata_t * ft)
389 {
390   WIN32_FIND_DATAW find_data;
391
392   if (!FindNextFileW((HANDLE)hand, &find_data))
393   {
394     *MSVCRT__errno() = MSVCRT_ENOENT;
395     return -1;
396   }
397
398   msvcrt_wfttofd(&find_data,ft);
399   return 0;
400 }
401
402 /*********************************************************************
403  *              _findnexti64 (MSVCRT.@)
404  *
405  * 64-bit version of _findnext.
406  */
407 int CDECL MSVCRT__findnexti64(MSVCRT_intptr_t hand, struct MSVCRT__finddatai64_t * ft)
408 {
409   WIN32_FIND_DATAA find_data;
410
411   if (!FindNextFileA((HANDLE)hand, &find_data))
412   {
413     *MSVCRT__errno() = MSVCRT_ENOENT;
414     return -1;
415   }
416
417   msvcrt_fttofdi64(&find_data,ft);
418   return 0;
419 }
420
421 /*********************************************************************
422  *              _findnext64 (MSVCRT.@)
423  *
424  * 64-bit version of _findnext.
425  */
426 int CDECL MSVCRT__findnext64(long hand, struct MSVCRT__finddata64_t * ft)
427 {
428   WIN32_FIND_DATAA find_data;
429
430   if (!FindNextFileA((HANDLE)hand, &find_data))
431   {
432     *MSVCRT__errno() = MSVCRT_ENOENT;
433     return -1;
434   }
435
436   msvcrt_fttofd64(&find_data,ft);
437   return 0;
438 }
439
440 /*********************************************************************
441  *              _wfindnexti64 (MSVCRT.@)
442  *
443  * Unicode version of _findnexti64.
444  */
445 int CDECL MSVCRT__wfindnexti64(MSVCRT_intptr_t hand, struct MSVCRT__wfinddatai64_t * ft)
446 {
447   WIN32_FIND_DATAW find_data;
448
449   if (!FindNextFileW((HANDLE)hand, &find_data))
450   {
451     *MSVCRT__errno() = MSVCRT_ENOENT;
452     return -1;
453   }
454
455   msvcrt_wfttofdi64(&find_data,ft);
456   return 0;
457 }
458
459 /*********************************************************************
460  *              _getcwd (MSVCRT.@)
461  *
462  * Get the current working directory.
463  *
464  * PARAMS
465  *  buf  [O] Destination for current working directory.
466  *  size [I] Size of buf in characters
467  *
468  * RETURNS
469  * Success: If buf is NULL, returns an allocated string containing the path.
470  *          Otherwise populates buf with the path and returns it.
471  * Failure: NULL. errno indicates the error.
472  */
473 char* CDECL _getcwd(char * buf, int size)
474 {
475   char dir[MAX_PATH];
476   int dir_len = GetCurrentDirectoryA(MAX_PATH,dir);
477
478   if (dir_len < 1)
479     return NULL; /* FIXME: Real return value untested */
480
481   if (!buf)
482   {
483       if (size <= dir_len) size = dir_len + 1;
484       if (!(buf = MSVCRT_malloc( size ))) return NULL;
485   }
486   else if (dir_len >= size)
487   {
488     *MSVCRT__errno() = MSVCRT_ERANGE;
489     return NULL; /* buf too small */
490   }
491   strcpy(buf,dir);
492   return buf;
493 }
494
495 /*********************************************************************
496  *              _wgetcwd (MSVCRT.@)
497  *
498  * Unicode version of _getcwd.
499  */
500 MSVCRT_wchar_t* CDECL _wgetcwd(MSVCRT_wchar_t * buf, int size)
501 {
502   MSVCRT_wchar_t dir[MAX_PATH];
503   int dir_len = GetCurrentDirectoryW(MAX_PATH,dir);
504
505   if (dir_len < 1)
506     return NULL; /* FIXME: Real return value untested */
507
508   if (!buf)
509   {
510       if (size <= dir_len) size = dir_len + 1;
511       if (!(buf = MSVCRT_malloc( size * sizeof(WCHAR) ))) return NULL;
512   }
513   if (dir_len >= size)
514   {
515     *MSVCRT__errno() = MSVCRT_ERANGE;
516     return NULL; /* buf too small */
517   }
518   strcpyW(buf,dir);
519   return buf;
520 }
521
522 /*********************************************************************
523  *              _getdrive (MSVCRT.@)
524  *
525  * Get the current drive number.
526  *
527  * PARAMS
528  *  None.
529  *
530  * RETURNS
531  *  Success: The drive letter number from 1 to 26 ("A:" to "Z:").
532  *  Failure: 0.
533  */
534 int CDECL _getdrive(void)
535 {
536     WCHAR buffer[MAX_PATH];
537     if (GetCurrentDirectoryW( MAX_PATH, buffer ) &&
538         buffer[0] >= 'A' && buffer[0] <= 'z' && buffer[1] == ':')
539         return toupperW(buffer[0]) - 'A' + 1;
540     return 0;
541 }
542
543 /*********************************************************************
544  *              _getdcwd (MSVCRT.@)
545  *
546  * Get the current working directory on a given disk.
547  * 
548  * PARAMS
549  *  drive [I] Drive letter to get the current working directory from.
550  *  buf   [O] Destination for the current working directory.
551  *  size  [I] Length of drive in characters.
552  *
553  * RETURNS
554  *  Success: If drive is NULL, returns an allocated string containing the path.
555  *           Otherwise populates drive with the path and returns it.
556  *  Failure: NULL. errno indicates the error.
557  */
558 char* CDECL _getdcwd(int drive, char * buf, int size)
559 {
560   static char* dummy;
561
562   TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
563
564   if (!drive || drive == _getdrive())
565     return _getcwd(buf,size); /* current */
566   else
567   {
568     char dir[MAX_PATH];
569     char drivespec[4] = {'A', ':', 0};
570     int dir_len;
571
572     drivespec[0] += drive - 1;
573     if (GetDriveTypeA(drivespec) < DRIVE_REMOVABLE)
574     {
575       *MSVCRT__errno() = MSVCRT_EACCES;
576       return NULL;
577     }
578
579     dir_len = GetFullPathNameA(drivespec,MAX_PATH,dir,&dummy);
580     if (dir_len >= size || dir_len < 1)
581     {
582       *MSVCRT__errno() = MSVCRT_ERANGE;
583       return NULL; /* buf too small */
584     }
585
586     TRACE(":returning '%s'\n", dir);
587     if (!buf)
588       return _strdup(dir); /* allocate */
589
590     strcpy(buf,dir);
591   }
592   return buf;
593 }
594
595 /*********************************************************************
596  *              _wgetdcwd (MSVCRT.@)
597  *
598  * Unicode version of _wgetdcwd.
599  */
600 MSVCRT_wchar_t* CDECL _wgetdcwd(int drive, MSVCRT_wchar_t * buf, int size)
601 {
602   static MSVCRT_wchar_t* dummy;
603
604   TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
605
606   if (!drive || drive == _getdrive())
607     return _wgetcwd(buf,size); /* current */
608   else
609   {
610     MSVCRT_wchar_t dir[MAX_PATH];
611     MSVCRT_wchar_t drivespec[4] = {'A', ':', '\\', 0};
612     int dir_len;
613
614     drivespec[0] += drive - 1;
615     if (GetDriveTypeW(drivespec) < DRIVE_REMOVABLE)
616     {
617       *MSVCRT__errno() = MSVCRT_EACCES;
618       return NULL;
619     }
620
621     dir_len = GetFullPathNameW(drivespec,MAX_PATH,dir,&dummy);
622     if (dir_len >= size || dir_len < 1)
623     {
624       *MSVCRT__errno() = MSVCRT_ERANGE;
625       return NULL; /* buf too small */
626     }
627
628     TRACE(":returning %s\n", debugstr_w(dir));
629     if (!buf)
630       return _wcsdup(dir); /* allocate */
631     strcpyW(buf,dir);
632   }
633   return buf;
634 }
635
636 /*********************************************************************
637  *              _getdiskfree (MSVCRT.@)
638  *
639  * Get information about the free space on a drive.
640  *
641  * PARAMS
642  *  disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
643  *  info [O] Destination for the resulting information.
644  *
645  * RETURNS
646  *  Success: 0. info is updated with the free space information.
647  *  Failure: An error code from GetLastError().
648  *
649  * NOTES
650  *  See GetLastError().
651  */
652 unsigned int CDECL MSVCRT__getdiskfree(unsigned int disk, struct MSVCRT__diskfree_t * d)
653 {
654   WCHAR drivespec[4] = {'@', ':', '\\', 0};
655   DWORD ret[4];
656   unsigned int err;
657
658   if (disk > 26)
659     return ERROR_INVALID_PARAMETER; /* MSVCRT doesn't set errno here */
660
661   drivespec[0] += disk; /* make a drive letter */
662
663   if (GetDiskFreeSpaceW(disk==0?NULL:drivespec,ret,ret+1,ret+2,ret+3))
664   {
665     d->sectors_per_cluster = ret[0];
666     d->bytes_per_sector = ret[1];
667     d->avail_clusters = ret[2];
668     d->total_clusters = ret[3];
669     return 0;
670   }
671   err = GetLastError();
672   msvcrt_set_errno(err);
673   return err;
674 }
675
676 /*********************************************************************
677  *              _mkdir (MSVCRT.@)
678  *
679  * Create a directory.
680  *
681  * PARAMS
682  *  newdir [I] Name of directory to create.
683  *
684  * RETURNS
685  *  Success: 0. The directory indicated by newdir is created.
686  *  Failure: -1. errno indicates the error.
687  *
688  * NOTES
689  *  See CreateDirectoryA.
690  */
691 int CDECL MSVCRT__mkdir(const char * newdir)
692 {
693   if (CreateDirectoryA(newdir,NULL))
694     return 0;
695   msvcrt_set_errno(GetLastError());
696   return -1;
697 }
698
699 /*********************************************************************
700  *              _wmkdir (MSVCRT.@)
701  *
702  * Unicode version of _mkdir.
703  */
704 int CDECL _wmkdir(const MSVCRT_wchar_t* newdir)
705 {
706   if (CreateDirectoryW(newdir,NULL))
707     return 0;
708   msvcrt_set_errno(GetLastError());
709   return -1;
710 }
711
712 /*********************************************************************
713  *              _rmdir (MSVCRT.@)
714  *
715  * Delete a directory.
716  *
717  * PARAMS
718  *  dir [I] Name of directory to delete.
719  *
720  * RETURNS
721  *  Success: 0. The directory indicated by newdir is deleted.
722  *  Failure: -1. errno indicates the error.
723  *
724  * NOTES
725  *  See RemoveDirectoryA.
726  */
727 int CDECL MSVCRT__rmdir(const char * dir)
728 {
729   if (RemoveDirectoryA(dir))
730     return 0;
731   msvcrt_set_errno(GetLastError());
732   return -1;
733 }
734
735 /*********************************************************************
736  *              _wrmdir (MSVCRT.@)
737  *
738  * Unicode version of _rmdir.
739  */
740 int CDECL _wrmdir(const MSVCRT_wchar_t * dir)
741 {
742   if (RemoveDirectoryW(dir))
743     return 0;
744   msvcrt_set_errno(GetLastError());
745   return -1;
746 }
747
748 /******************************************************************
749  *              _splitpath_s (MSVCRT.@)
750  */
751 int _splitpath_s(const char* inpath,
752         char* drive, MSVCRT_size_t sz_drive,
753         char* dir, MSVCRT_size_t sz_dir,
754         char* fname, MSVCRT_size_t sz_fname,
755         char* ext, MSVCRT_size_t sz_ext)
756 {
757     const char *p, *end;
758
759     if (!inpath || (!drive && sz_drive) ||
760             (drive && !sz_drive) ||
761             (!dir && sz_dir) ||
762             (dir && !sz_dir) ||
763             (!fname && sz_fname) ||
764             (fname && !sz_fname) ||
765             (!ext && sz_ext) ||
766             (ext && !sz_ext))
767     {
768         *MSVCRT__errno() = MSVCRT_EINVAL;
769         return MSVCRT_EINVAL;
770     }
771
772     if (inpath[0] && inpath[1] == ':')
773     {
774         if (drive)
775         {
776             if (sz_drive <= 2) goto do_error;
777             drive[0] = inpath[0];
778             drive[1] = inpath[1];
779             drive[2] = 0;
780         }
781         inpath += 2;
782     }
783     else if (drive) drive[0] = '\0';
784
785     /* look for end of directory part */
786     end = NULL;
787     for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
788
789     if (end)  /* got a directory */
790     {
791         if (dir)
792         {
793             if (sz_dir <= end - inpath) goto do_error;
794             memcpy( dir, inpath, (end - inpath) );
795             dir[end - inpath] = 0;
796         }
797         inpath = end;
798     }
799     else if (dir) dir[0] = 0;
800
801     /* look for extension: what's after the last dot */
802     end = NULL;
803     for (p = inpath; *p; p++) if (*p == '.') end = p;
804
805     if (!end) end = p; /* there's no extension */
806
807     if (fname)
808     {
809         if (sz_fname <= end - inpath) goto do_error;
810         memcpy( fname, inpath, (end - inpath) );
811         fname[end - inpath] = 0;
812     }
813     if (ext)
814     {
815         if (sz_ext <= strlen(end)) goto do_error;
816         strcpy( ext, end );
817     }
818     return 0;
819 do_error:
820     if (drive)  drive[0] = '\0';
821     if (dir)    dir[0] = '\0';
822     if (fname)  fname[0]= '\0';
823     if (ext)    ext[0]= '\0';
824     *MSVCRT__errno() = MSVCRT_ERANGE;
825     return MSVCRT_ERANGE;
826 }
827
828 /*********************************************************************
829  *              _splitpath (MSVCRT.@)
830  */
831 void CDECL _splitpath(const char *inpath, char *drv, char *dir,
832         char *fname, char *ext)
833 {
834     _splitpath_s(inpath, drv, drv?MSVCRT__MAX_DRIVE:0, dir, dir?MSVCRT__MAX_DIR:0,
835             fname, fname?MSVCRT__MAX_FNAME:0, ext, ext?MSVCRT__MAX_EXT:0);
836 }
837
838 /******************************************************************
839  *              _wsplitpath_s (MSVCRT.@)
840  *
841  * Secure version of _wsplitpath
842  */
843 int _wsplitpath_s(const MSVCRT_wchar_t* inpath,
844                   MSVCRT_wchar_t* drive, MSVCRT_size_t sz_drive,
845                   MSVCRT_wchar_t* dir, MSVCRT_size_t sz_dir,
846                   MSVCRT_wchar_t* fname, MSVCRT_size_t sz_fname,
847                   MSVCRT_wchar_t* ext, MSVCRT_size_t sz_ext)
848 {
849     const MSVCRT_wchar_t *p, *end;
850
851     if (!inpath || (!drive && sz_drive) ||
852             (drive && !sz_drive) ||
853             (!dir && sz_dir) ||
854             (dir && !sz_dir) ||
855             (!fname && sz_fname) ||
856             (fname && !sz_fname) ||
857             (!ext && sz_ext) ||
858             (ext && !sz_ext))
859     {
860         *MSVCRT__errno() = MSVCRT_EINVAL;
861         return MSVCRT_EINVAL;
862     }
863
864     if (inpath[0] && inpath[1] == ':')
865     {
866         if (drive)
867         {
868             if (sz_drive <= 2) goto do_error;
869             drive[0] = inpath[0];
870             drive[1] = inpath[1];
871             drive[2] = 0;
872         }
873         inpath += 2;
874     }
875     else if (drive) drive[0] = '\0';
876
877     /* look for end of directory part */
878     end = NULL;
879     for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
880
881     if (end)  /* got a directory */
882     {
883         if (dir)
884         {
885             if (sz_dir <= end - inpath) goto do_error;
886             memcpy( dir, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
887             dir[end - inpath] = 0;
888         }
889         inpath = end;
890     }
891     else if (dir) dir[0] = 0;
892
893     /* look for extension: what's after the last dot */
894     end = NULL;
895     for (p = inpath; *p; p++) if (*p == '.') end = p;
896
897     if (!end) end = p; /* there's no extension */
898
899     if (fname)
900     {
901         if (sz_fname <= end - inpath) goto do_error;
902         memcpy( fname, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
903         fname[end - inpath] = 0;
904     }
905     if (ext)
906     {
907         if (sz_ext <= strlenW(end)) goto do_error;
908         strcpyW( ext, end );
909     }
910     return 0;
911 do_error:
912     if (drive)  drive[0] = '\0';
913     if (dir)    dir[0] = '\0';
914     if (fname)  fname[0]= '\0';
915     if (ext)    ext[0]= '\0';
916     *MSVCRT__errno() = MSVCRT_ERANGE;
917     return MSVCRT_ERANGE;
918 }
919
920 /*********************************************************************
921  *              _wsplitpath (MSVCRT.@)
922  *
923  * Unicode version of _splitpath.
924  */
925 void CDECL _wsplitpath(const MSVCRT_wchar_t *inpath, MSVCRT_wchar_t *drv, MSVCRT_wchar_t *dir,
926         MSVCRT_wchar_t *fname, MSVCRT_wchar_t *ext)
927 {
928     _wsplitpath_s(inpath, drv, drv?MSVCRT__MAX_DRIVE:0, dir, dir?MSVCRT__MAX_DIR:0,
929             fname, fname?MSVCRT__MAX_FNAME:0, ext, ext?MSVCRT__MAX_EXT:0);
930 }
931
932 /*********************************************************************
933  *              _wfullpath (MSVCRT.@)
934  *
935  * Unicode version of _fullpath.
936  */
937 MSVCRT_wchar_t * CDECL _wfullpath(MSVCRT_wchar_t * absPath, const MSVCRT_wchar_t* relPath, MSVCRT_size_t size)
938 {
939   DWORD rc;
940   WCHAR* buffer;
941   WCHAR* lastpart;
942   BOOL alloced = FALSE;
943
944   if (!relPath || !*relPath)
945     return _wgetcwd(absPath, size);
946
947   if (absPath == NULL)
948   {
949       buffer = MSVCRT_malloc(MAX_PATH * sizeof(WCHAR));
950       size = MAX_PATH;
951       alloced = TRUE;
952   }
953   else
954       buffer = absPath;
955
956   if (size < 4)
957   {
958     *MSVCRT__errno() = MSVCRT_ERANGE;
959     return NULL;
960   }
961
962   TRACE(":resolving relative path %s\n",debugstr_w(relPath));
963
964   rc = GetFullPathNameW(relPath,size,buffer,&lastpart);
965
966   if (rc > 0 && rc <= size )
967     return buffer;
968   else
969   {
970       if (alloced)
971           MSVCRT_free(buffer);
972         return NULL;
973   }
974 }
975
976 /*********************************************************************
977  *              _fullpath (MSVCRT.@)
978  *
979  * Create an absolute path from a relative path.
980  *
981  * PARAMS
982  *  absPath [O] Destination for absolute path
983  *  relPath [I] Relative path to convert to absolute
984  *  size    [I] Length of absPath in characters.
985  *
986  * RETURNS
987  * Success: If absPath is NULL, returns an allocated string containing the path.
988  *          Otherwise populates absPath with the path and returns it.
989  * Failure: NULL. errno indicates the error.
990  */
991 char * CDECL _fullpath(char * absPath, const char* relPath, unsigned int size)
992 {
993   DWORD rc;
994   char* lastpart;
995   char* buffer;
996   BOOL alloced = FALSE;
997
998   if (!relPath || !*relPath)
999     return _getcwd(absPath, size);
1000
1001   if (absPath == NULL)
1002   {
1003       buffer = MSVCRT_malloc(MAX_PATH);
1004       size = MAX_PATH;
1005       alloced = TRUE;
1006   }
1007   else
1008       buffer = absPath;
1009
1010   if (size < 4)
1011   {
1012     *MSVCRT__errno() = MSVCRT_ERANGE;
1013     return NULL;
1014   }
1015
1016   TRACE(":resolving relative path '%s'\n",relPath);
1017
1018   rc = GetFullPathNameA(relPath,size,buffer,&lastpart);
1019
1020   if (rc > 0 && rc <= size)
1021     return buffer;
1022   else
1023   {
1024       if (alloced)
1025           MSVCRT_free(buffer);
1026         return NULL;
1027   }
1028 }
1029
1030 /*********************************************************************
1031  *              _makepath (MSVCRT.@)
1032  *
1033  * Create a pathname.
1034  *
1035  * PARAMS
1036  *  path      [O] Destination for created pathname
1037  *  drive     [I] Drive letter (e.g. "A:")
1038  *  directory [I] Directory
1039  *  filename  [I] Name of the file, excluding extension
1040  *  extension [I] File extension (e.g. ".TXT")
1041  *
1042  * RETURNS
1043  *  Nothing. If path is not large enough to hold the resulting pathname,
1044  *  random process memory will be overwritten.
1045  */
1046 VOID CDECL _makepath(char * path, const char * drive,
1047                      const char *directory, const char * filename,
1048                      const char * extension)
1049 {
1050     char *p = path;
1051
1052     TRACE("(%s %s %s %s)\n", debugstr_a(drive), debugstr_a(directory),
1053           debugstr_a(filename), debugstr_a(extension) );
1054
1055     if ( !path )
1056         return;
1057
1058     if (drive && drive[0])
1059     {
1060         *p++ = drive[0];
1061         *p++ = ':';
1062     }
1063     if (directory && directory[0])
1064     {
1065         unsigned int len = strlen(directory);
1066         memmove(p, directory, len);
1067         p += len;
1068         if (p[-1] != '/' && p[-1] != '\\')
1069             *p++ = '\\';
1070     }
1071     if (filename && filename[0])
1072     {
1073         unsigned int len = strlen(filename);
1074         memmove(p, filename, len);
1075         p += len;
1076     }
1077     if (extension && extension[0])
1078     {
1079         if (extension[0] != '.')
1080             *p++ = '.';
1081         strcpy(p, extension);
1082     }
1083     else
1084         *p = '\0';
1085     TRACE("returning %s\n",path);
1086 }
1087
1088 /*********************************************************************
1089  *              _wmakepath (MSVCRT.@)
1090  *
1091  * Unicode version of _wmakepath.
1092  */
1093 VOID CDECL _wmakepath(MSVCRT_wchar_t *path, const MSVCRT_wchar_t *drive, const MSVCRT_wchar_t *directory,
1094                       const MSVCRT_wchar_t *filename, const MSVCRT_wchar_t *extension)
1095 {
1096     MSVCRT_wchar_t *p = path;
1097
1098     TRACE("%s %s %s %s\n", debugstr_w(drive), debugstr_w(directory),
1099           debugstr_w(filename), debugstr_w(extension));
1100
1101     if ( !path )
1102         return;
1103
1104     if (drive && drive[0])
1105     {
1106         *p++ = drive[0];
1107         *p++ = ':';
1108     }
1109     if (directory && directory[0])
1110     {
1111         unsigned int len = strlenW(directory);
1112         memmove(p, directory, len * sizeof(MSVCRT_wchar_t));
1113         p += len;
1114         if (p[-1] != '/' && p[-1] != '\\')
1115             *p++ = '\\';
1116     }
1117     if (filename && filename[0])
1118     {
1119         unsigned int len = strlenW(filename);
1120         memmove(p, filename, len * sizeof(MSVCRT_wchar_t));
1121         p += len;
1122     }
1123     if (extension && extension[0])
1124     {
1125         if (extension[0] != '.')
1126             *p++ = '.';
1127         strcpyW(p, extension);
1128     }
1129     else
1130         *p = '\0';
1131
1132     TRACE("returning %s\n", debugstr_w(path));
1133 }
1134
1135 /*********************************************************************
1136  *              _makepath_s (MSVCRT.@)
1137  *
1138  * Safe version of _makepath.
1139  */
1140 int CDECL _makepath_s(char *path, MSVCRT_size_t size, const char *drive,
1141                       const char *directory, const char *filename,
1142                       const char *extension)
1143 {
1144     char *p = path;
1145
1146     if (!path || !size)
1147     {
1148         *MSVCRT__errno() = MSVCRT_EINVAL;
1149         return MSVCRT_EINVAL;
1150     }
1151
1152     if (drive && drive[0])
1153     {
1154         if (size <= 2)
1155             goto range;
1156
1157         *p++ = drive[0];
1158         *p++ = ':';
1159         size -= 2;
1160     }
1161
1162     if (directory && directory[0])
1163     {
1164         unsigned int len = strlen(directory);
1165         unsigned int needs_separator = directory[len - 1] != '/' && directory[len - 1] != '\\';
1166         unsigned int copylen = min(size - 1, len);
1167
1168         if (size < 2)
1169             goto range;
1170
1171         memmove(p, directory, copylen);
1172
1173         if (size <= len)
1174             goto range;
1175
1176         p += copylen;
1177         size -= copylen;
1178
1179         if (needs_separator)
1180         {
1181             if (size < 2)
1182                 goto range;
1183
1184             *p++ = '\\';
1185             size -= 1;
1186         }
1187     }
1188
1189     if (filename && filename[0])
1190     {
1191         unsigned int len = strlen(filename);
1192         unsigned int copylen = min(size - 1, len);
1193
1194         if (size < 2)
1195             goto range;
1196
1197         memmove(p, filename, copylen);
1198
1199         if (size <= len)
1200             goto range;
1201
1202         p += len;
1203         size -= len;
1204     }
1205
1206     if (extension && extension[0])
1207     {
1208         unsigned int len = strlen(extension);
1209         unsigned int needs_period = extension[0] != '.';
1210         unsigned int copylen;
1211
1212         if (size < 2)
1213             goto range;
1214
1215         if (needs_period)
1216         {
1217             *p++ = '.';
1218             size -= 1;
1219         }
1220
1221         copylen = min(size - 1, len);
1222         memcpy(p, extension, copylen);
1223
1224         if (size <= len)
1225             goto range;
1226
1227         p += copylen;
1228     }
1229
1230     *p = '\0';
1231     return 0;
1232
1233 range:
1234     path[0] = '\0';
1235     *MSVCRT__errno() = MSVCRT_ERANGE;
1236     return MSVCRT_ERANGE;
1237 }
1238
1239 /*********************************************************************
1240  *              _wmakepath_s (MSVCRT.@)
1241  *
1242  * Safe version of _wmakepath.
1243  */
1244 int CDECL _wmakepath_s(MSVCRT_wchar_t *path, MSVCRT_size_t size, const MSVCRT_wchar_t *drive,
1245                        const MSVCRT_wchar_t *directory, const MSVCRT_wchar_t *filename,
1246                        const MSVCRT_wchar_t *extension)
1247 {
1248     MSVCRT_wchar_t *p = path;
1249
1250     if (!path || !size)
1251     {
1252         *MSVCRT__errno() = MSVCRT_EINVAL;
1253         return MSVCRT_EINVAL;
1254     }
1255
1256     if (drive && drive[0])
1257     {
1258         if (size <= 2)
1259             goto range;
1260
1261         *p++ = drive[0];
1262         *p++ = ':';
1263         size -= 2;
1264     }
1265
1266     if (directory && directory[0])
1267     {
1268         unsigned int len = strlenW(directory);
1269         unsigned int needs_separator = directory[len - 1] != '/' && directory[len - 1] != '\\';
1270         unsigned int copylen = min(size - 1, len);
1271
1272         if (size < 2)
1273             goto range;
1274
1275         memmove(p, directory, copylen * sizeof(MSVCRT_wchar_t));
1276
1277         if (size <= len)
1278             goto range;
1279
1280         p += copylen;
1281         size -= copylen;
1282
1283         if (needs_separator)
1284         {
1285             if (size < 2)
1286                 goto range;
1287
1288             *p++ = '\\';
1289             size -= 1;
1290         }
1291     }
1292
1293     if (filename && filename[0])
1294     {
1295         unsigned int len = strlenW(filename);
1296         unsigned int copylen = min(size - 1, len);
1297
1298         if (size < 2)
1299             goto range;
1300
1301         memmove(p, filename, copylen * sizeof(MSVCRT_wchar_t));
1302
1303         if (size <= len)
1304             goto range;
1305
1306         p += len;
1307         size -= len;
1308     }
1309
1310     if (extension && extension[0])
1311     {
1312         unsigned int len = strlenW(extension);
1313         unsigned int needs_period = extension[0] != '.';
1314         unsigned int copylen;
1315
1316         if (size < 2)
1317             goto range;
1318
1319         if (needs_period)
1320         {
1321             *p++ = '.';
1322             size -= 1;
1323         }
1324
1325         copylen = min(size - 1, len);
1326         memcpy(p, extension, copylen * sizeof(MSVCRT_wchar_t));
1327
1328         if (size <= len)
1329             goto range;
1330
1331         p += copylen;
1332     }
1333
1334     *p = '\0';
1335     return 0;
1336
1337 range:
1338     path[0] = '\0';
1339     *MSVCRT__errno() = MSVCRT_ERANGE;
1340     return MSVCRT_ERANGE;
1341 }
1342
1343 /*********************************************************************
1344  *              _searchenv (MSVCRT.@)
1345  *
1346  * Search for a file in a list of paths from an environment variable.
1347  *
1348  * PARAMS
1349  *  file   [I] Name of the file to search for.
1350  *  env    [I] Name of the environment variable containing a list of paths.
1351  *  buf    [O] Destination for the found file path.
1352  *
1353  * RETURNS
1354  *  Nothing. If the file is not found, buf will contain an empty string
1355  *  and errno is set.
1356  */
1357 void CDECL _searchenv(const char* file, const char* env, char *buf)
1358 {
1359   char*envVal, *penv;
1360   char curPath[MAX_PATH];
1361
1362   *buf = '\0';
1363
1364   /* Try CWD first */
1365   if (GetFileAttributesA( file ) != INVALID_FILE_ATTRIBUTES)
1366   {
1367     GetFullPathNameA( file, MAX_PATH, buf, NULL );
1368     /* Sigh. This error is *always* set, regardless of success */
1369     msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1370     return;
1371   }
1372
1373   /* Search given environment variable */
1374   envVal = MSVCRT_getenv(env);
1375   if (!envVal)
1376   {
1377     msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1378     return;
1379   }
1380
1381   penv = envVal;
1382   TRACE(":searching for %s in paths %s\n", file, envVal);
1383
1384   do
1385   {
1386     char *end = penv;
1387
1388     while(*end && *end != ';') end++; /* Find end of next path */
1389     if (penv == end || !*penv)
1390     {
1391       msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1392       return;
1393     }
1394     memcpy(curPath, penv, end - penv);
1395     if (curPath[end - penv] != '/' && curPath[end - penv] != '\\')
1396     {
1397       curPath[end - penv] = '\\';
1398       curPath[end - penv + 1] = '\0';
1399     }
1400     else
1401       curPath[end - penv] = '\0';
1402
1403     strcat(curPath, file);
1404     TRACE("Checking for file %s\n", curPath);
1405     if (GetFileAttributesA( curPath ) != INVALID_FILE_ATTRIBUTES)
1406     {
1407       strcpy(buf, curPath);
1408       msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1409       return; /* Found */
1410     }
1411     penv = *end ? end + 1 : end;
1412   } while(1);
1413 }
1414
1415 /*********************************************************************
1416  *      _wsearchenv (MSVCRT.@)
1417  *
1418  * Unicode version of _searchenv
1419  */
1420 void CDECL _wsearchenv(const MSVCRT_wchar_t* file, const MSVCRT_wchar_t* env, MSVCRT_wchar_t *buf)
1421 {
1422   MSVCRT_wchar_t *envVal, *penv;
1423   MSVCRT_wchar_t curPath[MAX_PATH];
1424
1425   *buf = '\0';
1426
1427   /* Try CWD first */
1428   if (GetFileAttributesW( file ) != INVALID_FILE_ATTRIBUTES)
1429   {
1430     GetFullPathNameW( file, MAX_PATH, buf, NULL );
1431     /* Sigh. This error is *always* set, regardless of success */
1432     msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1433     return;
1434   }
1435
1436   /* Search given environment variable */
1437   envVal = _wgetenv(env);
1438   if (!envVal)
1439   {
1440     msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1441     return;
1442   }
1443
1444   penv = envVal;
1445   TRACE(":searching for %s in paths %s\n", debugstr_w(file), debugstr_w(envVal));
1446
1447   do
1448   {
1449     MSVCRT_wchar_t *end = penv;
1450
1451     while(*end && *end != ';') end++; /* Find end of next path */
1452     if (penv == end || !*penv)
1453     {
1454       msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1455       return;
1456     }
1457     memcpy(curPath, penv, (end - penv) * sizeof(MSVCRT_wchar_t));
1458     if (curPath[end - penv] != '/' && curPath[end - penv] != '\\')
1459     {
1460       curPath[end - penv] = '\\';
1461       curPath[end - penv + 1] = '\0';
1462     }
1463     else
1464       curPath[end - penv] = '\0';
1465
1466     strcatW(curPath, file);
1467     TRACE("Checking for file %s\n", debugstr_w(curPath));
1468     if (GetFileAttributesW( curPath ) != INVALID_FILE_ATTRIBUTES)
1469     {
1470       strcpyW(buf, curPath);
1471       msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1472       return; /* Found */
1473     }
1474     penv = *end ? end + 1 : end;
1475   } while(1);
1476 }