# HG changeset patch # User Geoff Voelker # Date 822184294 0 # Node ID ebdd1b50daba518bd884189ea8d7ebdba43453a4 # Parent 59d24d42958a06e8f76bb70f0ac6d5c9c38e8738 (nt_stat): Use alloca instead of xmalloc. (get_unassigned_drive_letter, is_toplevel_share_name, stat_toplevel_share): New functions for stat on remote shares. (readdir): Use IS_ANY_SEP. diff -r 59d24d42958a -r ebdd1b50daba src/w32.c --- a/src/w32.c Sun Jan 21 00:30:47 1996 +0000 +++ b/src/w32.c Sun Jan 21 00:31:34 1996 +0000 @@ -21,30 +21,37 @@ Geoff Voelker (voelker@cs.washington.edu) 7-29-94 */ + /* Define stat before including config.h. */ #include #include +#include + +static int is_toplevel_share_name (char *); +static int stat_toplevel_share (char *, void *); + int nt_stat (char *filename, struct stat *statbuf) { - int r, l = strlen (filename); + int l = strlen (filename); char *str = NULL; - extern long *xmalloc (); - extern void xfree (); /* stat has a bug when passed a name of a directory with a trailing backslash (but a trailing forward slash works fine). */ if (filename[l - 1] == '\\') { - str = (char *) xmalloc (l + 1); + str = (char *) alloca (l + 1); strcpy (str, filename); str[l - 1] = '/'; - r = stat (str, statbuf); - xfree (str); - return r; + return stat (str, statbuf); } + + if (stat (filename, statbuf) == 0) + return 0; + else if (is_toplevel_share_name (filename)) + return stat_toplevel_share (filename, statbuf); else - return stat (filename, statbuf); + return -1; } /* Place a wrapper around the NT version of ctime. It returns NULL @@ -76,6 +83,102 @@ extern int report_file_error (char *, Lisp_Object); +/* Routines for extending stat above. */ +static int +get_unassigned_drive_letter () +{ + int i; + unsigned int mask; + + mask = GetLogicalDrives (); + for (i = 0; i < 26; i++) + { + if (mask & (1 << i)) + continue; + break; + } + return (i == 26 ? -1 : 'A' + i); +} + +void dostounix_filename (char *); + +/* Return nonzero if NAME is of the form \\host\share (forward slashes + also valid), otherwise return 0. */ +static int +is_toplevel_share_name (char *filename) +{ + int len; + char *name; + char *host; + char *share; + char *suffix; + + len = strlen (filename); + name = alloca (len + 1); + strcpy (name, filename); + + dostounix_filename (name); + if (name[0] != '/' || name[1] != '/') + return 0; + + host = strtok (&name[2], "/"); + share = strtok (NULL, "/"); + suffix = strtok (NULL, "/"); + if (!host || !share || suffix) + return 0; + + return 1; +} + + +/* FILENAME is of the form \\host\share, and stat can't handle names + of this form. But stat can handle \\host\share if it's been + assigned a drive letter. So we create a network connection to this + share, assign it a drive letter, stat the drive letter, and + disconnect from the share. Hassle... */ +static int +stat_toplevel_share (char *filename, void *statbuf) +{ + NETRESOURCE net; + int drive_letter; + char drive[4]; + int result; + + drive_letter = get_unassigned_drive_letter (); + if (drive_letter < 0) + return -1; + + drive[0] = drive_letter; + drive[1] = ':'; + drive[2] = '\0'; + net.dwType = RESOURCETYPE_DISK; + net.lpLocalName = drive; + net.lpRemoteName = filename; + net.lpProvider = NULL; + + switch (WNetAddConnection2 (&net, NULL, NULL, 0)) + { + case NO_ERROR: + break; + case ERROR_ALREADY_ASSIGNED: + default: + return -1; + } + + /* Name the toplevel directory on the drive letter. */ + drive[2] = '/'; + drive[3] = '\0'; + result = stat (drive, (void *) statbuf); + + /* Strip the slash so we can disconnect. */ + drive[2] = '\0'; + if (WNetCancelConnection2 (drive, 0, TRUE) != NO_ERROR) + result = -1; + + return result; +} + + /* Get the current working directory. */ int getwd (char *dir) @@ -173,7 +276,7 @@ strncpy (filename, dirp->dd_buf, MAXNAMLEN); ln = strlen (filename)-1; - if (filename[ln] != '\\' && filename[ln] != ':') + if (!IS_ANY_SEP (filename[ln])) strcat (filename, "\\"); strcat (filename, "*.*");