root/lib-src/ntlib.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sleep
  2. getwd
  3. getppid
  4. getlogin
  5. getuid
  6. geteuid
  7. getgid
  8. getegid
  9. setuid
  10. setregid
  11. getpwuid
  12. getpass
  13. fchown
  14. sys_fopen
  15. sys_chdir
  16. sys_mkdir
  17. convert_time
  18. is_exec
  19. stat
  20. lstat
  21. fstat
  22. sys_rename
  23. sys_open
  24. nl_langinfo

     1 /* Utility and Unix shadow routines for GNU Emacs support programs on NT.
     2 
     3 Copyright (C) 1994, 2001-2023 Free Software Foundation, Inc.
     4 
     5 Author: Geoff Voelker (voelker@cs.washington.edu)
     6 Created: 10-8-94
     7 
     8 This file is part of GNU Emacs.
     9 
    10 GNU Emacs is free software: you can redistribute it and/or modify
    11 it under the terms of the GNU General Public License as published by
    12 the Free Software Foundation, either version 3 of the License, or (at
    13 your option) any later version.
    14 
    15 GNU Emacs is distributed in the hope that it will be useful,
    16 but WITHOUT ANY WARRANTY; without even the implied warranty of
    17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    18 GNU General Public License for more details.
    19 
    20 You should have received a copy of the GNU General Public License
    21 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    22 
    23 #define DEFER_MS_W32_H
    24 #include <config.h>
    25 
    26 #include <windows.h>
    27 #include <stdlib.h>
    28 #include <stdio.h>
    29 #include <time.h>
    30 #include <direct.h>
    31 #include <sys/types.h>
    32 #include <sys/stat.h>
    33 #include <errno.h>
    34 #include <ctype.h>
    35 #include <sys/timeb.h>
    36 #include <mbstring.h>
    37 #include <locale.h>
    38 
    39 #include <nl_types.h>
    40 #include <langinfo.h>
    41 
    42 #include "ntlib.h"
    43 
    44 char *sys_ctime (const time_t *);
    45 FILE *sys_fopen (const char *, const char *);
    46 int sys_mkdir (const char *, mode_t);
    47 int sys_chdir (const char *);
    48 int mkostemp (char *, int);
    49 int sys_rename (const char *, const char *);
    50 int sys_open (const char *, int, int);
    51 
    52 /* MinGW64 defines _TIMEZONE_DEFINED and defines 'struct timespec' in
    53    its system headers.  */
    54 #ifndef _TIMEZONE_DEFINED
    55 struct timezone
    56 {
    57   int           tz_minuteswest; /* minutes west of Greenwich */
    58   int           tz_dsttime;     /* type of dst correction */
    59 };
    60 #endif
    61 
    62 #define MAXPATHLEN _MAX_PATH
    63 
    64 /* Emulate sleep...we could have done this with a define, but that
    65    would necessitate including windows.h in the files that used it.
    66    This is much easier.  */
    67 unsigned
    68 sleep (unsigned seconds)
    69 {
    70   Sleep (seconds * 1000);
    71   return 0;
    72 }
    73 
    74 /* Get the current working directory.  */
    75 char *
    76 getwd (char *dir)
    77 {
    78   if (GetCurrentDirectory (MAXPATHLEN, dir) > 0)
    79     return dir;
    80   return NULL;
    81 }
    82 
    83 static HANDLE getppid_parent;
    84 static int    getppid_ppid;
    85 
    86 int
    87 getppid (void)
    88 {
    89   char *ppid;
    90   DWORD result;
    91 
    92   ppid = getenv ("EM_PARENT_PROCESS_ID");
    93   if (!ppid)
    94     {
    95       printf ("no pid.\n");
    96       return 0;
    97     }
    98   else
    99     {
   100       getppid_ppid = atoi (ppid);
   101     }
   102 
   103   if (!getppid_parent)
   104     {
   105       getppid_parent = OpenProcess (SYNCHRONIZE, FALSE, atoi (ppid));
   106       if (!getppid_parent)
   107         {
   108           printf ("Failed to open handle to parent process: %lu\n",
   109                  GetLastError ());
   110           exit (1);
   111         }
   112     }
   113 
   114   result = WaitForSingleObject (getppid_parent, 0);
   115   switch (result)
   116     {
   117     case WAIT_TIMEOUT:
   118       /* The parent is still alive.  */
   119       return getppid_ppid;
   120     case WAIT_OBJECT_0:
   121       /* The parent is gone.  Return the pid of Unix init (1).  */
   122       return 1;
   123     case WAIT_FAILED:
   124     default:
   125       printf ("Checking parent status failed: %lu\n", GetLastError ());
   126       exit (1);
   127     }
   128 }
   129 
   130 char *
   131 getlogin (void)
   132 {
   133   static char user_name[256];
   134   DWORD  length = sizeof (user_name);
   135 
   136   if (GetUserName (user_name, &length))
   137     return user_name;
   138   return NULL;
   139 }
   140 
   141 unsigned
   142 getuid (void)
   143 {
   144   return 0;
   145 }
   146 
   147 unsigned
   148 geteuid (void)
   149 {
   150   return getuid ();
   151 }
   152 
   153 unsigned
   154 getgid (void)
   155 {
   156   return 0;
   157 }
   158 
   159 unsigned
   160 getegid (void)
   161 {
   162   return 0;
   163 }
   164 
   165 int
   166 setuid (unsigned uid)
   167 {
   168   return 0;
   169 }
   170 
   171 int
   172 setregid (unsigned rgid, unsigned gid)
   173 {
   174   return 0;
   175 }
   176 
   177 struct passwd *
   178 getpwuid (unsigned uid)
   179 {
   180   return NULL;
   181 }
   182 
   183 char *
   184 getpass (const char * prompt)
   185 {
   186   static char input[256];
   187   HANDLE in;
   188   HANDLE err;
   189   DWORD  count;
   190 
   191   in = GetStdHandle (STD_INPUT_HANDLE);
   192   err = GetStdHandle (STD_ERROR_HANDLE);
   193 
   194   if (in == INVALID_HANDLE_VALUE || err == INVALID_HANDLE_VALUE)
   195     return NULL;
   196 
   197   if (WriteFile (err, prompt, strlen (prompt), &count, NULL))
   198     {
   199       int istty = (GetFileType (in) == FILE_TYPE_CHAR);
   200       DWORD old_flags;
   201       int rc;
   202 
   203       if (istty)
   204         {
   205           if (GetConsoleMode (in, &old_flags))
   206             SetConsoleMode (in, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
   207           else
   208             istty = 0;
   209         }
   210       rc = ReadFile (in, input, sizeof (input), &count, NULL);
   211       if (count >= 2 && input[count - 2] == '\r')
   212         input[count - 2] = '\0';
   213       else
   214         {
   215           char buf[256];
   216           while (ReadFile (in, buf, sizeof (buf), &count, NULL) > 0)
   217             if (count >= 2 && buf[count - 2] == '\r')
   218               break;
   219         }
   220       WriteFile (err, "\r\n", 2, &count, NULL);
   221       if (istty)
   222         SetConsoleMode (in, old_flags);
   223       if (rc)
   224         return input;
   225     }
   226 
   227   return NULL;
   228 }
   229 
   230 int
   231 fchown (int fd, unsigned uid, unsigned gid)
   232 {
   233   return 0;
   234 }
   235 
   236 FILE *
   237 sys_fopen (const char * path, const char * mode)
   238 {
   239   return fopen (path, mode);
   240 }
   241 
   242 int
   243 sys_chdir (const char * path)
   244 {
   245   return _chdir (path);
   246 }
   247 
   248 int
   249 sys_mkdir (const char * path, mode_t mode)
   250 {
   251   return _mkdir (path);
   252 }
   253 
   254 static FILETIME utc_base_ft;
   255 static long double utc_base;
   256 static int init = 0;
   257 
   258 static time_t
   259 convert_time (FILETIME ft)
   260 {
   261   long double ret;
   262 
   263   if (CompareFileTime (&ft, &utc_base_ft) < 0)
   264     return 0;
   265 
   266   ret = (long double) ft.dwHighDateTime
   267     * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
   268   ret -= utc_base;
   269   return (time_t) (ret * 1e-7L);
   270 }
   271 
   272 static int
   273 is_exec (const char * name)
   274 {
   275   char * p = strrchr (name, '.');
   276   return
   277     (p != NULL
   278      && (stricmp (p, ".exe") == 0 ||
   279          stricmp (p, ".com") == 0 ||
   280          stricmp (p, ".bat") == 0 ||
   281          stricmp (p, ".cmd") == 0));
   282 }
   283 
   284 /* We need stat/fsfat below because nt/inc/sys/stat.h defines struct
   285    stat that is incompatible with the MS run-time libraries.  */
   286 int
   287 stat (const char * path, struct stat * buf)
   288 {
   289   WIN32_FIND_DATA wfd;
   290   HANDLE fh;
   291   int permission;
   292   int len;
   293   int rootdir = FALSE;
   294   char *name = alloca (FILENAME_MAX);
   295 
   296   if (!init)
   297     {
   298       /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
   299       SYSTEMTIME st;
   300 
   301       st.wYear = 1970;
   302       st.wMonth = 1;
   303       st.wDay = 1;
   304       st.wHour = 0;
   305       st.wMinute = 0;
   306       st.wSecond = 0;
   307       st.wMilliseconds = 0;
   308 
   309       SystemTimeToFileTime (&st, &utc_base_ft);
   310       utc_base = (long double) utc_base_ft.dwHighDateTime
   311         * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
   312       init = 1;
   313     }
   314 
   315   if (path == NULL || buf == NULL || *path == '\0')
   316     {
   317       errno = EFAULT;
   318       return -1;
   319     }
   320   if (_mbspbrk (path, "*?|<>\""))
   321     {
   322       errno = ENOENT;
   323       return -1;
   324     }
   325 
   326   strcpy (name, path);
   327   /* Remove trailing directory separator, unless name is the root
   328      directory of a drive in which case ensure there is a trailing
   329      separator. */
   330   len = strlen (name);
   331   rootdir = IS_DIRECTORY_SEP (name[0])
   332     || (len == 3 && name[1] == ':' && IS_DIRECTORY_SEP (name[2]));
   333   if (rootdir)
   334     {
   335       if (GetDriveType (name) < 2)
   336         {
   337           errno = ENOENT;
   338           return -1;
   339         }
   340       memset (&wfd, 0, sizeof (wfd));
   341       wfd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
   342       wfd.ftCreationTime = utc_base_ft;
   343       wfd.ftLastAccessTime = utc_base_ft;
   344       wfd.ftLastWriteTime = utc_base_ft;
   345       strcpy (wfd.cFileName, name);
   346     }
   347   else
   348     {
   349       if (IS_DIRECTORY_SEP (name[len-1]))
   350         name[len - 1] = 0;
   351 
   352       fh = FindFirstFile (name, &wfd);
   353       if (fh == INVALID_HANDLE_VALUE)
   354         {
   355           errno = ENOENT;
   356           return -1;
   357         }
   358       FindClose (fh);
   359     }
   360   buf->st_mode = (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ?
   361     S_IFDIR : S_IFREG;
   362   buf->st_nlink = 1;
   363   buf->st_ino = 0;
   364 
   365   if (name[0] && name[1] == ':')
   366     buf->st_dev = tolower (name[0]) - 'a' + 1;
   367   else
   368     buf->st_dev = _getdrive ();
   369   buf->st_rdev = buf->st_dev;
   370 
   371   buf->st_size = wfd.nFileSizeHigh;
   372   buf->st_size <<= 32;
   373   buf->st_size += wfd.nFileSizeLow;
   374 
   375   /* Convert timestamps to Unix format. */
   376   buf->st_mtime = convert_time (wfd.ftLastWriteTime);
   377   buf->st_atime = convert_time (wfd.ftLastAccessTime);
   378   if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
   379   buf->st_ctime = convert_time (wfd.ftCreationTime);
   380   if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
   381 
   382   /* determine rwx permissions */
   383   if (wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
   384     permission = S_IREAD;
   385   else
   386     permission = S_IREAD | S_IWRITE;
   387 
   388   if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
   389     permission |= S_IEXEC;
   390   else if (is_exec (name))
   391     permission |= S_IEXEC;
   392 
   393   buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
   394 
   395   return 0;
   396 }
   397 
   398 int
   399 lstat (const char * path, struct stat * buf)
   400 {
   401   return stat (path, buf);
   402 }
   403 
   404 int
   405 fstat (int desc, struct stat * buf)
   406 {
   407   HANDLE fh = (HANDLE) _get_osfhandle (desc);
   408   BY_HANDLE_FILE_INFORMATION info;
   409   unsigned __int64 fake_inode;
   410   int permission;
   411 
   412   if (!init)
   413     {
   414       /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
   415       SYSTEMTIME st;
   416 
   417       st.wYear = 1970;
   418       st.wMonth = 1;
   419       st.wDay = 1;
   420       st.wHour = 0;
   421       st.wMinute = 0;
   422       st.wSecond = 0;
   423       st.wMilliseconds = 0;
   424 
   425       SystemTimeToFileTime (&st, &utc_base_ft);
   426       utc_base = (long double) utc_base_ft.dwHighDateTime
   427         * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
   428       init = 1;
   429     }
   430 
   431   switch (GetFileType (fh) & ~FILE_TYPE_REMOTE)
   432     {
   433     case FILE_TYPE_DISK:
   434       buf->st_mode = S_IFREG;
   435       if (!GetFileInformationByHandle (fh, &info))
   436         {
   437           errno = EACCES;
   438           return -1;
   439         }
   440       break;
   441     case FILE_TYPE_PIPE:
   442       buf->st_mode = S_IFIFO;
   443       goto non_disk;
   444     case FILE_TYPE_CHAR:
   445     case FILE_TYPE_UNKNOWN:
   446     default:
   447       buf->st_mode = S_IFCHR;
   448     non_disk:
   449       memset (&info, 0, sizeof (info));
   450       info.dwFileAttributes = 0;
   451       info.ftCreationTime = utc_base_ft;
   452       info.ftLastAccessTime = utc_base_ft;
   453       info.ftLastWriteTime = utc_base_ft;
   454     }
   455 
   456   if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
   457       buf->st_mode = S_IFDIR;
   458 
   459   buf->st_nlink = info.nNumberOfLinks;
   460   /* Might as well use file index to fake inode values, but this
   461      is not guaranteed to be unique unless we keep a handle open
   462      all the time. */
   463   fake_inode = info.nFileIndexHigh;
   464   fake_inode <<= 32;
   465   fake_inode += info.nFileIndexLow;
   466   buf->st_ino = fake_inode;
   467 
   468   buf->st_dev = info.dwVolumeSerialNumber;
   469   buf->st_rdev = info.dwVolumeSerialNumber;
   470 
   471   buf->st_size = info.nFileSizeHigh;
   472   buf->st_size <<= 32;
   473   buf->st_size += info.nFileSizeLow;
   474 
   475   /* Convert timestamps to Unix format. */
   476   buf->st_mtime = convert_time (info.ftLastWriteTime);
   477   buf->st_atime = convert_time (info.ftLastAccessTime);
   478   if (buf->st_atime == 0) buf->st_atime = buf->st_mtime;
   479   buf->st_ctime = convert_time (info.ftCreationTime);
   480   if (buf->st_ctime == 0) buf->st_ctime = buf->st_mtime;
   481 
   482   /* determine rwx permissions */
   483   if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
   484     permission = S_IREAD;
   485   else
   486     permission = S_IREAD | S_IWRITE;
   487 
   488   if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
   489     permission |= S_IEXEC;
   490 
   491   buf->st_mode |= permission | (permission >> 3) | (permission >> 6);
   492 
   493   return 0;
   494 }
   495 
   496 /* On Windows, you cannot rename into an existing file.  */
   497 int
   498 sys_rename (const char *from, const char *to)
   499 {
   500   int retval = rename (from, to);
   501 
   502   if (retval < 0 && errno == EEXIST)
   503     {
   504       if (unlink (to) == 0)
   505         retval = rename (from, to);
   506     }
   507   return retval;
   508 }
   509 
   510 int
   511 sys_open (const char * path, int oflag, int mode)
   512 {
   513   return _open (path, oflag, mode);
   514 }
   515 
   516 /* Emulation of nl_langinfo that supports only CODESET.
   517    Used in Gnulib regex.c.  */
   518 char *
   519 nl_langinfo (nl_item item)
   520 {
   521   switch (item)
   522     {
   523       case CODESET:
   524         {
   525           /* Shamelessly stolen from Gnulib's nl_langinfo.c, modulo
   526              CPP directives.  */
   527           static char buf[2 + 10 + 1];
   528           char const *locale = setlocale (LC_CTYPE, NULL);
   529           char *codeset = buf;
   530           size_t codesetlen;
   531           codeset[0] = '\0';
   532 
   533           if (locale && locale[0])
   534             {
   535               /* If the locale name contains an encoding after the
   536                  dot, return it.  */
   537               char *dot = strchr (locale, '.');
   538 
   539               if (dot)
   540                 {
   541                   /* Look for the possible @... trailer and remove it,
   542                      if any.  */
   543                   char *codeset_start = dot + 1;
   544                   char const *modifier = strchr (codeset_start, '@');
   545 
   546                   if (! modifier)
   547                     codeset = codeset_start;
   548                   else
   549                     {
   550                       codesetlen = modifier - codeset_start;
   551                       if (codesetlen < sizeof buf)
   552                         {
   553                           codeset = memcpy (buf, codeset_start, codesetlen);
   554                           codeset[codesetlen] = '\0';
   555                         }
   556                     }
   557                 }
   558             }
   559           /* If setlocale is successful, it returns the number of the
   560              codepage, as a string.  Otherwise, fall back on Windows
   561              API GetACP, which returns the locale's codepage as a
   562              number (although this doesn't change according to what
   563              the 'setlocale' call specified).  Either way, prepend
   564              "CP" to make it a valid codeset name.  */
   565           codesetlen = strlen (codeset);
   566           if (0 < codesetlen && codesetlen < sizeof buf - 2)
   567             memmove (buf + 2, codeset, codesetlen + 1);
   568           else
   569             sprintf (buf + 2, "%u", GetACP ());
   570           codeset = memcpy (buf, "CP", 2);
   571 
   572           return codeset;
   573         }
   574       default:
   575         return (char *) "";
   576     }
   577 }

/* [<][>][^][v][top][bottom][index][help] */