blob: f623f3c472dc2ec6c6e9b856653bd640d043f9f5 [file] [log] [blame]
Jon Griffiths1db20bf2001-01-10 23:59:25 +00001/*
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
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00008 *
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
Jonathan Ernst360a3f92006-05-18 14:49:52 +020021 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Jon Griffiths1db20bf2001-01-10 23:59:25 +000022 */
23
Alexandre Julliard5769d1d2002-04-26 19:05:15 +000024#include "config.h"
25#include "wine/port.h"
26
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000027#include <stdarg.h>
Jon Griffiths1db20bf2001-01-10 23:59:25 +000028#include <time.h>
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000029
30#include "windef.h"
31#include "winbase.h"
32#include "winreg.h"
Patrik Stridvall9c1de6d2002-09-12 22:07:02 +000033#include "winternl.h"
Jon Griffiths1db20bf2001-01-10 23:59:25 +000034#include "wine/unicode.h"
35#include "msvcrt.h"
Alexandre Julliardbd1689e2002-01-22 00:57:16 +000036#include "wine/debug.h"
37
38WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
Jon Griffiths1db20bf2001-01-10 23:59:25 +000039
Alexandre Julliarddec198a2004-01-13 05:45:05 +000040/* INTERNAL: Translate WIN32_FIND_DATAA to finddata_t */
Hans Leidekker821f4772004-03-16 19:17:11 +000041static void msvcrt_fttofd( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata_t* ft)
Jon Griffiths1db20bf2001-01-10 23:59:25 +000042{
43 DWORD dw;
44
45 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
46 ft->attrib = 0;
47 else
48 ft->attrib = fd->dwFileAttributes;
49
Eric Pouech0a258962004-11-30 21:38:57 +000050 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
Jon Griffiths1db20bf2001-01-10 23:59:25 +000051 ft->time_create = dw;
Eric Pouech0a258962004-11-30 21:38:57 +000052 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
Jon Griffiths1db20bf2001-01-10 23:59:25 +000053 ft->time_access = dw;
Eric Pouech0a258962004-11-30 21:38:57 +000054 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
Jon Griffiths1db20bf2001-01-10 23:59:25 +000055 ft->time_write = dw;
56 ft->size = fd->nFileSizeLow;
57 strcpy(ft->name, fd->cFileName);
58}
59
Alexandre Julliarddec198a2004-01-13 05:45:05 +000060/* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata_t */
Hans Leidekker821f4772004-03-16 19:17:11 +000061static void msvcrt_wfttofd( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata_t* ft)
Jon Griffiths1db20bf2001-01-10 23:59:25 +000062{
63 DWORD dw;
64
65 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
66 ft->attrib = 0;
67 else
68 ft->attrib = fd->dwFileAttributes;
69
Eric Pouech0a258962004-11-30 21:38:57 +000070 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
Jon Griffiths1db20bf2001-01-10 23:59:25 +000071 ft->time_create = dw;
Eric Pouech0a258962004-11-30 21:38:57 +000072 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
Jon Griffiths1db20bf2001-01-10 23:59:25 +000073 ft->time_access = dw;
Eric Pouech0a258962004-11-30 21:38:57 +000074 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
Jon Griffiths1db20bf2001-01-10 23:59:25 +000075 ft->time_write = dw;
76 ft->size = fd->nFileSizeLow;
77 strcpyW(ft->name, fd->cFileName);
78}
79
Alexandre Julliarddec198a2004-01-13 05:45:05 +000080/* INTERNAL: Translate WIN32_FIND_DATAA to finddatai64_t */
Hans Leidekker821f4772004-03-16 19:17:11 +000081static void msvcrt_fttofdi64( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddatai64_t* ft)
Alexandre Julliarddec198a2004-01-13 05:45:05 +000082{
83 DWORD dw;
84
85 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
86 ft->attrib = 0;
87 else
88 ft->attrib = fd->dwFileAttributes;
89
Eric Pouech0a258962004-11-30 21:38:57 +000090 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
Alexandre Julliarddec198a2004-01-13 05:45:05 +000091 ft->time_create = dw;
Eric Pouech0a258962004-11-30 21:38:57 +000092 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
Alexandre Julliarddec198a2004-01-13 05:45:05 +000093 ft->time_access = dw;
Eric Pouech0a258962004-11-30 21:38:57 +000094 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
Alexandre Julliarddec198a2004-01-13 05:45:05 +000095 ft->time_write = dw;
96 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
97 strcpy(ft->name, fd->cFileName);
98}
99
100/* INTERNAL: Translate WIN32_FIND_DATAW to wfinddatai64_t */
Hans Leidekker821f4772004-03-16 19:17:11 +0000101static void msvcrt_wfttofdi64( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddatai64_t* ft)
Alexandre Julliarddec198a2004-01-13 05:45:05 +0000102{
103 DWORD dw;
104
105 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
106 ft->attrib = 0;
107 else
108 ft->attrib = fd->dwFileAttributes;
109
Eric Pouech0a258962004-11-30 21:38:57 +0000110 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
Alexandre Julliarddec198a2004-01-13 05:45:05 +0000111 ft->time_create = dw;
Eric Pouech0a258962004-11-30 21:38:57 +0000112 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
Alexandre Julliarddec198a2004-01-13 05:45:05 +0000113 ft->time_access = dw;
Eric Pouech0a258962004-11-30 21:38:57 +0000114 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
Alexandre Julliarddec198a2004-01-13 05:45:05 +0000115 ft->time_write = dw;
116 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
117 strcpyW(ft->name, fd->cFileName);
118}
119
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000120/*********************************************************************
121 * _chdir (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000122 *
123 * Change the current working directory.
124 *
125 * PARAMS
126 * newdir [I] Directory to change to
127 *
128 * RETURNS
129 * Success: 0. The current working directory is set to newdir.
130 * Failure: -1. errno indicates the error.
131 *
132 * NOTES
133 * See SetCurrentDirectoryA.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000134 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200135int CDECL _chdir(const char * newdir)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000136{
137 if (!SetCurrentDirectoryA(newdir))
138 {
Dimitrie O. Paun03774622004-06-25 01:19:15 +0000139 msvcrt_set_errno(newdir?GetLastError():0);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000140 return -1;
141 }
142 return 0;
143}
144
145/*********************************************************************
146 * _wchdir (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000147 *
148 * Unicode version of _chdir.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000149 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200150int CDECL _wchdir(const MSVCRT_wchar_t * newdir)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000151{
152 if (!SetCurrentDirectoryW(newdir))
153 {
Dimitrie O. Paun03774622004-06-25 01:19:15 +0000154 msvcrt_set_errno(newdir?GetLastError():0);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000155 return -1;
156 }
157 return 0;
158}
159
160/*********************************************************************
161 * _chdrive (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000162 *
163 * Change the current drive.
164 *
165 * PARAMS
166 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
167 *
168 * RETURNS
169 * Success: 0. The current drive is set to newdrive.
170 * Failure: -1. errno indicates the error.
171 *
172 * NOTES
173 * See SetCurrentDirectoryA.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000174 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200175int CDECL _chdrive(int newdrive)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000176{
Jon Griffithsf90092c2004-02-09 20:45:59 +0000177 WCHAR buffer[3] = {'A', ':', 0};
178
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000179 buffer[0] += newdrive - 1;
Jon Griffithsf90092c2004-02-09 20:45:59 +0000180 if (!SetCurrentDirectoryW( buffer ))
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000181 {
Dimitrie O. Paun03774622004-06-25 01:19:15 +0000182 msvcrt_set_errno(GetLastError());
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000183 if (newdrive <= 0)
Alexandre Julliard44b42352002-07-19 03:24:50 +0000184 *MSVCRT__errno() = MSVCRT_EACCES;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000185 return -1;
186 }
187 return 0;
188}
189
190/*********************************************************************
191 * _findclose (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000192 *
193 * Close a handle returned by _findfirst().
194 *
195 * PARAMS
196 * hand [I] Handle to close
197 *
198 * RETURNS
199 * Success: 0. All resources associated with hand are freed.
200 * Failure: -1. errno indicates the error.
201 *
202 * NOTES
203 * See FindClose.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000204 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200205int CDECL MSVCRT__findclose(long hand)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000206{
207 TRACE(":handle %ld\n",hand);
208 if (!FindClose((HANDLE)hand))
209 {
Dimitrie O. Paun03774622004-06-25 01:19:15 +0000210 msvcrt_set_errno(GetLastError());
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000211 return -1;
212 }
213 return 0;
214}
215
216/*********************************************************************
217 * _findfirst (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000218 *
219 * Open a handle for iterating through a directory.
220 *
221 * PARAMS
222 * fspec [I] File specification of files to iterate.
223 * ft [O] Information for the first file found.
224 *
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.
229 *
230 * NOTES
231 * See FindFirstFileA.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000232 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200233long CDECL MSVCRT__findfirst(const char * fspec, struct MSVCRT__finddata_t* ft)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000234{
235 WIN32_FIND_DATAA find_data;
236 HANDLE hfind;
237
238 hfind = FindFirstFileA(fspec, &find_data);
239 if (hfind == INVALID_HANDLE_VALUE)
240 {
Dimitrie O. Paun03774622004-06-25 01:19:15 +0000241 msvcrt_set_errno(GetLastError());
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000242 return -1;
243 }
Francois Gouget203a8f82001-04-10 21:16:07 +0000244 msvcrt_fttofd(&find_data,ft);
Michael Stefaniuc789b4b42002-10-25 03:12:01 +0000245 TRACE(":got handle %p\n",hfind);
246 return (long)hfind;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000247}
248
249/*********************************************************************
250 * _wfindfirst (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000251 *
252 * Unicode version of _findfirst.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000253 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200254long CDECL MSVCRT__wfindfirst(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddata_t* ft)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000255{
256 WIN32_FIND_DATAW find_data;
257 HANDLE hfind;
258
259 hfind = FindFirstFileW(fspec, &find_data);
260 if (hfind == INVALID_HANDLE_VALUE)
261 {
Dimitrie O. Paun03774622004-06-25 01:19:15 +0000262 msvcrt_set_errno(GetLastError());
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000263 return -1;
264 }
Francois Gouget203a8f82001-04-10 21:16:07 +0000265 msvcrt_wfttofd(&find_data,ft);
Michael Stefaniuc789b4b42002-10-25 03:12:01 +0000266 TRACE(":got handle %p\n",hfind);
267 return (long)hfind;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000268}
269
270/*********************************************************************
Alexandre Julliarddec198a2004-01-13 05:45:05 +0000271 * _findfirsti64 (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000272 *
273 * 64-bit version of _findfirst.
Alexandre Julliarddec198a2004-01-13 05:45:05 +0000274 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200275long CDECL MSVCRT__findfirsti64(const char * fspec, struct MSVCRT__finddatai64_t* ft)
Alexandre Julliarddec198a2004-01-13 05:45:05 +0000276{
277 WIN32_FIND_DATAA find_data;
278 HANDLE hfind;
279
280 hfind = FindFirstFileA(fspec, &find_data);
281 if (hfind == INVALID_HANDLE_VALUE)
282 {
Dimitrie O. Paun03774622004-06-25 01:19:15 +0000283 msvcrt_set_errno(GetLastError());
Alexandre Julliarddec198a2004-01-13 05:45:05 +0000284 return -1;
285 }
286 msvcrt_fttofdi64(&find_data,ft);
287 TRACE(":got handle %p\n",hfind);
288 return (long)hfind;
289}
290
291/*********************************************************************
292 * _wfindfirsti64 (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000293 *
294 * Unicode version of _findfirsti64.
Alexandre Julliarddec198a2004-01-13 05:45:05 +0000295 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200296long CDECL MSVCRT__wfindfirsti64(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddatai64_t* ft)
Alexandre Julliarddec198a2004-01-13 05:45:05 +0000297{
298 WIN32_FIND_DATAW find_data;
299 HANDLE hfind;
300
301 hfind = FindFirstFileW(fspec, &find_data);
302 if (hfind == INVALID_HANDLE_VALUE)
303 {
Dimitrie O. Paun03774622004-06-25 01:19:15 +0000304 msvcrt_set_errno(GetLastError());
Alexandre Julliarddec198a2004-01-13 05:45:05 +0000305 return -1;
306 }
307 msvcrt_wfttofdi64(&find_data,ft);
308 TRACE(":got handle %p\n",hfind);
309 return (long)hfind;
310}
311
312/*********************************************************************
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000313 * _findnext (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000314 *
315 * Find the next file from a file search handle.
316 *
317 * PARAMS
318 * hand [I] Handle to the search returned from _findfirst().
319 * ft [O] Information for the file found.
320 *
321 * RETURNS
322 * Success: 0. ft is populated with the details of the found file.
323 * Failure: -1. errno indicates the error.
324 *
325 * NOTES
326 * See FindNextFileA.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000327 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200328int CDECL MSVCRT__findnext(long hand, struct MSVCRT__finddata_t * ft)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000329{
330 WIN32_FIND_DATAA find_data;
331
Michael Stefaniuc789b4b42002-10-25 03:12:01 +0000332 if (!FindNextFileA((HANDLE)hand, &find_data))
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000333 {
Alexandre Julliard44b42352002-07-19 03:24:50 +0000334 *MSVCRT__errno() = MSVCRT_ENOENT;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000335 return -1;
336 }
337
Francois Gouget203a8f82001-04-10 21:16:07 +0000338 msvcrt_fttofd(&find_data,ft);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000339 return 0;
340}
341
342/*********************************************************************
343 * _wfindnext (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000344 *
345 * Unicode version of _findnext.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000346 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200347int CDECL MSVCRT__wfindnext(long hand, struct MSVCRT__wfinddata_t * ft)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000348{
349 WIN32_FIND_DATAW find_data;
350
Michael Stefaniuc789b4b42002-10-25 03:12:01 +0000351 if (!FindNextFileW((HANDLE)hand, &find_data))
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000352 {
Alexandre Julliard44b42352002-07-19 03:24:50 +0000353 *MSVCRT__errno() = MSVCRT_ENOENT;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000354 return -1;
355 }
356
Francois Gouget203a8f82001-04-10 21:16:07 +0000357 msvcrt_wfttofd(&find_data,ft);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000358 return 0;
359}
360
361/*********************************************************************
Alexandre Julliarddec198a2004-01-13 05:45:05 +0000362 * _findnexti64 (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000363 *
364 * 64-bit version of _findnext.
Alexandre Julliarddec198a2004-01-13 05:45:05 +0000365 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200366int CDECL MSVCRT__findnexti64(long hand, struct MSVCRT__finddatai64_t * ft)
Alexandre Julliarddec198a2004-01-13 05:45:05 +0000367{
368 WIN32_FIND_DATAA find_data;
369
370 if (!FindNextFileA((HANDLE)hand, &find_data))
371 {
372 *MSVCRT__errno() = MSVCRT_ENOENT;
373 return -1;
374 }
375
376 msvcrt_fttofdi64(&find_data,ft);
377 return 0;
378}
379
380/*********************************************************************
381 * _wfindnexti64 (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000382 *
383 * Unicode version of _findnexti64.
Alexandre Julliarddec198a2004-01-13 05:45:05 +0000384 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200385int CDECL MSVCRT__wfindnexti64(long hand, struct MSVCRT__wfinddatai64_t * ft)
Alexandre Julliarddec198a2004-01-13 05:45:05 +0000386{
387 WIN32_FIND_DATAW find_data;
388
389 if (!FindNextFileW((HANDLE)hand, &find_data))
390 {
391 *MSVCRT__errno() = MSVCRT_ENOENT;
392 return -1;
393 }
394
395 msvcrt_wfttofdi64(&find_data,ft);
396 return 0;
397}
398
399/*********************************************************************
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000400 * _getcwd (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000401 *
402 * Get the current working directory.
403 *
404 * PARAMS
405 * buf [O] Destination for current working directory.
406 * size [I] Size of buf in characters
407 *
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.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000412 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200413char* CDECL _getcwd(char * buf, int size)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000414{
Alexandre Julliardb53f1302002-05-01 18:13:18 +0000415 char dir[MAX_PATH];
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000416 int dir_len = GetCurrentDirectoryA(MAX_PATH,dir);
417
418 if (dir_len < 1)
419 return NULL; /* FIXME: Real return value untested */
420
421 if (!buf)
422 {
423 if (size < 0)
Francois Gouget203a8f82001-04-10 21:16:07 +0000424 return _strdup(dir);
425 return msvcrt_strndup(dir,size);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000426 }
427 if (dir_len >= size)
428 {
Alexandre Julliard44b42352002-07-19 03:24:50 +0000429 *MSVCRT__errno() = MSVCRT_ERANGE;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000430 return NULL; /* buf too small */
431 }
432 strcpy(buf,dir);
433 return buf;
434}
435
436/*********************************************************************
437 * _wgetcwd (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000438 *
439 * Unicode version of _getcwd.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000440 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200441MSVCRT_wchar_t* CDECL _wgetcwd(MSVCRT_wchar_t * buf, int size)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000442{
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000443 MSVCRT_wchar_t dir[MAX_PATH];
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000444 int dir_len = GetCurrentDirectoryW(MAX_PATH,dir);
445
446 if (dir_len < 1)
447 return NULL; /* FIXME: Real return value untested */
448
449 if (!buf)
450 {
451 if (size < 0)
Francois Gouget203a8f82001-04-10 21:16:07 +0000452 return _wcsdup(dir);
453 return msvcrt_wstrndup(dir,size);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000454 }
455 if (dir_len >= size)
456 {
Alexandre Julliard44b42352002-07-19 03:24:50 +0000457 *MSVCRT__errno() = MSVCRT_ERANGE;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000458 return NULL; /* buf too small */
459 }
460 strcpyW(buf,dir);
461 return buf;
462}
463
464/*********************************************************************
465 * _getdrive (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000466 *
467 * Get the current drive number.
468 *
469 * PARAMS
470 * None.
471 *
472 * RETURNS
473 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
474 * Failure: 0.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000475 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200476int CDECL _getdrive(void)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000477{
Jon Griffithsf90092c2004-02-09 20:45:59 +0000478 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;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000483}
484
485/*********************************************************************
486 * _getdcwd (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000487 *
488 * Get the current working directory on a given disk.
489 *
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.
494 *
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.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000499 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200500char* CDECL _getdcwd(int drive, char * buf, int size)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000501{
502 static char* dummy;
503
504 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
505
Francois Gouget203a8f82001-04-10 21:16:07 +0000506 if (!drive || drive == _getdrive())
507 return _getcwd(buf,size); /* current */
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000508 else
509 {
Alexandre Julliardb53f1302002-05-01 18:13:18 +0000510 char dir[MAX_PATH];
Gunnar Dalsnes1b7e7362005-02-18 12:51:00 +0000511 char drivespec[4] = {'A', ':', 0};
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000512 int dir_len;
513
514 drivespec[0] += drive - 1;
515 if (GetDriveTypeA(drivespec) < DRIVE_REMOVABLE)
516 {
Alexandre Julliard44b42352002-07-19 03:24:50 +0000517 *MSVCRT__errno() = MSVCRT_EACCES;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000518 return NULL;
519 }
520
Alexandre Julliardb53f1302002-05-01 18:13:18 +0000521 dir_len = GetFullPathNameA(drivespec,MAX_PATH,dir,&dummy);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000522 if (dir_len >= size || dir_len < 1)
523 {
Alexandre Julliard44b42352002-07-19 03:24:50 +0000524 *MSVCRT__errno() = MSVCRT_ERANGE;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000525 return NULL; /* buf too small */
526 }
527
528 TRACE(":returning '%s'\n", dir);
529 if (!buf)
Francois Gouget203a8f82001-04-10 21:16:07 +0000530 return _strdup(dir); /* allocate */
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000531
532 strcpy(buf,dir);
533 }
534 return buf;
535}
536
537/*********************************************************************
538 * _wgetdcwd (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000539 *
540 * Unicode version of _wgetdcwd.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000541 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200542MSVCRT_wchar_t* CDECL _wgetdcwd(int drive, MSVCRT_wchar_t * buf, int size)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000543{
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000544 static MSVCRT_wchar_t* dummy;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000545
546 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
547
Francois Gouget203a8f82001-04-10 21:16:07 +0000548 if (!drive || drive == _getdrive())
549 return _wgetcwd(buf,size); /* current */
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000550 else
551 {
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000552 MSVCRT_wchar_t dir[MAX_PATH];
553 MSVCRT_wchar_t drivespec[4] = {'A', ':', '\\', 0};
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000554 int dir_len;
555
556 drivespec[0] += drive - 1;
557 if (GetDriveTypeW(drivespec) < DRIVE_REMOVABLE)
558 {
Alexandre Julliard44b42352002-07-19 03:24:50 +0000559 *MSVCRT__errno() = MSVCRT_EACCES;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000560 return NULL;
561 }
562
Alexandre Julliardb53f1302002-05-01 18:13:18 +0000563 dir_len = GetFullPathNameW(drivespec,MAX_PATH,dir,&dummy);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000564 if (dir_len >= size || dir_len < 1)
565 {
Alexandre Julliard44b42352002-07-19 03:24:50 +0000566 *MSVCRT__errno() = MSVCRT_ERANGE;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000567 return NULL; /* buf too small */
568 }
569
Francois Gougetee285b72001-05-11 20:03:40 +0000570 TRACE(":returning %s\n", debugstr_w(dir));
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000571 if (!buf)
Francois Gouget203a8f82001-04-10 21:16:07 +0000572 return _wcsdup(dir); /* allocate */
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000573 strcpyW(buf,dir);
574 }
575 return buf;
576}
577
578/*********************************************************************
579 * _getdiskfree (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000580 *
581 * Get information about the free space on a drive.
582 *
583 * PARAMS
584 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
585 * info [O] Destination for the resulting information.
586 *
587 * RETURNS
588 * Success: 0. info is updated with the free space information.
589 * Failure: An error code from GetLastError().
590 *
591 * NOTES
592 * See GetLastError().
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000593 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200594unsigned int CDECL MSVCRT__getdiskfree(unsigned int disk, struct MSVCRT__diskfree_t * d)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000595{
Jon Griffithsf90092c2004-02-09 20:45:59 +0000596 WCHAR drivespec[4] = {'@', ':', '\\', 0};
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000597 DWORD ret[4];
598 unsigned int err;
599
600 if (disk > 26)
601 return ERROR_INVALID_PARAMETER; /* MSVCRT doesn't set errno here */
602
603 drivespec[0] += disk; /* make a drive letter */
604
Jon Griffithsf90092c2004-02-09 20:45:59 +0000605 if (GetDiskFreeSpaceW(disk==0?NULL:drivespec,ret,ret+1,ret+2,ret+3))
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000606 {
Francois Gougete7f75c52001-04-10 23:25:25 +0000607 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];
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000611 return 0;
612 }
613 err = GetLastError();
Dimitrie O. Paun03774622004-06-25 01:19:15 +0000614 msvcrt_set_errno(err);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000615 return err;
616}
617
618/*********************************************************************
619 * _mkdir (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000620 *
621 * Create a directory.
622 *
623 * PARAMS
624 * newdir [I] Name of directory to create.
625 *
626 * RETURNS
627 * Success: 0. The directory indicated by newdir is created.
628 * Failure: -1. errno indicates the error.
629 *
630 * NOTES
631 * See CreateDirectoryA.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000632 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200633int CDECL _mkdir(const char * newdir)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000634{
635 if (CreateDirectoryA(newdir,NULL))
636 return 0;
Dimitrie O. Paun03774622004-06-25 01:19:15 +0000637 msvcrt_set_errno(GetLastError());
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000638 return -1;
639}
640
641/*********************************************************************
642 * _wmkdir (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000643 *
644 * Unicode version of _mkdir.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000645 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200646int CDECL _wmkdir(const MSVCRT_wchar_t* newdir)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000647{
648 if (CreateDirectoryW(newdir,NULL))
649 return 0;
Dimitrie O. Paun03774622004-06-25 01:19:15 +0000650 msvcrt_set_errno(GetLastError());
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000651 return -1;
652}
653
654/*********************************************************************
655 * _rmdir (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000656 *
657 * Delete a directory.
658 *
659 * PARAMS
660 * dir [I] Name of directory to delete.
661 *
662 * RETURNS
663 * Success: 0. The directory indicated by newdir is deleted.
664 * Failure: -1. errno indicates the error.
665 *
666 * NOTES
667 * See RemoveDirectoryA.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000668 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200669int CDECL _rmdir(const char * dir)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000670{
671 if (RemoveDirectoryA(dir))
672 return 0;
Dimitrie O. Paun03774622004-06-25 01:19:15 +0000673 msvcrt_set_errno(GetLastError());
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000674 return -1;
675}
676
677/*********************************************************************
678 * _wrmdir (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000679 *
680 * Unicode version of _rmdir.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000681 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200682int CDECL _wrmdir(const MSVCRT_wchar_t * dir)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000683{
684 if (RemoveDirectoryW(dir))
685 return 0;
Dimitrie O. Paun03774622004-06-25 01:19:15 +0000686 msvcrt_set_errno(GetLastError());
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000687 return -1;
688}
689
690/*********************************************************************
Jon Griffiths34c786b2001-01-22 02:21:54 +0000691 * _wsplitpath (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000692 *
693 * Unicode version of _splitpath.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000694 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200695void CDECL _wsplitpath(const MSVCRT_wchar_t *inpath, MSVCRT_wchar_t *drv, MSVCRT_wchar_t *dir,
696 MSVCRT_wchar_t *fname, MSVCRT_wchar_t *ext )
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000697{
Alexandre Julliard29378262003-10-15 02:34:51 +0000698 const MSVCRT_wchar_t *p, *end;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000699
Alexandre Julliard29378262003-10-15 02:34:51 +0000700 if (inpath[0] && inpath[1] == ':')
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000701 {
Alexandre Julliard29378262003-10-15 02:34:51 +0000702 if (drv)
703 {
704 drv[0] = inpath[0];
705 drv[1] = inpath[1];
706 drv[2] = 0;
707 }
708 inpath += 2;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000709 }
Alexandre Julliard29378262003-10-15 02:34:51 +0000710 else if (drv) drv[0] = 0;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000711
Alexandre Julliard29378262003-10-15 02:34:51 +0000712 /* look for end of directory part */
713 end = NULL;
714 for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000715
Alexandre Julliard29378262003-10-15 02:34:51 +0000716 if (end) /* got a directory */
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000717 {
Alexandre Julliard29378262003-10-15 02:34:51 +0000718 if (dir)
719 {
720 memcpy( dir, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
721 dir[end - inpath] = 0;
722 }
723 inpath = end;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000724 }
Alexandre Julliard29378262003-10-15 02:34:51 +0000725 else if (dir) dir[0] = 0;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000726
Dave Belanger2c391912003-10-21 23:51:06 +0000727 /* look for extension: what's after the last dot */
728 end = NULL;
729 for (p = inpath; *p; p++) if (*p == '.') end = p;
730
731 if (!end) end = p; /* there's no extension */
Alexandre Julliard29378262003-10-15 02:34:51 +0000732
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000733 if (fname)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000734 {
Alexandre Julliard29378262003-10-15 02:34:51 +0000735 memcpy( fname, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
736 fname[end - inpath] = 0;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000737 }
Alexandre Julliard29378262003-10-15 02:34:51 +0000738 if (ext) strcpyW( ext, end );
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000739}
740
Mike McCormack0bfa31e2003-05-12 03:31:16 +0000741/*********************************************************************
742 * _wfullpath (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000743 *
744 * Unicode version of _fullpath.
Mike McCormack0bfa31e2003-05-12 03:31:16 +0000745 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200746MSVCRT_wchar_t * CDECL _wfullpath(MSVCRT_wchar_t * absPath, const MSVCRT_wchar_t* relPath, MSVCRT_size_t size)
Mike McCormack0bfa31e2003-05-12 03:31:16 +0000747{
Aric Stewarte09a6c82006-01-06 21:45:26 +0100748 DWORD rc;
749 WCHAR* buffer;
750 WCHAR* lastpart;
751 BOOL alloced = FALSE;
Mike McCormack0bfa31e2003-05-12 03:31:16 +0000752
753 if (!relPath || !*relPath)
754 return _wgetcwd(absPath, size);
755
Aric Stewarte09a6c82006-01-06 21:45:26 +0100756 if (absPath == NULL)
757 {
758 buffer = MSVCRT_malloc(MAX_PATH * sizeof(WCHAR));
759 size = MAX_PATH;
760 alloced = TRUE;
761 }
762 else
763 buffer = absPath;
764
Mike McCormack0bfa31e2003-05-12 03:31:16 +0000765 if (size < 4)
766 {
767 *MSVCRT__errno() = MSVCRT_ERANGE;
768 return NULL;
769 }
770
771 TRACE(":resolving relative path '%s'\n",debugstr_w(relPath));
772
Aric Stewarte09a6c82006-01-06 21:45:26 +0100773 rc = GetFullPathNameW(relPath,size,buffer,&lastpart);
Mike McCormack0bfa31e2003-05-12 03:31:16 +0000774
Aric Stewarte09a6c82006-01-06 21:45:26 +0100775 if (rc > 0 && rc <= size )
776 return buffer;
Mike McCormack0bfa31e2003-05-12 03:31:16 +0000777 else
778 {
Aric Stewarte09a6c82006-01-06 21:45:26 +0100779 if (alloced)
780 MSVCRT_free(buffer);
781 return NULL;
Mike McCormack0bfa31e2003-05-12 03:31:16 +0000782 }
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000783}
784
785/*********************************************************************
786 * _fullpath (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000787 *
788 * Create an absolute path from a relative path.
789 *
790 * PARAMS
791 * absPath [O] Destination for absolute path
792 * relPath [I] Relative path to convert to absolute
793 * size [I] Length of absPath in characters.
794 *
795 * RETURNS
796 * Success: If absPath is NULL, returns an allocated string containing the path.
797 * Otherwise populates absPath with the path and returns it.
798 * Failure: NULL. errno indicates the error.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000799 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200800char * CDECL _fullpath(char * absPath, const char* relPath, unsigned int size)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000801{
Aric Stewarte09a6c82006-01-06 21:45:26 +0100802 DWORD rc;
803 char* lastpart;
804 char* buffer;
805 BOOL alloced = FALSE;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000806
807 if (!relPath || !*relPath)
Francois Gouget203a8f82001-04-10 21:16:07 +0000808 return _getcwd(absPath, size);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000809
Aric Stewarte09a6c82006-01-06 21:45:26 +0100810 if (absPath == NULL)
811 {
812 buffer = MSVCRT_malloc(MAX_PATH);
813 size = MAX_PATH;
814 alloced = TRUE;
815 }
816 else
817 buffer = absPath;
818
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000819 if (size < 4)
820 {
Alexandre Julliard44b42352002-07-19 03:24:50 +0000821 *MSVCRT__errno() = MSVCRT_ERANGE;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000822 return NULL;
823 }
824
825 TRACE(":resolving relative path '%s'\n",relPath);
826
Aric Stewarte09a6c82006-01-06 21:45:26 +0100827 rc = GetFullPathNameA(relPath,size,buffer,&lastpart);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000828
Aric Stewarte09a6c82006-01-06 21:45:26 +0100829 if (rc > 0 && rc <= size)
830 return buffer;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000831 else
832 {
Aric Stewarte09a6c82006-01-06 21:45:26 +0100833 if (alloced)
834 MSVCRT_free(buffer);
835 return NULL;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000836 }
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000837}
838
839/*********************************************************************
840 * _makepath (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000841 *
842 * Create a pathname.
843 *
844 * PARAMS
845 * path [O] Destination for created pathname
846 * drive [I] Drive letter (e.g. "A:")
847 * directory [I] Directory
848 * filename [I] Name of the file, excluding extension
849 * extension [I] File extension (e.g. ".TXT")
850 *
851 * RETURNS
852 * Nothing. If path is not large enough to hold the resulting pathname,
853 * random process memory will be overwritten.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000854 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200855VOID CDECL _makepath(char * path, const char * drive,
856 const char *directory, const char * filename,
857 const char * extension)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000858{
859 char ch;
Marcus Meissner71908c42006-01-17 16:20:37 +0100860
861 TRACE("(%s %s %s %s)\n", debugstr_a(drive), debugstr_a(directory),
Warren Baird586808f2003-02-19 03:43:08 +0000862 debugstr_a(filename), debugstr_a(extension) );
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000863
864 if ( !path )
865 return;
866
Marcus Meissner71908c42006-01-17 16:20:37 +0100867 path[0] = '\0';
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000868 if (drive && drive[0])
869 {
Marcus Meissner71908c42006-01-17 16:20:37 +0100870 path[0] = drive[0];
871 path[1] = ':';
872 path[2] = 0;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000873 }
874 if (directory && directory[0])
875 {
Marcus Meissner71908c42006-01-17 16:20:37 +0100876 strcat(path, directory);
877 ch = path[strlen(path)-1];
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000878 if (ch != '/' && ch != '\\')
Marcus Meissner71908c42006-01-17 16:20:37 +0100879 strcat(path,"\\");
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000880 }
881 if (filename && filename[0])
882 {
Marcus Meissner71908c42006-01-17 16:20:37 +0100883 strcat(path, filename);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000884 if (extension && extension[0])
885 {
886 if ( extension[0] != '.' )
Marcus Meissner71908c42006-01-17 16:20:37 +0100887 strcat(path,".");
888 strcat(path,extension);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000889 }
890 }
Francois Gougete7f75c52001-04-10 23:25:25 +0000891 TRACE("returning %s\n",path);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000892}
893
Dmitry Timoshkov08af06c2002-01-29 18:00:44 +0000894/*********************************************************************
895 * _wmakepath (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000896 *
897 * Unicode version of _wmakepath.
Dmitry Timoshkov08af06c2002-01-29 18:00:44 +0000898 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200899VOID CDECL _wmakepath(MSVCRT_wchar_t *path, const MSVCRT_wchar_t *drive, const MSVCRT_wchar_t *directory,
900 const MSVCRT_wchar_t *filename, const MSVCRT_wchar_t *extension)
Dmitry Timoshkov08af06c2002-01-29 18:00:44 +0000901{
Alexandre Julliard5f31b322002-12-19 04:21:30 +0000902 MSVCRT_wchar_t ch;
Dmitry Timoshkov08af06c2002-01-29 18:00:44 +0000903 TRACE("%s %s %s %s\n", debugstr_w(drive), debugstr_w(directory),
Jon Griffithsf90092c2004-02-09 20:45:59 +0000904 debugstr_w(filename), debugstr_w(extension));
Dmitry Timoshkov08af06c2002-01-29 18:00:44 +0000905
906 if ( !path )
907 return;
908
909 path[0] = 0;
910 if (drive && drive[0])
911 {
912 path[0] = drive[0];
913 path[1] = ':';
914 path[2] = 0;
915 }
916 if (directory && directory[0])
917 {
918 strcatW(path, directory);
919 ch = path[strlenW(path) - 1];
920 if (ch != '/' && ch != '\\')
Jon Griffithsf90092c2004-02-09 20:45:59 +0000921 {
922 static const MSVCRT_wchar_t backslashW[] = {'\\',0};
Dmitry Timoshkov08af06c2002-01-29 18:00:44 +0000923 strcatW(path, backslashW);
Jon Griffithsf90092c2004-02-09 20:45:59 +0000924 }
Dmitry Timoshkov08af06c2002-01-29 18:00:44 +0000925 }
926 if (filename && filename[0])
927 {
928 strcatW(path, filename);
929 if (extension && extension[0])
930 {
931 if ( extension[0] != '.' )
Jon Griffithsf90092c2004-02-09 20:45:59 +0000932 {
933 static const MSVCRT_wchar_t dotW[] = {'.',0};
Dmitry Timoshkov08af06c2002-01-29 18:00:44 +0000934 strcatW(path, dotW);
Jon Griffithsf90092c2004-02-09 20:45:59 +0000935 }
Dmitry Timoshkov08af06c2002-01-29 18:00:44 +0000936 strcatW(path, extension);
937 }
938 }
939
940 TRACE("returning %s\n", debugstr_w(path));
941}
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000942
943/*********************************************************************
944 * _searchenv (MSVCRT.@)
Jon Griffithsf90092c2004-02-09 20:45:59 +0000945 *
946 * Search for a file in a list of paths from an envronment variable.
947 *
948 * PARAMS
949 * file [I] Name of the file to search for.
950 * env [I] Name of the environment variable containing a list of paths.
951 * buf [O] Destination for the found file path.
952 *
953 * RETURNS
954 * Nothing. If the file is not found, buf will contain an empty string
955 * and errno is set.
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000956 */
Alexandre Julliard24beabf2006-06-13 11:21:19 +0200957void CDECL _searchenv(const char* file, const char* env, char *buf)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000958{
959 char*envVal, *penv;
960 char curPath[MAX_PATH];
961
962 *buf = '\0';
963
964 /* Try CWD first */
Rolf Kalbermatter76f13de2003-10-16 19:12:49 +0000965 if (GetFileAttributesA( file ) != INVALID_FILE_ATTRIBUTES)
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000966 {
967 GetFullPathNameA( file, MAX_PATH, buf, NULL );
968 /* Sigh. This error is *always* set, regardless of success */
Dimitrie O. Paun03774622004-06-25 01:19:15 +0000969 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000970 return;
971 }
972
973 /* Search given environment variable */
974 envVal = MSVCRT_getenv(env);
975 if (!envVal)
976 {
Dimitrie O. Paun03774622004-06-25 01:19:15 +0000977 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000978 return;
979 }
980
981 penv = envVal;
982 TRACE(":searching for %s in paths %s\n", file, envVal);
983
984 do
985 {
Jon Griffiths34c786b2001-01-22 02:21:54 +0000986 char *end = penv;
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000987
988 while(*end && *end != ';') end++; /* Find end of next path */
989 if (penv == end || !*penv)
990 {
Dimitrie O. Paun03774622004-06-25 01:19:15 +0000991 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000992 return;
993 }
Peter Berg Larsene732fc02005-03-28 14:17:51 +0000994 memcpy(curPath, penv, end - penv);
Jon Griffiths1db20bf2001-01-10 23:59:25 +0000995 if (curPath[end - penv] != '/' || curPath[end - penv] != '\\')
996 {
997 curPath[end - penv] = '\\';
998 curPath[end - penv + 1] = '\0';
999 }
1000 else
1001 curPath[end - penv] = '\0';
1002
1003 strcat(curPath, file);
1004 TRACE("Checking for file %s\n", curPath);
Rolf Kalbermatter76f13de2003-10-16 19:12:49 +00001005 if (GetFileAttributesA( curPath ) != INVALID_FILE_ATTRIBUTES)
Jon Griffiths1db20bf2001-01-10 23:59:25 +00001006 {
1007 strcpy(buf, curPath);
Dimitrie O. Paun03774622004-06-25 01:19:15 +00001008 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
Jon Griffiths1db20bf2001-01-10 23:59:25 +00001009 return; /* Found */
1010 }
1011 penv = *end ? end + 1 : end;
1012 } while(1);
1013}