+struct direct *
+readdir (DIR *dirp)
+{
+ if (wnet_enum_handle != INVALID_HANDLE_VALUE)
+ {
+ if (!read_unc_volume (wnet_enum_handle,
+ dir_find_data.cFileName,
+ MAX_PATH))
+ return NULL;
+ }
+ /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
+ else if (dir_find_handle == INVALID_HANDLE_VALUE)
+ {
+ char filename[MAXNAMLEN + 3];
+ int ln;
+
+ strcpy (filename, dir_pathname);
+ ln = strlen (filename) - 1;
+ if (!IS_DIRECTORY_SEP (filename[ln]))
+ strcat (filename, "\\");
+ strcat (filename, "*");
+
+ dir_find_handle = FindFirstFile (filename, &dir_find_data);
+
+ if (dir_find_handle == INVALID_HANDLE_VALUE)
+ return NULL;
+ }
+ else
+ {
+ if (!FindNextFile (dir_find_handle, &dir_find_data))
+ return NULL;
+ }
+
+ /* Emacs never uses this value, so don't bother making it match
+ value returned by stat(). */
+ dir_static.d_ino = 1;
+
+ dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
+ dir_static.d_namlen - dir_static.d_namlen % 4;
+
+ dir_static.d_namlen = strlen (dir_find_data.cFileName);
+ strcpy (dir_static.d_name, dir_find_data.cFileName);
+ if (dir_is_fat)
+ _strlwr (dir_static.d_name);
+ else if (!NILP (Vw32_downcase_file_names))
+ {
+ register char *p;
+ for (p = dir_static.d_name; *p; p++)
+ if (*p >= 'a' && *p <= 'z')
+ break;
+ if (!*p)
+ _strlwr (dir_static.d_name);
+ }
+
+ return &dir_static;
+}
+
+HANDLE
+open_unc_volume (const char *path)
+{
+ NETRESOURCE nr;
+ HANDLE henum;
+ int result;
+
+ nr.dwScope = RESOURCE_GLOBALNET;
+ nr.dwType = RESOURCETYPE_DISK;
+ nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
+ nr.dwUsage = RESOURCEUSAGE_CONTAINER;
+ nr.lpLocalName = NULL;
+ nr.lpRemoteName = (LPSTR)map_w32_filename (path, NULL);
+ nr.lpComment = NULL;
+ nr.lpProvider = NULL;
+
+ result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
+ RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
+
+ if (result == NO_ERROR)
+ return henum;
+ else
+ return INVALID_HANDLE_VALUE;
+}
+
+char *
+read_unc_volume (HANDLE henum, char *readbuf, int size)
+{
+ DWORD count;
+ int result;
+ DWORD bufsize = 512;
+ char *buffer;
+ char *ptr;
+
+ count = 1;
+ buffer = alloca (bufsize);
+ result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize);
+ if (result != NO_ERROR)
+ return NULL;
+
+ /* WNetEnumResource returns \\resource\share...skip forward to "share". */
+ ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
+ ptr += 2;
+ while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
+ ptr++;
+
+ strncpy (readbuf, ptr, size);
+ return readbuf;
+}
+
+void
+close_unc_volume (HANDLE henum)
+{
+ if (henum != INVALID_HANDLE_VALUE)
+ WNetCloseEnum (henum);
+}
+
+DWORD
+unc_volume_file_attributes (const char *path)
+{
+ HANDLE henum;
+ DWORD attrs;
+
+ henum = open_unc_volume (path);
+ if (henum == INVALID_HANDLE_VALUE)
+ return -1;
+
+ attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
+
+ close_unc_volume (henum);
+
+ return attrs;
+}
+
+
+/* Shadow some MSVC runtime functions to map requests for long filenames
+ to reasonable short names if necessary. This was originally added to
+ permit running Emacs on NT 3.1 on a FAT partition, which doesn't support
+ long file names. */
+
+int
+sys_access (const char * path, int mode)
+{
+ DWORD attributes;
+
+ /* MSVC implementation doesn't recognize D_OK. */
+ path = map_w32_filename (path, NULL);
+ if (is_unc_volume (path))
+ {
+ attributes = unc_volume_file_attributes (path);
+ if (attributes == -1) {
+ errno = EACCES;
+ return -1;
+ }
+ }
+ else if ((attributes = GetFileAttributes (path)) == -1)
+ {
+ /* Should try mapping GetLastError to errno; for now just indicate
+ that path doesn't exist. */
+ errno = EACCES;
+ return -1;
+ }
+ if ((mode & X_OK) != 0 && !is_exec (path))
+ {
+ errno = EACCES;
+ return -1;
+ }
+ if ((mode & W_OK) != 0 && (attributes & FILE_ATTRIBUTE_READONLY) != 0)
+ {
+ errno = EACCES;
+ return -1;
+ }
+ if ((mode & D_OK) != 0 && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
+ {
+ errno = EACCES;
+ return -1;
+ }
+ return 0;
+}
+
+int
+sys_chdir (const char * path)
+{
+ return _chdir (map_w32_filename (path, NULL));
+}
+
+int
+sys_chmod (const char * path, int mode)
+{
+ return _chmod (map_w32_filename (path, NULL), mode);
+}
+
+int
+sys_chown (const char *path, uid_t owner, gid_t group)
+{
+ if (sys_chmod (path, _S_IREAD) == -1) /* check if file exists */
+ return -1;
+ return 0;
+}
+
+int
+sys_creat (const char * path, int mode)
+{
+ return _creat (map_w32_filename (path, NULL), mode);
+}
+
+FILE *
+sys_fopen(const char * path, const char * mode)
+{
+ int fd;
+ int oflag;
+ const char * mode_save = mode;
+
+ /* Force all file handles to be non-inheritable. This is necessary to
+ ensure child processes don't unwittingly inherit handles that might
+ prevent future file access. */
+
+ if (mode[0] == 'r')
+ oflag = O_RDONLY;
+ else if (mode[0] == 'w' || mode[0] == 'a')
+ oflag = O_WRONLY | O_CREAT | O_TRUNC;
+ else
+ return NULL;
+
+ /* Only do simplistic option parsing. */
+ while (*++mode)
+ if (mode[0] == '+')
+ {
+ oflag &= ~(O_RDONLY | O_WRONLY);
+ oflag |= O_RDWR;
+ }
+ else if (mode[0] == 'b')
+ {
+ oflag &= ~O_TEXT;
+ oflag |= O_BINARY;
+ }
+ else if (mode[0] == 't')
+ {
+ oflag &= ~O_BINARY;
+ oflag |= O_TEXT;
+ }
+ else break;
+
+ fd = _open (map_w32_filename (path, NULL), oflag | _O_NOINHERIT, 0644);
+ if (fd < 0)
+ return NULL;
+
+ return _fdopen (fd, mode_save);
+}
+
+/* This only works on NTFS volumes, but is useful to have. */
+int
+sys_link (const char * old, const char * new)
+{
+ HANDLE fileh;
+ int result = -1;
+ char oldname[MAX_PATH], newname[MAX_PATH];
+
+ if (old == NULL || new == NULL)
+ {
+ errno = ENOENT;
+ return -1;
+ }
+
+ strcpy (oldname, map_w32_filename (old, NULL));
+ strcpy (newname, map_w32_filename (new, NULL));
+
+ fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (fileh != INVALID_HANDLE_VALUE)
+ {
+ int wlen;
+
+ /* Confusingly, the "alternate" stream name field does not apply
+ when restoring a hard link, and instead contains the actual
+ stream data for the link (ie. the name of the link to create).
+ The WIN32_STREAM_ID structure before the cStreamName field is
+ the stream header, which is then immediately followed by the
+ stream data. */
+
+ struct {
+ WIN32_STREAM_ID wid;
+ WCHAR wbuffer[MAX_PATH]; /* extra space for link name */
+ } data;
+
+ wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
+ data.wid.cStreamName, MAX_PATH);
+ if (wlen > 0)
+ {
+ LPVOID context = NULL;
+ DWORD wbytes = 0;
+
+ data.wid.dwStreamId = BACKUP_LINK;
+ data.wid.dwStreamAttributes = 0;
+ data.wid.Size.LowPart = wlen * sizeof(WCHAR);
+ data.wid.Size.HighPart = 0;
+ data.wid.dwStreamNameSize = 0;
+
+ if (BackupWrite (fileh, (LPBYTE)&data,
+ offsetof (WIN32_STREAM_ID, cStreamName)
+ + data.wid.Size.LowPart,
+ &wbytes, FALSE, FALSE, &context)
+ && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
+ {
+ /* succeeded */
+ result = 0;
+ }
+ else
+ {
+ /* Should try mapping GetLastError to errno; for now just
+ indicate a general error (eg. links not supported). */
+ errno = EINVAL; // perhaps EMLINK?
+ }
+ }
+
+ CloseHandle (fileh);
+ }
+ else
+ errno = ENOENT;
+
+ return result;
+}
+
+int
+sys_mkdir (const char * path)
+{
+ return _mkdir (map_w32_filename (path, NULL));
+}
+
+/* Because of long name mapping issues, we need to implement this
+ ourselves. Also, MSVC's _mktemp returns NULL when it can't generate
+ a unique name, instead of setting the input template to an empty
+ string.
+
+ Standard algorithm seems to be use pid or tid with a letter on the
+ front (in place of the 6 X's) and cycle through the letters to find a
+ unique name. We extend that to allow any reasonable character as the
+ first of the 6 X's. */
+char *
+sys_mktemp (char * template)
+{
+ char * p;
+ int i;
+ unsigned uid = GetCurrentThreadId ();
+ static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
+
+ if (template == NULL)
+ return NULL;
+ p = template + strlen (template);
+ i = 5;
+ /* replace up to the last 5 X's with uid in decimal */
+ while (--p >= template && p[0] == 'X' && --i >= 0)
+ {
+ p[0] = '0' + uid % 10;
+ uid /= 10;
+ }
+
+ if (i < 0 && p[0] == 'X')
+ {
+ i = 0;
+ do
+ {
+ int save_errno = errno;
+ p[0] = first_char[i];
+ if (sys_access (template, 0) < 0)
+ {
+ errno = save_errno;
+ return template;
+ }
+ }
+ while (++i < sizeof (first_char));
+ }
+
+ /* Template is badly formed or else we can't generate a unique name,
+ so return empty string */
+ template[0] = 0;
+ return template;
+}
+
+int