1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-31 17:30:54 -08:00

Converted and tested stat and fstatat.

This commit is contained in:
Eli Zaretskii 2013-11-18 16:29:23 +02:00
parent a868f601eb
commit df87c56cdf
2 changed files with 166 additions and 103 deletions

View file

@ -958,11 +958,11 @@ file_attributes (int fd, char const *name, Lisp_Object id_format)
unblock_input ();
}
if (uname)
values[2] = DECODE_SYSTEM (build_string (uname));
values[2] = DECODE_SYSTEM (build_unibyte_string (uname));
else
values[2] = make_fixnum_or_float (s.st_uid);
if (gname)
values[3] = DECODE_SYSTEM (build_string (gname));
values[3] = DECODE_SYSTEM (build_unibyte_string (gname));
else
values[3] = make_fixnum_or_float (s.st_gid);

265
src/w32.c
View file

@ -273,7 +273,8 @@ static BOOL g_b_init_lookup_account_sid;
static BOOL g_b_init_get_sid_sub_authority;
static BOOL g_b_init_get_sid_sub_authority_count;
static BOOL g_b_init_get_security_info;
static BOOL g_b_init_get_file_security;
static BOOL g_b_init_get_file_security_w;
static BOOL g_b_init_get_file_security_a;
static BOOL g_b_init_get_security_descriptor_owner;
static BOOL g_b_init_get_security_descriptor_group;
static BOOL g_b_init_is_valid_sid;
@ -327,12 +328,8 @@ GetProcessTimes_Proc get_process_times_fn = NULL;
#ifdef _UNICODE
const char * const LookupAccountSid_Name = "LookupAccountSidW";
const char * const GetFileSecurity_Name = "GetFileSecurityW";
const char * const SetFileSecurity_Name = "SetFileSecurityW";
#else
const char * const LookupAccountSid_Name = "LookupAccountSidA";
const char * const GetFileSecurity_Name = "GetFileSecurityA";
const char * const SetFileSecurity_Name = "SetFileSecurityA";
#endif
typedef BOOL (WINAPI * LookupAccountSid_Proc) (
LPCTSTR lpSystemName,
@ -356,8 +353,14 @@ typedef DWORD (WINAPI * GetSecurityInfo_Proc) (
PACL *ppDacl,
PACL *ppSacl,
PSECURITY_DESCRIPTOR *ppSecurityDescriptor);
typedef BOOL (WINAPI * GetFileSecurity_Proc) (
LPCTSTR lpFileName,
typedef BOOL (WINAPI * GetFileSecurityW_Proc) (
LPCWSTR lpFileName,
SECURITY_INFORMATION RequestedInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor,
DWORD nLength,
LPDWORD lpnLengthNeeded);
typedef BOOL (WINAPI * GetFileSecurityA_Proc) (
LPCSTR lpFileName,
SECURITY_INFORMATION RequestedInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor,
DWORD nLength,
@ -678,36 +681,68 @@ get_security_info (HANDLE handle,
ppSecurityDescriptor));
}
static int filename_to_ansi (const char *, char *);
static int filename_to_utf16 (const char *, wchar_t *);
static BOOL WINAPI
get_file_security (LPCTSTR lpFileName,
get_file_security (const char *lpFileName,
SECURITY_INFORMATION RequestedInformation,
PSECURITY_DESCRIPTOR pSecurityDescriptor,
DWORD nLength,
LPDWORD lpnLengthNeeded)
{
static GetFileSecurity_Proc s_pfn_Get_File_Security = NULL;
static GetFileSecurityA_Proc s_pfn_Get_File_SecurityA = NULL;
static GetFileSecurityW_Proc s_pfn_Get_File_SecurityW = NULL;
HMODULE hm_advapi32 = NULL;
if (is_windows_9x () == TRUE)
{
errno = ENOTSUP;
return FALSE;
}
if (g_b_init_get_file_security == 0)
if (w32_unicode_filenames)
{
g_b_init_get_file_security = 1;
hm_advapi32 = LoadLibrary ("Advapi32.dll");
s_pfn_Get_File_Security =
(GetFileSecurity_Proc) GetProcAddress (
hm_advapi32, GetFileSecurity_Name);
wchar_t filename_w[MAX_PATH];
if (g_b_init_get_file_security_w == 0)
{
g_b_init_get_file_security_w = 1;
hm_advapi32 = LoadLibrary ("Advapi32.dll");
s_pfn_Get_File_SecurityW =
(GetFileSecurityW_Proc) GetProcAddress (hm_advapi32,
"GetFileSecurityW");
}
if (s_pfn_Get_File_SecurityW == NULL)
{
errno = ENOTSUP;
return FALSE;
}
filename_to_utf16 (lpFileName, filename_w);
return (s_pfn_Get_File_SecurityW (filename_w, RequestedInformation,
pSecurityDescriptor, nLength,
lpnLengthNeeded));
}
if (s_pfn_Get_File_Security == NULL)
else
{
errno = ENOTSUP;
return FALSE;
char filename_a[MAX_PATH];
if (g_b_init_get_file_security_a == 0)
{
g_b_init_get_file_security_a = 1;
hm_advapi32 = LoadLibrary ("Advapi32.dll");
s_pfn_Get_File_SecurityA =
(GetFileSecurityA_Proc) GetProcAddress (hm_advapi32,
"GetFileSecurityA");
}
if (s_pfn_Get_File_SecurityA == NULL)
{
errno = ENOTSUP;
return FALSE;
}
filename_to_ansi (lpFileName, filename_a);
return (s_pfn_Get_File_SecurityA (filename_a, RequestedInformation,
pSecurityDescriptor, nLength,
lpnLengthNeeded));
}
return (s_pfn_Get_File_Security (lpFileName, RequestedInformation,
pSecurityDescriptor, nLength,
lpnLengthNeeded));
}
static BOOL WINAPI
@ -728,7 +763,7 @@ set_file_security (LPCTSTR lpFileName,
hm_advapi32 = LoadLibrary ("Advapi32.dll");
s_pfn_Set_File_Security =
(SetFileSecurity_Proc) GetProcAddress (
hm_advapi32, SetFileSecurity_Name);
hm_advapi32, "SetFileSecurityA");
}
if (s_pfn_Set_File_Security == NULL)
{
@ -2946,6 +2981,9 @@ static int dir_is_fat;
static char dir_pathname[MAX_UTF8_PATH];
static WIN32_FIND_DATAW dir_find_data_w;
static WIN32_FIND_DATAA dir_find_data_a;
#define DIR_FIND_DATA_W 1
#define DIR_FIND_DATA_A 2
static int last_dir_find_data = -1;
/* Support shares on a network resource as subdirectories of a read-only
root directory. */
@ -3051,7 +3089,13 @@ sys_readdir (DIR *dirp)
char fna[MAX_PATH];
filename_to_ansi (filename, fna);
dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
/* If FILENAME is not representable by the current ANSI
codepage, we don't want FindFirstFileA to interpret the
'?' characters as a wildcard. */
if (_mbspbrk (fna, "?"))
dir_find_handle = INVALID_HANDLE_VALUE;
else
dir_find_handle = FindFirstFileA (fna, &dir_find_data_a);
}
if (dir_find_handle == INVALID_HANDLE_VALUE)
@ -3084,6 +3128,7 @@ sys_readdir (DIR *dirp)
}
else
filename_from_utf16 (dir_find_data_w.cFileName, dir_static.d_name);
last_dir_find_data = DIR_FIND_DATA_W;
}
else
{
@ -3110,6 +3155,7 @@ sys_readdir (DIR *dirp)
_mbslwr (tem);
filename_from_ansi (tem, dir_static.d_name);
}
last_dir_find_data = DIR_FIND_DATA_A;
}
dir_static.d_namlen = strlen (dir_static.d_name);
@ -4324,18 +4370,21 @@ is_slow_fs (const char *name)
}
/* If this is non-zero, the caller wants accurate information about
file's owner and group, which could be expensive to get. */
file's owner and group, which could be expensive to get. dired.c
uses this flag when needed for the job at hand. */
int w32_stat_get_owner_group;
/* MSVC stat function can't cope with UNC names and has other bugs, so
replace it with our own. This also allows us to calculate consistent
inode values and owner/group without hacks in the main Emacs code. */
inode values and owner/group without hacks in the main Emacs code,
and support file names encoded in UTF-8. */
static int
stat_worker (const char * path, struct stat * buf, int follow_symlinks)
{
char *name, *save_name, *r;
WIN32_FIND_DATA wfd;
WIN32_FIND_DATAW wfd_w;
WIN32_FIND_DATAA wfd_a;
HANDLE fh;
unsigned __int64 fake_inode = 0;
int permission;
@ -4347,7 +4396,8 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
DWORD access_rights = 0;
DWORD fattrs = 0, serialnum = 0, fs_high = 0, fs_low = 0, nlinks = 1;
FILETIME ctime, atime, wtime;
int dbcs_p;
wchar_t name_w[MAX_PATH];
char name_a[MAX_PATH];
if (path == NULL || buf == NULL)
{
@ -4357,11 +4407,8 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
save_name = name = (char *) map_w32_filename (path, &path);
/* Must be valid filename, no wild cards or other invalid
characters. We use _mbspbrk to support multibyte strings that
might look to strpbrk as if they included literal *, ?, and other
characters mentioned below that are disallowed by Windows
filesystems. */
if (_mbspbrk (name, "*?|<>\""))
characters. */
if (strpbrk (name, "*?|<>\""))
{
errno = ENOENT;
return -1;
@ -4412,13 +4459,26 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
if (is_windows_9x () != TRUE)
access_rights |= READ_CONTROL;
fh = CreateFile (name, access_rights, 0, NULL, OPEN_EXISTING,
file_flags, NULL);
/* If CreateFile fails with READ_CONTROL, try again with zero as
access rights. */
if (fh == INVALID_HANDLE_VALUE && access_rights)
fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
file_flags, NULL);
if (w32_unicode_filenames)
{
filename_to_utf16 (name, name_w);
fh = CreateFileW (name_w, access_rights, 0, NULL, OPEN_EXISTING,
file_flags, NULL);
/* If CreateFile fails with READ_CONTROL, try again with
zero as access rights. */
if (fh == INVALID_HANDLE_VALUE && access_rights)
fh = CreateFileW (name_w, 0, 0, NULL, OPEN_EXISTING,
file_flags, NULL);
}
else
{
filename_to_ansi (name, name_a);
fh = CreateFileA (name_a, access_rights, 0, NULL, OPEN_EXISTING,
file_flags, NULL);
if (fh == INVALID_HANDLE_VALUE && access_rights)
fh = CreateFileA (name_a, 0, 0, NULL, OPEN_EXISTING,
file_flags, NULL);
}
if (fh == INVALID_HANDLE_VALUE)
goto no_true_file_attributes;
@ -4545,7 +4605,6 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
did not ask for extra precision, resolving symlinks will fly
in the face of that request, since the user then wants the
lightweight version of the code. */
dbcs_p = max_filename_mbslen () > 1;
rootdir = (path >= save_name + len - 1
&& (IS_DIRECTORY_SEP (*path) || *path == 0));
@ -4573,19 +4632,8 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
}
else if (rootdir)
{
if (!dbcs_p)
{
if (!IS_DIRECTORY_SEP (name[len-1]))
strcat (name, "\\");
}
else
{
char *end = name + len;
char *n = CharPrevExA (file_name_codepage, name, end, 0);
if (!IS_DIRECTORY_SEP (*n))
strcat (name, "\\");
}
if (!IS_DIRECTORY_SEP (name[len-1]))
strcat (name, "\\");
if (GetDriveType (name) < 2)
{
errno = ENOENT;
@ -4597,51 +4645,65 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
}
else
{
if (!dbcs_p)
{
if (IS_DIRECTORY_SEP (name[len-1]))
name[len - 1] = 0;
}
else
{
char *end = name + len;
char *n = CharPrevExA (file_name_codepage, name, end, 0);
int have_wfd = -1;
if (IS_DIRECTORY_SEP (*n))
*n = 0;
}
if (IS_DIRECTORY_SEP (name[len-1]))
name[len - 1] = 0;
/* (This is hacky, but helps when doing file completions on
network drives.) Optimize by using information available from
active readdir if possible. */
len = strlen (dir_pathname);
if (!dbcs_p)
{
if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
len--;
}
else
{
char *end = dir_pathname + len;
char *n = CharPrevExA (file_name_codepage, dir_pathname, end, 0);
if (IS_DIRECTORY_SEP (*n))
len--;
}
if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
len--;
if (dir_find_handle != INVALID_HANDLE_VALUE
&& last_dir_find_data != -1
&& !(is_a_symlink && follow_symlinks)
&& strnicmp (save_name, dir_pathname, len) == 0
/* The 2 file-name comparisons below support only ASCII
characters, and will lose (compare not equal) when
the file names include non-ASCII charcaters that are
the same but for the case. However, doing this
properly involves: (a) converting both file names to
UTF-16, (b) lower-casing both names using CharLowerW,
and (c) comparing the results; this would be quite a
bit slower, whereas Plan B is for users who want
lightweight albeit inaccurate version of 'stat'. */
&& c_strncasecmp (save_name, dir_pathname, len) == 0
&& IS_DIRECTORY_SEP (name[len])
&& xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
{
have_wfd = last_dir_find_data;
/* This was the last entry returned by readdir. */
wfd = dir_find_data_a; /* FIXME!!! */
if (last_dir_find_data == DIR_FIND_DATA_W)
wfd_w = dir_find_data_w;
else
wfd_a = dir_find_data_a;
}
else
{
logon_network_drive (name);
fh = FindFirstFile (name, &wfd);
if (w32_unicode_filenames)
{
filename_to_utf16 (name, name_w);
fh = FindFirstFileW (name_w, &wfd_w);
have_wfd = DIR_FIND_DATA_W;
}
else
{
filename_to_ansi (name, name_a);
/* If NAME includes characters not representable by
the current ANSI codepage, filename_to_ansi
usually replaces them with a '?'. We don't want
to let FindFirstFileA interpret those as widlcards,
and "succeed", returning us data from some random
file in the same directory. */
if (_mbspbrk (name_a, "?"))
fh = INVALID_HANDLE_VALUE;
else
fh = FindFirstFileA (name_a, &wfd_a);
have_wfd = DIR_FIND_DATA_A;
}
if (fh == INVALID_HANDLE_VALUE)
{
errno = ENOENT;
@ -4651,12 +4713,24 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
}
/* Note: if NAME is a symlink, the information we get from
FindFirstFile is for the symlink, not its target. */
fattrs = wfd.dwFileAttributes;
ctime = wfd.ftCreationTime;
atime = wfd.ftLastAccessTime;
wtime = wfd.ftLastWriteTime;
fs_high = wfd.nFileSizeHigh;
fs_low = wfd.nFileSizeLow;
if (have_wfd == DIR_FIND_DATA_W)
{
fattrs = wfd_w.dwFileAttributes;
ctime = wfd_w.ftCreationTime;
atime = wfd_w.ftLastAccessTime;
wtime = wfd_w.ftLastWriteTime;
fs_high = wfd_w.nFileSizeHigh;
fs_low = wfd_w.nFileSizeLow;
}
else
{
fattrs = wfd_a.dwFileAttributes;
ctime = wfd_a.ftCreationTime;
atime = wfd_a.ftLastAccessTime;
wtime = wfd_a.ftLastWriteTime;
fs_high = wfd_a.nFileSizeHigh;
fs_low = wfd_a.nFileSizeLow;
}
fake_inode = 0;
nlinks = 1;
serialnum = volume_info.serialnum;
@ -4671,18 +4745,6 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
get_file_owner_and_group (NULL, buf);
}
#if 0
/* Not sure if there is any point in this. */
if (!NILP (Vw32_generate_fake_inodes))
fake_inode = generate_inode_val (name);
else if (fake_inode == 0)
{
/* For want of something better, try to make everything unique. */
static DWORD gen_num = 0;
fake_inode = ++gen_num;
}
#endif
buf->st_ino = fake_inode;
buf->st_dev = serialnum;
@ -4741,7 +4803,7 @@ fstatat (int fd, char const *name, struct stat *st, int flags)
FIXME: Add proper support for fdopendir, fstatat, readlinkat.
Gnulib does this and can serve as a model. */
char fullname[MAX_PATH];
char fullname[MAX_UTF8_PATH];
if (fd != AT_FDCWD)
{
@ -8404,7 +8466,8 @@ globals_of_w32 (void)
g_b_init_get_sid_sub_authority = 0;
g_b_init_get_sid_sub_authority_count = 0;
g_b_init_get_security_info = 0;
g_b_init_get_file_security = 0;
g_b_init_get_file_security_w = 0;
g_b_init_get_file_security_a = 0;
g_b_init_get_security_descriptor_owner = 0;
g_b_init_get_security_descriptor_group = 0;
g_b_init_is_valid_sid = 0;