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:
Christopher Faylor 2001-10-05 04:21:41 +00:00
parent 291ae2c1e7
commit 8d817b0f9e
8 changed files with 223 additions and 213 deletions

View File

@ -1,3 +1,29 @@
Thu Oct 4 23:17:49 2001 Christopher Faylor <cgf@cygnus.com>
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.
Thu Oct 4 21:37:57 2001 Christopher Faylor <cgf@cygnus.com>
* spawn.cc (perhaps_suffix): Return NULL on non-existence of file as

View File

@ -85,7 +85,7 @@ opendir (const char *dirname)
path_conv real_dirname;
if (stat_worker (dirname, &statbuf, 1, &real_dirname) == -1)
if (stat_worker (dirname, &statbuf, 0, &real_dirname) == -1)
goto failed;
if (!(statbuf.st_mode & S_IFDIR))

View File

@ -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++)

View File

@ -313,11 +313,11 @@ public:
virtual int open (path_conv * real_path, int flags, mode_t mode = 0);
virtual int close ();
virtual int fstat (struct stat *buf) { return stat_dev (get_device (), get_unit (), get_namehash (), buf); }
virtual int __stdcall fstat (struct stat *buf, path_conv *) __attribute__ ((regparm (2)));
virtual int ioctl (unsigned int cmd, void *);
virtual int fcntl (int cmd, void *);
virtual char const * ttyname () { return get_name(); }
virtual int read (void *ptr, size_t len);
virtual int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (2)));
virtual int write (const void *ptr, size_t len);
virtual off_t lseek (off_t offset, int whence);
virtual int lock (int, struct flock *);
@ -397,7 +397,7 @@ public:
void set_shutdown_write () {FHSETF (SHUTWR);}
int write (const void *ptr, size_t len);
int read (void *ptr, size_t len);
int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (2)));
int ioctl (unsigned int cmd, void *);
int fcntl (int cmd, void *);
off_t lseek (off_t, int) { return 0; }
@ -438,7 +438,7 @@ public:
select_record *select_except (select_record *s);
int ready_for_read (int fd, DWORD howlong, int ignra);
void set_close_on_exec (int val);
int read (void *ptr, size_t len);
int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (2)));
int close ();
void create_guard (SECURITY_ATTRIBUTES *sa) {guard = CreateMutex (sa, FALSE, NULL);}
int dup (fhandler_base *child);
@ -481,7 +481,7 @@ public:
int raw_read (void *ptr, size_t ulen);
int raw_write (const void *ptr, size_t ulen);
int fstat (struct stat *buf);
int __stdcall fstat (struct stat *buf, path_conv *) __attribute__ ((regparm (2)));
int dup (fhandler_base *child);
@ -522,16 +522,16 @@ protected:
public:
fhandler_dev_tape (const char *name, int unit);
virtual int open (path_conv *, int flags, mode_t mode = 0);
virtual int close (void);
int open (path_conv *, int flags, mode_t mode = 0);
int close (void);
virtual off_t lseek (off_t offset, int whence);
off_t lseek (off_t offset, int whence);
virtual int fstat (struct stat *buf);
int __stdcall fstat (struct stat *buf, path_conv *) __attribute__ ((regparm (2)));
virtual int dup (fhandler_base *child);
int dup (fhandler_base *child);
virtual int ioctl (unsigned int cmd, void *buf);
int ioctl (unsigned int cmd, void *buf);
private:
int tape_write_marks (int marktype, DWORD len);
@ -557,7 +557,8 @@ public:
int close ();
int lock (int, struct flock *);
BOOL is_device () { return FALSE; }
int fstat (struct stat *buf);
int __stdcall fstat (struct stat *buf, path_conv *pc) __attribute__ ((regparm (2)));
int __stdcall fstat_helper (struct stat *buf) __attribute__ ((regparm (1)));
HANDLE mmap (caddr_t *addr, size_t len, DWORD access, int flags, off_t off);
int munmap (HANDLE h, caddr_t addr, size_t len);
@ -747,7 +748,7 @@ public:
int write (const void *ptr, size_t len);
void doecho (const void *str, DWORD len) { (void) write (str, len); }
int read (void *ptr, size_t len);
int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (2)));
int close ();
int tcflush (int);
@ -818,7 +819,7 @@ public:
int open (path_conv *, int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
int read (void *ptr, size_t len);
int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (2)));
void init (HANDLE, DWORD, mode_t);
int tcsetattr (int a, const struct termios *t);
@ -845,7 +846,7 @@ public:
int accept_input ();
int open (path_conv *, int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
int read (void *ptr, size_t len);
int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (2)));
int close ();
int tcsetattr (int a, const struct termios *t);
@ -891,7 +892,7 @@ public:
fhandler_dev_zero (const char *name);
int open (path_conv *, int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
int read (void *ptr, size_t len);
int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (2)));
off_t lseek (off_t offset, int whence);
int close (void);
@ -914,7 +915,7 @@ public:
int get_unit () { return unit; }
int open (path_conv *, int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
int read (void *ptr, size_t len);
int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (2)));
off_t lseek (off_t offset, int whence);
int close (void);
int dup (fhandler_base *child);
@ -935,10 +936,10 @@ public:
int open (path_conv *, int flags, mode_t mode = 0);
int write (const void *ptr, size_t ulen);
int read (void *ptr, size_t ulen);
int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (2)));
off_t lseek (off_t offset, int whence);
int close (void);
int fstat (struct stat *buf);
int __stdcall fstat (struct stat *buf, path_conv *) __attribute__ ((regparm (2)));
int dup (fhandler_base *child);
HANDLE mmap (caddr_t *addr, size_t len, DWORD access, int flags, off_t off);
@ -957,7 +958,7 @@ public:
int is_windows (void) { return 1; }
int open (path_conv *, int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
int read (void *ptr, size_t len);
int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (2)));
off_t lseek (off_t offset, int whence);
int close (void);
@ -982,7 +983,7 @@ public:
int is_windows (void) { return 1; }
int open (path_conv *, int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
int read (void *ptr, size_t len);
int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (2)));
int ioctl (unsigned int cmd, void *);
off_t lseek (off_t, int) { return 0; }
int close (void) { return 0; }
@ -1009,7 +1010,7 @@ public:
int open (path_conv *, int flags, mode_t mode = 0);
int write (const void *ptr, size_t len);
int read (void *ptr, size_t len);
int __stdcall read (void *ptr, size_t len) __attribute__ ((regparm (2)));
int ioctl (unsigned int cmd, void *);
off_t lseek (off_t, int);
int close (void);

View File

@ -403,23 +403,15 @@ fhandler_dev_mem::fixup_mmap_after_fork (HANDLE h, DWORD access, DWORD offset,
}
int
fhandler_dev_mem::fstat (struct stat *buf)
fhandler_dev_mem::fstat (struct stat *buf, path_conv *pc)
{
if (!buf)
{
set_errno (EINVAL);
return -1;
}
memset (buf, 0, sizeof *buf);
this->fhandler_base::fstat (buf, pc);
buf->st_mode = S_IFCHR;
if (!wincap.has_physical_mem_access ())
if (wincap.has_physical_mem_access ())
buf->st_mode |= S_IRUSR | S_IWUSR |
S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH;
buf->st_nlink = 1;
buf->st_blksize = getpagesize ();
buf->st_dev = buf->st_rdev = get_device () << 8 | (unit & 0xff);
return 0;
}

View File

@ -156,22 +156,10 @@ fhandler_dev_raw::close (void)
}
int
fhandler_dev_raw::fstat (struct stat *buf)
fhandler_dev_raw::fstat (struct stat *buf, path_conv *pc)
{
if (!buf)
{
set_errno (EINVAL);
return -1;
}
memset (buf, 0, sizeof *buf);
buf->st_mode = S_IFCHR |
S_IRUSR | S_IWUSR |
S_IRGRP | S_IWGRP |
S_IROTH | S_IWOTH;
buf->st_nlink = 1;
this->fhandler_base::fstat (buf, pc);
buf->st_blksize = devbuf ? devbufsiz : 1;
buf->st_dev = buf->st_rdev = get_device () << 8 | (unit & 0xff);
return 0;
}

View File

@ -148,11 +148,11 @@ fhandler_dev_tape::close (void)
}
int
fhandler_dev_tape::fstat (struct stat *buf)
fhandler_dev_tape::fstat (struct stat *buf, path_conv *pc)
{
int ret;
if (! (ret = fhandler_dev_raw::fstat (buf)))
if (!(ret = fhandler_dev_raw::fstat (buf, pc)))
{
struct mtget get;

View File

@ -952,36 +952,6 @@ fchmod (int fd, mode_t mode)
return chmod (path, mode);
}
/* Cygwin internal */
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;
}
extern "C" int
_fstat (int fd, struct stat *buf)
{
@ -997,7 +967,7 @@ _fstat (int fd, struct stat *buf)
else
{
memset (buf, 0, sizeof (struct stat));
r = cygheap->fdtab[fd]->fstat (buf);
r = cygheap->fdtab[fd]->fstat (buf, NULL);
syscall_printf ("%d = fstat (%d, %x)", r, fd, buf);
}
@ -1033,32 +1003,6 @@ sync ()
return 0;
}
int __stdcall
stat_dev (DWORD devn, int unit, unsigned long ino, struct stat *buf)
{
sigframe thisframe (mainthread);
switch (devn)
{
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 |= devn == FH_FLOPPY ? S_IFBLK : S_IFCHR;
buf->st_blksize = S_BLKSIZE;
buf->st_nlink = 1;
buf->st_dev = buf->st_rdev = FHDEVN (devn) << 8 | (unit & 0xff);
buf->st_ino = ino;
buf->st_atime = buf->st_mtime = buf->st_ctime = time (NULL);
return 0;
}
suffix_info stat_suffixes[] =
{
suffix_info ("", 1),
@ -1071,18 +1015,13 @@ int __stdcall
stat_worker (const char *name, struct stat *buf, int nofollow, path_conv *pc)
{
int res = -1;
int oret;
uid_t uid;
gid_t gid;
path_conv real_path;
fhandler_base *fh = NULL;
if (!pc)
pc = &real_path;
MALLOC_CHECK;
int open_flags = O_RDONLY | O_BINARY | O_DIROPEN
| (nofollow ? O_NOSYMLINK : 0);
MALLOC_CHECK;
if (check_null_invalid_struct_errno (buf))
goto done;
@ -1093,110 +1032,19 @@ stat_worker (const char *name, struct stat *buf, int nofollow, path_conv *pc)
| PC_FULL, stat_suffixes);
if (pc->error)
{
debug_printf ("got %d error from build_fhandler_from_name", pc->error);
set_errno (pc->error);
goto done;
}
debug_printf ("(%s, %p, %d, %p)", name, buf, nofollow, pc);
memset (buf, 0, sizeof (struct stat));
if (pc->is_device ())
return stat_dev (pc->get_devn (), pc->get_unitn (),
hash_path_name (0, pc->get_win32 ()), buf);
debug_printf ("%d = file_attributes for '%s'", (DWORD) real_path,
(char *) real_path);
if ((oret = fh->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. */
fh->set_query_open (TRUE);
if ((oret = fh->open (pc, open_flags, 0)))
/* ok */;
else if (allow_ntsec && pc->has_acls () && get_errno () == EACCES
&& !get_file_attribute (TRUE, real_path, &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, real_path, 0400);
oret = fh->open (pc, open_flags, 0);
set_file_attribute (TRUE, real_path, ntsec_atts);
}
}
if (oret)
{
res = fh->fstat (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 ()));
fh->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;
debug_printf ("(%s, %p, %d, %p), file_attributes %d", name, buf, nofollow,
pc, (DWORD) real_path);
memset (buf, 0, sizeof (struct stat));
res = fh->fstat (buf, pc);
delete fh;
}
done:
if (fh)
delete fh;
MALLOC_CHECK;
syscall_printf ("%d = (%s, %p)", res, name, buf);
return res;