From 8d817b0f9ed20cfa5e9482074999c2973a2a9543 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Fri, 5 Oct 2001 04:21:41 +0000 Subject: Add second path_conv * argument to fstat()s throughout. * fhandler.h: Change read and fstat to regparm/stdcall throughout. (fhandler_base::fstat): Just declare. Don't define. (fhandler_disk_file::fstat_helper): Declare. * fhandler.cc (fhandler_base::fstat): Move here from fhandler.h, adapt from former stat_dev(). (fhandler_disk_file::fstat): Move most of the disk-file-specific logic from stat_worker to here. Use fstat_helper to derive final fstat output. (fhandler_disk_file::fstat_helper): New method, renamed from former fstat method. (num_entries): Moved here from syscalls.cc. * fhandler_mem.cc (fhandler_dev_mem::fstat): Use base class to initialize most stuff. Invert has_physical_mem_access test for establishing permissions. * fhandler_raw.cc (fhandler_dev_raw::fstat): Eliminate unneed test and memory clearing. Use base class to initialize most stuff. * syscalls.cc (stat_dev): Eliminate. (stat_worker): Simply call fstat method to generate fstat output. Move all device specific code to appropriate fstats. * dir.cc (opendir): Pass correct arg to stat_worker to allow following symlinks. --- winsup/cygwin/fhandler.cc | 161 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 3 deletions(-) (limited to 'winsup/cygwin/fhandler.cc') diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index 0bad75cc9..6e2db18df 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -24,6 +24,8 @@ details. */ #include "dtable.h" #include "cygheap.h" #include "shared_info.h" +#include "sigproc.h" +#include "pinfo.h" #include static NO_COPY const int CHUNK_SIZE = 1024; /* Used for crlf conversions */ @@ -847,15 +849,168 @@ rootdir(char *full_path) return root; } +int __stdcall +fhandler_base::fstat (struct stat *buf, path_conv *) +{ + switch (get_device ()) + { + case FH_PIPEW: + buf->st_mode = STD_WBITS | S_IWGRP | S_IWOTH; + break; + case FH_PIPER: + buf->st_mode = STD_RBITS; + break; + default: + buf->st_mode = STD_RBITS | STD_WBITS | S_IWGRP | S_IWOTH; + break; + } + + buf->st_mode |= get_device () == FH_FLOPPY ? S_IFBLK : S_IFCHR; + buf->st_nlink = 1; + buf->st_blksize = S_BLKSIZE; + buf->st_dev = buf->st_rdev = FHDEVN (get_device ()) << 8 | (get_unit () & 0xff); + buf->st_ino = get_namehash (); + buf->st_atime = buf->st_mtime = buf->st_ctime = time (NULL); + return 0; +} + +static int +num_entries (const char *win32_name) +{ + WIN32_FIND_DATA buf; + HANDLE handle; + char buf1[MAX_PATH]; + int count = 0; + + strcpy (buf1, win32_name); + int len = strlen (buf1); + if (len == 0 || isdirsep (buf1[len - 1])) + strcat (buf1, "*"); + else + strcat (buf1, "/*"); /* */ + + handle = FindFirstFileA (buf1, &buf); + + if (handle == INVALID_HANDLE_VALUE) + return 0; + count ++; + while (FindNextFileA (handle, &buf)) + { + if ((buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + count ++; + } + FindClose (handle); + return count; +} + int -fhandler_disk_file::fstat (struct stat *buf) +fhandler_disk_file::fstat (struct stat *buf, path_conv *pc) +{ + int res = -1; + int oret; + uid_t uid; + gid_t gid; + int open_flags = O_RDONLY | O_BINARY | O_DIROPEN; + + if (!pc) + return fstat_helper (buf); + + if ((oret = open (pc, open_flags, 0))) + /* ok */; + else + { + int ntsec_atts = 0; + /* If we couldn't open the file, try a "query open" with no permissions. + This will allow us to determine *some* things about the file, at least. */ + set_query_open (TRUE); + if ((oret = open (pc, open_flags, 0))) + /* ok */; + else if (allow_ntsec && pc->has_acls () && get_errno () == EACCES + && !get_file_attribute (TRUE, get_win32_name (), &ntsec_atts, &uid, &gid) + && !ntsec_atts && uid == myself->uid && gid == myself->gid) + { + /* Check a special case here. If ntsec is ON it happens + that a process creates a file using mode 000 to disallow + other processes access. In contrast to UNIX, this results + in a failing open call in the same process. Check that + case. */ + set_file_attribute (TRUE, get_win32_name (), 0400); + oret = open (pc, open_flags, 0); + set_file_attribute (TRUE, get_win32_name (), ntsec_atts); + } + } + if (oret) + { + res = fstat_helper (buf); + /* The number of links to a directory includes the + number of subdirectories in the directory, since all + those subdirectories point to it. + This is too slow on remote drives, so we do without it and + set the number of links to 2. */ + /* Unfortunately the count of 2 confuses `find (1)' command. So + let's try it with `1' as link count. */ + if (pc->isdir ()) + buf->st_nlink = (pc->isremote () + ? 1 : num_entries (pc->get_win32 ())); + close (); + } + else if (pc->exists ()) + { + /* Unfortunately, the above open may fail if the file exists, though. + So we have to care for this case here, too. */ + WIN32_FIND_DATA wfd; + HANDLE handle; + buf->st_nlink = 1; + if (pc->isdir () && pc->isremote ()) + buf->st_nlink = num_entries (pc->get_win32 ()); + buf->st_dev = FHDEVN (FH_DISK) << 8; + buf->st_ino = hash_path_name (0, pc->get_win32 ()); + if (pc->isdir ()) + buf->st_mode = S_IFDIR; + else if (pc->issymlink ()) + buf->st_mode = S_IFLNK; + else if (pc->issocket ()) + buf->st_mode = S_IFSOCK; + else + buf->st_mode = S_IFREG; + if (!pc->has_acls () + || get_file_attribute (TRUE, pc->get_win32 (), + &buf->st_mode, + &buf->st_uid, &buf->st_gid)) + { + buf->st_mode |= STD_RBITS | STD_XBITS; + if (!(pc->has_attribute (FILE_ATTRIBUTE_READONLY))) + buf->st_mode |= STD_WBITS; + if (pc->issymlink ()) + buf->st_mode |= S_IRWXU | S_IRWXG | S_IRWXO; + get_file_attribute (FALSE, pc->get_win32 (), + NULL, &buf->st_uid, &buf->st_gid); + } + if ((handle = FindFirstFile (pc->get_win32 (), &wfd)) + != INVALID_HANDLE_VALUE) + { + buf->st_atime = to_time_t (&wfd.ftLastAccessTime); + buf->st_mtime = to_time_t (&wfd.ftLastWriteTime); + buf->st_ctime = to_time_t (&wfd.ftCreationTime); + buf->st_size = wfd.nFileSizeLow; + buf->st_blksize = S_BLKSIZE; + buf->st_blocks = ((unsigned long) buf->st_size + + S_BLKSIZE-1) / S_BLKSIZE; + FindClose (handle); + } + res = 0; + } + + return res; +} + +int +fhandler_disk_file::fstat_helper (struct stat *buf) { int res = 0; // avoid a compiler warning BY_HANDLE_FILE_INFORMATION local; save_errno saved_errno; - memset (buf, 0, sizeof (*buf)); - /* NT 3.51 seems to have a bug when attempting to get vol serial numbers. This loop gets around this. */ for (int i = 0; i < 2; i++) -- cgit v1.2.3