1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | /*++ |
6 | |
7 | |
8 | |
9 | Module Name: |
10 | |
11 | directory.c |
12 | |
13 | Abstract: |
14 | |
15 | Implementation of the file WIN API for the PAL |
16 | |
17 | Revision History: |
18 | |
19 | |
20 | |
21 | --*/ |
22 | |
23 | #include "pal/palinternal.h" |
24 | #include "pal/dbgmsg.h" |
25 | #include "pal/file.h" |
26 | #include "pal/stackstring.hpp" |
27 | |
28 | #include <stdlib.h> |
29 | #include <sys/param.h> |
30 | #include <sys/types.h> |
31 | #include <sys/stat.h> |
32 | #include <errno.h> |
33 | |
34 | SET_DEFAULT_DEBUG_CHANNEL(FILE); |
35 | |
36 | |
37 | |
38 | /*++ |
39 | Function: |
40 | CreateDirectoryW |
41 | |
42 | Note: |
43 | lpSecurityAttributes always NULL. |
44 | |
45 | See MSDN doc. |
46 | --*/ |
47 | BOOL |
48 | PALAPI |
49 | CreateDirectoryW( |
50 | IN LPCWSTR lpPathName, |
51 | IN LPSECURITY_ATTRIBUTES lpSecurityAttributes) |
52 | { |
53 | BOOL bRet = FALSE; |
54 | DWORD dwLastError = 0; |
55 | int mb_size; |
56 | char *mb_dir = NULL; |
57 | |
58 | PERF_ENTRY(CreateDirectoryW); |
59 | ENTRY("CreateDirectoryW(lpPathName=%p (%S), lpSecurityAttr=%p)\n" , |
60 | lpPathName?lpPathName:W16_NULLSTRING, |
61 | lpPathName?lpPathName:W16_NULLSTRING, lpSecurityAttributes); |
62 | |
63 | if ( lpSecurityAttributes ) |
64 | { |
65 | ASSERT("lpSecurityAttributes is not NULL as it should be\n" ); |
66 | dwLastError = ERROR_INVALID_PARAMETER; |
67 | goto done; |
68 | } |
69 | |
70 | /* translate the wide char lpPathName string to multibyte string */ |
71 | if(0 == (mb_size = WideCharToMultiByte( CP_ACP, 0, lpPathName, -1, NULL, 0, |
72 | NULL, NULL ))) |
73 | { |
74 | ASSERT("WideCharToMultiByte failure! error is %d\n" , GetLastError()); |
75 | dwLastError = ERROR_INTERNAL_ERROR; |
76 | goto done; |
77 | } |
78 | |
79 | if (((mb_dir = (char *)PAL_malloc(mb_size)) == NULL) || |
80 | (WideCharToMultiByte( CP_ACP, 0, lpPathName, -1, mb_dir, mb_size, NULL, |
81 | NULL) != mb_size)) |
82 | { |
83 | ASSERT("WideCharToMultiByte or PAL_malloc failure! LastError:%d errno:%d\n" , |
84 | GetLastError(), errno); |
85 | dwLastError = ERROR_INTERNAL_ERROR; |
86 | goto done; |
87 | } |
88 | |
89 | bRet = CreateDirectoryA(mb_dir,NULL); |
90 | done: |
91 | if( dwLastError ) |
92 | { |
93 | SetLastError( dwLastError ); |
94 | } |
95 | if (mb_dir != NULL) |
96 | { |
97 | PAL_free(mb_dir); |
98 | } |
99 | LOGEXIT("CreateDirectoryW returns BOOL %d\n" , bRet); |
100 | PERF_EXIT(CreateDirectoryW); |
101 | return bRet; |
102 | } |
103 | |
104 | /*++ |
105 | Routine Name: |
106 | |
107 | RemoveDirectoryHelper |
108 | |
109 | Routine Description: |
110 | |
111 | Core function which removes a directory. Called by RemoveDirectory[AW] |
112 | |
113 | Parameters: |
114 | |
115 | LPSTR lpPathName - [in/out] |
116 | The directory name to remove. It is converted in place to a unix path. |
117 | |
118 | Return Value: |
119 | |
120 | BOOL - |
121 | TRUE <=> successful |
122 | |
123 | --*/ |
124 | |
125 | static |
126 | BOOL |
127 | RemoveDirectoryHelper ( |
128 | PathCharString& lpPathName, |
129 | LPDWORD dwLastError |
130 | ) |
131 | { |
132 | BOOL bRet = FALSE; |
133 | *dwLastError = 0; |
134 | |
135 | FILEDosToUnixPathA( lpPathName ); |
136 | |
137 | if ( rmdir(lpPathName) != 0 ) |
138 | { |
139 | TRACE("Removal of directory [%s] was unsuccessful, errno = %d.\n" , |
140 | lpPathName.GetString(), errno); |
141 | |
142 | switch( errno ) |
143 | { |
144 | case ENOTDIR: |
145 | /* FALL THROUGH */ |
146 | case ENOENT: |
147 | { |
148 | struct stat stat_data; |
149 | |
150 | if ( stat( lpPathName, &stat_data) == 0 && |
151 | (stat_data.st_mode & S_IFMT) == S_IFREG ) |
152 | { |
153 | /* Not a directory, it is a file. */ |
154 | *dwLastError = ERROR_DIRECTORY; |
155 | } |
156 | else |
157 | { |
158 | FILEGetProperNotFoundError( lpPathName, dwLastError ); |
159 | } |
160 | break; |
161 | } |
162 | case ENOTEMPTY: |
163 | *dwLastError = ERROR_DIR_NOT_EMPTY; |
164 | break; |
165 | default: |
166 | *dwLastError = ERROR_ACCESS_DENIED; |
167 | } |
168 | } |
169 | else { |
170 | TRACE("Removal of directory [%s] was successful.\n" , lpPathName.GetString()); |
171 | bRet = TRUE; |
172 | } |
173 | |
174 | return bRet; |
175 | } |
176 | |
177 | /*++ |
178 | Function: |
179 | RemoveDirectoryA |
180 | |
181 | See MSDN doc. |
182 | --*/ |
183 | BOOL |
184 | PALAPI |
185 | RemoveDirectoryA( |
186 | IN LPCSTR lpPathName) |
187 | { |
188 | DWORD dwLastError = 0; |
189 | BOOL bRet = FALSE; |
190 | PathCharString mb_dirPathString; |
191 | |
192 | PERF_ENTRY(RemoveDirectoryA); |
193 | ENTRY("RemoveDirectoryA(lpPathName=%p (%s))\n" , |
194 | lpPathName, |
195 | lpPathName); |
196 | |
197 | if (lpPathName == NULL) |
198 | { |
199 | dwLastError = ERROR_PATH_NOT_FOUND; |
200 | goto done; |
201 | } |
202 | |
203 | if (!mb_dirPathString.Set(lpPathName, strlen(lpPathName))) |
204 | { |
205 | WARN("Set failed !\n" ); |
206 | dwLastError = ERROR_NOT_ENOUGH_MEMORY; |
207 | goto done; |
208 | } |
209 | |
210 | bRet = RemoveDirectoryHelper (mb_dirPathString, &dwLastError); |
211 | |
212 | done: |
213 | if( dwLastError ) |
214 | { |
215 | SetLastError( dwLastError ); |
216 | } |
217 | |
218 | LOGEXIT("RemoveDirectoryA returns BOOL %d\n" , bRet); |
219 | PERF_EXIT(RemoveDirectoryA); |
220 | return bRet; |
221 | } |
222 | |
223 | /*++ |
224 | Function: |
225 | RemoveDirectoryW |
226 | |
227 | See MSDN doc. |
228 | --*/ |
229 | BOOL |
230 | PALAPI |
231 | RemoveDirectoryW( |
232 | IN LPCWSTR lpPathName) |
233 | { |
234 | PathCharString mb_dirPathString; |
235 | int mb_size; |
236 | DWORD dwLastError = 0; |
237 | BOOL bRet = FALSE; |
238 | size_t length; |
239 | char * mb_dir = NULL; |
240 | |
241 | PERF_ENTRY(RemoveDirectoryW); |
242 | ENTRY("RemoveDirectoryW(lpPathName=%p (%S))\n" , |
243 | lpPathName?lpPathName:W16_NULLSTRING, |
244 | lpPathName?lpPathName:W16_NULLSTRING); |
245 | |
246 | if (lpPathName == NULL) |
247 | { |
248 | dwLastError = ERROR_PATH_NOT_FOUND; |
249 | goto done; |
250 | } |
251 | |
252 | length = (PAL_wcslen(lpPathName)+1) * 3; |
253 | mb_dir = mb_dirPathString.OpenStringBuffer(length); |
254 | if (NULL == mb_dir) |
255 | { |
256 | dwLastError = ERROR_NOT_ENOUGH_MEMORY; |
257 | goto done; |
258 | } |
259 | |
260 | mb_size = WideCharToMultiByte( CP_ACP, 0, lpPathName, -1, mb_dir, length, |
261 | NULL, NULL ); |
262 | |
263 | if( mb_size == 0 ) |
264 | { |
265 | mb_dirPathString.CloseBuffer(0); |
266 | ASSERT("WideCharToMultiByte failure! error is %d\n" , dwLastError); |
267 | dwLastError = ERROR_INTERNAL_ERROR; |
268 | goto done; |
269 | } |
270 | |
271 | mb_dirPathString.CloseBuffer(mb_size - 1); |
272 | |
273 | if ((bRet = RemoveDirectoryHelper (mb_dirPathString, &dwLastError))) |
274 | { |
275 | TRACE("Removal of directory [%s] was successful.\n" , mb_dir); |
276 | } |
277 | |
278 | done: |
279 | if( dwLastError ) |
280 | { |
281 | SetLastError( dwLastError ); |
282 | } |
283 | |
284 | LOGEXIT("RemoveDirectoryW returns BOOL %d\n" , bRet); |
285 | PERF_EXIT(RemoveDirectoryW); |
286 | return bRet; |
287 | } |
288 | |
289 | |
290 | /*++ |
291 | Function: |
292 | GetCurrentDirectoryA |
293 | |
294 | --*/ |
295 | DWORD |
296 | GetCurrentDirectoryA(PathCharString& lpBuffer) |
297 | { |
298 | DWORD dwDirLen = 0; |
299 | DWORD dwLastError = 0; |
300 | |
301 | char *current_dir; |
302 | |
303 | PERF_ENTRY(GetCurrentDirectoryA); |
304 | ENTRY("GetCurrentDirectoryA(lpBuffer=%p)\n" , lpBuffer.GetString()); |
305 | |
306 | current_dir = lpBuffer.OpenStringBuffer(MAX_PATH); |
307 | /* NULL first arg means getcwd will allocate the string */ |
308 | current_dir = PAL__getcwd( current_dir, MAX_PATH); |
309 | |
310 | if (current_dir != NULL ) |
311 | { |
312 | dwDirLen = strlen( current_dir ); |
313 | lpBuffer.CloseBuffer(dwDirLen); |
314 | goto done; |
315 | } |
316 | else if ( errno == ERANGE ) |
317 | { |
318 | lpBuffer.CloseBuffer(0); |
319 | current_dir = PAL__getcwd( NULL, 0); |
320 | } |
321 | |
322 | if ( !current_dir ) |
323 | { |
324 | WARN("Getcwd failed with errno=%d [%s]\n" , errno, strerror(errno)); |
325 | dwLastError = DIRGetLastErrorFromErrno(); |
326 | dwDirLen = 0; |
327 | goto done; |
328 | } |
329 | |
330 | dwDirLen = strlen( current_dir ); |
331 | lpBuffer.Set(current_dir, dwDirLen); |
332 | PAL_free(current_dir); |
333 | done: |
334 | |
335 | if ( dwLastError ) |
336 | { |
337 | SetLastError(dwLastError); |
338 | } |
339 | |
340 | LOGEXIT("GetCurrentDirectoryA returns DWORD %u\n" , dwDirLen); |
341 | PERF_EXIT(GetCurrentDirectoryA); |
342 | return dwDirLen; |
343 | } |
344 | |
345 | /*++ |
346 | Function: |
347 | GetCurrentDirectoryA |
348 | |
349 | See MSDN doc. |
350 | --*/ |
351 | DWORD |
352 | PALAPI |
353 | GetCurrentDirectoryA( |
354 | IN DWORD nBufferLength, |
355 | OUT LPSTR lpBuffer) |
356 | { |
357 | |
358 | PathCharString lpBufferString; |
359 | DWORD dwDirLen = GetCurrentDirectoryA(lpBufferString); |
360 | |
361 | /* if the supplied buffer isn't long enough, return the required |
362 | length, including room for the NULL terminator */ |
363 | if ( nBufferLength <= dwDirLen ) |
364 | { |
365 | ++dwDirLen; /* include space for the NULL */ |
366 | } |
367 | else |
368 | { |
369 | strcpy_s( lpBuffer, nBufferLength, lpBufferString ); |
370 | } |
371 | |
372 | return dwDirLen; |
373 | } |
374 | |
375 | /*++ |
376 | Function: |
377 | GetCurrentDirectoryW |
378 | |
379 | See MSDN doc. |
380 | --*/ |
381 | DWORD |
382 | PALAPI |
383 | GetCurrentDirectoryW( |
384 | IN DWORD nBufferLength, |
385 | OUT LPWSTR lpBuffer) |
386 | { |
387 | DWORD dwWideLen = 0; |
388 | DWORD dwLastError = ERROR_BAD_PATHNAME; |
389 | int dir_len; |
390 | PathCharString current_dir; |
391 | |
392 | PERF_ENTRY(GetCurrentDirectoryW); |
393 | ENTRY("GetCurrentDirectoryW(nBufferLength=%u, lpBuffer=%p)\n" , |
394 | nBufferLength, lpBuffer); |
395 | |
396 | |
397 | dir_len = GetCurrentDirectoryA(current_dir); |
398 | |
399 | if( dir_len == 0) |
400 | { |
401 | dwLastError = DIRGetLastErrorFromErrno(); |
402 | goto done; |
403 | } |
404 | |
405 | dwWideLen = MultiByteToWideChar( CP_ACP, 0, |
406 | current_dir, dir_len, |
407 | NULL, 0 ); |
408 | |
409 | /* if the supplied buffer isn't long enough, return the required |
410 | length, including room for the NULL terminator */ |
411 | if ( nBufferLength > dwWideLen ) |
412 | { |
413 | if(!MultiByteToWideChar( CP_ACP, 0, current_dir, dir_len + 1, |
414 | lpBuffer, nBufferLength )) |
415 | { |
416 | ASSERT("MultiByteToWideChar failure!\n" ); |
417 | dwWideLen = 0; |
418 | dwLastError = ERROR_INTERNAL_ERROR; |
419 | } |
420 | } |
421 | else |
422 | { |
423 | ++dwWideLen; /* include the space for the NULL */ |
424 | } |
425 | |
426 | done: |
427 | |
428 | if ( dwLastError ) |
429 | { |
430 | SetLastError(dwLastError); |
431 | } |
432 | |
433 | LOGEXIT("GetCurrentDirectoryW returns DWORD %u\n" , dwWideLen); |
434 | PERF_EXIT(GetCurrentDirectoryW); |
435 | return dwWideLen; |
436 | } |
437 | |
438 | |
439 | /*++ |
440 | Function: |
441 | SetCurrentDirectoryW |
442 | |
443 | See MSDN doc. |
444 | --*/ |
445 | BOOL |
446 | PALAPI |
447 | SetCurrentDirectoryW( |
448 | IN LPCWSTR lpPathName) |
449 | { |
450 | BOOL bRet; |
451 | DWORD dwLastError = 0; |
452 | PathCharString dirPathString; |
453 | int size; |
454 | size_t length; |
455 | char * dir = NULL; |
456 | |
457 | PERF_ENTRY(SetCurrentDirectoryW); |
458 | ENTRY("SetCurrentDirectoryW(lpPathName=%p (%S))\n" , |
459 | lpPathName?lpPathName:W16_NULLSTRING, |
460 | lpPathName?lpPathName:W16_NULLSTRING); |
461 | |
462 | /*check if the given path is null. If so |
463 | return FALSE*/ |
464 | if (lpPathName == NULL ) |
465 | { |
466 | ERROR("Invalid path/directory name\n" ); |
467 | dwLastError = ERROR_INVALID_NAME; |
468 | bRet = FALSE; |
469 | goto done; |
470 | } |
471 | |
472 | length = (PAL_wcslen(lpPathName)+1) * 3; |
473 | dir = dirPathString.OpenStringBuffer(length); |
474 | if (NULL == dir) |
475 | { |
476 | dwLastError = ERROR_NOT_ENOUGH_MEMORY; |
477 | bRet = FALSE; |
478 | goto done; |
479 | } |
480 | |
481 | size = WideCharToMultiByte( CP_ACP, 0, lpPathName, -1, dir, length, |
482 | NULL, NULL ); |
483 | |
484 | if( size == 0 ) |
485 | { |
486 | dirPathString.CloseBuffer(0); |
487 | dwLastError = GetLastError(); |
488 | ASSERT("WideCharToMultiByte failure! error is %d\n" , dwLastError); |
489 | dwLastError = ERROR_INTERNAL_ERROR; |
490 | bRet = FALSE; |
491 | goto done; |
492 | } |
493 | |
494 | dirPathString.CloseBuffer(size - 1); |
495 | bRet = SetCurrentDirectoryA(dir); |
496 | done: |
497 | if( dwLastError ) |
498 | { |
499 | SetLastError(dwLastError); |
500 | } |
501 | |
502 | LOGEXIT("SetCurrentDirectoryW returns BOOL %d\n" , bRet); |
503 | PERF_EXIT(SetCurrentDirectoryW); |
504 | return bRet; |
505 | } |
506 | |
507 | /*++ |
508 | Function: |
509 | CreateDirectoryA |
510 | |
511 | Note: |
512 | lpSecurityAttributes always NULL. |
513 | |
514 | See MSDN doc. |
515 | --*/ |
516 | BOOL |
517 | PALAPI |
518 | CreateDirectoryA( |
519 | IN LPCSTR lpPathName, |
520 | IN LPSECURITY_ATTRIBUTES lpSecurityAttributes) |
521 | { |
522 | BOOL bRet = FALSE; |
523 | DWORD dwLastError = 0; |
524 | PathCharString realPath; |
525 | char* realPathBuf; |
526 | LPSTR unixPathName = NULL; |
527 | int pathLength; |
528 | int i; |
529 | const int mode = S_IRWXU | S_IRWXG | S_IRWXO; |
530 | |
531 | PERF_ENTRY(CreateDirectoryA); |
532 | ENTRY("CreateDirectoryA(lpPathName=%p (%s), lpSecurityAttr=%p)\n" , |
533 | lpPathName?lpPathName:"NULL" , |
534 | lpPathName?lpPathName:"NULL" , lpSecurityAttributes); |
535 | |
536 | if ( lpSecurityAttributes ) |
537 | { |
538 | ASSERT("lpSecurityAttributes is not NULL as it should be\n" ); |
539 | dwLastError = ERROR_INVALID_PARAMETER; |
540 | goto done; |
541 | } |
542 | |
543 | // Windows returns ERROR_PATH_NOT_FOUND when called with NULL. |
544 | // If we don't have this check, strdup(NULL) segfaults. |
545 | if (lpPathName == NULL) |
546 | { |
547 | ERROR("CreateDirectoryA called with NULL pathname!\n" ); |
548 | dwLastError = ERROR_PATH_NOT_FOUND; |
549 | goto done; |
550 | } |
551 | |
552 | unixPathName = PAL__strdup(lpPathName); |
553 | if (unixPathName == NULL ) |
554 | { |
555 | ERROR("PAL__strdup() failed\n" ); |
556 | dwLastError = ERROR_NOT_ENOUGH_MEMORY; |
557 | goto done; |
558 | } |
559 | FILEDosToUnixPathA( unixPathName ); |
560 | // Remove any trailing slashes at the end because mkdir might not |
561 | // handle them appropriately on all platforms. |
562 | pathLength = strlen(unixPathName); |
563 | i = pathLength; |
564 | while(i > 1) |
565 | { |
566 | if(unixPathName[i - 1] =='/') |
567 | { |
568 | unixPathName[i - 1]='\0'; |
569 | i--; |
570 | } |
571 | else |
572 | { |
573 | break; |
574 | } |
575 | } |
576 | |
577 | |
578 | // Get an absolute path. |
579 | if (unixPathName[0] == '/') |
580 | { |
581 | realPathBuf = unixPathName; |
582 | } |
583 | else |
584 | { |
585 | |
586 | DWORD len = GetCurrentDirectoryA(realPath); |
587 | if (len == 0 || !realPath.Reserve(realPath.GetCount() + pathLength + 1 )) |
588 | { |
589 | dwLastError = DIRGetLastErrorFromErrno(); |
590 | WARN("Getcwd failed with errno=%d \n" , dwLastError); |
591 | goto done; |
592 | } |
593 | |
594 | realPath.Append("/" , 1); |
595 | realPath.Append(unixPathName, pathLength); |
596 | realPathBuf = realPath.OpenStringBuffer(realPath.GetCount()); |
597 | } |
598 | |
599 | // Canonicalize the path so we can determine its length. |
600 | FILECanonicalizePath(realPathBuf); |
601 | |
602 | if ( mkdir(realPathBuf, mode) != 0 ) |
603 | { |
604 | TRACE("Creation of directory [%s] was unsuccessful, errno = %d.\n" , |
605 | unixPathName, errno); |
606 | |
607 | switch( errno ) |
608 | { |
609 | case ENOTDIR: |
610 | /* FALL THROUGH */ |
611 | case ENOENT: |
612 | FILEGetProperNotFoundError( realPathBuf, &dwLastError ); |
613 | goto done; |
614 | case EEXIST: |
615 | dwLastError = ERROR_ALREADY_EXISTS; |
616 | break; |
617 | default: |
618 | dwLastError = ERROR_ACCESS_DENIED; |
619 | } |
620 | } |
621 | else |
622 | { |
623 | TRACE("Creation of directory [%s] was successful.\n" , unixPathName); |
624 | bRet = TRUE; |
625 | } |
626 | |
627 | realPath.CloseBuffer(0); //The PathCharString usage is done |
628 | done: |
629 | if( dwLastError ) |
630 | { |
631 | SetLastError( dwLastError ); |
632 | } |
633 | PAL_free( unixPathName ); |
634 | LOGEXIT("CreateDirectoryA returns BOOL %d\n" , bRet); |
635 | PERF_EXIT(CreateDirectoryA); |
636 | return bRet; |
637 | } |
638 | |
639 | /*++ |
640 | Function: |
641 | SetCurrentDirectoryA |
642 | |
643 | See MSDN doc. |
644 | --*/ |
645 | BOOL |
646 | PALAPI |
647 | SetCurrentDirectoryA( |
648 | IN LPCSTR lpPathName) |
649 | { |
650 | BOOL bRet = FALSE; |
651 | DWORD dwLastError = 0; |
652 | int result; |
653 | LPSTR unixPathName = NULL; |
654 | |
655 | PERF_ENTRY(SetCurrentDirectoryA); |
656 | ENTRY("SetCurrentDirectoryA(lpPathName=%p (%s))\n" , |
657 | lpPathName?lpPathName:"NULL" , |
658 | lpPathName?lpPathName:"NULL" ); |
659 | |
660 | /*check if the given path is null. If so |
661 | return FALSE*/ |
662 | if (lpPathName == NULL ) |
663 | { |
664 | ERROR("Invalid path/directory name\n" ); |
665 | dwLastError = ERROR_INVALID_NAME; |
666 | goto done; |
667 | } |
668 | |
669 | unixPathName = PAL__strdup(lpPathName); |
670 | if (unixPathName == NULL ) |
671 | { |
672 | ERROR("PAL__strdup() failed\n" ); |
673 | dwLastError = ERROR_NOT_ENOUGH_MEMORY; |
674 | goto done; |
675 | } |
676 | FILEDosToUnixPathA( unixPathName ); |
677 | |
678 | TRACE("Attempting to open Unix dir [%s]\n" , unixPathName); |
679 | result = chdir(unixPathName); |
680 | |
681 | if ( result == 0 ) |
682 | { |
683 | bRet = TRUE; |
684 | } |
685 | else |
686 | { |
687 | if ( errno == ENOTDIR || errno == ENOENT ) |
688 | { |
689 | struct stat stat_data; |
690 | |
691 | if ( stat( unixPathName, &stat_data) == 0 && |
692 | (stat_data.st_mode & S_IFMT) == S_IFREG ) |
693 | { |
694 | /* Not a directory, it is a file. */ |
695 | dwLastError = ERROR_DIRECTORY; |
696 | } |
697 | else |
698 | { |
699 | FILEGetProperNotFoundError( unixPathName, &dwLastError ); |
700 | } |
701 | TRACE("chdir() failed, path was invalid.\n" ); |
702 | } |
703 | else |
704 | { |
705 | dwLastError = ERROR_ACCESS_DENIED; |
706 | ERROR("chdir() failed; errno is %d (%s)\n" , errno, strerror(errno)); |
707 | } |
708 | } |
709 | |
710 | |
711 | done: |
712 | if( dwLastError ) |
713 | { |
714 | SetLastError(dwLastError); |
715 | } |
716 | |
717 | if(unixPathName != NULL) |
718 | { |
719 | PAL_free( unixPathName ); |
720 | } |
721 | |
722 | LOGEXIT("SetCurrentDirectoryA returns BOOL %d\n" , bRet); |
723 | PERF_EXIT(SetCurrentDirectoryA); |
724 | return bRet; |
725 | } |
726 | |