mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-23 07:19:15 +00:00
Dirent functions and directory-files are converted and work.
This commit is contained in:
parent
f5441ba43c
commit
0b9de7cd60
@ -40,7 +40,7 @@ struct dirent /* data from readdir() */
|
||||
__int64 d_time_write;
|
||||
_fsize_t d_size;
|
||||
#endif
|
||||
char d_name[MAXNAMLEN+1]; /* name of file */
|
||||
char d_name[MAXNAMLEN * 4 + 1]; /* name of file */
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
@ -224,6 +224,14 @@ extern struct tm * sys_localtime (const time_t *);
|
||||
#define strerror sys_strerror
|
||||
#undef unlink
|
||||
#define unlink sys_unlink
|
||||
#undef opendir
|
||||
#define opendir sys_opendir
|
||||
#undef closedir
|
||||
#define closedir sys_closedir
|
||||
#undef readdir
|
||||
#define readdir sys_readdir
|
||||
#undef seekdir
|
||||
#define seekdir sys_seekdir
|
||||
/* This prototype is needed because some files include config.h
|
||||
_after_ the standard headers, so sys_unlink gets no prototype from
|
||||
stdio.h or io.h. */
|
||||
|
324
src/w32.c
324
src/w32.c
@ -2934,25 +2934,28 @@ is_exec (const char * name)
|
||||
xstrcasecmp (p, ".cmd") == 0));
|
||||
}
|
||||
|
||||
/* Emulate the Unix directory procedures opendir, closedir,
|
||||
and readdir. We can't use the procedures supplied in sysdep.c,
|
||||
so we provide them here. */
|
||||
/* Emulate the Unix directory procedures opendir, closedir, and
|
||||
readdir. We rename them to sys_* names because some versions of
|
||||
MinGW startup code call opendir and readdir to glob wildcards, and
|
||||
the code that calls them doesn't grok UTF-8 encoded file names we
|
||||
produce in dirent->d_name[]. */
|
||||
|
||||
struct dirent dir_static; /* simulated directory contents */
|
||||
static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
|
||||
static int dir_is_fat;
|
||||
static char dir_pathname[MAXPATHLEN+1];
|
||||
static WIN32_FIND_DATA dir_find_data;
|
||||
static char dir_pathname[MAX_UTF8_PATH];
|
||||
static WIN32_FIND_DATAW dir_find_data_w;
|
||||
static WIN32_FIND_DATAA dir_find_data_a;
|
||||
|
||||
/* Support shares on a network resource as subdirectories of a read-only
|
||||
root directory. */
|
||||
static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
|
||||
static HANDLE open_unc_volume (const char *);
|
||||
static char *read_unc_volume (HANDLE, char *, int);
|
||||
static void *read_unc_volume (HANDLE, wchar_t *, char *, int);
|
||||
static void close_unc_volume (HANDLE);
|
||||
|
||||
DIR *
|
||||
opendir (const char *filename)
|
||||
sys_opendir (const char *filename)
|
||||
{
|
||||
DIR *dirp;
|
||||
|
||||
@ -2981,8 +2984,8 @@ opendir (const char *filename)
|
||||
dirp->dd_loc = 0;
|
||||
dirp->dd_size = 0;
|
||||
|
||||
strncpy (dir_pathname, map_w32_filename (filename, NULL), MAXPATHLEN);
|
||||
dir_pathname[MAXPATHLEN] = '\0';
|
||||
strncpy (dir_pathname, map_w32_filename (filename, NULL), MAX_UTF8_PATH - 1);
|
||||
dir_pathname[MAX_UTF8_PATH - 1] = '\0';
|
||||
/* Note: We don't support symlinks to file names on FAT volumes.
|
||||
Doing so would mean punishing 99.99% of use cases by resolving
|
||||
all the possible symlinks in FILENAME, recursively. */
|
||||
@ -2992,7 +2995,7 @@ opendir (const char *filename)
|
||||
}
|
||||
|
||||
void
|
||||
closedir (DIR *dirp)
|
||||
sys_closedir (DIR *dirp)
|
||||
{
|
||||
/* If we have a find-handle open, close it. */
|
||||
if (dir_find_handle != INVALID_HANDLE_VALUE)
|
||||
@ -3009,52 +3012,59 @@ closedir (DIR *dirp)
|
||||
}
|
||||
|
||||
struct dirent *
|
||||
readdir (DIR *dirp)
|
||||
sys_readdir (DIR *dirp)
|
||||
{
|
||||
int downcase = !NILP (Vw32_downcase_file_names);
|
||||
|
||||
if (wnet_enum_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (!read_unc_volume (wnet_enum_handle,
|
||||
dir_find_data.cFileName,
|
||||
dir_find_data_w.cFileName,
|
||||
dir_find_data_a.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];
|
||||
char filename[MAX_UTF8_PATH + 2];
|
||||
int ln;
|
||||
int dbcs_p = max_filename_mbslen () > 1;
|
||||
|
||||
strcpy (filename, dir_pathname);
|
||||
ln = strlen (filename) - 1;
|
||||
if (!dbcs_p)
|
||||
{
|
||||
if (!IS_DIRECTORY_SEP (filename[ln]))
|
||||
strcat (filename, "\\");
|
||||
}
|
||||
else
|
||||
{
|
||||
char *end = filename + ln + 1;
|
||||
char *last_char = CharPrevExA (file_name_codepage, filename, end, 0);
|
||||
|
||||
if (!IS_DIRECTORY_SEP (*last_char))
|
||||
strcat (filename, "\\");
|
||||
}
|
||||
if (!IS_DIRECTORY_SEP (filename[ln]))
|
||||
strcat (filename, "\\");
|
||||
strcat (filename, "*");
|
||||
|
||||
/* Note: No need to resolve symlinks in FILENAME, because
|
||||
FindFirst opens the directory that is the target of a
|
||||
symlink. */
|
||||
dir_find_handle = FindFirstFile (filename, &dir_find_data);
|
||||
if (w32_unicode_filenames)
|
||||
{
|
||||
wchar_t fnw[MAX_PATH];
|
||||
|
||||
filename_to_utf16 (filename, fnw);
|
||||
dir_find_handle = FindFirstFileW (fnw, &dir_find_data_w);
|
||||
}
|
||||
else
|
||||
{
|
||||
char fna[MAX_PATH];
|
||||
|
||||
filename_to_ansi (filename, fna);
|
||||
dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
|
||||
}
|
||||
|
||||
if (dir_find_handle == INVALID_HANDLE_VALUE)
|
||||
return NULL;
|
||||
}
|
||||
else if (w32_unicode_filenames)
|
||||
{
|
||||
if (!FindNextFileW (dir_find_handle, &dir_find_data_w))
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!FindNextFile (dir_find_handle, &dir_find_data))
|
||||
if (!FindNextFileA (dir_find_handle, &dir_find_data_a))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -3062,112 +3072,153 @@ readdir (DIR *dirp)
|
||||
value returned by stat(). */
|
||||
dir_static.d_ino = 1;
|
||||
|
||||
strcpy (dir_static.d_name, dir_find_data.cFileName);
|
||||
|
||||
/* If the file name in cFileName[] includes `?' characters, it means
|
||||
the original file name used characters that cannot be represented
|
||||
by the current ANSI codepage. To avoid total lossage, retrieve
|
||||
the short 8+3 alias of the long file name. */
|
||||
if (_mbspbrk (dir_static.d_name, "?"))
|
||||
if (w32_unicode_filenames)
|
||||
{
|
||||
strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
|
||||
downcase = 1; /* 8+3 aliases are returned in all caps */
|
||||
}
|
||||
dir_static.d_namlen = strlen (dir_static.d_name);
|
||||
dir_static.d_reclen = sizeof (struct dirent) - MAXNAMLEN + 3 +
|
||||
dir_static.d_namlen - dir_static.d_namlen % 4;
|
||||
if (downcase || dir_is_fat)
|
||||
{
|
||||
wchar_t tem[MAX_PATH];
|
||||
|
||||
/* If the file name in cFileName[] includes `?' characters, it means
|
||||
the original file name used characters that cannot be represented
|
||||
by the current ANSI codepage. To avoid total lossage, retrieve
|
||||
the short 8+3 alias of the long file name. */
|
||||
if (_mbspbrk (dir_find_data.cFileName, "?"))
|
||||
{
|
||||
strcpy (dir_static.d_name, dir_find_data.cAlternateFileName);
|
||||
/* 8+3 aliases are returned in all caps, which could break
|
||||
various alists that look at filenames' extensions. */
|
||||
downcase = 1;
|
||||
wcscpy (tem, dir_find_data_w.cFileName);
|
||||
CharLowerW (tem);
|
||||
filename_from_utf16 (tem, dir_static.d_name);
|
||||
}
|
||||
else
|
||||
filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
|
||||
}
|
||||
else
|
||||
strcpy (dir_static.d_name, dir_find_data.cFileName);
|
||||
dir_static.d_namlen = strlen (dir_static.d_name);
|
||||
if (dir_is_fat)
|
||||
_mbslwr (dir_static.d_name);
|
||||
else if (downcase)
|
||||
{
|
||||
register char *p;
|
||||
int dbcs_p = max_filename_mbslen () > 1;
|
||||
for (p = dir_static.d_name; *p; )
|
||||
char tem[MAX_PATH];
|
||||
|
||||
/* If the file name in cFileName[] includes `?' characters, it
|
||||
means the original file name used characters that cannot be
|
||||
represented by the current ANSI codepage. To avoid total
|
||||
lossage, retrieve the short 8+3 alias of the long file
|
||||
name. */
|
||||
if (_mbspbrk (dir_find_data_a.cFileName, "?"))
|
||||
{
|
||||
if (*p >= 'a' && *p <= 'z')
|
||||
break;
|
||||
if (dbcs_p)
|
||||
p = CharNextExA (file_name_codepage, p, 0);
|
||||
else
|
||||
p++;
|
||||
strcpy (tem, dir_find_data_a.cAlternateFileName);
|
||||
/* 8+3 aliases are returned in all caps, which could break
|
||||
various alists that look at filenames' extensions. */
|
||||
downcase = 1;
|
||||
}
|
||||
else if (downcase || dir_is_fat)
|
||||
strcpy (tem, dir_find_data_a.cFileName);
|
||||
else
|
||||
filename_from_ansi (dir_find_data_a.cFileName, dir_static.d_name);
|
||||
if (downcase || dir_is_fat)
|
||||
{
|
||||
_mbslwr (tem);
|
||||
filename_from_ansi (tem, dir_static.d_name);
|
||||
}
|
||||
if (!*p)
|
||||
_mbslwr (dir_static.d_name);
|
||||
}
|
||||
|
||||
dir_static.d_namlen = strlen (dir_static.d_name);
|
||||
dir_static.d_reclen = sizeof (struct dirent) - MAX_UTF8_PATH + 3 +
|
||||
dir_static.d_namlen - dir_static.d_namlen % 4;
|
||||
|
||||
return &dir_static;
|
||||
}
|
||||
|
||||
static HANDLE
|
||||
open_unc_volume (const char *path)
|
||||
{
|
||||
NETRESOURCE nr;
|
||||
const char *fn = map_w32_filename (path, NULL);
|
||||
DWORD result;
|
||||
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;
|
||||
if (w32_unicode_filenames)
|
||||
{
|
||||
NETRESOURCEW nrw;
|
||||
wchar_t fnw[MAX_PATH];
|
||||
|
||||
result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
|
||||
RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
|
||||
nrw.dwScope = RESOURCE_GLOBALNET;
|
||||
nrw.dwType = RESOURCETYPE_DISK;
|
||||
nrw.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
|
||||
nrw.dwUsage = RESOURCEUSAGE_CONTAINER;
|
||||
nrw.lpLocalName = NULL;
|
||||
filename_to_utf16 (fn, fnw);
|
||||
nrw.lpRemoteName = fnw;
|
||||
nrw.lpComment = NULL;
|
||||
nrw.lpProvider = NULL;
|
||||
|
||||
result = WNetOpenEnumW (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
|
||||
RESOURCEUSAGE_CONNECTABLE, &nrw, &henum);
|
||||
}
|
||||
else
|
||||
{
|
||||
NETRESOURCEA nra;
|
||||
char fna[MAX_PATH];
|
||||
|
||||
nra.dwScope = RESOURCE_GLOBALNET;
|
||||
nra.dwType = RESOURCETYPE_DISK;
|
||||
nra.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
|
||||
nra.dwUsage = RESOURCEUSAGE_CONTAINER;
|
||||
nra.lpLocalName = NULL;
|
||||
filename_to_ansi (fn, fna);
|
||||
nra.lpRemoteName = fna;
|
||||
nra.lpComment = NULL;
|
||||
nra.lpProvider = NULL;
|
||||
|
||||
result = WNetOpenEnumA (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
|
||||
RESOURCEUSAGE_CONNECTABLE, &nra, &henum);
|
||||
}
|
||||
if (result == NO_ERROR)
|
||||
return henum;
|
||||
else
|
||||
return INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
static char *
|
||||
read_unc_volume (HANDLE henum, char *readbuf, int size)
|
||||
static void *
|
||||
read_unc_volume (HANDLE henum, wchar_t *fname_w, char *fname_a, int size)
|
||||
{
|
||||
DWORD count;
|
||||
int result;
|
||||
DWORD bufsize = 512;
|
||||
char *buffer;
|
||||
char *ptr;
|
||||
int dbcs_p = max_filename_mbslen () > 1;
|
||||
DWORD bufsize = 512;
|
||||
void *retval;
|
||||
|
||||
count = 1;
|
||||
buffer = alloca (bufsize);
|
||||
result = WNetEnumResource (henum, &count, buffer, &bufsize);
|
||||
if (result != NO_ERROR)
|
||||
return NULL;
|
||||
if (w32_unicode_filenames)
|
||||
{
|
||||
wchar_t *ptrw;
|
||||
|
||||
/* WNetEnumResource returns \\resource\share...skip forward to "share". */
|
||||
ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
|
||||
ptr += 2;
|
||||
if (!dbcs_p)
|
||||
while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
|
||||
bufsize *= 2;
|
||||
buffer = alloca (bufsize);
|
||||
result = WNetEnumResourceW (henum, &count, buffer, &bufsize);
|
||||
if (result != NO_ERROR)
|
||||
return NULL;
|
||||
/* WNetEnumResource returns \\resource\share...skip forward to "share". */
|
||||
ptrw = ((LPNETRESOURCEW) buffer)->lpRemoteName;
|
||||
ptrw += 2;
|
||||
while (*ptrw && *ptrw != L'/' && *ptrw != L'\\') ptrw++;
|
||||
ptrw++;
|
||||
wcsncpy (fname_w, ptrw, size);
|
||||
retval = fname_w;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (*ptr && !IS_DIRECTORY_SEP (*ptr))
|
||||
ptr = CharNextExA (file_name_codepage, ptr, 0);
|
||||
}
|
||||
ptr++;
|
||||
int dbcs_p = max_filename_mbslen () > 1;
|
||||
char *ptra;
|
||||
|
||||
strncpy (readbuf, ptr, size);
|
||||
return readbuf;
|
||||
buffer = alloca (bufsize);
|
||||
result = WNetEnumResourceA (henum, &count, buffer, &bufsize);
|
||||
if (result != NO_ERROR)
|
||||
return NULL;
|
||||
ptra = ((LPNETRESOURCEA) buffer)->lpRemoteName;
|
||||
ptra += 2;
|
||||
if (!dbcs_p)
|
||||
while (*ptra && !IS_DIRECTORY_SEP (*ptra)) ptra++;
|
||||
else
|
||||
{
|
||||
while (*ptra && !IS_DIRECTORY_SEP (*ptra))
|
||||
ptra = CharNextExA (file_name_codepage, ptra, 0);
|
||||
}
|
||||
ptra++;
|
||||
strncpy (fname_a, ptra, size);
|
||||
retval = fname_a;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -3198,13 +3249,12 @@ unc_volume_file_attributes (const char *path)
|
||||
static void
|
||||
logon_network_drive (const char *path)
|
||||
{
|
||||
NETRESOURCE resource;
|
||||
char share[MAX_PATH];
|
||||
char share[MAX_UTF8_PATH];
|
||||
int n_slashes;
|
||||
char drive[4];
|
||||
UINT drvtype;
|
||||
char *p;
|
||||
int dbcs_p;
|
||||
DWORD val;
|
||||
|
||||
if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
|
||||
drvtype = DRIVE_REMOTE;
|
||||
@ -3224,28 +3274,70 @@ logon_network_drive (const char *path)
|
||||
return;
|
||||
|
||||
n_slashes = 2;
|
||||
strncpy (share, path, MAX_PATH);
|
||||
strncpy (share, path, MAX_UTF8_PATH);
|
||||
/* Truncate to just server and share name. */
|
||||
dbcs_p = max_filename_mbslen () > 1;
|
||||
for (p = share + 2; *p && p < share + MAX_PATH; )
|
||||
for (p = share + 2; *p && p < share + MAX_UTF8_PATH; p++)
|
||||
{
|
||||
if (IS_DIRECTORY_SEP (*p) && ++n_slashes > 3)
|
||||
{
|
||||
*p = '\0';
|
||||
break;
|
||||
}
|
||||
if (dbcs_p)
|
||||
p = CharNextExA (file_name_codepage, p, 0);
|
||||
else
|
||||
p++;
|
||||
}
|
||||
|
||||
resource.dwType = RESOURCETYPE_DISK;
|
||||
resource.lpLocalName = NULL;
|
||||
resource.lpRemoteName = share;
|
||||
resource.lpProvider = NULL;
|
||||
if (w32_unicode_filenames)
|
||||
{
|
||||
NETRESOURCEW resourcew;
|
||||
wchar_t share_w[MAX_PATH];
|
||||
|
||||
WNetAddConnection2 (&resource, NULL, NULL, CONNECT_INTERACTIVE);
|
||||
resourcew.dwScope = RESOURCE_GLOBALNET;
|
||||
resourcew.dwType = RESOURCETYPE_DISK;
|
||||
resourcew.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
|
||||
resourcew.dwUsage = RESOURCEUSAGE_CONTAINER;
|
||||
resourcew.lpLocalName = NULL;
|
||||
filename_to_utf16 (share, share_w);
|
||||
resourcew.lpRemoteName = share_w;
|
||||
resourcew.lpProvider = NULL;
|
||||
|
||||
val = WNetAddConnection2W (&resourcew, NULL, NULL, CONNECT_INTERACTIVE);
|
||||
}
|
||||
else
|
||||
{
|
||||
NETRESOURCEA resourcea;
|
||||
char share_a[MAX_PATH];
|
||||
|
||||
resourcea.dwScope = RESOURCE_GLOBALNET;
|
||||
resourcea.dwType = RESOURCETYPE_DISK;
|
||||
resourcea.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
|
||||
resourcea.dwUsage = RESOURCEUSAGE_CONTAINER;
|
||||
resourcea.lpLocalName = NULL;
|
||||
filename_to_ansi (share, share_a);
|
||||
resourcea.lpRemoteName = share_a;
|
||||
resourcea.lpProvider = NULL;
|
||||
|
||||
val = WNetAddConnection2A (&resourcea, NULL, NULL, CONNECT_INTERACTIVE);
|
||||
}
|
||||
|
||||
switch (val)
|
||||
{
|
||||
case NO_ERROR:
|
||||
case ERROR_ALREADY_ASSIGNED:
|
||||
break;
|
||||
case ERROR_ACCESS_DENIED:
|
||||
case ERROR_LOGON_FAILURE:
|
||||
errno = EACCES;
|
||||
break;
|
||||
case ERROR_BUSY:
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
case ERROR_BAD_NET_NAME:
|
||||
case ERROR_NO_NET_OR_BAD_PATH:
|
||||
case ERROR_NO_NETWORK:
|
||||
case ERROR_CANCELLED:
|
||||
default:
|
||||
errno = ENOENT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Emulate faccessat(2). */
|
||||
@ -4338,7 +4430,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
|
||||
&& xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
|
||||
{
|
||||
/* This was the last entry returned by readdir. */
|
||||
wfd = dir_find_data;
|
||||
wfd = dir_find_data_a; /* FIXME!!! */
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user