1095 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1095 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /*  Part of SWI-Prolog
 | |
| 
 | |
|     Author:        Jan Wielemaker
 | |
|     E-mail:        J.Wielemaker@vu.nl
 | |
|     WWW:           http://www.swi-prolog.org
 | |
|     Copyright (C): 1985-2012, University of Amsterdam
 | |
| 			      Vu University Amsterdam
 | |
| 
 | |
|     This library is free software; you can redistribute it and/or
 | |
|     modify it under the terms of the GNU Lesser General Public
 | |
|     License as published by the Free Software Foundation; either
 | |
|     version 2.1 of the License, or (at your option) any later version.
 | |
| 
 | |
|     This library is distributed in the hope that it will be useful,
 | |
|     but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|     Lesser General Public License for more details.
 | |
| 
 | |
|     You should have received a copy of the GNU Lesser General Public
 | |
|     License along with this library; if not, write to the Free Software
 | |
|     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 | |
| */
 | |
| 
 | |
| #if defined(_WIN32) || defined(__MINGW32__) || defined(__MSYS__)
 | |
| 
 | |
| #define UNICODE 1
 | |
| #define _UNICODE 1
 | |
| 
 | |
| #define _UXNT_KERNEL 1
 | |
| #include "uxnt.h"			/* my prototypes */
 | |
| #include "utf8.c"
 | |
| 
 | |
| #include <windows.h>
 | |
| #include <tchar.h>
 | |
| #include <wchar.h>
 | |
| #include "dirent.h"
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <stdarg.h>
 | |
| #include <stddef.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <ctype.h>
 | |
| #undef mkdir				/* avoid conflict */
 | |
| #include <direct.h>
 | |
| #ifndef __LCC__				/* not delete altogether? */
 | |
| #define mkdir _xos_mkdir
 | |
| #endif
 | |
| #include <errno.h>
 | |
| 
 | |
| #ifndef TRUE
 | |
| #define TRUE 1
 | |
| #define FALSE 0
 | |
| #endif
 | |
| 
 | |
| #ifdef __LCC__
 | |
| #define _close close
 | |
| #define _read read
 | |
| #define _write write
 | |
| #define _lseek lseek
 | |
| #define _tell tell
 | |
| #define _chdir chdir
 | |
| #define _mkdir mkdir
 | |
| #define _rmdir rmdir
 | |
| #define _getcwd getcwd
 | |
| #endif
 | |
| 
 | |
| #define XENOMAP 1
 | |
| #define XENOMEM 2
 | |
| 
 | |
| #ifndef PATH_MAX
 | |
| #define PATH_MAX 260
 | |
| #endif
 | |
| 
 | |
| 
 | |
| 		 /*******************************
 | |
| 		 *	       ERRNO		*
 | |
| 		 *******************************/
 | |
| 
 | |
| int
 | |
| _xos_errno()
 | |
| { return errno;
 | |
| }
 | |
| 
 | |
| 		 /*******************************
 | |
| 		 *		UTF-8		*
 | |
| 		 *******************************/
 | |
| 
 | |
| static char *
 | |
| wcstoutf8(char *dest, const wchar_t *src, size_t len)
 | |
| { char *o = dest;
 | |
|   char *e = &o[len];
 | |
| 
 | |
|   for(; *src; src++)
 | |
|   { if ( o+6 > e )
 | |
|     { errno = ENAMETOOLONG;
 | |
|       return NULL;
 | |
|     }
 | |
|     o = utf8_put_char(o, *src);
 | |
|   }
 | |
|   *o = '\0';
 | |
| 
 | |
|   return dest;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* length of src in UTF-8, excluding terminating EOS */
 | |
| 
 | |
| static size_t
 | |
| wcutf8len(const wchar_t *src)
 | |
| { size_t len = 0;
 | |
| 
 | |
|   for(; *src; src++)
 | |
|   { if ( *src < 0x80 )
 | |
|     { len++;
 | |
|     } else
 | |
|     { char o[6];
 | |
|       char *e;
 | |
|       e = utf8_put_char(o, *src);
 | |
|       len += e-o;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return len;
 | |
| }
 | |
| 
 | |
| 
 | |
| static wchar_t *
 | |
| utf8towcs(wchar_t *dest, const char *src, size_t len)
 | |
| { wchar_t *o = dest;
 | |
|   wchar_t *e = &o[len-1];
 | |
| 
 | |
|   for( ; *src; )
 | |
|   { int wc;
 | |
| 
 | |
|     src = utf8_get_char(src, &wc);
 | |
|     if ( o >= e )
 | |
|     { errno = ENAMETOOLONG;
 | |
|       return NULL;
 | |
|     }
 | |
|     *o++ = wc;
 | |
|   }
 | |
|   *o = 0;
 | |
| 
 | |
|   return dest;
 | |
| }
 | |
| 
 | |
| 
 | |
| static size_t
 | |
| utf8_strlen(const char *s, size_t len)
 | |
| { const char *e = &s[len];
 | |
|   unsigned int l = 0;
 | |
| 
 | |
|   while(s<e)
 | |
|   { int chr;
 | |
| 
 | |
|     s = utf8_get_char(s, &chr);
 | |
|     l++;
 | |
|   }
 | |
| 
 | |
|   return l;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 		 /*******************************
 | |
| 		 *	       HOME		*
 | |
| 		 *******************************/
 | |
| 
 | |
| static int
 | |
| existsAndWriteableDir(const TCHAR *name)
 | |
| { DWORD a;
 | |
| 
 | |
|   if ( (a=GetFileAttributes(name)) != 0xFFFFFFFF )
 | |
|   { if ( a & FILE_ATTRIBUTE_DIRECTORY )
 | |
|     { if ( !(a & FILE_ATTRIBUTE_READONLY) )
 | |
| 	return TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| char *
 | |
| _xos_home()				/* expansion of ~ */
 | |
| { static char home[PATH_MAX];
 | |
|   static int done = FALSE;
 | |
| 
 | |
|   if ( !done )
 | |
|   { TCHAR h[PATH_MAX];
 | |
| 
 | |
| 					/* Unix, set by user */
 | |
|     if ( GetEnvironmentVariable(_T("HOME"), h, sizeof(h)) &&
 | |
| 	 existsAndWriteableDir(h) )
 | |
|     { _xos_canonical_filenameW(h, home, sizeof(home), 0);
 | |
|     } else if ( GetEnvironmentVariable(_T("USERPROFILE"), h, sizeof(h)) &&
 | |
| 		existsAndWriteableDir(h) )
 | |
|     { _xos_canonical_filenameW(h, home, sizeof(home), 0);
 | |
|     } else
 | |
|     { TCHAR d[100];
 | |
|       TCHAR p[PATH_MAX];
 | |
|       TCHAR tmp[PATH_MAX];
 | |
|       int haved, havep;
 | |
| 
 | |
|       haved = GetEnvironmentVariable(_T("HOMEDRIVE"), d, sizeof(d));
 | |
|       havep = GetEnvironmentVariable(_T("HOMEPATH"),  p, sizeof(p));
 | |
| 
 | |
|       tmp[0] = '\0';
 | |
|       if ( haved && havep )		/* Windows-NT */
 | |
|       { _tcscpy(tmp, d);
 | |
| 	_tcscat(tmp, p);
 | |
|       } else if ( haved )
 | |
|       { _tcscpy(tmp, d);
 | |
| 	_tcscat(tmp, _T("\\"));
 | |
|       } else if ( havep )
 | |
|       { _tcscpy(tmp, p);
 | |
|       } else if ( GetWindowsDirectory(tmp, sizeof(tmp)) == 0 )
 | |
|       { int drv = _getdrive();		/* A=1 */
 | |
| 
 | |
| 	tmp[0] = drv-1+'a';
 | |
| 	_tcscpy(&tmp[1], _T(":\\"));
 | |
|       }
 | |
| 
 | |
|       _xos_canonical_filenameW(tmp, home, sizeof(home), 0);
 | |
|     }
 | |
| 
 | |
|     done = TRUE;
 | |
|   }
 | |
| 
 | |
|   return home;
 | |
| }
 | |
| 
 | |
| 
 | |
| 		 /*******************************
 | |
| 		 *	  NAME CONVERSION	*
 | |
| 		 *******************************/
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | |
| Map a UTF-8 string in Prolog internal representation to a UNICODE string
 | |
| to be used with the Windows UNICODE access functions.
 | |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| wchar_t *
 | |
| _xos_os_filenameW(const char *cname, wchar_t *osname, size_t len)
 | |
| { wchar_t *s = osname;
 | |
|   wchar_t *e = &osname[len-1];
 | |
|   const char *q = cname;
 | |
| 
 | |
|   s = osname;
 | |
| 					/* /c:/ --> c:/ */
 | |
|   if ( q[0] == '/' && q[1] < 0x80 && isalpha(q[1]) && q[2] == ':' &&
 | |
|        (q[3] == '/' || q[3] == '\0') )
 | |
|   { if ( s+2 >= e )
 | |
|     { errno = ENAMETOOLONG;
 | |
|       return NULL;
 | |
|     }
 | |
|     *s++ = q[1];
 | |
|     *s++ = ':';
 | |
|     q += 3;
 | |
|   }
 | |
| 
 | |
|   if ( (q[0] == '/' || q[0] == '\\') &&
 | |
|        (q[1] == '/' || q[1] == '\\') )	/* deal with //host/share */
 | |
|   { if ( s+1 >= e )
 | |
|     { errno = ENAMETOOLONG;
 | |
|       return NULL;
 | |
|     }
 | |
|     *s++ = '\\';
 | |
|   }
 | |
| 
 | |
| #if __MINGW32__
 | |
|   if ( q == cname && q[0] == '/' )	/* deal with /host/share in mingw32 */
 | |
|   {
 | |
|     UINT is_drive;
 | |
| 
 | |
|     q++;
 | |
|     while (*q && *q != '/') {
 | |
|       if ( s+3 >= e )
 | |
| 	{ errno = ENAMETOOLONG;
 | |
| 	  return NULL;
 | |
| 	}
 | |
|       *s++ = *q++;
 | |
|     }
 | |
|     s[0] = ':';
 | |
|     s[1] = '\\';
 | |
|     s[2] = '\0';
 | |
|     q++;
 | |
|     is_drive = GetDriveType( osname );
 | |
|     if ( is_drive != DRIVE_UNKNOWN &&
 | |
| 	 is_drive != DRIVE_NO_ROOT_DIR ) {
 | |
|       // we actually found a drive
 | |
|       s+=2;
 | |
|     } else {
 | |
|       // restart
 | |
|       q = cname;
 | |
|       s = osname;
 | |
|     }
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   while( *q )				/* map / --> \, delete multiple '\' */
 | |
|   { if ( *q == '/' || *q == '\\' )
 | |
|     { if ( s+1 >= e )
 | |
|       { errno = ENAMETOOLONG;
 | |
| 	return NULL;
 | |
|       }
 | |
|       *s++ = '\\';
 | |
|       q++;
 | |
|       while(*q == '/' || *q == '\\')
 | |
| 	q++;
 | |
|     } else
 | |
|     { int wc;
 | |
| 
 | |
|       q = utf8_get_char(q, &wc);
 | |
|       if ( s+2 >= e )
 | |
|       { errno = ENAMETOOLONG;
 | |
| 	return NULL;
 | |
|       }
 | |
|       *s++ = wc;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   while(s > osname+1 && s[-1] == '\\' )	/* delete trailing '\' */
 | |
|     s--;
 | |
| 					/* d: --> d:\ */
 | |
|   if ( s == &osname[2] && osname[1] == ':' &&
 | |
|        osname[0] < 0x80 && isalpha(osname[0]) )
 | |
|     *s++ = '\\';
 | |
|   *s = '\0';
 | |
| 
 | |
|   return osname;
 | |
| }
 | |
| 
 | |
| 
 | |
| char *
 | |
| _xos_os_filename(const char *cname, char *osname, size_t len)
 | |
| { TCHAR buf[PATH_MAX];
 | |
| 
 | |
|   if ( !_xos_os_filenameW(cname, buf, PATH_MAX) )
 | |
|     return NULL;
 | |
| 
 | |
|   return wcstoutf8(osname, buf, len);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | |
| Transform a UNICODE Windows filename into a UTF-8 representation of the
 | |
| filename in Prolog canonical representation.
 | |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| char *
 | |
| _xos_canonical_filenameW(const wchar_t *spec,
 | |
| 			 char *xname, size_t len,
 | |
| 			 int flags)
 | |
| { const wchar_t *s = spec;
 | |
|   char *p = xname;
 | |
|   char *e = &xname[len];
 | |
| 
 | |
|   if ( s[0] < 0x80 && isupper(s[0]) && s[1] == ':' )
 | |
|   { *p++ = tolower(s[0]);
 | |
|     *p++ = (char)s[1];
 | |
|     s += 2;
 | |
|   }
 | |
| 
 | |
|   for(; *s; s++)
 | |
|   { int c = *s;
 | |
| 
 | |
|     if ( c == '\\' )
 | |
|     { c = '/';
 | |
|     } else if ( (flags&XOS_DOWNCASE) )
 | |
|     { c = towlower((wchar_t)c);
 | |
|     }
 | |
| 
 | |
|     if ( p+6 >= e )
 | |
|     { errno = ENAMETOOLONG;
 | |
|       return NULL;
 | |
|     }
 | |
|     p = utf8_put_char(p, c);
 | |
|   }
 | |
|   *p = '\0';
 | |
| 
 | |
|   return xname;
 | |
| }
 | |
| 
 | |
| 
 | |
| char *
 | |
| _xos_canonical_filename(const char *spec, char *xname, size_t len, int flags)
 | |
| { TCHAR buf[PATH_MAX];
 | |
| 
 | |
|   if ( !utf8towcs(buf, spec, PATH_MAX) )
 | |
|     return NULL;
 | |
| 
 | |
|   return _xos_canonical_filenameW(buf, xname, len, flags);
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| _xos_is_absolute_filename(const char *spec)
 | |
| { TCHAR buf[PATH_MAX];
 | |
| 
 | |
|   _xos_os_filenameW(spec, buf, PATH_MAX);
 | |
|   if ( buf[1] == ':' && buf[0] < 0x80 && iswalpha(buf[0]) )
 | |
|     return TRUE;			/* drive */
 | |
|   if ( buf[0] == '\\' && buf[1] == '\\' )
 | |
|     return TRUE;			/* UNC */
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | |
| Get rid of possible  8+3  characters   in  the  path.  The documentation
 | |
| suggests  you  can  do   that   using    a   single   FindFirstFile   or
 | |
| GetFullPathName, but it appears you cannot.  If   you  like, here is the
 | |
| code that doesn't work:
 | |
| 
 | |
| char *
 | |
| _xos_long_file_nameW(const char *file, char *longname)
 | |
| { DWORD len;
 | |
|   LPTSTR fp;
 | |
| 
 | |
|   if ( !(len=GetFullPathName(file, PATH_MAX, longname, &fp)) ||
 | |
|        len >= PATH_MAX )
 | |
|     strcpy(longname, file);
 | |
| 
 | |
|   return longname;
 | |
| }
 | |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| TCHAR *
 | |
| _xos_long_file_nameW(const TCHAR *file, TCHAR *longname, size_t len)
 | |
| { const TCHAR *i = file;
 | |
|   TCHAR *o = longname;
 | |
|   TCHAR *ok = longname;
 | |
|   TCHAR *e = &longname[len-1];
 | |
|   int changed = 0;
 | |
| 
 | |
|   while(*i)
 | |
|   { int dirty = FALSE;
 | |
| 
 | |
|     while(*i && *i != '\\' && *i != '/' )
 | |
|     { if ( *i == '~' )
 | |
| 	dirty++;
 | |
|       if ( o >= e )
 | |
|       { errno = ENAMETOOLONG;
 | |
| 	return NULL;
 | |
|       }
 | |
|       *o++ = *i++;
 | |
|     }
 | |
|     if ( dirty )
 | |
|     { WIN32_FIND_DATA data;
 | |
|       HANDLE h;
 | |
| 
 | |
|       *o = '\0';
 | |
|       if ( (h=FindFirstFile(longname, &data)) != INVALID_HANDLE_VALUE )
 | |
|       { size_t l = _tcslen(data.cFileName);
 | |
| 
 | |
| 	if ( ok+l >= e )
 | |
| 	{ errno = ENAMETOOLONG;
 | |
| 	  return NULL;
 | |
| 	}
 | |
| 
 | |
| 	_tcscpy(ok, data.cFileName);
 | |
| 	FindClose(h);
 | |
| 	o = ok + l;
 | |
| 	changed++;
 | |
|       }
 | |
|     }
 | |
|     if ( *i )
 | |
|     { if ( o >= e )
 | |
|       { errno = ENAMETOOLONG;
 | |
| 	return NULL;
 | |
|       }
 | |
|       *o++ = *i++;
 | |
|     }
 | |
|     ok = o;
 | |
|   }
 | |
| 
 | |
|   *o = '\0';
 | |
| 
 | |
|   return longname;
 | |
| }
 | |
| 
 | |
| 
 | |
| char *
 | |
| _xos_long_file_name_toA(const wchar_t *file, char *longname, size_t len)
 | |
| { TCHAR buf[PATH_MAX];
 | |
| 
 | |
|   if ( !_xos_long_file_nameW(file, buf, PATH_MAX) )
 | |
|     return NULL;
 | |
| 
 | |
|   return wcstoutf8(longname, buf, len);
 | |
| }
 | |
| 
 | |
| 
 | |
| char *
 | |
| _xos_long_file_name(const char *file, char *longname, size_t len)
 | |
| { TCHAR in[PATH_MAX];
 | |
|   TCHAR out[PATH_MAX];
 | |
| 
 | |
|   if ( !utf8towcs(in, file, PATH_MAX) )
 | |
|     return NULL;
 | |
| 
 | |
|   if ( !_xos_long_file_nameW(in, out, PATH_MAX) )
 | |
|     return NULL;
 | |
| 
 | |
|   return wcstoutf8(longname, out, len);
 | |
| }
 | |
| 
 | |
| 
 | |
| char *
 | |
| _xos_absolute_filename(const char *local, char *absolute, size_t len)
 | |
| { TCHAR buf[PATH_MAX];
 | |
|   TCHAR *filepart;
 | |
|   TCHAR abs[PATH_MAX];
 | |
| 
 | |
|   if ( !_xos_os_filenameW(local, buf, PATH_MAX) )
 | |
|     return NULL;
 | |
| 
 | |
|   if ( GetFullPathName(buf, PATH_MAX, abs, &filepart) )
 | |
|     return _xos_canonical_filenameW(abs, absolute, len, 0);
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| _xos_same_file(const char *p1, const char *p2)
 | |
| {
 | |
|   TCHAR buf1[PATH_MAX];
 | |
|   TCHAR buf2[PATH_MAX];
 | |
|   int rc = FALSE, found = FALSE;
 | |
|   if ( !_xos_os_filenameW(p1, buf1, PATH_MAX) )
 | |
|     return FALSE;
 | |
|   if ( !_xos_os_filenameW(p2, buf2, PATH_MAX) )
 | |
|     return FALSE;
 | |
| 
 | |
|   HANDLE hFile1 = CreateFile(buf1, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 | |
|   HANDLE hFile2 = CreateFile(buf2, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 | |
| 
 | |
|   if (hFile1 != INVALID_HANDLE_VALUE &&
 | |
|       hFile2 != INVALID_HANDLE_VALUE) {
 | |
|     BY_HANDLE_FILE_INFORMATION f1, f2;
 | |
|     if (GetFileInformationByHandle(hFile1, &f1) &&
 | |
| 	GetFileInformationByHandle(hFile2, &f2) ) {
 | |
|       rc =
 | |
| 	f1.dwVolumeSerialNumber == f2.dwVolumeSerialNumber &&
 | |
| 	f1.nFileIndexLow == f2.nFileIndexLow &&
 | |
| 	f1.nFileIndexLow == f2.nFileIndexLow;
 | |
|       found = TRUE;
 | |
|     }
 | |
|   }
 | |
|   if ( hFile1 != INVALID_HANDLE_VALUE )
 | |
|     CloseHandle(hFile1);
 | |
|   if ( hFile2 != INVALID_HANDLE_VALUE )
 | |
|     CloseHandle(hFile2);
 | |
| 
 | |
|   if (found)
 | |
|     return rc;
 | |
| 
 | |
|   // compare by string names
 | |
|   // old SWI code
 | |
| 
 | |
|   if ( strcmp(p1, p2) == 0 )
 | |
|   { return TRUE;
 | |
|   } else
 | |
|   { TCHAR osp1[PATH_MAX], osp2[PATH_MAX];
 | |
|     TCHAR abs1[PATH_MAX], abs2[PATH_MAX];
 | |
|     TCHAR *fp;
 | |
| 
 | |
|     if ( !_xos_os_filenameW(p1, osp1, PATH_MAX) ||
 | |
| 	 !_xos_os_filenameW(p2, osp2, PATH_MAX) )
 | |
|       return -1;			/* error */
 | |
| 
 | |
|     if ( !GetFullPathName(osp1, PATH_MAX, abs1, &fp) ||
 | |
| 	 !GetFullPathName(osp2, PATH_MAX, abs2, &fp) )
 | |
|       return -1;
 | |
| 
 | |
|     //fwprintf(stderr, _T("f1='%s'\nf2='%s'\n"), abs1, abs2);
 | |
| 
 | |
|     if ( _tcsicmp(abs1, abs2) == 0 )
 | |
|       return TRUE;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | |
| Apply file-name limitations to a   path-name.  For DOS-type filesystems,
 | |
| this implies limitation to  the  8+3   convention  and  omitting illegal
 | |
| characters.  NT doesn't have all this,   but  filenames are matched case
 | |
| insensitive, so we map everything to one case.  Note that both arguments
 | |
| are in UTF-8 encoding!
 | |
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | |
| 
 | |
| char *
 | |
| _xos_limited_os_filename(const char *spec, char *limited)
 | |
| { const char *i = spec;
 | |
|   char *o = limited;
 | |
| 
 | |
|   while(*i)
 | |
|   { int wc;
 | |
| 
 | |
|     i = utf8_get_char(i, &wc);
 | |
|     wc = towlower((wchar_t)wc);
 | |
|     o = utf8_put_char(o, wc);
 | |
|   }
 | |
|   *o = '\0';
 | |
| 
 | |
|   return limited;
 | |
| }
 | |
| 
 | |
| 
 | |
| 		 /*******************************
 | |
| 		 *	  FILE READ/WRITE	*
 | |
| 		 *******************************/
 | |
| 
 | |
| int
 | |
| _xos_open(const char *path, int access, ...)
 | |
| { va_list args;
 | |
|   TCHAR buf[PATH_MAX];
 | |
|   int mode;
 | |
| 
 | |
|   va_start(args, access);
 | |
|   mode = va_arg(args, int);
 | |
|   va_end(args);
 | |
| 
 | |
|   if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
 | |
|     return -1;
 | |
| 
 | |
|   return _wopen(buf, access, mode);
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| _xos_close(int handle)
 | |
| { return _close(handle);
 | |
| }
 | |
| 
 | |
| 
 | |
| ssize_t
 | |
| _xos_read(int handle, void *buf, size_t size)
 | |
| { return _read(handle, buf, (unsigned int)size);
 | |
| }
 | |
| 
 | |
| 
 | |
| ssize_t
 | |
| _xos_write(int handle, const void *buf, size_t size)
 | |
| { return _write(handle, buf, (unsigned int)size);
 | |
| }
 | |
| 
 | |
| 
 | |
| long
 | |
| _xos_lseek(int handle, long offset, int whence)
 | |
| { return _lseek(handle, offset, whence);
 | |
| }
 | |
| 
 | |
| 
 | |
| long
 | |
| _xos_tell(int handle)
 | |
| { return _tell(handle);
 | |
| }
 | |
| 
 | |
| 
 | |
| FILE *
 | |
| _xos_fopen(const char *path, const char *mode)
 | |
| { TCHAR buf[PATH_MAX];
 | |
|   TCHAR m[10];
 | |
|   int i;
 | |
| 
 | |
|   if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
 | |
|     return NULL;
 | |
| 
 | |
|   for(i=0; *mode && i < sizeof(m-1); )
 | |
|     m[i++] = (*mode++)&0xff;
 | |
|   m[i] = 0;
 | |
| 
 | |
|   return _wfopen(buf, m);
 | |
| }
 | |
| 
 | |
| 
 | |
| 		 /*******************************
 | |
| 		 *      FILE MANIPULATIONS	*
 | |
| 		 *******************************/
 | |
| 
 | |
| int
 | |
| _xos_access(const char *path, int mode)
 | |
| { TCHAR buf[PATH_MAX];
 | |
|   char sd_buf[512];
 | |
|   SECURITY_DESCRIPTOR *sd;
 | |
|   BOOL access_status;
 | |
|   DWORD desired_access = 0;
 | |
|   DWORD sd_size, granted_access;
 | |
|   HANDLE token = 0, imp_token = 0;
 | |
|   GENERIC_MAPPING generic_mapping;
 | |
|   PRIVILEGE_SET privelege_set;
 | |
|   DWORD  priv_set_len = sizeof(PRIVILEGE_SET);
 | |
|   int retval = -1;
 | |
|   SECURITY_INFORMATION sec_info =
 | |
|     DACL_SECURITY_INFORMATION |
 | |
|     OWNER_SECURITY_INFORMATION |
 | |
|     GROUP_SECURITY_INFORMATION;
 | |
| 
 | |
|   if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
 | |
|     return -1;
 | |
| 
 | |
|   if ( mode == F_OK )
 | |
|     return _waccess(buf, F_OK);
 | |
| 
 | |
|   sd = (SECURITY_DESCRIPTOR*)&sd_buf;
 | |
|   if ( !GetFileSecurity(buf, sec_info, sd, sizeof(sd_buf), &sd_size) )
 | |
|   { if ( GetLastError() == ERROR_INVALID_FUNCTION )
 | |
|     { goto simple;
 | |
|     } else if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
 | |
|     { errno = ENOENT;
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|     if ( !(sd = malloc(sd_size)) )
 | |
|     { errno = ENOMEM;
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|     if ( !GetFileSecurity(buf, sec_info, sd, sd_size, &sd_size) )
 | |
|       goto simple;
 | |
|   }
 | |
| 
 | |
|   if ( mode & W_OK )
 | |
|   { if ( _waccess(buf, W_OK ) < 0 )		/* read-only bit set */
 | |
|       goto out;
 | |
|   }
 | |
| 
 | |
|   if ( !OpenThreadToken(GetCurrentThread(),
 | |
| 			TOKEN_DUPLICATE | TOKEN_READ,
 | |
| 			TRUE,
 | |
| 			&token) )
 | |
|   { if ( GetLastError() != ERROR_NO_TOKEN )
 | |
|       goto simple;
 | |
| 
 | |
|     if ( !OpenProcessToken(GetCurrentProcess(),
 | |
| 			   TOKEN_DUPLICATE | TOKEN_READ,
 | |
| 			   &token) )
 | |
|       goto simple;
 | |
|   }
 | |
| 
 | |
|   if ( !DuplicateToken(token,
 | |
| 		       SecurityImpersonation,
 | |
| 		       &imp_token) )
 | |
|     goto simple;
 | |
| 
 | |
|   if (mode & R_OK) desired_access |= GENERIC_READ;
 | |
|   if (mode & W_OK) desired_access |= GENERIC_WRITE;
 | |
|   if (mode & X_OK) desired_access |= GENERIC_EXECUTE;
 | |
| 
 | |
|   generic_mapping.GenericRead    = FILE_GENERIC_READ;
 | |
|   generic_mapping.GenericWrite   = FILE_GENERIC_WRITE;
 | |
|   generic_mapping.GenericExecute = FILE_GENERIC_EXECUTE;
 | |
|   generic_mapping.GenericAll     = FILE_ALL_ACCESS;
 | |
|   MapGenericMask(&desired_access, &generic_mapping);
 | |
| 
 | |
|   if ( !AccessCheck(sd,
 | |
| 		    imp_token,
 | |
| 		    desired_access,
 | |
| 		    &generic_mapping,
 | |
| 		    &privelege_set,
 | |
| 		    &priv_set_len,
 | |
| 		    &granted_access,
 | |
| 		    &access_status) )
 | |
|     goto simple;
 | |
| 
 | |
|   if ( access_status )
 | |
|     retval  = 0;
 | |
| 
 | |
| out:
 | |
|   if ( sd && (char*)sd != sd_buf ) free(sd);
 | |
|   if (imp_token) CloseHandle(imp_token);
 | |
|   if (token) CloseHandle(token);
 | |
| 
 | |
|   return retval;
 | |
| 
 | |
| simple:
 | |
|   retval = _waccess(buf, mode);
 | |
|   goto out;
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| _xos_chmod(const char *path, mode_t mode)
 | |
| { TCHAR buf[PATH_MAX];
 | |
| 
 | |
|   if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
 | |
|     return -1;
 | |
| 
 | |
|   return _wchmod(buf, mode);
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| _xos_remove(const char *path)
 | |
| { TCHAR buf[PATH_MAX];
 | |
| 
 | |
|   if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
 | |
|     return -1;
 | |
| 
 | |
|   return _wremove(buf);
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| _xos_rename(const char *old, const char *new)
 | |
| { TCHAR osold[PATH_MAX];
 | |
|   TCHAR osnew[PATH_MAX];
 | |
| 
 | |
|   if ( !_xos_os_filenameW(old, osold, PATH_MAX) ||
 | |
|        !_xos_os_filenameW(new, osnew, PATH_MAX) )
 | |
|     return -1;
 | |
| 
 | |
|   if ( MoveFileEx(osold, osnew, MOVEFILE_REPLACE_EXISTING) )
 | |
|     return 0;
 | |
| 
 | |
|   errno = EPERM;
 | |
|   return -1;				/* TBD: map error codes */
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| _xos_stat(const char *path, struct _stati64 *sbuf)
 | |
| { TCHAR buf[PATH_MAX];
 | |
| 
 | |
|    if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
 | |
|     return -1;
 | |
| 
 | |
|   return _wstati64(buf, sbuf);
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| _xos_exists(const char *path, int flags)
 | |
| { TCHAR buf[PATH_MAX];
 | |
|   DWORD a;
 | |
| 
 | |
|   if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
 | |
|     return -1;
 | |
| 
 | |
|   if ( (a=GetFileAttributes(buf)) != 0xFFFFFFFF )
 | |
|   { if ( flags & _XOS_DIR )
 | |
|     { if ( a & FILE_ATTRIBUTE_DIRECTORY )
 | |
| 	return TRUE;
 | |
|       else
 | |
| 	return FALSE;
 | |
|     }
 | |
|     if ( flags & _XOS_FILE )
 | |
|     { if ( a & FILE_ATTRIBUTE_DIRECTORY )
 | |
| 	return FALSE;
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| 		 /*******************************
 | |
| 		 *	    DIRECTORIES		*
 | |
| 		 *******************************/
 | |
| 
 | |
| DIR *
 | |
| opendir(const char *path)
 | |
| { TCHAR buf[PATH_MAX];
 | |
|   DIR *dp = malloc(sizeof(DIR));
 | |
| 
 | |
|   if ( !_xos_os_filenameW(path, buf, PATH_MAX-4) )
 | |
|   { free(dp);
 | |
|     return NULL;
 | |
|   }
 | |
|   _tcscat(buf, _T("\\*.*"));
 | |
| 
 | |
|   if ( !(dp->data = malloc(sizeof(WIN32_FIND_DATA))) )
 | |
|   { free(dp);
 | |
|     errno = ENOMEM;
 | |
|     return NULL;
 | |
|   }
 | |
|   dp->first = 1;
 | |
|   dp->handle = FindFirstFile(buf, dp->data);
 | |
| 
 | |
|   if ( dp->handle == INVALID_HANDLE_VALUE )
 | |
|   { if ( _waccess(buf, 04) )		/* does not exist */
 | |
|     { free(dp->data);
 | |
|       free(dp);
 | |
|       return NULL;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return dp;
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| closedir(DIR *dp)
 | |
| { if ( dp )
 | |
|   { if ( dp->handle )
 | |
|       FindClose(dp->handle);
 | |
|     free(dp->data);
 | |
|     free(dp);
 | |
| 
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| 
 | |
| static struct dirent *
 | |
| translate_data(DIR *dp)
 | |
| { WIN32_FIND_DATA *data;
 | |
| 
 | |
|   if ( !dp->handle )
 | |
|     return NULL;
 | |
| 
 | |
|   data = dp->data;
 | |
|   if ( wcstoutf8(dp->d_name, data->cFileName, sizeof(dp->d_name)) )
 | |
|     return dp;
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| struct dirent *
 | |
| readdir(DIR *dp)
 | |
| { for(;;)
 | |
|   { struct dirent *de;
 | |
| 
 | |
|     if ( dp->first )
 | |
|     { dp->first = 0;
 | |
|     } else
 | |
|     { if ( dp->handle )
 | |
|       { if ( !FindNextFile(dp->handle, dp->data) )
 | |
| 	  return NULL;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if ( (de = translate_data(dp)) )
 | |
|       return de;
 | |
|   }
 | |
| return 	FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| _xos_chdir(const char *path)
 | |
| { TCHAR buf[PATH_MAX];
 | |
| 
 | |
|   if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
 | |
|     return -1;
 | |
| 
 | |
|   if ( buf[0] < 0x80 && isalpha(buf[0]) && buf[1] == ':' )
 | |
|   { int drv = tolower(buf[0]) - 'a' + 1;
 | |
| 
 | |
|     if ( _getdrive() != drv )
 | |
|     { if ( _chdrive(drv) < 0 )
 | |
| 	return -1;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return _wchdir(buf);
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| _xos_mkdir(const char *path, int mode)
 | |
| { TCHAR buf[PATH_MAX];
 | |
| 
 | |
|   if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
 | |
|     return -1;
 | |
| 
 | |
|   return _wmkdir(buf);
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| _xos_rmdir(const char *path)
 | |
| { TCHAR buf[PATH_MAX];
 | |
| 
 | |
|   if ( !_xos_os_filenameW(path, buf, PATH_MAX) )
 | |
|     return -1;
 | |
| 
 | |
|   return _wrmdir(buf);
 | |
| }
 | |
| 
 | |
| 
 | |
| char *
 | |
| _xos_getcwd(char *buf, size_t len)
 | |
| { TCHAR buf0[PATH_MAX];
 | |
|   TCHAR buf1[PATH_MAX];
 | |
| 
 | |
|   if ( _wgetcwd(buf0, sizeof(buf0)/sizeof(TCHAR)) &&
 | |
|        _xos_long_file_nameW(buf0, buf1, sizeof(buf0)/sizeof(TCHAR)) )
 | |
|   { return _xos_canonical_filenameW(buf1, buf, len, 0);
 | |
|   }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| char *
 | |
| _xos_getcwd_i(char *buf, int len)
 | |
| { TCHAR buf0[PATH_MAX];
 | |
|   TCHAR buf1[PATH_MAX];
 | |
| 
 | |
|   if ( _wgetcwd(buf0, sizeof(buf0)/sizeof(TCHAR)) &&
 | |
|        _xos_long_file_nameW(buf0, buf1, sizeof(buf0)/sizeof(TCHAR)) )
 | |
|   { return _xos_canonical_filenameW(buf1, buf, len, 0);
 | |
|   }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| 		 /*******************************
 | |
| 		 *	    ENVIRONMENT		*
 | |
| 		 *******************************/
 | |
| 
 | |
| size_t
 | |
| _xos_getenv(const char *name, char *buf, size_t buflen)
 | |
| { TCHAR nm[PATH_MAX];
 | |
|   TCHAR val[PATH_MAX];
 | |
|   TCHAR *valp = val;
 | |
|   DWORD size;
 | |
| 
 | |
|   if ( !utf8towcs(nm, name, PATH_MAX) )
 | |
|     return -1;
 | |
|   size = GetEnvironmentVariable(nm, valp, PATH_MAX);
 | |
| 
 | |
|   if ( size > 0 )
 | |
|   { size_t rc;
 | |
| 
 | |
|     if ( size >= PATH_MAX )
 | |
|     { if ( (valp = malloc((size+1)*sizeof(TCHAR))) == NULL )
 | |
| 	return -1;
 | |
|       size = GetEnvironmentVariable(nm, valp, size+1);
 | |
|     }
 | |
| 
 | |
|     size = wcslen(valp);		/* return sometimes holds 0-bytes */
 | |
|     if ( wcstoutf8(buf, valp, buflen) )
 | |
|       rc = strlen(buf);
 | |
|     else
 | |
|       rc = wcutf8len(valp);
 | |
| 
 | |
|     if ( valp != val )
 | |
|       free(valp);
 | |
| 
 | |
|     return rc;
 | |
|   }
 | |
| 
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| _xos_setenv(const char *name, char *value, int overwrite)
 | |
| { TCHAR nm[PATH_MAX];
 | |
|   TCHAR buf[PATH_MAX];
 | |
|   TCHAR *val = buf;
 | |
|   int rc;
 | |
| 
 | |
|   if ( !utf8towcs(nm, name, PATH_MAX) )
 | |
|     return -1;
 | |
|   if ( !overwrite && GetEnvironmentVariable(nm, NULL, 0) > 0 )
 | |
|     return 0;
 | |
|   if ( !utf8towcs(val, value, PATH_MAX) )
 | |
|   { size_t wlen = utf8_strlen(value, strlen(value)) + 1;
 | |
| 
 | |
|     if ( (val = malloc(wlen*sizeof(TCHAR))) == NULL )
 | |
|       return -1;
 | |
|     utf8towcs(val, value, wlen);
 | |
|   }
 | |
| 
 | |
|   rc = SetEnvironmentVariable(nm, val);
 | |
|   if ( val != buf )
 | |
|     free(val);
 | |
| 
 | |
|   if ( rc )
 | |
|     return 0;
 | |
| 
 | |
|   return -1;				/* TBD: convert error */
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 |