4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-02-01 03:50:28 +08:00

* dir.cc (readdir_worker): Drop dir parameter from call to

readdir_get_ino.
	* fhandler.h (fhandler_disk_file::readdir_helper): Switch file name
	parameter to PUNICODE_STRING.
	* fhandler_disk_file.cc: Drop including ntdef.h.
	(class __DIR_mounts): Store mount points in UNICODE.  Additionally
	store cygdrive prefix in unicode here.  Change methods accordingly.
	(__DIR_mounts::eval_ino): Call new stat_worker instead of lstat64.
	(__DIR_mounts::~__DIR_mounts): New destructor to free UNICODE buffers.
	(path_conv::ndisk_links): Rewrite using native NT functions.
	(fhandler_base::fstat_by_handle): Use NAME_MAX instead of CYG_MAX_PATH.
	Always set pfvi->VolumeSerialNumber to non-0.  Remove last resort
	code.
	(fhandler_base::fstat_by_name): Rewrite using native NT functions.
	(fhandler_base::fstat_fs): Always call fstat_by_name if fstat_by_handle
	fails.
	(fhandler_base::fstat_helper): Rely on dwVolumeSerialNumber.
	(fhandler_disk_file::facl): Call fstat_by_name if fstat_by_handle fails.
	(DIR_BUF_SIZE): Define using NAME_MAX instead of CYG_MAX_PATH.
	(__DIR_cache): Remove __name.
	(d_dirname): Remove.
	(fhandler_disk_file::opendir): Drop pathname length check.
	Remove outdated comment.  Use get_name method instead of accessing
	pc.normalized_path directly.
	(readdir_get_ino): Drop unused dir parameter.  Accomodate throughout.
	Allocate fname dynamically.  Call new stat_worker instead of lstat64.
	Call NtOpenFile instead of CreateFile.  Call NtClose instead of
	CloseHandle.
	(fhandler_disk_file::readdir_helper): Use native NT functions.
	Check for volume mount points and use correct inode number.
	(fhandler_disk_file::readdir): Simplify slightly.
	Use get_name instead of pc.normalized_path.
	(fhandler_disk_file::rewinddir): Use RtlInitUnicodeString.
	(fhandler_cygdrive::fstat): Ignore floppy drives.  Set st_nlink
	correctly.
	(fhandler_cygdrive::readdir): Ignore floppy drives.
	* fhandler_netdrive.cc (fhandler_netdrive::readdir): Accommodate
	change to readdir_get_ino.
	* fhandler_proc.cc (PROC_DIR_COUNT): Define.
	(fhandler_proc::fstat): Evaluate correct link count for /proc.
	* ntdll.h (struct _FILE_DIRECTORY_INFORMATION): Define.
	(NtFsControlFile): Declare.
	(RtlAppendUnicodeToString): Declare.
	(RtlAppendUnicodeStringToString): Declare.
	(RtlCompareUnicodeString): Declare.
	(RtlCopyUnicodeString): Declare.
	(RtlCreateUnicodeStringFromAsciiz): Declare.
	(RtlEqualUnicodeString): Declare.
	(RtlFreeUnicodeString): Declare.
	(RtlInitEmptyUnicodeString): Declare.
	(RtlSecondsSince1970ToTime): Declare.
	(RtlInitEmptyUnicodeString): Define as inline function.
	(RtlInitCountedUnicodeString): Define as inline function.
	* path.cc (path_conv::check): New method with PUNICODE_STRING as path,
	preliminary implementation.
	(mount_info::get_mounts_here): Change to create UNICODE_STRINGs.
	Also copy cygpath prefix into UNICODE_STRING.
	(is_floppy): Drop 9x consideration.
	* path.h: Drop including ntdef.h.
	(path_conv::check): Add declaration.
	(path_conv::path_conv): Add constructor for UNICODE_STRING paths.
	* shared_info.h (mount_info::get_mounts_here): Change declaration.
	* syscalls.cc: Drop forward declaration of stat_worker.
	(stat_worke): Take path_conv as parameter.  Drop nofollow flag.
	(stat64): Create matching path_conv and call stat_worker with it.
	(lstat64): Ditto.
	* winsup.h: Include ntdef.h.
	(stat_worker): Declare.
	(readdir_get_ino): Change declaration.
This commit is contained in:
Corinna Vinschen 2007-07-26 17:30:54 +00:00
parent 4b62a570de
commit 214c3a1167
12 changed files with 572 additions and 269 deletions

View File

@ -1,3 +1,75 @@
2007-07-26 Corinna Vinschen <corinna@vinschen.de>
* dir.cc (readdir_worker): Drop dir parameter from call to
readdir_get_ino.
* fhandler.h (fhandler_disk_file::readdir_helper): Switch file name
parameter to PUNICODE_STRING.
* fhandler_disk_file.cc: Drop including ntdef.h.
(class __DIR_mounts): Store mount points in UNICODE. Additionally
store cygdrive prefix in unicode here. Change methods accordingly.
(__DIR_mounts::eval_ino): Call new stat_worker instead of lstat64.
(__DIR_mounts::~__DIR_mounts): New destructor to free UNICODE buffers.
(path_conv::ndisk_links): Rewrite using native NT functions.
(fhandler_base::fstat_by_handle): Use NAME_MAX instead of CYG_MAX_PATH.
Always set pfvi->VolumeSerialNumber to non-0. Remove last resort
code.
(fhandler_base::fstat_by_name): Rewrite using native NT functions.
(fhandler_base::fstat_fs): Always call fstat_by_name if fstat_by_handle
fails.
(fhandler_base::fstat_helper): Rely on dwVolumeSerialNumber.
(fhandler_disk_file::facl): Call fstat_by_name if fstat_by_handle fails.
(DIR_BUF_SIZE): Define using NAME_MAX instead of CYG_MAX_PATH.
(__DIR_cache): Remove __name.
(d_dirname): Remove.
(fhandler_disk_file::opendir): Drop pathname length check.
Remove outdated comment. Use get_name method instead of accessing
pc.normalized_path directly.
(readdir_get_ino): Drop unused dir parameter. Accomodate throughout.
Allocate fname dynamically. Call new stat_worker instead of lstat64.
Call NtOpenFile instead of CreateFile. Call NtClose instead of
CloseHandle.
(fhandler_disk_file::readdir_helper): Use native NT functions.
Check for volume mount points and use correct inode number.
(fhandler_disk_file::readdir): Simplify slightly.
Use get_name instead of pc.normalized_path.
(fhandler_disk_file::rewinddir): Use RtlInitUnicodeString.
(fhandler_cygdrive::fstat): Ignore floppy drives. Set st_nlink
correctly.
(fhandler_cygdrive::readdir): Ignore floppy drives.
* fhandler_netdrive.cc (fhandler_netdrive::readdir): Accommodate
change to readdir_get_ino.
* fhandler_proc.cc (PROC_DIR_COUNT): Define.
(fhandler_proc::fstat): Evaluate correct link count for /proc.
* ntdll.h (struct _FILE_DIRECTORY_INFORMATION): Define.
(NtFsControlFile): Declare.
(RtlAppendUnicodeToString): Declare.
(RtlAppendUnicodeStringToString): Declare.
(RtlCompareUnicodeString): Declare.
(RtlCopyUnicodeString): Declare.
(RtlCreateUnicodeStringFromAsciiz): Declare.
(RtlEqualUnicodeString): Declare.
(RtlFreeUnicodeString): Declare.
(RtlInitEmptyUnicodeString): Declare.
(RtlSecondsSince1970ToTime): Declare.
(RtlInitEmptyUnicodeString): Define as inline function.
(RtlInitCountedUnicodeString): Define as inline function.
* path.cc (path_conv::check): New method with PUNICODE_STRING as path,
preliminary implementation.
(mount_info::get_mounts_here): Change to create UNICODE_STRINGs.
Also copy cygpath prefix into UNICODE_STRING.
(is_floppy): Drop 9x consideration.
* path.h: Drop including ntdef.h.
(path_conv::check): Add declaration.
(path_conv::path_conv): Add constructor for UNICODE_STRING paths.
* shared_info.h (mount_info::get_mounts_here): Change declaration.
* syscalls.cc: Drop forward declaration of stat_worker.
(stat_worke): Take path_conv as parameter. Drop nofollow flag.
(stat64): Create matching path_conv and call stat_worker with it.
(lstat64): Ditto.
* winsup.h: Include ntdef.h.
(stat_worker): Declare.
(readdir_get_ino): Change declaration.
2007-07-25 Corinna Vinschen <corinna@vinschen.de> 2007-07-25 Corinna Vinschen <corinna@vinschen.de>
* autoload.cc (CreateToolhelp32Snapshot): Remove. * autoload.cc (CreateToolhelp32Snapshot): Remove.
@ -172,8 +244,8 @@
2007-07-16 Corinna Vinschen <corinna@vinschen.de> 2007-07-16 Corinna Vinschen <corinna@vinschen.de>
* cygheap.h (cygheap_user::curr_imp_token): Rename from current_token. * cygheap.h (cygheap_user::curr_imp_token): Rename from current_token.
Accommodate changge throughout Cygwin. Accommodate change throughout Cygwin.
(cygheap_user::imp_token): Rename from token. Accommodate changge (cygheap_user::imp_token): Rename from token. Accommodate change
throughout Cygwin. throughout Cygwin.
(rcygheap_user::eimpersonate): Use primary token for impersonation. (rcygheap_user::eimpersonate): Use primary token for impersonation.
* grp.cc (internal_getgroups): Use primary impersonation token when * grp.cc (internal_getgroups): Use primary impersonation token when

View File

@ -132,8 +132,7 @@ readdir_worker (DIR *dir, dirent *de)
} }
if (is_dot_dot && !(dir->__flags & dirent_isroot)) if (is_dot_dot && !(dir->__flags & dirent_isroot))
de->d_ino = readdir_get_ino (dir, de->d_ino = readdir_get_ino (((fhandler_base *) dir->__fh)->get_name (),
((fhandler_base *) dir->__fh)->get_name (),
true); true);
else else
{ {

View File

@ -671,7 +671,7 @@ class fhandler_dev_tape: public fhandler_dev_raw
class fhandler_disk_file: public fhandler_base class fhandler_disk_file: public fhandler_base
{ {
int readdir_helper (DIR *, dirent *, DWORD, DWORD, char *) __attribute__ ((regparm (3))); int readdir_helper (DIR *, dirent *, DWORD, DWORD, PUNICODE_STRING fname) __attribute__ ((regparm (3)));
public: public:
fhandler_disk_file (); fhandler_disk_file ();

View File

@ -26,7 +26,6 @@ details. */
#include "cygheap.h" #include "cygheap.h"
#include "shared_info.h" #include "shared_info.h"
#include "pinfo.h" #include "pinfo.h"
#include <ntdef.h>
#include "ntdll.h" #include "ntdll.h"
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
@ -37,11 +36,12 @@ details. */
class __DIR_mounts class __DIR_mounts
{ {
int count; int count;
const char *parent_dir; const char *parent_dir;
int parent_dir_len; int parent_dir_len;
char *mounts[MAX_MOUNTS]; UNICODE_STRING mounts[MAX_MOUNTS];
bool found[MAX_MOUNTS + 2]; bool found[MAX_MOUNTS + 2];
UNICODE_STRING cygdrive;
#define __DIR_PROC (MAX_MOUNTS) #define __DIR_PROC (MAX_MOUNTS)
#define __DIR_CYGDRIVE (MAX_MOUNTS+1) #define __DIR_CYGDRIVE (MAX_MOUNTS+1)
@ -49,15 +49,16 @@ class __DIR_mounts
__ino64_t eval_ino (int idx) __ino64_t eval_ino (int idx)
{ {
__ino64_t ino = 0; __ino64_t ino = 0;
char fname[CYG_MAX_PATH]; char fname[parent_dir_len + mounts[idx].Length / sizeof (WCHAR) + 2];
struct __stat64 st; struct __stat64 st;
int len = parent_dir_len;
strcpy (fname, parent_dir); char *c = stpcpy (fname, parent_dir);
if (fname[len - 1] != '/') if (c[- 1] != '/')
fname[len++] = '/'; *c++ = '/';
strcpy (fname + len, mounts[idx]); sys_wcstombs (c, mounts[idx].Length / sizeof (WCHAR) + 1,
if (!lstat64 (fname, &st)) mounts[idx].Buffer, mounts[idx].Length / sizeof (WCHAR));
path_conv pc (fname, PC_SYM_NOFOLLOW | PC_POSIX);
if (!stat_worker (pc, &st))
ino = st.st_ino; ino = st.st_ino;
return ino; return ino;
} }
@ -67,59 +68,73 @@ public:
: parent_dir (posix_path) : parent_dir (posix_path)
{ {
parent_dir_len = strlen (parent_dir); parent_dir_len = strlen (parent_dir);
count = mount_table->get_mounts_here (parent_dir, parent_dir_len, mounts); count = mount_table->get_mounts_here (parent_dir, parent_dir_len, mounts,
&cygdrive);
rewind (); rewind ();
} }
__ino64_t check_mount (const char *name, __ino64_t ino, bool eval = true) ~__DIR_mounts ()
{
for (int i = 0; i < count; ++i)
RtlFreeUnicodeString (&mounts[i]);
RtlFreeUnicodeString (&cygdrive);
}
__ino64_t check_mount (PUNICODE_STRING fname, __ino64_t ino,
bool eval = true)
{ {
if (parent_dir_len == 1) /* root dir */ if (parent_dir_len == 1) /* root dir */
{ {
if (strcasematch (name, "proc")) UNICODE_STRING proc;
RtlInitUnicodeString (&proc, L"proc");
if (RtlEqualUnicodeString (fname, &proc, TRUE))
{ {
found[__DIR_PROC] = true; found[__DIR_PROC] = true;
return hash_path_name (0, "/proc"); return 2;
} }
if (strlen (name) == mount_table->cygdrive_len - 2 if (fname->Length / sizeof (WCHAR) == mount_table->cygdrive_len - 2
&& strncasematch (name, mount_table->cygdrive + 1, && RtlEqualUnicodeString (fname, &cygdrive, TRUE))
mount_table->cygdrive_len - 2))
{ {
found[__DIR_CYGDRIVE] = true; found[__DIR_CYGDRIVE] = true;
return 2; return 2;
} }
} }
for (int i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
if (strcasematch (name, mounts[i])) if (RtlEqualUnicodeString (fname, &mounts[i], TRUE))
{ {
found[i] = true; found[i] = true;
return eval ? eval_ino (i) : 1; return eval ? eval_ino (i) : 1;
} }
return ino; return ino;
} }
__ino64_t check_missing_mount (char *ret_name, bool eval = true) __ino64_t check_missing_mount (PUNICODE_STRING retname = NULL)
{ {
for (int i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
if (!found[i]) if (!found[i])
{ {
found[i] = true; found[i] = true;
strcpy (ret_name, mounts[i]); if (retname)
return eval ? eval_ino (i) : 1; {
*retname = mounts[i];
return eval_ino (i);
}
return 1;
} }
if (parent_dir_len == 1) /* root dir */ if (parent_dir_len == 1) /* root dir */
{ {
if (!found[__DIR_PROC]) if (!found[__DIR_PROC])
{ {
found[__DIR_PROC] = true; found[__DIR_PROC] = true;
strcpy (ret_name, "proc"); if (retname)
return hash_path_name (0, "/proc"); RtlInitUnicodeString (retname, L"proc");
return 2;
} }
if (!found[__DIR_CYGDRIVE]) if (!found[__DIR_CYGDRIVE])
{ {
found[__DIR_CYGDRIVE] = true; found[__DIR_CYGDRIVE] = true;
if (mount_table->cygdrive_len > 1) if (cygdrive.Length > 0)
{ {
strncpy (ret_name, mount_table->cygdrive + 1, if (retname)
mount_table->cygdrive_len - 2); *retname = cygdrive;
ret_name[mount_table->cygdrive_len - 2] = '\0';
return 2; return 2;
} }
} }
@ -135,66 +150,91 @@ path_conv::ndisk_links (DWORD nNumberOfLinks)
if (!isdir () || isremote ()) if (!isdir () || isremote ())
return nNumberOfLinks; return nNumberOfLinks;
int len = strlen (*this); OBJECT_ATTRIBUTES attr;
char fn[len + 3]; IO_STATUS_BLOCK io;
strcpy (fn, *this); HANDLE fh;
const char *s; if (!NT_SUCCESS (NtOpenFile (&fh, SYNCHRONIZE | FILE_LIST_DIRECTORY,
unsigned count; get_object_attr (attr, sec_none_nih),
&io, FILE_SHARE_VALID_FLAGS,
FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_FOR_BACKUP_INTENT
| FILE_DIRECTORY_FILE)))
return nNumberOfLinks;
unsigned count = 0;
bool first = true;
NTSTATUS status;
PFILE_DIRECTORY_INFORMATION fdibuf = (PFILE_DIRECTORY_INFORMATION)
alloca (65536);
__DIR_mounts *dir = new __DIR_mounts (normalized_path); __DIR_mounts *dir = new __DIR_mounts (normalized_path);
if (nNumberOfLinks <= 1) while (NT_SUCCESS (NtQueryDirectoryFile (fh, NULL, NULL, 0, &io, fdibuf,
65536, FileDirectoryInformation,
FALSE, NULL, first)))
{ {
s = "\\*"; if (first)
count = 0; {
} first = false;
else /* All directories have . and .. as their first entries.
{ If . is not present as first entry, we're on a drive's
s = "\\.."; root direcotry, which doesn't have these entries. */
count = nNumberOfLinks; if (fdibuf->FileNameLength != 2 || fdibuf->FileName[0] != L'.')
} count = 2;
}
for (PFILE_DIRECTORY_INFORMATION pfdi = fdibuf;
pfdi;
pfdi = (PFILE_DIRECTORY_INFORMATION)
(pfdi->NextEntryOffset ? (PBYTE) pfdi + pfdi->NextEntryOffset
: NULL))
{
switch (pfdi->FileAttributes
& (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT))
{
case FILE_ATTRIBUTE_DIRECTORY:
/* Just a directory */
++count;
break;
case FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT:
/* Volume mount point or symlink to directory */
{
HANDLE reph;
UNICODE_STRING fname;
if (len == 0 || isdirsep (fn[len - 1])) RtlInitCountedUnicodeString (&fname, pfdi->FileNameLength,
strcpy (fn + len, s + 1); pfdi->FileName);
else InitializeObjectAttributes (&attr, &fname,
strcpy (fn + len, s); OBJ_CASE_INSENSITIVE, fh, NULL);
if (NT_SUCCESS (status = NtOpenFile (&reph, READ_CONTROL, &attr, &io,
WIN32_FIND_DATA buf; FILE_SHARE_VALID_FLAGS,
HANDLE h = FindFirstFile (fn, &buf); FILE_OPEN_FOR_BACKUP_INTENT
| FILE_OPEN_REPARSE_POINT)))
int saw_dot = 2; {
if (h != INVALID_HANDLE_VALUE) PREPARSE_DATA_BUFFER rp = (PREPARSE_DATA_BUFFER)
{ alloca (MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
if (nNumberOfLinks > 1) if (NT_SUCCESS (NtFsControlFile (reph, NULL, NULL, NULL,
saw_dot--; &io, FSCTL_GET_REPARSE_POINT, NULL, 0,
else (LPVOID) rp, MAXIMUM_REPARSE_DATA_BUFFER_SIZE))
do && rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT
{ && rp->SymbolicLinkReparseBuffer.PrintNameLength == 0)
if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ++count;
count++; NtClose (reph);
if (buf.cFileName[0] == '.' }
&& (buf.cFileName[1] == '\0' }
|| (buf.cFileName[1] == '.' && buf.cFileName[2] == '\0'))) break;
saw_dot--; default:
dir->check_mount (buf.cFileName, 0, false); break;
} }
while (FindNextFileA (h, &buf)); UNICODE_STRING fname;
FindClose (h); RtlInitCountedUnicodeString (&fname, pfdi->FileNameLength,
pfdi->FileName);
dir->check_mount (&fname, 0, false);
}
} }
while (dir->check_missing_mount ())
if (nNumberOfLinks > 1)
{
fn[len + 2] = '\0';
h = FindFirstFile (fn, &buf);
if (h)
saw_dot--;
FindClose (h);
}
while (dir->check_missing_mount (buf.cFileName, false))
++count; ++count;
NtClose (dir);
delete dir; delete dir;
return count;
return count + saw_dot;
} }
inline bool inline bool
@ -214,9 +254,10 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
NTSTATUS status; NTSTATUS status;
IO_STATUS_BLOCK io; IO_STATUS_BLOCK io;
/* The entries potentially contain a name of MAX_PATH wide characters. */ /* The entries potentially contain a name of MAX_PATH wide characters. */
const DWORD fvi_size = 2 * CYG_MAX_PATH const DWORD fvi_size = (NAME_MAX + 1) * sizeof (WCHAR)
+ sizeof (FILE_FS_VOLUME_INFORMATION); + sizeof (FILE_FS_VOLUME_INFORMATION);
const DWORD fai_size = 2 * CYG_MAX_PATH + sizeof (FILE_ALL_INFORMATION); const DWORD fai_size = (NAME_MAX + 1) * sizeof (WCHAR)
+ sizeof (FILE_ALL_INFORMATION);
PFILE_FS_VOLUME_INFORMATION pfvi = (PFILE_FS_VOLUME_INFORMATION) PFILE_FS_VOLUME_INFORMATION pfvi = (PFILE_FS_VOLUME_INFORMATION)
alloca (fvi_size); alloca (fvi_size);
@ -228,7 +269,7 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
{ {
debug_printf ("%u = NtQueryVolumeInformationFile)", debug_printf ("%u = NtQueryVolumeInformationFile)",
RtlNtStatusToDosError (status)); RtlNtStatusToDosError (status));
pfvi->VolumeSerialNumber = 0; /* Set to pc.volser () in helper. */ pfvi->VolumeSerialNumber = pc.volser ();
} }
status = NtQueryInformationFile (get_handle (), &io, pfai, fai_size, status = NtQueryInformationFile (get_handle (), &io, pfai, fai_size,
FileAllInformation); FileAllInformation);
@ -241,9 +282,9 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
pfai->BasicInformation.FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY; pfai->BasicInformation.FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
pc.file_attributes (pfai->BasicInformation.FileAttributes); pc.file_attributes (pfai->BasicInformation.FileAttributes);
return fstat_helper (buf, return fstat_helper (buf,
pfai->BasicInformation.ChangeTime.QuadPart ? pfai->BasicInformation.ChangeTime.QuadPart
*(FILETIME *) &pfai->BasicInformation.ChangeTime : ? *(FILETIME *) &pfai->BasicInformation.ChangeTime
*(FILETIME *) &pfai->BasicInformation.LastWriteTime, : *(FILETIME *) &pfai->BasicInformation.LastWriteTime,
*(FILETIME *) &pfai->BasicInformation.LastAccessTime, *(FILETIME *) &pfai->BasicInformation.LastAccessTime,
*(FILETIME *) &pfai->BasicInformation.LastWriteTime, *(FILETIME *) &pfai->BasicInformation.LastWriteTime,
*(FILETIME *) &pfai->BasicInformation.CreationTime, *(FILETIME *) &pfai->BasicInformation.CreationTime,
@ -254,66 +295,119 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
pfai->StandardInformation.NumberOfLinks, pfai->StandardInformation.NumberOfLinks,
pfai->BasicInformation.FileAttributes); pfai->BasicInformation.FileAttributes);
} }
debug_printf ("%u = NtQueryInformationFile)", debug_printf ("%u = NtQueryInformationFile)",
RtlNtStatusToDosError (status)); RtlNtStatusToDosError (status));
return -1;
/* Last resort */
FILETIME ft = { 0, 0 };
DWORD lowfs, highfs;
lowfs = GetFileSize (get_handle (), &highfs);
if (lowfs == 0xffffffff && GetLastError ())
lowfs = highfs = 0;
return fstat_helper (buf, ft, ft, ft, ft, 0, (ULONGLONG) highfs << 32 | lowfs,
-1LL, 0ULL, 1, DWORD (pc));
} }
int __stdcall int __stdcall
fhandler_base::fstat_by_name (struct __stat64 *buf) fhandler_base::fstat_by_name (struct __stat64 *buf)
{ {
int res = -1;
NTSTATUS status; NTSTATUS status;
OBJECT_ATTRIBUTES attr; OBJECT_ATTRIBUTES attr;
FILE_NETWORK_OPEN_INFORMATION fnoi; IO_STATUS_BLOCK io;
UNICODE_STRING dirname;
UNICODE_STRING basename;
HANDLE dir;
const DWORD fdi_size = (NAME_MAX + 1) * sizeof (WCHAR)
+ sizeof (FILE_ID_BOTH_DIR_INFORMATION);
const DWORD fvi_size = (NAME_MAX + 1) * sizeof (WCHAR)
+ sizeof (FILE_FS_VOLUME_INFORMATION);
PFILE_ID_BOTH_DIR_INFORMATION pfdi = (PFILE_ID_BOTH_DIR_INFORMATION)
alloca (fdi_size);
PFILE_FS_VOLUME_INFORMATION pfvi = (PFILE_FS_VOLUME_INFORMATION)
alloca (fvi_size);
LARGE_INTEGER FileId;
if (!pc.exists ()) if (!pc.exists ())
{ {
debug_printf ("already determined that pc does not exist"); debug_printf ("already determined that pc does not exist");
set_errno (ENOENT); set_errno (ENOENT);
return -1;
} }
else if (NT_SUCCESS (status = NtQueryFullAttributesFile ( /* Split path in dirname and basename */
pc.get_object_attr (attr, sec_none_nih), &fnoi))) dirname = *pc.get_nt_native_path ();
USHORT len = dirname.Length / sizeof (WCHAR);
while (len > 0 && dirname.Buffer[--len] != L'\\')
;
++len;
RtlInitCountedUnicodeString (&basename,
dirname.Length - len * sizeof (WCHAR),
&dirname.Buffer[len]);
dirname.Length = len * sizeof (WCHAR);
InitializeObjectAttributes (&attr, &dirname, OBJ_CASE_INSENSITIVE,
NULL, NULL);
if (!NT_SUCCESS (status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
&attr, &io, FILE_SHARE_VALID_FLAGS,
FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_FOR_BACKUP_INTENT
| FILE_DIRECTORY_FILE)))
{ {
if (pc.is_rep_symlink ()) debug_printf ("%u = NtOpenFile)", RtlNtStatusToDosError (status));
fnoi.FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY; goto too_bad;
pc.file_attributes (fnoi.FileAttributes); }
res = fstat_helper (buf, if (wincap.has_fileid_dirinfo ()
*(FILETIME *) (fnoi.ChangeTime.QuadPart && NT_SUCCESS (status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io,
? &fnoi.ChangeTime pfdi, fdi_size,
: &fnoi.LastWriteTime), FileIdBothDirectoryInformation,
*(FILETIME *) &fnoi.LastAccessTime, TRUE, &basename, TRUE)))
*(FILETIME *) &fnoi.LastWriteTime, FileId = pfdi->FileId;
*(FILETIME *) &fnoi.CreationTime, else if (NT_SUCCESS (status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io,
pfdi, fdi_size,
FileBothDirectoryInformation,
TRUE, &basename, TRUE)))
FileId.QuadPart = 0; /* get_namehash is called in fstat_helper. */
if (!NT_SUCCESS (status))
{
debug_printf ("%u = NtQueryDirectoryFile)",
RtlNtStatusToDosError (status));
NtClose (dir);
goto too_bad;
}
status = NtQueryVolumeInformationFile (dir, &io, pfvi, fvi_size,
FileFsVolumeInformation);
if (!NT_SUCCESS (status))
{
debug_printf ("%u = NtQueryVolumeInformationFile)",
RtlNtStatusToDosError (status));
pfvi->VolumeSerialNumber = pc.volser ();
}
NtClose (dir);
/* If the change time is 0, it's a file system which doesn't
support a change timestamp. In that case use the LastWriteTime
entry, as in other calls to fstat_helper. */
if (pc.is_rep_symlink ())
pfdi->FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
pc.file_attributes (pfdi->FileAttributes);
return fstat_helper (buf,
pfdi->ChangeTime.QuadPart ?
*(FILETIME *) &pfdi->ChangeTime :
*(FILETIME *) &pfdi->LastWriteTime,
*(FILETIME *) &pfdi->LastAccessTime,
*(FILETIME *) &pfdi->LastWriteTime,
*(FILETIME *) &pfdi->CreationTime,
pfvi->VolumeSerialNumber,
pfdi->EndOfFile.QuadPart,
pfdi->AllocationSize.QuadPart,
pfdi->FileId.QuadPart,
1,
pfdi->FileAttributes);
too_bad:
LARGE_INTEGER ft;
/* Arbitrary value: 2006-12-01 */
RtlSecondsSince1970ToTime (1164931200L, &ft);
return fstat_helper (buf,
*(FILETIME *) &ft,
*(FILETIME *) &ft,
*(FILETIME *) &ft,
*(FILETIME *) &ft,
pc.volser (), pc.volser (),
fnoi.EndOfFile.QuadPart, 0ULL,
fnoi.AllocationSize.QuadPart, -1LL,
0ULL, 0ULL,
1, 1,
fnoi.FileAttributes); pc.file_attributes ());
}
else if (pc.isdir ())
{
FILETIME ft = {};
res = fstat_helper (buf, ft, ft, ft, ft, pc.volser (), 0ULL, -1LL, 0ULL,
1, FILE_ATTRIBUTE_DIRECTORY);
}
else
{
__seterrno_from_nt_status (status);
res = -1;
}
return res;
} }
int __stdcall int __stdcall
@ -325,10 +419,11 @@ fhandler_base::fstat_fs (struct __stat64 *buf)
if (get_io_handle ()) if (get_io_handle ())
{ {
if (nohandle () || is_fs_special ()) if (!nohandle () && !is_fs_special ())
return fstat_by_name (buf); res = fstat_by_handle (buf);
else if (res)
return fstat_by_handle (buf); res = fstat_by_name (buf);
return res;
} }
query_open (query_stat_control); query_open (query_stat_control);
if (!(oret = open_fs (open_flags, 0)) && get_errno () == EACCES) if (!(oret = open_fs (open_flags, 0)) && get_errno () == EACCES)
@ -353,7 +448,7 @@ fhandler_base::fstat_fs (struct __stat64 *buf)
nohandle (no_handle); nohandle (no_handle);
set_io_handle (NULL); set_io_handle (NULL);
} }
else if (res)
res = fstat_by_name (buf); res = fstat_by_name (buf);
return res; return res;
@ -389,7 +484,7 @@ fhandler_base::fstat_helper (struct __stat64 *buf,
to_timestruc_t (&ftLastWriteTime, &buf->st_mtim); to_timestruc_t (&ftLastWriteTime, &buf->st_mtim);
to_timestruc_t (&ftChangeTime, &buf->st_ctim); to_timestruc_t (&ftChangeTime, &buf->st_ctim);
to_timestruc_t (&ftCreationTime, &buf->st_birthtim); to_timestruc_t (&ftCreationTime, &buf->st_birthtim);
buf->st_dev = dwVolumeSerialNumber ?: pc.volser (); buf->st_dev = dwVolumeSerialNumber;
buf->st_size = (_off64_t) nFileSize; buf->st_size = (_off64_t) nFileSize;
/* The number of links to a directory includes the /* The number of links to a directory includes the
number of subdirectories in the directory, since all number of subdirectories in the directory, since all
@ -753,10 +848,10 @@ fhandler_disk_file::facl (int cmd, int nentries, __aclent32_t *aclbufp)
if (!get_io_handle ()) if (!get_io_handle ())
{ {
query_open (query_read_attributes); query_open (query_read_attributes);
if (!(oret = open (O_BINARY, 0))) oret = open (O_BINARY, 0);
return -1;
} }
if (!fstat_by_handle (&st)) if ((!oret && !fstat_by_handle (&st))
|| !fstat_by_name (&st))
{ {
aclbufp[0].a_type = USER_OBJ; aclbufp[0].a_type = USER_OBJ;
aclbufp[0].a_id = st.st_uid; aclbufp[0].a_id = st.st_uid;
@ -1482,22 +1577,20 @@ fhandler_disk_file::rmdir ()
/* This is the minimal number of entries which fit into the readdir cache. /* This is the minimal number of entries which fit into the readdir cache.
The number of bytes allocated by the cache is determined by this number, The number of bytes allocated by the cache is determined by this number,
To tune caching, just tweak this number. To get a feeling for the size, To tune caching, just tweak this number. To get a feeling for the size,
the size of the readdir cache is DIR_NUM_ENTRIES * 632 + 264 bytes. */ the size of the readdir cache is DIR_NUM_ENTRIES * 624 + 4 bytes. */
#define DIR_NUM_ENTRIES 100 /* Cache size 63464 bytes */ #define DIR_NUM_ENTRIES 100 /* Cache size 62404 bytes */
#define DIR_BUF_SIZE (DIR_NUM_ENTRIES \ #define DIR_BUF_SIZE (DIR_NUM_ENTRIES \
* (sizeof (FILE_ID_BOTH_DIR_INFORMATION) \ * (sizeof (FILE_ID_BOTH_DIR_INFORMATION) \
+ 2 * CYG_MAX_PATH)) + 2 * (NAME_MAX + 1)))
struct __DIR_cache struct __DIR_cache
{ {
char __name[CYG_MAX_PATH];
ULONG __pos; ULONG __pos;
char __cache[DIR_BUF_SIZE]; char __cache[DIR_BUF_SIZE];
}; };
#define d_dirname(d) (((__DIR_cache *) (d)->__d_dirname)->__name)
#define d_cachepos(d) (((__DIR_cache *) (d)->__d_dirname)->__pos) #define d_cachepos(d) (((__DIR_cache *) (d)->__d_dirname)->__pos)
#define d_cache(d) (((__DIR_cache *) (d)->__d_dirname)->__cache) #define d_cache(d) (((__DIR_cache *) (d)->__d_dirname)->__cache)
@ -1508,12 +1601,9 @@ fhandler_disk_file::opendir (int fd)
{ {
DIR *dir; DIR *dir;
DIR *res = NULL; DIR *res = NULL;
size_t len;
if (!pc.isdir ()) if (!pc.isdir ())
set_errno (ENOTDIR); set_errno (ENOTDIR);
else if ((len = strlen (pc)) > CYG_MAX_PATH - 3)
set_errno (ENAMETOOLONG);
else if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL) else if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL)
set_errno (ENOMEM); set_errno (ENOMEM);
else if ((dir->__d_dirname = (char *) malloc ( sizeof (struct __DIR_cache))) else if ((dir->__d_dirname = (char *) malloc ( sizeof (struct __DIR_cache)))
@ -1530,30 +1620,17 @@ fhandler_disk_file::opendir (int fd)
} }
else else
{ {
strcpy (d_dirname (dir), get_win32_name ());
dir->__d_dirent->__d_version = __DIRENT_VERSION;
cygheap_fdnew cfd; cygheap_fdnew cfd;
if (cfd < 0 && fd < 0) if (cfd < 0 && fd < 0)
goto free_dirent; goto free_dirent;
/* FindFirstFile doesn't seem to like duplicate /'s. dir->__d_dirent->__d_version = __DIRENT_VERSION;
The dirname is generated with trailing backslash here which
simplifies later usage of dirname for checking symlinks.
Appending a "*" is moved right before calling FindFirstFile.
Since FindFirstFile is only called once, this should even be a
teeny little bit faster. */
len = strlen (d_dirname (dir));
if (len && !isdirsep (d_dirname (dir)[len - 1]))
strcpy (d_dirname (dir) + len, "\\");
dir->__d_cookie = __DIRENT_COOKIE; dir->__d_cookie = __DIRENT_COOKIE;
dir->__handle = INVALID_HANDLE_VALUE; dir->__handle = INVALID_HANDLE_VALUE;
dir->__d_position = 0; dir->__d_position = 0;
dir->__flags = (get_name ()[0] == '/' && get_name ()[1] == '\0')
dir->__flags = (pc.normalized_path[0] == '/'
&& pc.normalized_path[1] == '\0')
? dirent_isroot : 0; ? dirent_isroot : 0;
dir->__d_internal = (unsigned) new __DIR_mounts (pc.normalized_path); dir->__d_internal = (unsigned) new __DIR_mounts (get_name ());
d_cachepos (dir) = 0; d_cachepos (dir) = 0;
if (!pc.iscygdrive ()) if (!pc.iscygdrive ())
@ -1628,50 +1705,6 @@ free_dir:
return res; return res;
} }
int
fhandler_disk_file::readdir_helper (DIR *dir, dirent *de, DWORD w32_err,
DWORD attr, char *fname)
{
if (w32_err)
{
bool added = false;
if ((de->d_ino = d_mounts (dir)->check_missing_mount (fname)))
added = true;
if (!added)
return geterrno_from_win_error (w32_err);
attr = 0;
dir->__flags &= ~dirent_set_d_ino;
}
/* Check for Windows shortcut. If it's a Cygwin or U/WIN
symlink, drop the .lnk suffix. */
if (attr & FILE_ATTRIBUTE_READONLY)
{
char *c = fname;
char *e = strchr (fname, '\0') - 4;
if (e > c && strcasematch (e, ".lnk"))
{
char fbuf[CYG_MAX_PATH];
strcpy (fbuf, d_dirname (dir));
strcat (fbuf, c);
path_conv fpath (fbuf, PC_SYM_NOFOLLOW);
if (fpath.issymlink () || fpath.is_fs_special ())
*e = '\0';
}
}
if (pc.isencoded ())
fnunmunge (de->d_name, fname);
else
strcpy (de->d_name, fname);
if (dir->__d_position == 0 && !strcmp (fname, "."))
dir->__flags |= dirent_saw_dot;
else if (dir->__d_position == 1 && !strcmp (fname, ".."))
dir->__flags |= dirent_saw_dot_dot;
return 0;
}
static inline __ino64_t static inline __ino64_t
readdir_get_ino_by_handle (HANDLE hdl) readdir_get_ino_by_handle (HANDLE hdl)
{ {
@ -1685,45 +1718,150 @@ readdir_get_ino_by_handle (HANDLE hdl)
} }
__ino64_t __stdcall __ino64_t __stdcall
readdir_get_ino (DIR *dir, const char *path, bool dot_dot) readdir_get_ino (const char *path, bool dot_dot)
{ {
char fname[CYG_MAX_PATH]; char *fname;
struct __stat64 st; struct __stat64 st;
HANDLE hdl; HANDLE hdl;
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK io;
__ino64_t ino = 0; __ino64_t ino = 0;
strcpy (fname, path);
if (dot_dot) if (dot_dot)
strcat (fname, (*fname && fname[strlen (fname) - 1] == '/') {
? ".." : "/.."); fname = (char *) alloca (strlen (path) + 4);
path_conv pc (fname, PC_SYM_NOFOLLOW); char *c = stpcpy (fname, path);
if (c[-1] != '/')
*c++ = '/';
strcpy (c, "..");
path = fname;
}
path_conv pc (path, PC_SYM_NOFOLLOW | PC_POSIX);
if (pc.isspecial ()) if (pc.isspecial ())
{ {
if (!lstat64 (fname, &st)) if (!stat_worker (pc, &st))
ino = st.st_ino; ino = st.st_ino;
} }
else if (!pc.hasgood_inode ()) else if (!pc.hasgood_inode ())
ino = hash_path_name (0, pc); ino = hash_path_name (0, pc);
else if ((hdl = CreateFile (pc, GENERIC_READ, FILE_SHARE_VALID_FLAGS, else if (NT_SUCCESS (NtOpenFile (&hdl, READ_CONTROL,
NULL, OPEN_EXISTING, pc.get_object_attr (attr, sec_none_nih),
FILE_FLAG_BACKUP_SEMANTICS, NULL)) &io, FILE_SHARE_VALID_FLAGS,
!= INVALID_HANDLE_VALUE) FILE_OPEN_FOR_BACKUP_INTENT)))
{ {
ino = readdir_get_ino_by_handle (hdl); ino = readdir_get_ino_by_handle (hdl);
CloseHandle (hdl); NtClose (hdl);
} }
return ino; return ino;
} }
int
fhandler_disk_file::readdir_helper (DIR *dir, dirent *de, DWORD w32_err,
DWORD attr, PUNICODE_STRING fname)
{
if (w32_err)
{
bool added = false;
if ((de->d_ino = d_mounts (dir)->check_missing_mount (fname)))
added = true;
if (!added)
return geterrno_from_win_error (w32_err);
attr = 0;
dir->__flags &= ~dirent_set_d_ino;
}
/* Check for directory reparse point. These are potential volume mount
points which have another inode than the underlying directory. */
if ((attr & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT))
== (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT))
{
HANDLE reph;
OBJECT_ATTRIBUTES attr;
IO_STATUS_BLOCK io;
InitializeObjectAttributes (&attr, fname, OBJ_CASE_INSENSITIVE,
get_handle (), NULL);
if (NT_SUCCESS (NtOpenFile (&reph, READ_CONTROL, &attr, &io,
FILE_SHARE_VALID_FLAGS,
FILE_OPEN_FOR_BACKUP_INTENT
| FILE_OPEN_REPARSE_POINT)))
{
PREPARSE_DATA_BUFFER rp = (PREPARSE_DATA_BUFFER)
alloca (MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
if (NT_SUCCESS (NtFsControlFile (reph, NULL, NULL, NULL,
&io, FSCTL_GET_REPARSE_POINT, NULL, 0,
(LPVOID) rp, MAXIMUM_REPARSE_DATA_BUFFER_SIZE))
&& rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT
&& rp->SymbolicLinkReparseBuffer.PrintNameLength == 0)
{
NtClose (reph);
if (NT_SUCCESS (NtOpenFile (&reph, READ_CONTROL, &attr, &io,
FILE_SHARE_VALID_FLAGS,
FILE_OPEN_FOR_BACKUP_INTENT)))
{
de->d_ino = readdir_get_ino_by_handle (reph);
NtClose (reph);
}
}
else
NtClose (reph);
}
}
/* Check for Windows shortcut. If it's a Cygwin or U/WIN
symlink, drop the .lnk suffix. */
if ((attr & FILE_ATTRIBUTE_READONLY) && fname->Length > 4 * sizeof (WCHAR))
{
UNICODE_STRING uname;
UNICODE_STRING lname;
RtlInitCountedUnicodeString (&uname, 4 * sizeof (WCHAR),
fname->Buffer +
fname->Length / sizeof (WCHAR) - 4);
RtlInitCountedUnicodeString (&lname, 4 * sizeof (WCHAR),
(PWCHAR) L".lnk");
if (RtlEqualUnicodeString (&uname, &lname, TRUE))
{
UNICODE_STRING dirname = *pc.get_nt_native_path ();
dirname.Buffer += 4; /* Skip leading \??\ */
dirname.Length -= 4 * sizeof (WCHAR);
UNICODE_STRING fbuf;
ULONG len = dirname.Length + fname->Length + 2 * sizeof (WCHAR);
RtlInitEmptyUnicodeString (&fbuf, (PCWSTR) alloca (len), len);
RtlCopyUnicodeString (&fbuf, &dirname);
RtlAppendUnicodeToString (&fbuf, L"\\");
RtlAppendUnicodeStringToString (&fbuf, fname);
path_conv fpath (&fbuf, PC_SYM_NOFOLLOW);
if (fpath.issymlink () || fpath.is_fs_special ())
fname->Length -= 4 * sizeof (WCHAR);
}
}
char tmp[NAME_MAX + 1];
sys_wcstombs (tmp, NAME_MAX, fname->Buffer, fname->Length / sizeof (WCHAR));
if (pc.isencoded ())
fnunmunge (de->d_name, tmp);
else
strcpy (de->d_name, tmp);
if (dir->__d_position == 0 && !strcmp (tmp, "."))
dir->__flags |= dirent_saw_dot;
else if (dir->__d_position == 1 && !strcmp (tmp, ".."))
dir->__flags |= dirent_saw_dot_dot;
return 0;
}
int int
fhandler_disk_file::readdir (DIR *dir, dirent *de) fhandler_disk_file::readdir (DIR *dir, dirent *de)
{ {
int res = 0; int res = 0;
NTSTATUS status = STATUS_SUCCESS; NTSTATUS status = STATUS_SUCCESS;
PFILE_ID_BOTH_DIR_INFORMATION buf = NULL; PFILE_ID_BOTH_DIR_INFORMATION buf = NULL;
wchar_t *FileName; PWCHAR FileName;
char fname[CYG_MAX_PATH];
IO_STATUS_BLOCK io; IO_STATUS_BLOCK io;
UNICODE_STRING fname;
/* d_cachepos always refers to the next cache entry to use. If it's 0 /* d_cachepos always refers to the next cache entry to use. If it's 0
we must reload the cache. */ we must reload the cache. */
@ -1818,9 +1956,8 @@ go_ahead:
} }
else else
FileName = ((PFILE_BOTH_DIR_INFORMATION) buf)->FileName; FileName = ((PFILE_BOTH_DIR_INFORMATION) buf)->FileName;
sys_wcstombs (fname, CYG_MAX_PATH - 1, FileName, buf->FileNameLength / 2); RtlInitCountedUnicodeString (&fname, buf->FileNameLength, FileName);
de->d_ino = d_mounts (dir)->check_mount (&fname, de->d_ino);
de->d_ino = d_mounts (dir)->check_mount (fname, de->d_ino);
if (de->d_ino == 0 && (dir->__flags & dirent_set_d_ino)) if (de->d_ino == 0 && (dir->__flags & dirent_set_d_ino))
{ {
OBJECT_ATTRIBUTES attr; OBJECT_ATTRIBUTES attr;
@ -1829,24 +1966,23 @@ go_ahead:
&& FileName[0] == '.') && FileName[0] == '.')
de->d_ino = readdir_get_ino_by_handle (get_handle ()); de->d_ino = readdir_get_ino_by_handle (get_handle ());
else if (dir->__d_position == 1 && buf->FileNameLength == 4 else if (dir->__d_position == 1 && buf->FileNameLength == 4
&& FileName[0] == '.' && FileName[1] == '.') && FileName[0] == L'.' && FileName[1] == L'.')
if (!(dir->__flags & dirent_isroot)) if (!(dir->__flags & dirent_isroot))
de->d_ino = readdir_get_ino (dir, pc.normalized_path, true); de->d_ino = readdir_get_ino (get_name (), true);
else else
de->d_ino = readdir_get_ino_by_handle (get_handle ()); de->d_ino = readdir_get_ino_by_handle (get_handle ());
else else
{ {
HANDLE hdl; HANDLE hdl;
UNICODE_STRING upath = {buf->FileNameLength, CYG_MAX_PATH * 2,
FileName}; InitializeObjectAttributes (&attr, &fname, OBJ_CASE_INSENSITIVE,
InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, get_handle (), NULL);
get_handle () , NULL); if (NT_SUCCESS (NtOpenFile (&hdl, READ_CONTROL, &attr, &io,
if (!NtOpenFile (&hdl, READ_CONTROL, &attr, &io, FILE_SHARE_VALID_FLAGS,
FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT)))
FILE_OPEN_FOR_BACKUP_INTENT))
{ {
de->d_ino = readdir_get_ino_by_handle (hdl); de->d_ino = readdir_get_ino_by_handle (hdl);
CloseHandle (hdl); NtClose (hdl);
} }
} }
/* Enforce namehash as inode number on untrusted file systems. */ /* Enforce namehash as inode number on untrusted file systems. */
@ -1859,7 +1995,7 @@ go_ahead:
} }
if (!(res = readdir_helper (dir, de, RtlNtStatusToDosError (status), if (!(res = readdir_helper (dir, de, RtlNtStatusToDosError (status),
buf ? buf->FileAttributes : 0, fname))) buf ? buf->FileAttributes : 0, &fname)))
dir->__d_position++; dir->__d_position++;
else if (!(dir->__flags & dirent_saw_dot)) else if (!(dir->__flags & dirent_saw_dot))
{ {
@ -1873,7 +2009,7 @@ go_ahead:
{ {
strcpy (de->d_name , ".."); strcpy (de->d_name , "..");
if (!(dir->__flags & dirent_isroot)) if (!(dir->__flags & dirent_isroot))
de->d_ino = readdir_get_ino (dir, pc.normalized_path, true); de->d_ino = readdir_get_ino (get_name (), true);
else else
de->d_ino = readdir_get_ino_by_handle (get_handle ()); de->d_ino = readdir_get_ino_by_handle (get_handle ());
dir->__d_position++; dir->__d_position++;
@ -1910,12 +2046,13 @@ fhandler_disk_file::rewinddir (DIR *dir)
to NtQueryDirectoryFile on remote shares is ignored, thus to NtQueryDirectoryFile on remote shares is ignored, thus
resulting in not being able to rewind on remote shares. By resulting in not being able to rewind on remote shares. By
reopening the directory, we get a fresh new directory pointer. */ reopening the directory, we get a fresh new directory pointer. */
UNICODE_STRING fname = {0, CYG_MAX_PATH * 2, (WCHAR *) L""}; UNICODE_STRING fname;
OBJECT_ATTRIBUTES attr; OBJECT_ATTRIBUTES attr;
NTSTATUS status; NTSTATUS status;
IO_STATUS_BLOCK io; IO_STATUS_BLOCK io;
HANDLE new_dir; HANDLE new_dir;
RtlInitUnicodeString (&fname, L"");
InitializeObjectAttributes (&attr, &fname, OBJ_CASE_INSENSITIVE, InitializeObjectAttributes (&attr, &fname, OBJ_CASE_INSENSITIVE,
get_handle (), NULL); get_handle (), NULL);
status = NtOpenFile (&new_dir, SYNCHRONIZE | FILE_LIST_DIRECTORY, status = NtOpenFile (&new_dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
@ -2003,9 +2140,18 @@ fhandler_cygdrive::set_drives ()
int int
fhandler_cygdrive::fstat (struct __stat64 *buf) fhandler_cygdrive::fstat (struct __stat64 *buf)
{ {
buf->st_mode = S_IFDIR | 0555; fhandler_base::fstat (buf);
buf->st_ino = 2; buf->st_ino = 2;
buf->st_nlink = 1; buf->st_mode = S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
if (!ndrives)
set_drives ();
char flptst[] = "X:";
int n = ndrives;
for (const char *p = pdrive; p && *p; p = strchr (p, '\0') + 1)
if (is_floppy ((flptst[0] = *p, flptst))
|| GetFileAttributes (p) == INVALID_FILE_ATTRIBUTES)
--n;
buf->st_nlink = n + 2;
return 0; return 0;
} }
@ -2024,6 +2170,8 @@ fhandler_cygdrive::opendir (int fd)
int int
fhandler_cygdrive::readdir (DIR *dir, dirent *de) fhandler_cygdrive::readdir (DIR *dir, dirent *de)
{ {
char flptst[] = "X:";
while (true) while (true)
{ {
if (!pdrive || !*pdrive) if (!pdrive || !*pdrive)
@ -2036,13 +2184,15 @@ fhandler_cygdrive::readdir (DIR *dir, dirent *de)
} }
return ENMFILE; return ENMFILE;
} }
if (GetFileAttributes (pdrive) != INVALID_FILE_ATTRIBUTES) if (!is_floppy ((flptst[0] = *pdrive, flptst))
&& GetFileAttributes (pdrive) != INVALID_FILE_ATTRIBUTES)
break; break;
pdrive = strchr (pdrive, '\0') + 1; pdrive = strchr (pdrive, '\0') + 1;
} }
*de->d_name = cyg_tolower (*pdrive); *de->d_name = cyg_tolower (*pdrive);
de->d_name[1] = '\0'; de->d_name[1] = '\0';
de->d_ino = readdir_get_ino (dir, pdrive, false); user_shared->warned_msdos = true;
de->d_ino = readdir_get_ino (pdrive, false);
dir->__d_position++; dir->__d_position++;
pdrive = strchr (pdrive, '\0') + 1; pdrive = strchr (pdrive, '\0') + 1;
syscall_printf ("%p = readdir (%p) (%s)", &de, dir, de->d_name); syscall_printf ("%p = readdir (%p) (%s)", &de, dir, de->d_name);

View File

@ -210,7 +210,7 @@ fhandler_netdrive::readdir (DIR *dir, dirent *de)
de->d_ino = hash_path_name (get_namehash (), de->d_name); de->d_ino = hash_path_name (get_namehash (), de->d_name);
else else
{ {
de->d_ino = readdir_get_ino (dir, nro->lpRemoteName, false); de->d_ino = readdir_get_ino (nro->lpRemoteName, false);
/* We can't trust remote inode numbers of only 32 bit. That means, /* We can't trust remote inode numbers of only 32 bit. That means,
all remote inode numbers when running under NT4, as well as all remote inode numbers when running under NT4, as well as
remote NT4 NTFS, as well as shares of Samba version < 3.0. */ remote NT4 NTFS, as well as shares of Samba version < 3.0. */

View File

@ -65,6 +65,8 @@ static const char *proc_listing[] = {
NULL NULL
}; };
#define PROC_DIR_COUNT 4
static const int PROC_LINK_COUNT = (sizeof (proc_listing) / sizeof (const char *)) - 1; static const int PROC_LINK_COUNT = (sizeof (proc_listing) / sizeof (const char *)) - 1;
/* FH_PROC in the table below means the file/directory is handles by /* FH_PROC in the table below means the file/directory is handles by
@ -178,8 +180,10 @@ fhandler_proc::fstat (struct __stat64 *buf)
if (!*path) if (!*path)
{ {
buf->st_nlink = 1; winpids pids ((DWORD) 0);
buf->st_ino = 2;
buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
buf->st_nlink = PROC_DIR_COUNT + 2 + pids.npids;
return 0; return 0;
} }
else else

View File

@ -88,6 +88,20 @@ typedef struct _FILE_NAMES_INFORMATION
WCHAR FileName[1]; WCHAR FileName[1];
} FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION; } FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION;
typedef struct _FILE_DIRECTORY_INFORMATION {
ULONG NextEntryOffset;
ULONG FileIndex;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
typedef struct _FILE_BOTH_DIR_INFORMATION typedef struct _FILE_BOTH_DIR_INFORMATION
{ {
ULONG NextEntryOffset; ULONG NextEntryOffset;
@ -709,6 +723,9 @@ extern "C"
PTOKEN_GROUPS, PTOKEN_PRIVILEGES, PTOKEN_OWNER, PTOKEN_GROUPS, PTOKEN_PRIVILEGES, PTOKEN_OWNER,
PTOKEN_PRIMARY_GROUP, PTOKEN_DEFAULT_DACL, PTOKEN_PRIMARY_GROUP, PTOKEN_DEFAULT_DACL,
PTOKEN_SOURCE); PTOKEN_SOURCE);
NTSTATUS NTAPI NtFsControlFile (HANDLE, HANDLE, PVOID, PVOID,
PIO_STATUS_BLOCK, ULONG, PVOID, ULONG,
PVOID, ULONG);
NTSTATUS NTAPI NtLockVirtualMemory (HANDLE, PVOID *, ULONG *, ULONG); NTSTATUS NTAPI NtLockVirtualMemory (HANDLE, PVOID *, ULONG *, ULONG);
NTSTATUS NTAPI NtMapViewOfSection (HANDLE, HANDLE, PVOID *, ULONG, ULONG, NTSTATUS NTAPI NtMapViewOfSection (HANDLE, HANDLE, PVOID *, ULONG, ULONG,
PLARGE_INTEGER, PULONG, SECTION_INHERIT, PLARGE_INTEGER, PULONG, SECTION_INHERIT,
@ -750,11 +767,42 @@ extern "C"
PSECURITY_DESCRIPTOR); PSECURITY_DESCRIPTOR);
NTSTATUS NTAPI NtUnlockVirtualMemory (HANDLE, PVOID *, ULONG *, ULONG); NTSTATUS NTAPI NtUnlockVirtualMemory (HANDLE, PVOID *, ULONG *, ULONG);
NTSTATUS NTAPI NtUnmapViewOfSection (HANDLE, PVOID); NTSTATUS NTAPI NtUnmapViewOfSection (HANDLE, PVOID);
NTSTATUS NTAPI RtlAppendUnicodeToString (PUNICODE_STRING, PCWSTR);
NTSTATUS NTAPI RtlAppendUnicodeStringToString (PUNICODE_STRING,
PUNICODE_STRING);
NTSTATUS NTAPI RtlAnsiStringToUnicodeString (PUNICODE_STRING, PANSI_STRING, NTSTATUS NTAPI RtlAnsiStringToUnicodeString (PUNICODE_STRING, PANSI_STRING,
BOOLEAN); BOOLEAN);
LONG NTAPI RtlCompareUnicodeString (PUNICODE_STRING, PUNICODE_STRING,
BOOLEAN);
VOID NTAPI RtlCopyUnicodeString (PUNICODE_STRING, PUNICODE_STRING);
ULONG WINAPI RtlCreateUnicodeStringFromAsciiz (PUNICODE_STRING, PCSTR);
BOOLEAN NTAPI RtlEqualUnicodeString (PUNICODE_STRING, PUNICODE_STRING,
BOOLEAN);
VOID NTAPI RtlFreeUnicodeString (PUNICODE_STRING);
VOID NTAPI RtlInitEmptyUnicodeString (PUNICODE_STRING, PCWSTR, USHORT);
VOID NTAPI RtlInitUnicodeString (PUNICODE_STRING, PCWSTR); VOID NTAPI RtlInitUnicodeString (PUNICODE_STRING, PCWSTR);
ULONG NTAPI RtlIsDosDeviceName_U (PCWSTR); ULONG NTAPI RtlIsDosDeviceName_U (PCWSTR);
ULONG NTAPI RtlNtStatusToDosError (NTSTATUS); ULONG NTAPI RtlNtStatusToDosError (NTSTATUS);
NTSTATUS NTAPI RtlOemStringToUnicodeString (PUNICODE_STRING, POEM_STRING, NTSTATUS NTAPI RtlOemStringToUnicodeString (PUNICODE_STRING, POEM_STRING,
BOOLEAN); BOOLEAN);
VOID NTAPI RtlSecondsSince1970ToTime (ULONG, PLARGE_INTEGER);
/* A few Rtl functions are either actually macros, or they just don't
exist even though they would be a big help. We implement them here
as inline functions. */
inline
VOID NTAPI RtlInitEmptyUnicodeString(PUNICODE_STRING dest, PCWSTR buf,
USHORT len)
{
dest->Length = 0;
dest->MaximumLength = len;
dest->Buffer = (PWSTR) buf;
}
inline
VOID NTAPI RtlInitCountedUnicodeString (PUNICODE_STRING dest, USHORT len,
PCWSTR buf)
{
dest->Length = dest->MaximumLength = len;
dest->Buffer = (PWSTR) buf;
}
} }

View File

@ -637,6 +637,23 @@ warn_msdos (const char *src)
SYMLINK_CONTENTS - just return symlink contents SYMLINK_CONTENTS - just return symlink contents
*/ */
/* TODO: This implementation is only preliminary. For internal
purposes it's necessary to have a path_conv::check function which
takes a UNICODE_STRING src path, otherwise we waste a lot of time
for converting back and forth. The below implementation does
realy nothing but converting to char *, until path_conv handles
wide-char paths directly. */
void
path_conv::check (PUNICODE_STRING src, unsigned opt,
const suffix_info *suffixes)
{
char path[CYG_MAX_PATH];
user_shared->warned_msdos = true;
sys_wcstombs (path, CYG_MAX_PATH, src->Buffer, src->Length / 2);
path_conv::check (path, opt, suffixes);
}
void void
path_conv::check (const char *src, unsigned opt, path_conv::check (const char *src, unsigned opt,
const suffix_info *suffixes) const suffix_info *suffixes)
@ -1840,7 +1857,8 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev,
int int
mount_info::get_mounts_here (const char *parent_dir, int parent_dir_len, mount_info::get_mounts_here (const char *parent_dir, int parent_dir_len,
char **mount_points) PUNICODE_STRING mount_points,
PUNICODE_STRING cygd)
{ {
int n_mounts = 0; int n_mounts = 0;
@ -1853,12 +1871,16 @@ mount_info::get_mounts_here (const char *parent_dir, int parent_dir_len,
if (last_slash == mi->posix_path) if (last_slash == mi->posix_path)
{ {
if (parent_dir_len == 1 && mi->posix_pathlen > 1) if (parent_dir_len == 1 && mi->posix_pathlen > 1)
mount_points[n_mounts++] = last_slash + 1; RtlCreateUnicodeStringFromAsciiz (&mount_points[n_mounts++],
last_slash + 1);
} }
else if (parent_dir_len == last_slash - mi->posix_path else if (parent_dir_len == last_slash - mi->posix_path
&& strncasematch (parent_dir, mi->posix_path, parent_dir_len)) && strncasematch (parent_dir, mi->posix_path, parent_dir_len))
mount_points[n_mounts++] = last_slash + 1; RtlCreateUnicodeStringFromAsciiz (&mount_points[n_mounts++],
last_slash + 1);
} }
RtlCreateUnicodeStringFromAsciiz (cygd, cygdrive + 1);
cygd->Length -= 2; // Strip trailing slash
return n_mounts; return n_mounts;
} }
@ -2794,8 +2816,7 @@ is_floppy (const char *dos)
char dev[256]; char dev[256];
if (!QueryDosDevice (dos, dev, 256)) if (!QueryDosDevice (dos, dev, 256))
return false; return false;
return strncasematch (dev, "\\Device\\Floppy", 14) return strncasematch (dev, "\\Device\\Floppy", 14);
|| strcasematch (dev, "A:");
} }
extern "C" FILE * extern "C" FILE *

View File

@ -13,7 +13,6 @@ details. */
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <fcntl.h> #include <fcntl.h>
#include <ntdef.h>
#define isproc_dev(devn) \ #define isproc_dev(devn) \
(devn == FH_PROC || devn == FH_REGISTRY || devn == FH_PROCESS || \ (devn == FH_PROC || devn == FH_REGISTRY || devn == FH_PROCESS || \
@ -234,8 +233,10 @@ class path_conv
void set_has_symlinks () {path_flags |= PATH_HAS_SYMLINKS;} void set_has_symlinks () {path_flags |= PATH_HAS_SYMLINKS;}
void set_exec (int x = 1) {path_flags |= x ? PATH_EXEC : PATH_NOTEXEC;} void set_exec (int x = 1) {path_flags |= x ? PATH_EXEC : PATH_NOTEXEC;}
void check (PUNICODE_STRING upath, unsigned opt = PC_SYM_FOLLOW,
const suffix_info *suffixes = NULL) __attribute__ ((regparm(3)));
void check (const char *src, unsigned opt = PC_SYM_FOLLOW, void check (const char *src, unsigned opt = PC_SYM_FOLLOW,
const suffix_info *suffixes = NULL) __attribute__ ((regparm(3))); const suffix_info *suffixes = NULL) __attribute__ ((regparm(3)));
path_conv (const device& in_dev): fileattr (INVALID_FILE_ATTRIBUTES), path_conv (const device& in_dev): fileattr (INVALID_FILE_ATTRIBUTES),
wide_path (NULL), path_flags (0), known_suffix (NULL), error (0), wide_path (NULL), path_flags (0), known_suffix (NULL), error (0),
@ -250,6 +251,12 @@ class path_conv
check (src, opt, suffixes); check (src, opt, suffixes);
} }
path_conv (PUNICODE_STRING src, unsigned opt = PC_SYM_FOLLOW,
const suffix_info *suffixes = NULL)
{
check (src, opt | PC_NULLEMPTY, suffixes);
}
path_conv (const char *src, unsigned opt = PC_SYM_FOLLOW, path_conv (const char *src, unsigned opt = PC_SYM_FOLLOW,
const suffix_info *suffixes = NULL) const suffix_info *suffixes = NULL)
{ {

View File

@ -91,7 +91,9 @@ class mount_info
int get_cygdrive_info (char *user, char *system, char* user_flags, int get_cygdrive_info (char *user, char *system, char* user_flags,
char* system_flags); char* system_flags);
void cygdrive_posix_path (const char *src, char *dst, int trailing_slash_p); void cygdrive_posix_path (const char *src, char *dst, int trailing_slash_p);
int get_mounts_here (const char *parent_dir, int, char **mount_points); int get_mounts_here (const char *parent_dir, int,
PUNICODE_STRING mount_points,
PUNICODE_STRING cygd);
private: private:

View File

@ -96,9 +96,6 @@ SYSTEM_INFO system_info;
static int __stdcall mknod_worker (const char *, mode_t, mode_t, _major_t, static int __stdcall mknod_worker (const char *, mode_t, mode_t, _major_t,
_minor_t); _minor_t);
static int __stdcall stat_worker (const char *name, struct __stat64 *buf,
int nofollow) __attribute__ ((regparm (3)));
/* Close all files and process any queued deletions. /* Close all files and process any queued deletions.
Lots of unix style applications will open a tmp file, unlink it, Lots of unix style applications will open a tmp file, unlink it,
but never call close. This function is called by _exit to but never call close. This function is called by _exit to
@ -1225,8 +1222,8 @@ sync ()
} }
/* Cygwin internal */ /* Cygwin internal */
static int __stdcall int __stdcall
stat_worker (const char *name, struct __stat64 *buf, int nofollow) stat_worker (path_conv &pc, struct __stat64 *buf)
{ {
int res = -1; int res = -1;
fhandler_base *fh = NULL; fhandler_base *fh = NULL;
@ -1235,8 +1232,7 @@ stat_worker (const char *name, struct __stat64 *buf, int nofollow)
if (efault.faulted (EFAULT)) if (efault.faulted (EFAULT))
goto error; goto error;
if (!(fh = build_fh_name (name, NULL, nofollow ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW, if (!(fh = build_fh_pc (pc)))
stat_suffixes)))
goto error; goto error;
if (fh->error ()) if (fh->error ())
@ -1246,8 +1242,8 @@ stat_worker (const char *name, struct __stat64 *buf, int nofollow)
} }
else if (fh->exists ()) else if (fh->exists ())
{ {
debug_printf ("(%s, %p, %d, %p), file_attributes %d", name, buf, nofollow, debug_printf ("(%s, %p, %p), file_attributes %d",
fh, (DWORD) *fh); pc.normalized_path, buf, fh, (DWORD) *fh);
memset (buf, 0, sizeof (*buf)); memset (buf, 0, sizeof (*buf));
res = fh->fstat (buf); res = fh->fstat (buf);
if (!res) if (!res)
@ -1266,7 +1262,7 @@ stat_worker (const char *name, struct __stat64 *buf, int nofollow)
delete fh; delete fh;
error: error:
MALLOC_CHECK; MALLOC_CHECK;
syscall_printf ("%d = (%s, %p)", res, name, buf); syscall_printf ("%d = (%s, %p)", res, pc.normalized_path, buf);
return res; return res;
} }
@ -1274,7 +1270,8 @@ extern "C" int
stat64 (const char *name, struct __stat64 *buf) stat64 (const char *name, struct __stat64 *buf)
{ {
syscall_printf ("entering"); syscall_printf ("entering");
return stat_worker (name, buf, 0); path_conv pc (name, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes);
return stat_worker (pc, buf);
} }
extern "C" int extern "C" int
@ -1312,7 +1309,8 @@ extern "C" int
lstat64 (const char *name, struct __stat64 *buf) lstat64 (const char *name, struct __stat64 *buf)
{ {
syscall_printf ("entering"); syscall_printf ("entering");
return stat_worker (name, buf, 1); path_conv pc (name, PC_SYM_NOFOLLOW | PC_POSIX, stat_suffixes);
return stat_worker (pc, buf);
} }
/* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */ /* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */

View File

@ -97,6 +97,7 @@ extern const char case_folded_upper[];
#include <windows.h> #include <windows.h>
#include <wincrypt.h> #include <wincrypt.h>
#include <lmcons.h> #include <lmcons.h>
#include <ntdef.h>
#undef _WINGDI_H #undef _WINGDI_H
#undef _WINUSER_H #undef _WINUSER_H
#undef _WINNLS_H #undef _WINNLS_H
@ -290,8 +291,9 @@ int symlink_worker (const char *, const char *, bool, bool)
class path_conv; class path_conv;
int fcntl_worker (int fd, int cmd, void *arg); int fcntl_worker (int fd, int cmd, void *arg);
int __stdcall stat_worker (path_conv &pc, struct __stat64 *buf) __attribute__ ((regparm (2)));
__ino64_t __stdcall readdir_get_ino (struct __DIR *dir, const char *path, bool dot_dot) __attribute__ ((regparm (3))); __ino64_t __stdcall readdir_get_ino (const char *path, bool dot_dot) __attribute__ ((regparm (2)));
extern "C" int low_priority_sleep (DWORD) __attribute__ ((regparm (1))); extern "C" int low_priority_sleep (DWORD) __attribute__ ((regparm (1)));
#define SLEEP_0_STAY_LOW INFINITE #define SLEEP_0_STAY_LOW INFINITE