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