* autoload.cc (NtQueryDirectoryFile): Define.

* dir.cc (__opendir_with_d_ino): Just call opendir.
	(opendir): Remove CYGWIN_VERSION_CHECK_FOR_NEEDS_D_INO handling.
	(readdir_worker): Only try generating d_ino if it's 0.
	Utilize namehash of directories fhandler.  Call readdir_get_ino to
	generate d_ino for "..".
	(seekdir64): Keep dirent_set_d_ino flag.
	* fhandler.h (enum dirent_states): Add dirent_get_d_ino.
	(class fhandler_disk_file): Declare new private methods readdir_helper
	and readdir_9x.
	* fhandler_disk_file.cc (path_conv::hasgood_inode): New method to
	evaluate if a filesystem has reliable inode numbers.
	(fhandler_base::fstat_by_handle): Accomodate structure member name
	change from IndexNumber to FileId.
	(fhandler_base::fstat_helper): Call hasgood_inode here.
	(fhandler_disk_file::opendir): Call fhaccess only for real files.
	Don't append '*' to __d_dirname here, move to readdir_9x.  On NT,
	open directory handle here.  Set dirent_get_d_ino and dirent_set_d_ino
	flags according to wincap and filesystem.
	(fhandler_disk_file::readdir_helper): New method to implement readdir
	postprocessing only once.
	(readdir_get_ino_by_handle): New static function.
	(readdir_get_ino): New function to centralize inode number evaluation
	in case inode number hasn't been returned by NtQueryDirectoryFile.
	(fhandler_disk_file::readdir): Move old functionality to readdir_9x.
	Call readdir_9x when on 9x/Me.  Implement NT specific readdir here.
	(fhandler_disk_file::readdir_9x): Move 9x specific readdir here.
	(fhandler_disk_file::seekdir): Accomodate new NT readdir method.
	(fhandler_disk_file::closedir): Ditto.
	(fhandler_cygdrive::fstat): Set d_ino to namehash. Add comment.
	(fhandler_cygdrive::opendir): Call get_namehash to prepare later
	correct evaluation of d_ino.
	(fhandler_cygdrive::readdir): Replace recursion with loop. Evaluate
	drive's d_ino by calling readdir_get_ino.
	* fhandler_proc.cc (fhandler_proc::readdir): Set dirent_saw_dot and
	dirent_saw_dot_dot to avoid seeing . and .. entries twice.
	* fhandler_process.cc (fhandler_process::readdir): Ditto.
	* fhandler_registry.cc (fhandler_registry::readdir): Ditto.
	* ntdll.h (STATUS_INVALID_PARAMETER): New define.
	(STATUS_INVALID_LEVEL): New define.
	(struct _FILE_INTERNAL_INFORMATION): Rename member IndexNumber to
	FileId (as in Nebbitt).
	* path.h (path_conv::hasgood_inode): Now implemented in
	fhandler_disk_file.cc.
	* wincap.h (wincaps::has_fileid_dirinfo): New element.
	* wincap.cc: Implement above element throughout.
	* winsup.h (readdir_get_ino): Add declaration.
	* include/sys/dirent.h (struct dirent): Slightly rename structure
	members to accomodate changes.
	Remove __USE_EXPENSIVE_CYGWIN_D_INO handling and declaration of
	__opendir_with_d_ino.
This commit is contained in:
Corinna Vinschen 2006-01-27 21:50:42 +00:00
parent e7a9c71d62
commit 9e5f45ed6f
14 changed files with 474 additions and 204 deletions

View File

@ -1,3 +1,57 @@
2006-01-26 Corinna Vinschen <corinna@vinschen.de>
* autoload.cc (NtQueryDirectoryFile): Define.
* dir.cc (__opendir_with_d_ino): Just call opendir.
(opendir): Remove CYGWIN_VERSION_CHECK_FOR_NEEDS_D_INO handling.
(readdir_worker): Only try generating d_ino if it's 0.
Utilize namehash of directories fhandler. Call readdir_get_ino to
generate d_ino for "..".
(seekdir64): Keep dirent_set_d_ino flag.
* fhandler.h (enum dirent_states): Add dirent_get_d_ino.
(class fhandler_disk_file): Declare new private methods readdir_helper
and readdir_9x.
* fhandler_disk_file.cc (path_conv::hasgood_inode): New method to
evaluate if a filesystem has reliable inode numbers.
(fhandler_base::fstat_by_handle): Accomodate structure member name
change from IndexNumber to FileId.
(fhandler_base::fstat_helper): Call hasgood_inode here.
(fhandler_disk_file::opendir): Call fhaccess only for real files.
Don't append '*' to __d_dirname here, move to readdir_9x. On NT,
open directory handle here. Set dirent_get_d_ino and dirent_set_d_ino
flags according to wincap and filesystem.
(fhandler_disk_file::readdir_helper): New method to implement readdir
postprocessing only once.
(readdir_get_ino_by_handle): New static function.
(readdir_get_ino): New function to centralize inode number evaluation
in case inode number hasn't been returned by NtQueryDirectoryFile.
(fhandler_disk_file::readdir): Move old functionality to readdir_9x.
Call readdir_9x when on 9x/Me. Implement NT specific readdir here.
(fhandler_disk_file::readdir_9x): Move 9x specific readdir here.
(fhandler_disk_file::seekdir): Accomodate new NT readdir method.
(fhandler_disk_file::closedir): Ditto.
(fhandler_cygdrive::fstat): Set d_ino to namehash. Add comment.
(fhandler_cygdrive::opendir): Call get_namehash to prepare later
correct evaluation of d_ino.
(fhandler_cygdrive::readdir): Replace recursion with loop. Evaluate
drive's d_ino by calling readdir_get_ino.
* fhandler_proc.cc (fhandler_proc::readdir): Set dirent_saw_dot and
dirent_saw_dot_dot to avoid seeing . and .. entries twice.
* fhandler_process.cc (fhandler_process::readdir): Ditto.
* fhandler_registry.cc (fhandler_registry::readdir): Ditto.
* ntdll.h (STATUS_INVALID_PARAMETER): New define.
(STATUS_INVALID_LEVEL): New define.
(struct _FILE_INTERNAL_INFORMATION): Rename member IndexNumber to
FileId (as in Nebbitt).
* path.h (path_conv::hasgood_inode): Now implemented in
fhandler_disk_file.cc.
* wincap.h (wincaps::has_fileid_dirinfo): New element.
* wincap.cc: Implement above element throughout.
* winsup.h (readdir_get_ino): Add declaration.
* include/sys/dirent.h (struct dirent): Slightly rename structure
members to accomodate changes.
Remove __USE_EXPENSIVE_CYGWIN_D_INO handling and declaration of
__opendir_with_d_ino.
2006-01-27 Christopher Faylor <cgf@timesys.com>
* spawn.cc (spawn_guts): Fix potential handle leak when failing exec.

View File

@ -1,6 +1,6 @@
/* autoload.cc: all dynamic load stuff.
Copyright 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.
Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
This file is part of Cygwin.
@ -385,6 +385,7 @@ LoadDLLfuncEx (NtLockVirtualMemory, 16, ntdll, 1)
LoadDLLfuncEx (NtMapViewOfSection, 40, ntdll, 1)
LoadDLLfuncEx (NtOpenFile, 24, ntdll, 1)
LoadDLLfuncEx (NtOpenSection, 12, ntdll, 1)
LoadDLLfuncEx2 (NtQueryDirectoryFile, 44, ntdll, 1, 1)
LoadDLLfuncEx2 (NtQueryInformationFile, 20, ntdll, 1, 1)
LoadDLLfuncEx (NtQueryInformationProcess, 20, ntdll, 1)
LoadDLLfuncEx2 (NtQueryObject, 20, ntdll, 1, 1)

View File

@ -42,13 +42,12 @@ dirfd (DIR *dir)
return dir->__d_fd;
}
/* Symbol kept for backward compatibility. Don't remove. Don't declare
in public header file. */
extern "C" DIR *
__opendir_with_d_ino (const char *name)
{
DIR *res = opendir (name);
if (res)
res->__flags |= dirent_set_d_ino;
return res;
return opendir (name);
}
/* opendir: POSIX 5.1.2.1 */
@ -69,9 +68,7 @@ opendir (const char *name)
res = NULL;
}
if (res)
res->__flags |= CYGWIN_VERSION_CHECK_FOR_NEEDS_D_INO ? dirent_set_d_ino : 0;
else if (fh)
if (!res && fh)
delete fh;
return res;
}
@ -89,6 +86,7 @@ readdir_worker (DIR *dir, dirent *de)
return EBADF;
}
de->d_ino = 0;
int res = ((fhandler_base *) dir->__fh)->readdir (dir, de);
if (res == ENMFILE)
@ -109,39 +107,38 @@ readdir_worker (DIR *dir, dirent *de)
}
}
if (!res)
if (!res && !de->d_ino)
{
/* Compute d_ino by combining filename hash with the directory hash
(which was stored in dir->__d_dirhash when opendir was called). */
if (de->d_name[0] != '.')
/* relax */;
else if (de->d_name[1] == '\0')
dir->__flags |= dirent_saw_dot;
else if (de->d_name[1] == '.' && de->d_name[2] == '\0')
dir->__flags |= dirent_saw_dot_dot;
if (!(dir->__flags & dirent_set_d_ino))
de->__dirent_internal = 0;
else
bool is_dot = false;
bool is_dot_dot = false;
if (de->d_name[0] == '.')
{
#if 0
size_t len = strlen (dir->__d_dirname) + strlen (de->d_name);
char *path = (char *) alloca (len);
char *p = strchr (strcpy (path, dir->__d_dirname), '\0');
strcpy (p - 1, de->d_name);
struct __stat64 st;
if (lstat64 (path, &st) == 0)
de->__dirent_internal = st.st_ino;
else
{
#endif
de->__dirent_internal = hash_path_name (0, dir->__d_dirname);
de->__dirent_internal = hash_path_name (de->__dirent_internal, de->d_name);
#if 0
}
#endif
if (de->d_name[1] == '\0')
is_dot = true;
else if (de->d_name[1] == '.' && de->d_name[2] == '\0')
is_dot_dot = true;
}
if (is_dot_dot && !(dir->__flags & dirent_isroot))
de->d_ino = readdir_get_ino (dir,
((fhandler_base *) dir->__fh)->get_name (),
true);
else
{
/* Compute d_ino by combining filename hash with directory hash. */
de->d_ino = ((fhandler_base *) dir->__fh)->get_namehash ();
if (!is_dot && !is_dot_dot)
{
const char *w32name = ((fhandler_base *) dir->__fh)->get_win32_name ();
/* A drive's root dir has a trailing backslash already. */
if (w32name[1] != ':' || w32name[2] != '\\' || w32name[3])
de->d_ino = hash_path_name (de->d_ino, "\\");
de->d_ino = hash_path_name (de->d_ino, de->d_name);
}
}
de->__dirent_internal1 = de->__dirent_internal;
}
de->__d_internal1 = de->d_ino;
return res;
}
@ -201,7 +198,7 @@ seekdir64 (DIR *dir, _off64_t loc)
if (dir->__d_cookie != __DIRENT_COOKIE)
return;
dir->__flags &= (dirent_isroot | dirent_set_d_ino);
dir->__flags &= (dirent_isroot | dirent_get_d_ino | dirent_set_d_ino);
return ((fhandler_base *) dir->__fh)->seekdir (dir, loc);
}

View File

@ -48,7 +48,8 @@ enum dirent_states
dirent_saw_cygdrive = 0x0010,
dirent_saw_dev = 0x0020,
dirent_saw_proc = 0x0040,
dirent_set_d_ino = 0x0080
dirent_set_d_ino = 0x0080,
dirent_get_d_ino = 0x0100
};
enum conn_state
@ -650,6 +651,8 @@ class fhandler_dev_tape: public fhandler_dev_raw
class fhandler_disk_file: public fhandler_base
{
void touch_ctime ();
int readdir_helper (DIR *, dirent *, DWORD, DWORD, char *) __attribute__ ((regparm (3)));
int readdir_9x (DIR *, dirent *) __attribute__ ((regparm (3)));
public:
fhandler_disk_file ();

View File

@ -1,7 +1,7 @@
/* fhandler_disk_file.cc
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005 Red Hat, Inc.
2005, 2006 Red Hat, Inc.
This file is part of Cygwin.
@ -96,6 +96,38 @@ path_conv::ndisk_links (DWORD nNumberOfLinks)
return count + saw_dot;
}
bool
path_conv::hasgood_inode ()
{
/* Assume that if a drive has ACL support it MAY have valid "inodes".
It definitely does not have valid inodes if it does not have ACL
support. Decouple from has_acls() which follows smbntsec setting. */
if (!(fs_flags () & FILE_PERSISTENT_ACLS) || drive_type () == DRIVE_UNKNOWN)
return false;
if (drive_type () == DRIVE_REMOTE)
{
/* From own experiments and replies from the Cygwin mailing list,
we're now trying to figure out how to determine remote file
systems which are capable of returning persistent inode
numbers. It seems that NT4 NTFS, when accessed remotly, and
some other remote file systems return unreliable values in
nFileIndex. The common factor of these unreliable remote FS
seem to be that FILE_SUPPORTS_OBJECT_IDS isn't set, even though
this should have nothing to do with inode numbers.
An exception is Samba, which seems to return valid inode numbers
without having the FILE_SUPPORTS_OBJECT_IDS flag set. So we're
testing for the flag values returned by a 3.x Samba explicitely
for now. */
#define FS_IS_SAMBA (FILE_CASE_SENSITIVE_SEARCH \
| FILE_CASE_PRESERVED_NAMES \
| FILE_PERSISTENT_ACLS)
if (!(fs_flags () & FILE_SUPPORTS_OBJECT_IDS)
&& fs_flags () != FS_IS_SAMBA)
return false;
}
return true;
}
int __stdcall
fhandler_base::fstat_by_handle (struct __stat64 *buf)
{
@ -139,8 +171,8 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
pfai->StandardInformation.EndOfFile.HighPart,
pfai->StandardInformation.EndOfFile.LowPart,
pfai->StandardInformation.AllocationSize.QuadPart,
pfai->InternalInformation.IndexNumber.HighPart,
pfai->InternalInformation.IndexNumber.LowPart,
pfai->InternalInformation.FileId.HighPart,
pfai->InternalInformation.FileId.LowPart,
pfai->StandardInformation.NumberOfLinks,
pfai->BasicInformation.FileAttributes);
}
@ -315,53 +347,11 @@ fhandler_base::fstat_helper (struct __stat64 *buf,
let's try it with `1' as link count. */
buf->st_nlink = pc.ndisk_links (nNumberOfLinks);
/* Assume that if a drive has ACL support it MAY have valid "inodes".
It definitely does not have valid inodes if it does not have ACL
support. Decouple from has_acls() which follows smbntsec setting. */
switch ((pc.fs_flags () & FILE_PERSISTENT_ACLS)
&& (nFileIndexHigh || nFileIndexLow)
? pc.drive_type () : DRIVE_UNKNOWN)
{
case DRIVE_FIXED:
case DRIVE_REMOVABLE:
case DRIVE_CDROM:
case DRIVE_RAMDISK:
/* Although the documentation indicates otherwise, it seems like
"inodes" on these devices are persistent, at least across reboots. */
buf->st_ino = (((__ino64_t) nFileIndexHigh) << 32)
| (__ino64_t) nFileIndexLow;
break;
case DRIVE_REMOTE:
/* From own experiments and replies from the Cygwin mailing list,
we're now trying to figure out how to determine remote file
systems which are capable of returning persistent inode
numbers. It seems that NT4 NTFS, when accessed remotly, and
some other remote file systems return unreliable values in
nFileIndex. The common factor of these unreliable remote FS
seem to be that FILE_SUPPORTS_OBJECT_IDS isn't set, even though
this should have nothing to do with inode numbers.
An exception is Samba, which seems to return valid inode numbers
without having the FILE_SUPPORTS_OBJECT_IDS flag set. So we're
testing for the flag values returned by a 3.x Samba explicitely
for now. */
#define FS_IS_SAMBA (FILE_CASE_SENSITIVE_SEARCH \
| FILE_CASE_PRESERVED_NAMES \
| FILE_PERSISTENT_ACLS)
if ((pc.fs_flags () & FILE_SUPPORTS_OBJECT_IDS)
|| pc.fs_flags () == FS_IS_SAMBA)
{
buf->st_ino = (((__ino64_t) nFileIndexHigh) << 32)
| (__ino64_t) nFileIndexLow;
break;
}
/*FALLTHRU*/
default:
/* Either the nFileIndex* fields are unreliable or unavailable. Use the
next best alternative. */
buf->st_ino = get_namehash ();
break;
}
if (pc.hasgood_inode ())
buf->st_ino = (((__ino64_t) nFileIndexHigh) << 32)
| (__ino64_t) nFileIndexLow;
else
buf->st_ino = get_namehash ();
buf->st_blksize = S_BLKSIZE;
@ -1376,7 +1366,7 @@ fhandler_disk_file::opendir ()
set_errno (ENOMEM);
goto free_dirname;
}
else if (fhaccess (R_OK) != 0)
else if (!pc.isspecial () && fhaccess (R_OK) != 0)
goto free_dirent;
else
{
@ -1391,18 +1381,36 @@ fhandler_disk_file::opendir ()
fd->nohandle (true);
dir->__d_fd = fd;
dir->__fh = this;
/* FindFirstFile doesn't seem to like duplicate /'s. */
/* FindFirstFile doesn't seem to like duplicate /'s.
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 (dir->__d_dirname);
if (len == 0 || isdirsep (dir->__d_dirname[len - 1]))
strcat (dir->__d_dirname, "*");
else
strcat (dir->__d_dirname, "\\*"); /**/
if (len && !isdirsep (dir->__d_dirname[len - 1]))
strcpy (dir->__d_dirname + len, "\\");
dir->__d_cookie = __DIRENT_COOKIE;
dir->__handle = INVALID_HANDLE_VALUE;
dir->__d_position = 0;
res = dir;
dir->__flags = (pc.normalized_path[0] == '/' && pc.normalized_path[1] == '\0') ? dirent_isroot : 0;
if (!pc.isspecial () && wincap.is_winnt ())
{
dir->__handle = CreateFile (get_win32_name (), GENERIC_READ,
wincap.shared (), NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (dir->__handle == INVALID_HANDLE_VALUE)
{
__seterrno ();
goto free_dirent;
}
if (wincap.has_fileid_dirinfo ())
dir->__flags |= dirent_get_d_ino;
if (pc.hasgood_inode ())
dir->__flags |= dirent_set_d_ino;
}
res = dir;
}
syscall_printf ("%p = opendir (%s)", res, get_name ());
@ -1417,21 +1425,262 @@ free_dir:
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 (!(dir->__flags & dirent_isroot))
/* nothing */;
else if (0 && !(dir->__flags & dirent_saw_dev))
{
strcpy (fname, "dev");
added = true;
}
else if (!(dir->__flags & dirent_saw_proc))
{
strcpy (fname, "proc");
added = true;
}
else if (!(dir->__flags & dirent_saw_cygdrive)
&& mount_table->cygdrive_len > 1)
{
strcpy (fname, mount_table->cygdrive + 1);
fname[mount_table->cygdrive_len - 2] = '\0';
added = true;
}
if (added)
{
attr = 0;
dir->__flags &= ~dirent_set_d_ino;
}
else
return geterrno_from_win_error (w32_err);
}
/* 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;
int len = strlen (c);
if (strcasematch (c + len - 4, ".lnk"))
{
char fbuf[CYG_MAX_PATH];
strcpy (fbuf, dir->__d_dirname);
strcat (fbuf, c);
path_conv fpath (fbuf, PC_SYM_NOFOLLOW);
if (fpath.issymlink () || fpath.is_fs_special ())
c[len - 4] = '\0';
}
}
if (pc.isencoded ())
fnunmunge (de->d_name, fname);
else
strcpy (de->d_name, fname);
if (dir->__flags & dirent_isroot)
{
if (strcasematch (de->d_name, "dev"))
{
dir->__flags |= dirent_saw_dev;
de->d_ino = hash_path_name (0, "/dev");
}
else if (strcasematch (de->d_name, "proc"))
{
dir->__flags |= dirent_saw_proc;
de->d_ino = hash_path_name (0, "/proc");
}
if (strlen (de->d_name) == mount_table->cygdrive_len - 2
&& strncasematch (de->d_name, mount_table->cygdrive + 1,
mount_table->cygdrive_len - 2))
{
dir->__flags |= dirent_saw_cygdrive;
de->d_ino = 0;
}
}
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
readdir_get_ino_by_handle (HANDLE hdl)
{
IO_STATUS_BLOCK io;
FILE_INTERNAL_INFORMATION pfai;
if (!NtQueryInformationFile (hdl, &io, &pfai, sizeof pfai,
FileInternalInformation))
return pfai.FileId.QuadPart;
return 0;
}
__ino64_t __stdcall
readdir_get_ino (DIR *dir, const char *path, bool dot_dot)
{
char fname[CYG_MAX_PATH];
struct __stat64 st;
HANDLE hdl;
__ino64_t ino = 0;
if (!(dir->__flags & dirent_isroot))
{
strcpy (fname, path);
if (dot_dot)
strcat (fname, (*fname && fname[strlen (fname) - 1] == '/')
? ".." : "/..");
path_conv pc (fname);
if (pc.isspecial ())
{
if (!lstat64 (fname, &st))
ino = st.st_ino;
}
else if (!pc.hasgood_inode ())
ino = hash_path_name (0, pc);
else if ((hdl = CreateFile (pc, GENERIC_READ, wincap.shared (), NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
NULL)) != INVALID_HANDLE_VALUE)
{
ino = readdir_get_ino_by_handle (hdl);
CloseHandle (hdl);
}
}
else
ino = readdir_get_ino_by_handle (dir->__handle);
return ino;
}
int
fhandler_disk_file::readdir (DIR *dir, dirent *de)
{
WIN32_FIND_DATA buf;
HANDLE handle;
int res;
int res = 0;
NTSTATUS status = STATUS_SUCCESS;
if (!dir->__handle)
{
res = ENMFILE;
goto out;
}
if (!wincap.is_winnt ())
return readdir_9x (dir, de);
#define DIR_BUF_SIZE (sizeof (FILE_ID_BOTH_DIR_INFORMATION) + 2 * CYG_MAX_PATH)
PFILE_ID_BOTH_DIR_INFORMATION buf = (PFILE_ID_BOTH_DIR_INFORMATION)
alloca (DIR_BUF_SIZE);
IO_STATUS_BLOCK io;
wchar_t *FileName = buf->FileName;
char fname[CYG_MAX_PATH];
if ((dir->__flags & dirent_get_d_ino))
{
status = NtQueryDirectoryFile (dir->__handle, NULL, NULL, 0, &io,
buf, DIR_BUF_SIZE,
FileIdBothDirectoryInformation,
TRUE, NULL, dir->__d_position == 0);
/* FileIdBothDirectoryInformation isn't supported for remote drives
on NT4 and 2K systems, and it's also not supported on 2K at all,
when accessing network drives on any remote OS. We just fall
back to using a standard directory query in this case and note
this case using the dirent_get_d_ino flag. */
if (!status)
{
if ((dir->__flags & dirent_set_d_ino))
de->d_ino = buf->FileId.QuadPart;
}
else if (status == STATUS_INVALID_LEVEL
|| status == STATUS_INVALID_PARAMETER)
dir->__flags &= ~dirent_get_d_ino;
}
if (!(dir->__flags & dirent_get_d_ino))
{
status = NtQueryDirectoryFile (dir->__handle, NULL, NULL, 0, &io, buf,
DIR_BUF_SIZE, FileBothDirectoryInformation,
TRUE, NULL, dir->__d_position == 0);
FileName = ((PFILE_BOTH_DIR_INFORMATION) buf)->FileName;
}
if (!status && de->d_ino == 0 && (dir->__flags & dirent_set_d_ino))
{
OBJECT_ATTRIBUTES attr;
if (dir->__d_position == 0 && buf->FileNameLength == 2
&& FileName[0] == '.')
de->d_ino = readdir_get_ino_by_handle (dir->__handle);
else if (dir->__d_position == 1 && buf->FileNameLength == 4
&& FileName[0] == '.' && FileName[1] == '.')
de->d_ino = readdir_get_ino (dir, pc.normalized_path, true);
else
{
HANDLE hdl;
UNICODE_STRING upath = {buf->FileNameLength, CYG_MAX_PATH * 2,
FileName};
InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE,
dir->__handle , NULL);
if (!NtOpenFile (&hdl, READ_CONTROL, &attr, &io,
wincap.shared (), 0))
{
de->d_ino = readdir_get_ino_by_handle (hdl);
CloseHandle (hdl);
}
}
}
if (!status)
{
wcstombs (fname, FileName, buf->FileNameLength / 2);
fname[buf->FileNameLength / 2] = '\0';
}
if (!(res = readdir_helper (dir, de, RtlNtStatusToDosError (status),
buf->FileAttributes, fname)))
dir->__d_position++;
else if (!(dir->__flags & dirent_saw_dot))
{
strcpy (de->d_name , ".");
de->d_ino = readdir_get_ino_by_handle (dir->__handle);
dir->__d_position++;
dir->__flags |= dirent_saw_dot;
res = 0;
}
else if (!(dir->__flags & dirent_saw_dot))
{
strcpy (de->d_name , "..");
de->d_ino = readdir_get_ino (dir, pc.normalized_path, true);
dir->__d_position++;
dir->__flags |= dirent_saw_dot_dot;
res = 0;
}
else
{
CloseHandle (dir->__handle);
dir->__handle = NULL;
}
out:
syscall_printf ("%d = readdir (%p) (%s)", dir, &de, de->d_name);
return res;
}
int
fhandler_disk_file::readdir_9x (DIR *dir, dirent *de)
{
WIN32_FIND_DATA buf;
HANDLE handle;
int res = 0;
BOOL ret = TRUE;
if (dir->__handle == INVALID_HANDLE_VALUE && dir->__d_position == 0)
{
int len = strlen (dir->__d_dirname);
strcpy (dir->__d_dirname + len, "*");
handle = FindFirstFileA (dir->__d_dirname, &buf);
dir->__d_dirname[len] = '\0';
DWORD lasterr = GetLastError ();
dir->__handle = handle;
if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES))
@ -1445,76 +1694,18 @@ fhandler_disk_file::readdir (DIR *dir, dirent *de)
res = EBADF;
goto out;
}
else if (!FindNextFileA (dir->__handle, &buf))
{
bool added = false;
if (!(dir->__flags & dirent_isroot))
/* nothing */;
else if (0 && !(dir->__flags & dirent_saw_dev))
{
strcpy (buf.cFileName, "dev");
added = true;
}
else if (!(dir->__flags & dirent_saw_proc))
{
strcpy (buf.cFileName, "proc");
added = true;
}
else if (!(dir->__flags & dirent_saw_cygdrive)
&& mount_table->cygdrive_len > 1)
{
strcpy (buf.cFileName, mount_table->cygdrive + 1);
buf.cFileName[mount_table->cygdrive_len - 2] = '\0';
added = true;
}
if (added)
buf.dwFileAttributes = 0;
else
{
res = geterrno_from_win_error ();
FindClose (dir->__handle);
dir->__handle = NULL;
goto out;
}
}
/* Check for Windows shortcut. If it's a Cygwin or U/WIN
symlink, drop the .lnk suffix. */
if (buf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
{
char *c = buf.cFileName;
int len = strlen (c);
if (strcasematch (c + len - 4, ".lnk"))
{
char fbuf[CYG_MAX_PATH];
strcpy (fbuf, dir->__d_dirname);
strcpy (fbuf + strlen (fbuf) - 1, c);
path_conv fpath (fbuf, PC_SYM_NOFOLLOW);
if (fpath.issymlink () || fpath.is_fs_special ())
c[len - 4] = '\0';
}
}
/* We get here if `buf' contains valid data. */
if (pc.isencoded ())
fnunmunge (de->d_name, buf.cFileName);
else
strcpy (de->d_name, buf.cFileName);
if (dir->__flags & dirent_isroot)
ret = FindNextFileA (dir->__handle, &buf);
if (!(res = readdir_helper (dir, de, ret ? 0 : GetLastError (),
buf.dwFileAttributes, buf.cFileName)))
dir->__d_position++;
else
{
if (strcasematch (de->d_name, "dev"))
dir->__flags |= dirent_saw_dev;
else if (strcasematch (de->d_name, "proc"))
dir->__flags |= dirent_saw_proc;
if (strlen (de->d_name) == mount_table->cygdrive_len - 2
&& strncasematch (de->d_name, mount_table->cygdrive + 1,
mount_table->cygdrive_len - 2))
dir->__flags |= dirent_saw_cygdrive;
FindClose (dir->__handle);
dir->__handle = NULL;
}
dir->__d_position++;
res = 0;
out:
syscall_printf ("%d = readdir (%p) (%s)", dir, &de, de->d_name);
return res;
@ -1538,7 +1729,7 @@ fhandler_disk_file::seekdir (DIR *dir, _off64_t loc)
void
fhandler_disk_file::rewinddir (DIR *dir)
{
if (dir->__handle != INVALID_HANDLE_VALUE)
if (!wincap.is_winnt () && dir->__handle != INVALID_HANDLE_VALUE)
{
if (dir->__handle)
FindClose (dir->__handle);
@ -1552,7 +1743,8 @@ fhandler_disk_file::closedir (DIR *dir)
{
int res = 0;
if (dir->__handle && dir->__handle != INVALID_HANDLE_VALUE
&& FindClose (dir->__handle) == 0)
&& ((wincap.is_winnt () && !CloseHandle (dir->__handle))
|| (!wincap.is_winnt () && !FindClose (dir->__handle))))
{
__seterrno ();
res = -1;
@ -1580,6 +1772,9 @@ int
fhandler_cygdrive::fstat (struct __stat64 *buf)
{
buf->st_mode = S_IFDIR | 0555;
/* Call get_namehash before calling set_drives, otherwise the namehash
is broken due to overwriting the win32 path in set_drives. */
buf->st_ino = get_namehash ();
if (!ndrives)
set_drives ();
buf->st_nlink = ndrives + 2;
@ -1592,6 +1787,9 @@ fhandler_cygdrive::opendir ()
DIR *dir;
dir = fhandler_disk_file::opendir ();
/* Call get_namehash before calling set_drives, otherwise the namehash
is broken due to overwriting the win32 path in set_drives. */
get_namehash ();
if (dir && !ndrives)
set_drives ();
@ -1601,16 +1799,17 @@ fhandler_cygdrive::opendir ()
int
fhandler_cygdrive::readdir (DIR *dir, dirent *de)
{
if (!pdrive || !*pdrive)
return ENMFILE;
if (GetFileAttributes (pdrive) == INVALID_FILE_ATTRIBUTES)
while (true)
{
if (!pdrive || !*pdrive)
return ENMFILE;
if (GetFileAttributes (pdrive) != INVALID_FILE_ATTRIBUTES)
break;
pdrive = strchr (pdrive, '\0') + 1;
return readdir (dir, de);
}
*de->d_name = cyg_tolower (*pdrive);
de->d_name[1] = '\0';
de->d_ino = readdir_get_ino (dir, pdrive, false);
dir->__d_position++;
pdrive = strchr (pdrive, '\0') + 1;
syscall_printf ("%p = readdir (%p) (%s)", &de, dir, de->d_name);

View File

@ -202,6 +202,7 @@ fhandler_proc::readdir (DIR *dir, dirent *de)
if (dir->__d_position < PROC_LINK_COUNT)
{
strcpy (de->d_name, proc_listing[dir->__d_position++]);
dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
res = 0;
}
else

View File

@ -1,6 +1,6 @@
/* fhandler_process.cc: fhandler for /proc/<pid> virtual filesystem
Copyright 2002, 2003, 2004, 2005 Red Hat, Inc.
Copyright 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
This file is part of Cygwin.
@ -227,6 +227,7 @@ fhandler_process::readdir (DIR *dir, dirent *de)
}
else
strcpy (de->d_name, process_listing[dir->__d_position++]);
dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
res = 0;
out:
syscall_printf ("%d = readdir (%p, %p) (%s)", res, dir, de, de->d_name);

View File

@ -1,6 +1,6 @@
/* fhandler_registry.cc: fhandler for /proc/registry virtual filesystem
Copyright 2002, 2003, 2003, 2004, 2005 Red Hat, Inc.
Copyright 2002, 2003, 2003, 2004, 2005, 2006 Red Hat, Inc.
This file is part of Cygwin.
@ -283,6 +283,7 @@ fhandler_registry::readdir (DIR *dir, dirent *de)
LONG error;
int res = ENMFILE;
dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
if (*path == 0)
{
if (dir->__d_position >= ROOT_KEY_COUNT)

View File

@ -1,6 +1,6 @@
/* Posix dirent.h for WIN32.
Copyright 2001, 2002, 2003, 2005 Red Hat, Inc.
Copyright 2001, 2002, 2003, 2005, 2006 Red Hat, Inc.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
@ -20,9 +20,9 @@
struct dirent
{
long __d_version; /* Used internally */
__ino64_t __dirent_internal;
__uint32_t __dirent_unused1;
__uint32_t __dirent_internal1;
__ino64_t d_ino;
__uint32_t __d_fd;
__uint32_t __d_internal1;
char d_name[256]; /* FIXME: use NAME_MAX? */
};
#else
@ -31,7 +31,7 @@ struct dirent
long d_version;
long d_reserved[2];
long d_fd;
ino_t __invalid_d_ino; /* DO NOT USE: No longer available since cygwin 1.5.19 */
ino_t d_ino;
char d_name[256];
};
#endif
@ -55,14 +55,7 @@ typedef struct __DIR
} DIR;
#pragma pack(pop)
#ifndef __USE_EXPENSIVE_CYGWIN_D_INO
DIR *opendir (const char *);
#else
#define d_ino __dirent_internal
DIR *__opendir_with_d_ino (const char *);
#define opendir __opendir_with_d_ino
#endif
struct dirent *readdir (DIR *);
int readdir_r (DIR *, struct dirent *, struct dirent **);
void rewinddir (DIR *);

View File

@ -1,6 +1,6 @@
/* ntdll.h. Contains ntdll specific stuff not defined elsewhere.
Copyright 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
This file is part of Cygwin.
@ -9,8 +9,10 @@
details. */
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xc0000004)
#define STATUS_INVALID_PARAMETER ((NTSTATUS) 0xc000000d)
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xc0000023)
#define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xc00000a1L)
#define STATUS_INVALID_LEVEL ((NTSTATUS) 0xc0000148)
#define STATUS_NO_MORE_FILES ((NTSTATUS)0x80000006L)
#define PDI_MODULES 0x01
#define PDI_HEAPS 0x04
@ -460,7 +462,7 @@ typedef struct _FILE_STANDARD_INFORMATION {
} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;
typedef struct _FILE_INTERNAL_INFORMATION {
LARGE_INTEGER IndexNumber;
LARGE_INTEGER FileId;
} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION;
typedef struct _FILE_EA_INFORMATION {

View File

@ -1,6 +1,7 @@
/* path.h: path data structures
Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.
Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005,
2006 Red Hat, Inc.
This file is part of Cygwin.
@ -135,7 +136,7 @@ class path_conv
bool isremote () {return fs.is_remote_drive ();}
int has_acls () const {return fs.has_acls (); }
int has_symlinks () const {return path_flags & PATH_HAS_SYMLINKS;}
int hasgood_inode () const {return has_acls ();} // Not strictly correct
bool hasgood_inode (); /* Implemented in fhandler_disk_file.cc */
int has_buggy_open () const {return fs.has_buggy_open ();}
bool isencoded () {return path_flags & PATH_ENC;}
int binmode () const

View File

@ -63,7 +63,8 @@ static NO_COPY wincaps wincap_unknown = {
has_null_console_handler_routine:false,
has_disk_ex_ioctls:false,
has_working_virtual_lock:false,
has_disabled_user_tos_setting:false
has_disabled_user_tos_setting:false,
has_fileid_dirinfo:false
};
static NO_COPY wincaps wincap_95 = {
@ -118,7 +119,8 @@ static NO_COPY wincaps wincap_95 = {
has_null_console_handler_routine:false,
has_disk_ex_ioctls:false,
has_working_virtual_lock:false,
has_disabled_user_tos_setting:false
has_disabled_user_tos_setting:false,
has_fileid_dirinfo:false
};
static NO_COPY wincaps wincap_95osr2 = {
@ -173,7 +175,8 @@ static NO_COPY wincaps wincap_95osr2 = {
has_null_console_handler_routine:false,
has_disk_ex_ioctls:false,
has_working_virtual_lock:false,
has_disabled_user_tos_setting:false
has_disabled_user_tos_setting:false,
has_fileid_dirinfo:false
};
static NO_COPY wincaps wincap_98 = {
@ -228,7 +231,8 @@ static NO_COPY wincaps wincap_98 = {
has_null_console_handler_routine:false,
has_disk_ex_ioctls:false,
has_working_virtual_lock:false,
has_disabled_user_tos_setting:false
has_disabled_user_tos_setting:false,
has_fileid_dirinfo:false
};
static NO_COPY wincaps wincap_98se = {
@ -283,7 +287,8 @@ static NO_COPY wincaps wincap_98se = {
has_null_console_handler_routine:false,
has_disk_ex_ioctls:false,
has_working_virtual_lock:false,
has_disabled_user_tos_setting:false
has_disabled_user_tos_setting:false,
has_fileid_dirinfo:false
};
static NO_COPY wincaps wincap_me = {
@ -338,7 +343,8 @@ static NO_COPY wincaps wincap_me = {
has_null_console_handler_routine:false,
has_disk_ex_ioctls:false,
has_working_virtual_lock:false,
has_disabled_user_tos_setting:false
has_disabled_user_tos_setting:false,
has_fileid_dirinfo:false
};
static NO_COPY wincaps wincap_nt3 = {
@ -393,7 +399,8 @@ static NO_COPY wincaps wincap_nt3 = {
has_null_console_handler_routine:true,
has_disk_ex_ioctls:false,
has_working_virtual_lock:true,
has_disabled_user_tos_setting:false
has_disabled_user_tos_setting:false,
has_fileid_dirinfo:false
};
static NO_COPY wincaps wincap_nt4 = {
@ -448,7 +455,8 @@ static NO_COPY wincaps wincap_nt4 = {
has_null_console_handler_routine:true,
has_disk_ex_ioctls:false,
has_working_virtual_lock:true,
has_disabled_user_tos_setting:false
has_disabled_user_tos_setting:false,
has_fileid_dirinfo:false
};
static NO_COPY wincaps wincap_nt4sp4 = {
@ -503,7 +511,8 @@ static NO_COPY wincaps wincap_nt4sp4 = {
has_null_console_handler_routine:true,
has_disk_ex_ioctls:false,
has_working_virtual_lock:true,
has_disabled_user_tos_setting:false
has_disabled_user_tos_setting:false,
has_fileid_dirinfo:false
};
static NO_COPY wincaps wincap_2000 = {
@ -558,7 +567,8 @@ static NO_COPY wincaps wincap_2000 = {
has_null_console_handler_routine:true,
has_disk_ex_ioctls:false,
has_working_virtual_lock:true,
has_disabled_user_tos_setting:true
has_disabled_user_tos_setting:true,
has_fileid_dirinfo:true
};
static NO_COPY wincaps wincap_xp = {
@ -613,7 +623,8 @@ static NO_COPY wincaps wincap_xp = {
has_null_console_handler_routine:true,
has_disk_ex_ioctls:true,
has_working_virtual_lock:true,
has_disabled_user_tos_setting:true
has_disabled_user_tos_setting:true,
has_fileid_dirinfo:true
};
static NO_COPY wincaps wincap_2003 = {
@ -668,7 +679,8 @@ static NO_COPY wincaps wincap_2003 = {
has_null_console_handler_routine:true,
has_disk_ex_ioctls:true,
has_working_virtual_lock:true,
has_disabled_user_tos_setting:true
has_disabled_user_tos_setting:true,
has_fileid_dirinfo:true
};
static NO_COPY wincaps wincap_vista = {
@ -723,7 +735,8 @@ static NO_COPY wincaps wincap_vista = {
has_null_console_handler_routine:true,
has_disk_ex_ioctls:true,
has_working_virtual_lock:true,
has_disabled_user_tos_setting:true
has_disabled_user_tos_setting:true,
has_fileid_dirinfo:true
};
wincapc wincap __attribute__((section (".cygwin_dll_common"), shared));

View File

@ -65,6 +65,7 @@ struct wincaps
unsigned has_disk_ex_ioctls : 1;
unsigned has_working_virtual_lock : 1;
unsigned has_disabled_user_tos_setting : 1;
unsigned has_fileid_dirinfo : 1;
};
class wincapc
@ -136,6 +137,7 @@ public:
bool IMPLEMENT (has_disk_ex_ioctls)
bool IMPLEMENT (has_working_virtual_lock)
bool IMPLEMENT (has_disabled_user_tos_setting)
bool IMPLEMENT (has_fileid_dirinfo)
#undef IMPLEMENT
};

View File

@ -1,7 +1,7 @@
/* winsup.h: main Cygwin header file.
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
2005 Red Hat, Inc.
2005, 2006 Red Hat, Inc.
This file is part of Cygwin.
@ -293,6 +293,8 @@ class path_conv;
int fcntl_worker (int fd, int cmd, void *arg);
__ino64_t __stdcall readdir_get_ino (struct __DIR *dir, const char *path, bool dot_dot) __attribute__ ((regparm (3)));
extern "C" int low_priority_sleep (DWORD) __attribute__ ((regparm (1)));
#define SLEEP_0_STAY_LOW INFINITE