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.
This commit is contained in:
@@ -24,6 +24,8 @@ details. */
|
||||
#include "dtable.h"
|
||||
#include "cygheap.h"
|
||||
#include "shared_info.h"
|
||||
#include "sigproc.h"
|
||||
#include "pinfo.h"
|
||||
#include <assert.h>
|
||||
|
||||
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++)
|
||||
|
Reference in New Issue
Block a user