1 /* Part of SWI-Prolog
2
3 Author: Jan Wielemaker
4 E-mail: J.Wielemaker@vu.nl
5 WWW: http://www.swi-prolog.org
6 Copyright (c) 2011-2015, University of Amsterdam
7 Vu University Amsterdam
8 All rights reserved.
9
10 Redistribution and use in source and binary forms, with or without
11 modification, are permitted provided that the following conditions
12 are met:
13
14 1. Redistributions of source code must retain the above copyright
15 notice, this list of conditions and the following disclaimer.
16
17 2. Redistributions in binary form must reproduce the above copyright
18 notice, this list of conditions and the following disclaimer in
19 the documentation and/or other materials provided with the
20 distribution.
21
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #define UNICODE 1
37 #define _UNICODE 1
38
39 #define _UXNT_KERNEL 1
40 #include "uxnt.h" /* my prototypes */
41 #include "utf8.c"
42
43 #ifdef _MSC_VER
44 #pragma warning(disable : 4996) /* deprecate open() etc */
45 #endif
46
47 #include <windows.h>
48 #include <tchar.h>
49 #include <wchar.h>
50 #include "dirent.h"
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #include <stdarg.h>
54 #include <stddef.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <ctype.h>
58 #undef mkdir /* avoid conflict */
59 #include <direct.h>
60 #ifndef __LCC__ /* not delete altogether? */
61 #define mkdir _xos_mkdir
62 #endif
63 #include <errno.h>
64 #include <fcntl.h>
65
66 #ifndef TRUE
67 #define TRUE 1
68 #define FALSE 0
69 #endif
70
71 #ifdef __LCC__
72 #define _close close
73 #define _read read
74 #define _write write
75 #define _lseek lseek
76 #define _tell tell
77 #define _chdir chdir
78 #define _mkdir mkdir
79 #define _rmdir rmdir
80 #define _getcwd getcwd
81 #endif
82
83 #define XENOMAP 1
84 #define XENOMEM 2
85
86 #ifndef PATH_MAX
87 #define PATH_MAX 260
88 #endif
89
90 static int exists_file_or_dir(const TCHAR *path, int flags);
91
92
93 /*******************************
94 * ERRNO *
95 *******************************/
96
97 int
_xos_errno(void)98 _xos_errno(void)
99 { return errno;
100 }
101
102 /*******************************
103 * UTF-8 *
104 *******************************/
105
106 static char *
wcstoutf8(char * dest,const wchar_t * src,size_t len)107 wcstoutf8(char *dest, const wchar_t *src, size_t len)
108 { char *o = dest;
109 char *e = &o[len];
110
111 for(; *src; src++)
112 { if ( o+6 >= e && o+utf8_code_bytes(*src) >= e )
113 { errno = ENAMETOOLONG;
114 return NULL;
115 }
116 o = utf8_put_char(o, *src);
117 }
118 *o = '\0';
119
120 return dest;
121 }
122
123
124 /* length of src in UTF-8, excluding terminating EOS */
125
126 static size_t
wcutf8len(const wchar_t * src)127 wcutf8len(const wchar_t *src)
128 { size_t len = 0;
129
130 for(; *src; src++)
131 { if ( *src < 0x80 )
132 { len++;
133 } else
134 { char o[6];
135 char *e;
136 e = utf8_put_char(o, *src);
137 len += e-o;
138 }
139 }
140
141 return len;
142 }
143
144
145 static wchar_t *
utf8towcs(wchar_t * dest,const char * src,size_t len)146 utf8towcs(wchar_t *dest, const char *src, size_t len)
147 { wchar_t *o = dest;
148 wchar_t *e = &o[len-1];
149
150 for( ; *src; )
151 { int wc;
152
153 src = utf8_get_char(src, &wc);
154 if ( o >= e )
155 { errno = ENAMETOOLONG;
156 return NULL;
157 }
158 *o++ = wc;
159 }
160 *o = 0;
161
162 return dest;
163 }
164
165
166 static size_t
utf8_strlen(const char * s,size_t len)167 utf8_strlen(const char *s, size_t len)
168 { const char *e = &s[len];
169 unsigned int l = 0;
170
171 while(s<e)
172 { int chr;
173
174 s = utf8_get_char(s, &chr);
175 l++;
176 }
177
178 return l;
179 }
180
181
182
183 /*******************************
184 * HOME *
185 *******************************/
186
187 static int
existsAndWriteableDir(const TCHAR * name)188 existsAndWriteableDir(const TCHAR *name)
189 { DWORD a;
190
191 if ( (a=GetFileAttributes(name)) != 0xFFFFFFFF )
192 { if ( a & FILE_ATTRIBUTE_DIRECTORY )
193 { if ( !(a & FILE_ATTRIBUTE_READONLY) )
194 return TRUE;
195 }
196 }
197
198 return FALSE;
199 }
200
201
202 char *
_xos_home()203 _xos_home() /* expansion of ~ */
204 { static char home[PATH_MAX];
205 static int done = FALSE;
206
207 if ( !done )
208 { TCHAR h[PATH_MAX];
209
210 /* Unix, set by user */
211 if ( GetEnvironmentVariable(_T("HOME"), h, sizeof(h)) &&
212 existsAndWriteableDir(h) )
213 { _xos_canonical_filenameW(h, home, sizeof(home), 0);
214 } else if ( GetEnvironmentVariable(_T("USERPROFILE"), h, sizeof(h)) &&
215 existsAndWriteableDir(h) )
216 { _xos_canonical_filenameW(h, home, sizeof(home), 0);
217 } else
218 { TCHAR d[100];
219 TCHAR p[PATH_MAX];
220 TCHAR tmp[PATH_MAX];
221 int haved, havep;
222
223 haved = GetEnvironmentVariable(_T("HOMEDRIVE"), d, sizeof(d));
224 havep = GetEnvironmentVariable(_T("HOMEPATH"), p, sizeof(p));
225
226 tmp[0] = '\0';
227 if ( haved && havep ) /* Windows-NT */
228 { _tcscpy(tmp, d);
229 _tcscat(tmp, p);
230 } else if ( haved )
231 { _tcscpy(tmp, d);
232 _tcscat(tmp, _T("\\"));
233 } else if ( havep )
234 { _tcscpy(tmp, p);
235 } else if ( GetWindowsDirectory(tmp, sizeof(tmp)) == 0 )
236 { int drv = _getdrive(); /* A=1 */
237
238 tmp[0] = drv-1+'a';
239 _tcscpy(&tmp[1], _T(":\\"));
240 }
241
242 _xos_canonical_filenameW(tmp, home, sizeof(home), 0);
243 }
244
245 done = TRUE;
246 }
247
248 return home;
249 }
250
251
252 /*******************************
253 * NAME CONVERSION *
254 *******************************/
255
256 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
257 Map a UTF-8 string in Prolog internal representation to a UNICODE string
258 to be used with the Windows UNICODE access functions.
259 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
260
261 wchar_t *
_xos_os_filenameW(const char * cname,wchar_t * osname,size_t len)262 _xos_os_filenameW(const char *cname, wchar_t *osname, size_t len)
263 { wchar_t *s = osname;
264 wchar_t *e = &osname[len-1];
265 const char *q = cname;
266
267 s = osname;
268 /* /c:/ --> c:/ */
269 if ( q[0] == '/' && q[1] < 0x80 && isalpha(q[1]) && q[2] == ':' &&
270 (q[3] == '/' || q[3] == '\0') )
271 { if ( s+2 >= e )
272 { errno = ENAMETOOLONG;
273 return NULL;
274 }
275 *s++ = q[1];
276 *s++ = ':';
277 q += 3;
278 }
279
280 if ( (q[0] == '/' || q[0] == '\\') &&
281 (q[1] == '/' || q[1] == '\\') ) /* deal with //host/share */
282 { if ( s+1 >= e )
283 { errno = ENAMETOOLONG;
284 return NULL;
285 }
286 *s++ = '\\';
287 }
288
289 while( *q ) /* map / --> \, delete multiple '\' */
290 { if ( *q == '/' || *q == '\\' )
291 { if ( s+1 >= e )
292 { errno = ENAMETOOLONG;
293 return NULL;
294 }
295 *s++ = '\\';
296 q++;
297 while(*q == '/' || *q == '\\')
298 q++;
299 } else
300 { int wc;
301
302 q = utf8_get_char(q, &wc);
303 if ( s+2 >= e )
304 { errno = ENAMETOOLONG;
305 return NULL;
306 }
307 *s++ = wc;
308 }
309 }
310
311 while(s > osname+1 && s[-1] == '\\' ) /* delete trailing '\' */
312 s--;
313 /* d: --> d:\ */
314 if ( s == &osname[2] && osname[1] == ':' &&
315 osname[0] < 0x80 && isalpha(osname[0]) )
316 *s++ = '\\';
317 *s = '\0';
318
319 return osname;
320 }
321
322
323 char *
_xos_os_filename(const char * cname,char * osname,size_t len)324 _xos_os_filename(const char *cname, char *osname, size_t len)
325 { TCHAR buf[PATH_MAX];
326
327 if ( !_xos_os_filenameW(cname, buf, PATH_MAX) )
328 return NULL;
329
330 return wcstoutf8(osname, buf, len);
331 }
332
333
334 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
335 Transform a UNICODE Windows filename into a UTF-8 representation of the
336 filename in Prolog canonical representation.
337 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
338
339 char *
_xos_canonical_filenameW(const wchar_t * spec,char * xname,size_t len,int flags)340 _xos_canonical_filenameW(const wchar_t *spec,
341 char *xname, size_t len,
342 int flags)
343 { const wchar_t *s = spec;
344 char *p = xname;
345 char *e = &xname[len];
346
347 if ( s[0] < 0x80 && isupper(s[0]) && s[1] == ':' )
348 { *p++ = tolower(s[0]);
349 *p++ = (char)s[1];
350 s += 2;
351 }
352
353 for(; *s; s++)
354 { int c = *s;
355
356 if ( c == '\\' )
357 { c = '/';
358 } else if ( (flags&XOS_DOWNCASE) )
359 { c = towlower((wchar_t)c);
360 }
361
362 if ( p+6 >= e )
363 { errno = ENAMETOOLONG;
364 return NULL;
365 }
366 p = utf8_put_char(p, c);
367 }
368 *p = '\0';
369
370 return xname;
371 }
372
373
374 char *
_xos_canonical_filename(const char * spec,char * xname,size_t len,int flags)375 _xos_canonical_filename(const char *spec, char *xname, size_t len, int flags)
376 { TCHAR buf[PATH_MAX];
377
378 if ( !utf8towcs(buf, spec, PATH_MAX) )
379 return NULL;
380
381 return _xos_canonical_filenameW(buf, xname, len, flags);
382 }
383
384
385 int
_xos_is_absolute_filename(const char * spec)386 _xos_is_absolute_filename(const char *spec)
387 { TCHAR buf[PATH_MAX];
388
389 _xos_os_filenameW(spec, buf, PATH_MAX);
390 if ( buf[1] == ':' && buf[0] < 0x80 && iswalpha(buf[0]) )
391 return TRUE; /* drive */
392 if ( buf[0] == '\\' && buf[1] == '\\' )
393 return TRUE; /* UNC */
394
395 return FALSE;
396 }
397
398
399 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
400 Get rid of possible 8+3 characters in the path. The documentation
401 suggests you can do that using a single FindFirstFile or
402 GetFullPathName, but it appears you cannot. If you like, here is the
403 code that doesn't work:
404
405 char *
406 _xos_long_file_nameW(const char *file, char *longname)
407 { DWORD len;
408 LPTSTR fp;
409
410 if ( !(len=GetFullPathName(file, PATH_MAX, longname, &fp)) ||
411 len >= PATH_MAX )
412 strcpy(longname, file);
413
414 return longname;
415 }
416 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
417
418 TCHAR *
_xos_long_file_nameW(const TCHAR * file,TCHAR * longname,size_t len)419 _xos_long_file_nameW(const TCHAR *file, TCHAR *longname, size_t len)
420 { const TCHAR *i = file;
421 TCHAR *o = longname;
422 TCHAR *ok = longname;
423 TCHAR *e = &longname[len-1];
424 int changed = 0;
425
426 while(*i)
427 { int dirty = FALSE;
428
429 while(*i && *i != '\\' && *i != '/' )
430 { if ( *i == '~' )
431 dirty++;
432 if ( o >= e )
433 { errno = ENAMETOOLONG;
434 return NULL;
435 }
436 *o++ = *i++;
437 }
438 if ( dirty )
439 { WIN32_FIND_DATA data;
440 HANDLE h;
441
442 *o = '\0';
443 if ( (h=FindFirstFile(longname, &data)) != INVALID_HANDLE_VALUE )
444 { size_t l = _tcslen(data.cFileName);
445
446 if ( ok+l >= e )
447 { errno = ENAMETOOLONG;
448 FindClose(h);
449 return NULL;
450 }
451
452 _tcscpy(ok, data.cFileName);
453 FindClose(h);
454 o = ok + l;
455 changed++;
456 }
457 }
458 if ( *i )
459 { if ( o >= e )
460 { errno = ENAMETOOLONG;
461 return NULL;
462 }
463 *o++ = *i++;
464 }
465 ok = o;
466 }
467
468 *o = '\0';
469
470 return longname;
471 }
472
473
474 char *
_xos_long_file_name_toA(const wchar_t * file,char * longname,size_t len)475 _xos_long_file_name_toA(const wchar_t *file, char *longname, size_t len)
476 { TCHAR buf[PATH_MAX];
477
478 if ( !_xos_long_file_nameW(file, buf, PATH_MAX) )
479 return NULL;
480
481 return wcstoutf8(longname, buf, len);
482 }
483
484
485 char *
_xos_long_file_name(const char * file,char * longname,size_t len)486 _xos_long_file_name(const char *file, char *longname, size_t len)
487 { TCHAR in[PATH_MAX];
488 TCHAR out[PATH_MAX];
489
490 if ( !utf8towcs(in, file, PATH_MAX) )
491 return NULL;
492
493 if ( !_xos_long_file_nameW(in, out, PATH_MAX) )
494 return NULL;
495
496 return wcstoutf8(longname, out, len);
497 }
498
499
500 char *
_xos_absolute_filename(const char * local,char * absolute,size_t len)501 _xos_absolute_filename(const char *local, char *absolute, size_t len)
502 { TCHAR buf[PATH_MAX];
503 TCHAR *filepart;
504 TCHAR abs[PATH_MAX];
505
506 if ( !_xos_os_filenameW(local, buf, PATH_MAX) )
507 return NULL;
508
509 if ( GetFullPathName(buf, PATH_MAX, abs, &filepart) )
510 return _xos_canonical_filenameW(abs, absolute, len, 0);
511
512 return NULL;
513 }
514
515
516 int
_xos_same_file(const char * p1,const char * p2)517 _xos_same_file(const char *p1, const char *p2)
518 { if ( strcmp(p1, p2) == 0 )
519 { return TRUE;
520 } else
521 { TCHAR osp1[PATH_MAX], osp2[PATH_MAX];
522 TCHAR abs1[PATH_MAX], abs2[PATH_MAX];
523 TCHAR *fp;
524
525 if ( !_xos_os_filenameW(p1, osp1, PATH_MAX) ||
526 !_xos_os_filenameW(p2, osp2, PATH_MAX) )
527 return -1; /* error */
528
529 if ( !GetFullPathName(osp1, PATH_MAX, abs1, &fp) ||
530 !GetFullPathName(osp2, PATH_MAX, abs2, &fp) )
531 return -1;
532
533 //fwprintf(stderr, _T("f1='%s'\nf2='%s'\n"), abs1, abs2);
534
535 if ( _tcsicmp(abs1, abs2) == 0 )
536 return TRUE;
537 }
538
539 return FALSE;
540 }
541
542
543 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
544 Apply file-name limitations to a path-name. For DOS-type filesystems,
545 this implies limitation to the 8+3 convention and omitting illegal
546 characters. NT doesn't have all this, but filenames are matched case
547 insensitive, so we map everything to one case. Note that both arguments
548 are in UTF-8 encoding!
549 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
550
551 char *
_xos_limited_os_filename(const char * spec,char * limited)552 _xos_limited_os_filename(const char *spec, char *limited)
553 { const char *i = spec;
554 char *o = limited;
555
556 while(*i)
557 { int wc;
558
559 i = utf8_get_char(i, &wc);
560 wc = towlower((wchar_t)wc);
561 o = utf8_put_char(o, wc);
562 }
563 *o = '\0';
564
565 return limited;
566 }
567
568
569 /*******************************
570 * FILE READ/WRITE *
571 *******************************/
572
573 int
_xos_open(const char * path,int access,...)574 _xos_open(const char *path, int access, ...)
575 { va_list args;
576 TCHAR buf[PATH_MAX];
577 int mode;
578
579 va_start(args, access);
580 mode = va_arg(args, int);
581 va_end(args);
582
583 if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
584 return -1;
585
586 return _wopen(buf, access, mode);
587 }
588
589
590 int
_xos_close(int handle)591 _xos_close(int handle)
592 { return _close(handle);
593 }
594
595
596 ssize_t
_xos_read(int handle,void * buf,size_t size)597 _xos_read(int handle, void *buf, size_t size)
598 { return _read(handle, buf, (unsigned int)size);
599 }
600
601
602 ssize_t
_xos_write(int handle,const void * buf,size_t size)603 _xos_write(int handle, const void *buf, size_t size)
604 { return _write(handle, buf, (unsigned int)size);
605 }
606
607
608 long
_xos_lseek(int handle,long offset,int whence)609 _xos_lseek(int handle, long offset, int whence)
610 { return _lseek(handle, offset, whence);
611 }
612
613
614 long
_xos_tell(int handle)615 _xos_tell(int handle)
616 { return _tell(handle);
617 }
618
619
620 #define MAX_FOPEN_FLAGS 10
621
622 FILE *
_xos_fopen(const char * path,const char * mode)623 _xos_fopen(const char *path, const char *mode)
624 { TCHAR buf[PATH_MAX];
625 TCHAR m[MAX_FOPEN_FLAGS];
626 int i;
627
628 if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
629 return NULL;
630
631 for(i=0; *mode && i < MAX_FOPEN_FLAGS-1; )
632 m[i++] = (*mode++)&0xff;
633 m[i] = 0;
634
635 return _wfopen(buf, m);
636 }
637
638
639 /*******************************
640 * FILE MANIPULATIONS *
641 *******************************/
642
643 static int win_file_access_check = XOS_ACCESS_OPENCLOSE;
644
645 int
_xos_set_win_file_access_check(int new)646 _xos_set_win_file_access_check(int new)
647 { int old = win_file_access_check;
648
649 win_file_access_check = new;
650 return old;
651 }
652
653 int
_xos_get_win_file_access_check(void)654 _xos_get_win_file_access_check(void)
655 { return win_file_access_check;
656 }
657
658 int
_xos_access(const char * path,int mode)659 _xos_access(const char *path, int mode)
660 { TCHAR buf[PATH_MAX];
661 char sd_buf[512];
662 SECURITY_DESCRIPTOR *sd;
663 BOOL access_status;
664 DWORD desired_access = 0;
665 DWORD sd_size, granted_access;
666 HANDLE token = 0, imp_token = 0;
667 GENERIC_MAPPING generic_mapping;
668 PRIVILEGE_SET privelege_set;
669 DWORD priv_set_len = sizeof(PRIVILEGE_SET);
670 int retval = -1;
671 SECURITY_INFORMATION sec_info =
672 DACL_SECURITY_INFORMATION |
673 OWNER_SECURITY_INFORMATION |
674 GROUP_SECURITY_INFORMATION;
675
676 if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
677 return -1;
678
679 if ( mode == F_OK || win_file_access_check == XOS_ACCESS_ACCESS )
680 return _waccess(buf, mode);
681
682 if ( win_file_access_check == XOS_ACCESS_OPENCLOSE )
683 { int m = 0;
684 int fd;
685
686 if ( exists_file_or_dir(buf, _XOS_DIR) )
687 return _waccess(buf, mode);
688
689 if ( mode & X_OK )
690 mode |= R_OK;
691
692 if ( (mode&(R_OK|W_OK)) == (R_OK|W_OK) )
693 m = _O_RDWR;
694 else if ( mode&R_OK )
695 m = _O_RDONLY;
696 else
697 m = _O_WRONLY;
698
699 if ( (fd=_wopen(buf, m)) >= 0 )
700 { _close(fd);
701 return 0;
702 }
703 return -1;
704 }
705
706 sd = (SECURITY_DESCRIPTOR*)&sd_buf;
707 if ( !GetFileSecurity(buf, sec_info, sd, sizeof(sd_buf), &sd_size) )
708 { if ( GetLastError() == ERROR_INVALID_FUNCTION )
709 { goto simple;
710 } else if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
711 { errno = ENOENT;
712 return -1;
713 }
714
715 if ( !(sd = malloc(sd_size)) )
716 { errno = ENOMEM;
717 return -1;
718 }
719
720 if ( !GetFileSecurity(buf, sec_info, sd, sd_size, &sd_size) )
721 goto simple;
722 }
723
724 if ( mode & W_OK )
725 { if ( _waccess(buf, W_OK ) < 0 ) /* read-only bit set */
726 goto out;
727 }
728
729 if ( !OpenThreadToken(GetCurrentThread(),
730 TOKEN_DUPLICATE | TOKEN_READ,
731 TRUE,
732 &token) )
733 { if ( GetLastError() != ERROR_NO_TOKEN )
734 goto simple;
735
736 if ( !OpenProcessToken(GetCurrentProcess(),
737 TOKEN_DUPLICATE | TOKEN_READ,
738 &token) )
739 goto simple;
740 }
741
742 if ( !DuplicateToken(token,
743 SecurityImpersonation,
744 &imp_token) )
745 goto simple;
746
747 if (mode & R_OK) desired_access |= GENERIC_READ;
748 if (mode & W_OK) desired_access |= GENERIC_WRITE;
749 if (mode & X_OK) desired_access |= GENERIC_EXECUTE;
750
751 generic_mapping.GenericRead = FILE_GENERIC_READ;
752 generic_mapping.GenericWrite = FILE_GENERIC_WRITE;
753 generic_mapping.GenericExecute = FILE_GENERIC_EXECUTE;
754 generic_mapping.GenericAll = FILE_ALL_ACCESS;
755 MapGenericMask(&desired_access, &generic_mapping);
756
757 if ( !AccessCheck(sd,
758 imp_token,
759 desired_access,
760 &generic_mapping,
761 &privelege_set,
762 &priv_set_len,
763 &granted_access,
764 &access_status) )
765 goto simple;
766
767 if ( access_status )
768 retval = 0;
769
770 out:
771 if ( sd && (char*)sd != sd_buf ) free(sd);
772 if (imp_token) CloseHandle(imp_token);
773 if (token) CloseHandle(token);
774
775 return retval;
776
777 simple:
778 retval = _waccess(buf, mode);
779 goto out;
780 }
781
782
783 int
_xos_access_dir(const char * path,int mode)784 _xos_access_dir(const char *path, int mode)
785 { TCHAR buf[PATH_MAX];
786
787 if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
788 return -1;
789
790 return _waccess(buf, mode);
791 }
792
793
794 int
_xos_chmod(const char * path,int mode)795 _xos_chmod(const char *path, int mode)
796 { TCHAR buf[PATH_MAX];
797
798 if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
799 return -1;
800
801 return _wchmod(buf, mode);
802 }
803
804
805 int
_xos_remove(const char * path)806 _xos_remove(const char *path)
807 { TCHAR buf[PATH_MAX];
808
809 if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
810 return -1;
811
812 return _wremove(buf);
813 }
814
815
816 int
_xos_rename(const char * old,const char * new)817 _xos_rename(const char *old, const char *new)
818 { TCHAR osold[PATH_MAX];
819 TCHAR osnew[PATH_MAX];
820
821 if ( !_xos_os_filenameW(old, osold, PATH_MAX) ||
822 !_xos_os_filenameW(new, osnew, PATH_MAX) )
823 return -1;
824
825 if ( MoveFileEx(osold, osnew, MOVEFILE_REPLACE_EXISTING) )
826 return 0;
827
828 errno = EPERM;
829 return -1; /* TBD: map error codes */
830 }
831
832
833 int
_xos_stat(const char * path,struct _stati64 * sbuf)834 _xos_stat(const char *path, struct _stati64 *sbuf)
835 { TCHAR buf[PATH_MAX];
836
837 if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
838 return -1;
839
840 return _wstati64(buf, sbuf);
841 }
842
843
844 static int
exists_file_or_dir(const TCHAR * path,int flags)845 exists_file_or_dir(const TCHAR *path, int flags)
846 { DWORD a;
847
848 if ( (a=GetFileAttributes(path)) != 0xFFFFFFFF )
849 { if ( flags & _XOS_DIR )
850 { if ( a & FILE_ATTRIBUTE_DIRECTORY )
851 return TRUE;
852 else
853 return FALSE;
854 }
855 if ( flags & _XOS_FILE )
856 { if ( a & FILE_ATTRIBUTE_DIRECTORY )
857 return FALSE;
858 }
859
860 return TRUE;
861 }
862
863 return FALSE;
864 }
865
866
867 int
_xos_exists(const char * path,int flags)868 _xos_exists(const char *path, int flags)
869 { TCHAR buf[PATH_MAX];
870
871 if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
872 return -1;
873
874 return exists_file_or_dir(buf, flags);
875 }
876
877
878 /*******************************
879 * DIRECTORIES *
880 *******************************/
881
882 DIR *
opendir(const char * path)883 opendir(const char *path)
884 { TCHAR buf[PATH_MAX];
885 DIR *dp = malloc(sizeof(DIR));
886
887 if ( !dp )
888 { errno = ENOMEM;
889 return NULL;
890 }
891
892 if ( !_xos_os_filenameW(path, buf, PATH_MAX-4) )
893 { free(dp);
894 return NULL;
895 }
896 _tcscat(buf, _T("\\*.*"));
897
898 if ( !(dp->data = malloc(sizeof(WIN32_FIND_DATA))) )
899 { free(dp);
900 errno = ENOMEM;
901 return NULL;
902 }
903 dp->first = 1;
904 dp->handle = FindFirstFile(buf, dp->data);
905
906 if ( dp->handle == INVALID_HANDLE_VALUE )
907 { if ( _waccess(buf, 04) ) /* does not exist */
908 { free(dp->data);
909 free(dp);
910 return NULL;
911 }
912 }
913
914 return dp;
915 }
916
917
918 int
closedir(DIR * dp)919 closedir(DIR *dp)
920 { if ( dp )
921 { if ( dp->handle )
922 FindClose(dp->handle);
923 free(dp->data);
924 free(dp);
925
926 return 0;
927 }
928
929 return -1;
930 }
931
932
933 static struct dirent *
translate_data(DIR * dp)934 translate_data(DIR *dp)
935 { WIN32_FIND_DATA *data;
936
937 if ( !dp->handle )
938 return NULL;
939
940 data = dp->data;
941 if ( wcstoutf8(dp->d_name, data->cFileName, sizeof(dp->d_name)) )
942 return dp;
943
944 return NULL;
945 }
946
947
948 struct dirent *
readdir(DIR * dp)949 readdir(DIR *dp)
950 { for(;;)
951 { struct dirent *de;
952
953 if ( dp->first )
954 { dp->first = 0;
955 } else
956 { if ( dp->handle )
957 { if ( !FindNextFile(dp->handle, dp->data) )
958 return NULL;
959 }
960 }
961
962 if ( (de = translate_data(dp)) )
963 return de;
964 }
965 }
966
967
968 int
_xos_chdir(const char * path)969 _xos_chdir(const char *path)
970 { TCHAR buf[PATH_MAX];
971
972 if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
973 return -1;
974
975 if ( buf[0] < 0x80 && isalpha(buf[0]) && buf[1] == ':' )
976 { int drv = tolower(buf[0]) - 'a' + 1;
977
978 if ( _getdrive() != drv )
979 { if ( _chdrive(drv) < 0 )
980 return -1;
981 }
982 }
983
984 return _wchdir(buf);
985 }
986
987
988 int
_xos_mkdir(const char * path,int mode)989 _xos_mkdir(const char *path, int mode)
990 { TCHAR buf[PATH_MAX];
991
992 if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
993 return -1;
994
995 return _wmkdir(buf);
996 }
997
998
999 int
_xos_rmdir(const char * path)1000 _xos_rmdir(const char *path)
1001 { TCHAR buf[PATH_MAX];
1002
1003 if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
1004 return -1;
1005
1006 return _wrmdir(buf);
1007 }
1008
1009
1010 char *
_xos_getcwd(char * buf,size_t len)1011 _xos_getcwd(char *buf, size_t len)
1012 { TCHAR buf0[PATH_MAX];
1013 TCHAR buf1[PATH_MAX];
1014
1015 if ( _wgetcwd(buf0, sizeof(buf0)/sizeof(TCHAR)) &&
1016 _xos_long_file_nameW(buf0, buf1, sizeof(buf0)/sizeof(TCHAR)) )
1017 { return _xos_canonical_filenameW(buf1, buf, len, 0);
1018 }
1019
1020 return NULL;
1021 }
1022
1023
1024 /*******************************
1025 * ENVIRONMENT *
1026 *******************************/
1027
1028 size_t
_xos_getenv(const char * name,char * buf,size_t buflen)1029 _xos_getenv(const char *name, char *buf, size_t buflen)
1030 { TCHAR nm[PATH_MAX];
1031 TCHAR val[PATH_MAX];
1032 TCHAR *valp = val;
1033 size_t size;
1034
1035 if ( !utf8towcs(nm, name, PATH_MAX) )
1036 return -1;
1037 size = GetEnvironmentVariable(nm, valp, PATH_MAX);
1038
1039 if ( size > 0 )
1040 { size_t rc;
1041
1042 if ( size >= PATH_MAX )
1043 { if ( (valp = malloc((size+1)*sizeof(TCHAR))) == NULL )
1044 return -1;
1045 size = GetEnvironmentVariable(nm, valp, (DWORD)(size+1));
1046 }
1047
1048 size = wcslen(valp); /* return sometimes holds 0-bytes */
1049 if ( wcstoutf8(buf, valp, buflen) )
1050 rc = strlen(buf);
1051 else
1052 rc = wcutf8len(valp);
1053
1054 if ( valp != val )
1055 free(valp);
1056
1057 return rc;
1058 }
1059
1060 return -1;
1061 }
1062
1063
1064 int
_xos_setenv(const char * name,char * value,int overwrite)1065 _xos_setenv(const char *name, char *value, int overwrite)
1066 { TCHAR nm[PATH_MAX];
1067 TCHAR buf[PATH_MAX];
1068 TCHAR *val = buf;
1069 int rc;
1070
1071 if ( !utf8towcs(nm, name, PATH_MAX) )
1072 return -1;
1073 if ( !overwrite && GetEnvironmentVariable(nm, NULL, 0) > 0 )
1074 return 0;
1075 if ( !utf8towcs(val, value, PATH_MAX) )
1076 { size_t wlen = utf8_strlen(value, strlen(value)) + 1;
1077
1078 if ( (val = malloc(wlen*sizeof(TCHAR))) == NULL )
1079 return -1;
1080 utf8towcs(val, value, wlen);
1081 }
1082
1083 rc = SetEnvironmentVariable(nm, val);
1084 if ( val != buf )
1085 free(val);
1086
1087 if ( rc )
1088 return 0;
1089
1090 return -1; /* TBD: convert error */
1091 }
1092