operators to simplify testing for directory and attributes, throughout.
* path.h (path_conv::exists): New method.
(path_conv::has_attribute): Ditto.
(path_conv::isdir): Ditto.
(path_conv::DWORD &): New operator.
(path_conv::int &): Ditto.
* dir.cc (rmdir): Eliminate a goto.
* dtable.cc (dtable::build_fhandler): Accept opt and suffix info for
path_conv.check. Return fh == NULL on path_conv error. Pass unit to set_name
as appropriate.
(dtable::reset_unix_path_name): New method.
* dtable.h (dtable): Declare new method. Reflect arg changes to
build_fhandler.
* fhandler.cc (fhandler_disk_dummy_name): Eliminate.
(fhandler_base::set_name): Expect paths to be NULL. Build unix_path_name from
win32_path_name when it is a device.
(fhandler_base::reset_unix_path_name): New method.
(fhandler_base::raw_read): Report EISDIR when ERROR_INVALID_FUNCTION or
ERROR_INVALID_PARAMETER and reading a directory.
(fhandler_disk_file::fstat): Don't call stat_dev since we should now never be
calling fhandler_disk_file methods with devices.
(fhandler_base::fhandler_base): Clear {unix,win32}_path_name.
(fhandler_base::~fhandler_base): Always free {unix,win32}_path_name.
(fhandler_disk_file::fhandler_disk_file): Remove set_no_free_names kludge.
(fhandler_disk_file::open): Ditto.
* fhandler.h (fhandler_base::no_free_names): Eliminate.
(fhandler_base::set_no_free_names): Ditto.
* fhandler_tty.cc (fhandler_tty_slave::fhandler_tty_slave): Don't set
unix_path_name here.
* path.cc (fchdir): Lock fd table throughout. Use new
dtable::reset_unix_path_name method to reset path.
* syscalls.cc (stat_worker): Reorganize to always call fstat method. Pass
path_conv method to fhandler_*::open.
(chroot): Elminate a goto.
+Sun Sep 30 22:51:41 2001 Christopher Faylor <cgf@cygnus.com>
+
+ Add "path.h" include throughout, where needed. Use new path_conv
+ methods and operators to simplify testing for directory and attributes,
+ throughout.
+ * path.h (path_conv::exists): New method.
+ (path_conv::has_attribute): Ditto.
+ (path_conv::isdir): Ditto.
+ (path_conv::DWORD &): New operator.
+ (path_conv::int &): Ditto.
+ * dir.cc (rmdir): Eliminate a goto.
+ * dtable.cc (dtable::build_fhandler): Accept opt and suffix info for
+ path_conv.check. Return fh == NULL on path_conv error. Pass unit to
+ set_name as appropriate.
+ (dtable::reset_unix_path_name): New method.
+ * dtable.h (dtable): Declare new method. Reflect arg changes to
+ build_fhandler.
+ * fhandler.cc (fhandler_disk_dummy_name): Eliminate.
+ (fhandler_base::set_name): Expect paths to be NULL. Build
+ unix_path_name from win32_path_name when it is a device.
+ (fhandler_base::reset_unix_path_name): New method.
+ (fhandler_base::raw_read): Report EISDIR when ERROR_INVALID_FUNCTION
+ or ERROR_INVALID_PARAMETER and reading a directory.
+ (fhandler_disk_file::fstat): Don't call stat_dev since we should now
+ never be calling fhandler_disk_file methods with devices.
+ (fhandler_base::fhandler_base): Clear {unix,win32}_path_name.
+ (fhandler_base::~fhandler_base): Always free {unix,win32}_path_name.
+ (fhandler_disk_file::fhandler_disk_file): Remove set_no_free_names
+ kludge.
+ (fhandler_disk_file::open): Ditto.
+ * fhandler.h (fhandler_base::no_free_names): Eliminate.
+ (fhandler_base::set_no_free_names): Ditto.
+ * fhandler_tty.cc (fhandler_tty_slave::fhandler_tty_slave): Don't set
+ unix_path_name here.
+ * path.cc (fchdir): Lock fd table throughout. Use new
+ dtable::reset_unix_path_name method to reset path.
+ * syscalls.cc (stat_worker): Reorganize to always call fstat method.
+ Pass path_conv method to fhandler_*::open.
+ (chroot): Elminate a goto.
+
Sun Sep 30 17:37:43 2001 Christopher Faylor <cgf@cygnus.com>
* environ.cc (winenv): Allocate exact amount of space needed for forced
#include <stdlib.h>
#include "security.h"
#include "fhandler.h"
-#include "dtable.h"
#include "path.h"
+#include "dtable.h"
#include "cygheap.h"
#include "child_info.h"
#include "heap.h"
#include "perprocess.h"
#include "security.h"
#include "fhandler.h"
-#include "dtable.h"
#include "path.h"
+#include "dtable.h"
#include "cygheap.h"
#include "child_info.h"
#include "perthread.h"
if (real_dir.error)
{
set_errno (real_dir.error);
- goto done;
+ res = -1;
}
-
- /* Does the file exist? */
- if (real_dir.file_attributes () == (DWORD) -1)
+ else if (!real_dir.exists ())
{
set_errno (ENOENT);
- goto done;
+ res = -1;
}
-
- /* Is `dir' a directory? */
- if (!(real_dir.file_attributes () & FILE_ATTRIBUTE_DIRECTORY))
+ else if (!real_dir.isdir ())
{
set_errno (ENOTDIR);
- goto done;
- }
-
- /* Even own directories can't be removed if R/O attribute is set. */
- if (real_dir.file_attributes () & FILE_ATTRIBUTE_READONLY)
- SetFileAttributes (real_dir.get_win32 (), real_dir.file_attributes () &
- ~FILE_ATTRIBUTE_READONLY);
-
- if (RemoveDirectoryA (real_dir.get_win32 ()))
- {
- /* RemoveDirectory on a samba drive doesn't return an error if the
- directory can't be removed because it's not empty. Checking for
- existence afterwards keeps us informed about success. */
- if (GetFileAttributesA (real_dir.get_win32 ()) != (DWORD) -1)
- set_errno (ENOTEMPTY);
- else
- res = 0;
+ res = -1;
}
else
{
- /* This kludge detects if we are attempting to remove the current working
- directory. If so, we will move elsewhere to potentially allow the
- rmdir to succeed. This means that cygwin's concept of the current working
- directory != Windows concept but, hey, whaddaregonnado?
- Note that this will not cause something like the following to work:
- $ cd foo
- $ rmdir .
- since the shell will have foo "open" in the above case and so Windows will
- not allow the deletion.
- FIXME: A potential workaround for this is for cygwin apps to *never* call
- SetCurrentDirectory. */
- if (strcasematch (real_dir, cygheap->cwd.win32)
- && !strcasematch ("c:\\", cygheap->cwd.win32))
+ /* Even own directories can't be removed if R/O attribute is set. */
+ if (real_dir.has_attribute (FILE_ATTRIBUTE_READONLY))
+ SetFileAttributes (real_dir,
+ (DWORD) real_dir & ~FILE_ATTRIBUTE_READONLY);
+
+ if (RemoveDirectory (real_dir))
{
- DWORD err = GetLastError ();
- if (!SetCurrentDirectory ("c:\\"))
- SetLastError (err);
+ /* RemoveDirectory on a samba drive doesn't return an error if the
+ directory can't be removed because it's not empty. Checking for
+ existence afterwards keeps us informed about success. */
+ if (GetFileAttributes (real_dir) != (DWORD) -1)
+ set_errno (ENOTEMPTY);
else
- return rmdir (dir);
+ res = 0;
}
- if (GetLastError() == ERROR_ACCESS_DENIED)
+ else
{
+ /* This kludge detects if we are attempting to remove the current working
+ directory. If so, we will move elsewhere to potentially allow the
+ rmdir to succeed. This means that cygwin's concept of the current working
+ directory != Windows concept but, hey, whaddaregonnado?
+ Note that this will not cause something like the following to work:
+ $ cd foo
+ $ rmdir .
+ since the shell will have foo "open" in the above case and so Windows will
+ not allow the deletion.
+ FIXME: A potential workaround for this is for cygwin apps to *never* call
+ SetCurrentDirectory. */
+ if (strcasematch (real_dir, cygheap->cwd.win32)
+ && !strcasematch ("c:\\", cygheap->cwd.win32))
+ {
+ DWORD err = GetLastError ();
+ if (!SetCurrentDirectory ("c:\\"))
+ SetLastError (err);
+ else if ((res = rmdir (dir)))
+ SetCurrentDirectory (cygheap->cwd.win32);
+ }
+ if (GetLastError () == ERROR_ACCESS_DENIED)
+ {
- /* On 9X ERROR_ACCESS_DENIED is returned if you try to remove
- a non-empty directory. */
- if (wincap.access_denied_on_delete ())
- set_errno (ENOTEMPTY);
+ /* On 9X ERROR_ACCESS_DENIED is returned if you try to remove
+ a non-empty directory. */
+ if (wincap.access_denied_on_delete ())
+ set_errno (ENOTEMPTY);
+ else
+ __seterrno ();
+ }
else
__seterrno ();
- }
- else
- __seterrno ();
- /* If directory still exists, restore R/O attribute. */
- if (real_dir.file_attributes () & FILE_ATTRIBUTE_READONLY)
- SetFileAttributes (real_dir.get_win32 (), real_dir.file_attributes ());
+ /* If directory still exists, restore R/O attribute. */
+ if (real_dir.has_attribute (FILE_ATTRIBUTE_READONLY))
+ SetFileAttributes (real_dir, real_dir);
+ }
}
-done:
syscall_printf ("%d = rmdir (%s)", res, dir);
return res;
}
#include "environ.h"
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
}
}
- build_fhandler (fd, name, handle)->init (handle, myaccess, bin);
+ path_conv pc;
+ build_fhandler (fd, name, handle, &pc)->init (handle, myaccess, bin);
set_std_handle (fd);
paranoid_printf ("fd %d, handle %p", fd, handle);
}
}
fhandler_base *
-dtable::build_fhandler (int fd, const char *name, HANDLE handle, path_conv *pc)
+dtable::build_fhandler (int fd, const char *name, HANDLE handle, path_conv *pc,
+ unsigned opt, suffix_info *si)
{
int unit;
DWORD devn;
devn = get_device_number (name, unit);
else
{
- pc->check (name);
+ pc->check (name, opt | PC_NULLEMPTY, si);
+ if (pc->error)
+ {
+ set_errno (pc->error);
+ return NULL;
+ }
devn = pc->get_devn ();
unit = pc->get_unitn ();
}
fh = build_fhandler (fd, devn, name, unit);
if (pc)
- fh->set_name (name, *pc);
+ fh->set_name (name, *pc, unit);
return fh;
}
return res;
}
+void
+dtable::reset_unix_path_name (int fd, const char *name)
+{
+ SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "reset_unix_name");
+ fds[fd]->reset_unix_path_name (name);
+ ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "reset_unix_name");
+}
+
select_record *
dtable::select_read (int fd, select_record *s)
{
#include "thread.h"
+class suffix_info;
class dtable
{
fhandler_base **fds;
fhandler_base *build_fhandler (int fd, DWORD dev, const char *name,
int unit = -1);
fhandler_base *build_fhandler (int fd, const char *name, HANDLE h = NULL,
- path_conv *pc = NULL);
+ path_conv *pc = NULL,
+ unsigned opts = PC_SYM_FOLLOW, suffix_info *si = NULL);
inline int not_open (int fd)
{
SetResourceLock (LOCK_FD_LIST, READ_LOCK, "not_open");
ReleaseResourceLock (LOCK_FD_LIST, READ_LOCK, "not open");
return res;
}
+ void reset_unix_path_name (int fd, const char *name);
int find_unused_handle (int start);
int find_unused_handle () { return find_unused_handle (first_fd_for_open);}
void release (int fd);
#include <unistd.h>
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
#include "cygerrno.h"
#include "security.h"
#include "cygwin/version.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
-#include "path.h"
#include "shared_info.h"
+#include <assert.h>
static NO_COPY const int CHUNK_SIZE = 1024; /* Used for crlf conversions */
-static NO_COPY char fhandler_disk_dummy_name[] = "some disk file";
-
struct __cygwin_perfile *perfile_table;
DWORD binmode;
/* Record the file name.
Filenames are used mostly for debugging messages, and it's hoped that
in cases where the name is really required, the filename wouldn't ever
- be too long (e.g. devices or some such).
-*/
-
+ be too long (e.g. devices or some such). */
void
fhandler_base::set_name (const char *unix_path, const char *win32_path, int unit)
{
- if (!no_free_names ())
- {
- if (unix_path_name != NULL && unix_path_name != fhandler_disk_dummy_name)
- cfree (unix_path_name);
- if (win32_path_name != NULL && unix_path_name != fhandler_disk_dummy_name)
- cfree (win32_path_name);
- }
-
- unix_path_name = win32_path_name = NULL;
if (unix_path == NULL || !*unix_path)
return;
- unix_path_name = cstrdup (unix_path);
- if (unix_path_name == NULL)
- {
- system_printf ("fatal error. strdup failed");
- exit (ENOMEM);
- }
-
if (win32_path)
win32_path_name = cstrdup (win32_path);
else
system_printf ("fatal error. strdup failed");
exit (ENOMEM);
}
+
+ assert (unix_path_name == NULL);
+ /* FIXME: This isn't really right. It ignores the first argument if we're
+ building names for a device and just converts the device name from the
+ win32 name since it has theoretically been previously detected by
+ path_conv. Ideally, we should pass in a format string and build the
+ unix_path, too. */
+ if (!is_device () || *win32_path_name != '\\')
+ unix_path_name = cstrdup (unix_path);
+ else
+ {
+ unix_path_name = cstrdup (win32_path_name);
+ for (char *p = unix_path_name; (p = strchr (p, '\\')); p++)
+ *p = '/';
+ }
+
+ if (unix_path_name == NULL)
+ {
+ system_printf ("fatal error. strdup failed");
+ exit (ENOMEM);
+ }
+}
+
+void
+fhandler_base::reset_unix_path_name (const char *unix_path)
+{
+ cfree (unix_path_name);
+ unix_path_name = cstrdup (unix_path);
}
/* Detect if we are sitting at EOF for conditions where Windows
case ERROR_NOACCESS:
if (is_at_eof (get_handle (), errcode))
return 0;
+ case ERROR_INVALID_FUNCTION:
+ case ERROR_INVALID_PARAMETER:
+ if (openflags & O_DIROPEN)
+ {
+ set_errno (EISDIR);
+ return -1;
+ }
default:
syscall_printf ("ReadFile %s failed, %E", unix_path_name);
__seterrno_from_win_error (errcode);
}
if (get_query_open ())
- {
- access = 0;
- }
+ access = 0;
else if (get_device () == FH_TAPE)
- {
- access = GENERIC_READ | GENERIC_WRITE;
- }
+ access = GENERIC_READ | GENERIC_WRITE;
else if ((flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_RDONLY)
- {
- access = GENERIC_READ;
- }
+ access = GENERIC_READ;
else if ((flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_WRONLY)
- {
- access = GENERIC_WRITE;
- }
+ access = GENERIC_WRITE;
else
- {
- access = GENERIC_READ | GENERIC_WRITE;
- }
+ access = GENERIC_READ | GENERIC_WRITE;
/* Allow reliable lseek on disk devices. */
if (get_device () == FH_FLOPPY)
- {
- access |= GENERIC_READ;
- }
+ access |= GENERIC_READ;
/* FIXME: O_EXCL handling? */
if ((flags & O_TRUNC) && ((flags & O_ACCMODE) != O_RDONLY))
{
if (flags & O_CREAT)
- {
- creation_distribution = CREATE_ALWAYS;
- }
+ creation_distribution = CREATE_ALWAYS;
else
- {
- creation_distribution = TRUNCATE_EXISTING;
- }
+ creation_distribution = TRUNCATE_EXISTING;
}
else if (flags & O_CREAT)
creation_distribution = OPEN_ALWAYS;
creation_distribution = OPEN_EXISTING;
if ((flags & O_EXCL) && (flags & O_CREAT))
- {
- creation_distribution = CREATE_NEW;
- }
+ creation_distribution = CREATE_NEW;
if (flags & O_APPEND)
set_append_p();
memset (buf, 0, sizeof (*buf));
- if (is_device ())
- return stat_dev (get_device (), get_unit (), get_namehash (), 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++)
raixget (0),
raixput (0),
rabuflen (0),
+ unix_path_name (NULL),
+ win32_path_name (NULL),
open_status (0)
{
status = devtype;
if (!get_w_binset ())
set_w_binary (bin);
}
- unix_path_name = win32_path_name = NULL;
- set_name (name, NULL, unit);
}
/* Normal I/O destructor */
fhandler_base::~fhandler_base (void)
{
- if (!no_free_names ())
- {
- if (unix_path_name != NULL && unix_path_name != fhandler_disk_dummy_name)
- cfree (unix_path_name);
- if (win32_path_name != NULL && win32_path_name != fhandler_disk_dummy_name)
- cfree (win32_path_name);
- }
+ if (unix_path_name != NULL)
+ cfree (unix_path_name);
+ if (win32_path_name != NULL)
+ cfree (win32_path_name);
if (rabuf)
free (rabuf);
unix_path_name = win32_path_name = NULL;
fhandler_base (FH_DISK, name)
{
set_cb (sizeof *this);
- set_no_free_names ();
- unix_path_name = win32_path_name = fhandler_disk_dummy_name;
}
int
}
set_name (path, real_path.get_win32 ());
- set_no_free_names (0);
return open (real_path, flags, mode);
}
int
fhandler_disk_file::open (path_conv& real_path, int flags, mode_t mode)
{
- if (get_win32_name () == fhandler_disk_dummy_name)
- {
- win32_path_name = real_path.get_win32 ();
- set_no_free_names ();
- }
-
if (real_path.isbinary ())
{
set_r_binary (1);
set_has_acls (real_path.has_acls ());
set_isremote (real_path.isremote ());
- if (real_path.file_attributes () != (DWORD)-1
- && (real_path.file_attributes () & FILE_ATTRIBUTE_DIRECTORY))
+ if (real_path.isdir ())
flags |= O_DIROPEN;
int res = this->fhandler_base::open (flags, mode);
FH_W95LSBUG = 0x00400000, /* set when lseek is called as a flag that
* _write should check if we've moved beyond
* EOF, zero filling if so. */
- FH_NOFRNAME = 0x00800000, /* Set if shouldn't free unix_path_name and
- windows_path_name_ on destruction. */
+ FH_UNUSED = 0x00800000, /* currently unused. */
FH_NOEINTR = 0x01000000, /* Set if I/O should be uninterruptible. */
FH_FFIXUP = 0x02000000, /* Set if need to fixup after fork. */
FH_LOCAL = 0x04000000, /* File is unix domain socket */
void set_name (const char * unix_path, const char * win32_path = NULL,
int unit = 0);
+ void reset_unix_path_name (const char *);
virtual fhandler_base& operator =(fhandler_base &x);
fhandler_base (DWORD dev, const char *name = 0, int unit = 0);
virtual ~fhandler_base ();
int isremote () { return FHISSETF (ISREMOTE); }
void set_isremote (int val) { FHCONDSETF (val, ISREMOTE); }
- int no_free_names () { return FHISSETF (NOFRNAME); }
- void set_no_free_names (int val) { FHCONDSETF (val, NOFRNAME); }
- void set_no_free_names () { FHSETF (NOFRNAME); }
-
const char *get_name () { return unix_path_name; }
const char *get_win32_name () { return win32_path_name; }
unsigned long get_namehash () { return namehash; }
#include "cygerrno.h"
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
#include "sync.h"
#include "perprocess.h"
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
-#include "path.h"
/* static wrapper functions to hide the effect of media changes and
bus resets which occurs after a new media is inserted. This is
#include "cygwin/version.h"
#include "perprocess.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
#include "sigproc.h"
#include "perprocess.h"
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
-#include "path.h"
/**********************************************************************/
/* fhandler_dev_tape */
#include "cygerrno.h"
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "sync.h"
#include "sigproc.h"
{
set_cb (sizeof *this);
ttynum = num;
- /* FIXME: This is wasteful. We should rewrite the set_name path to eliminate the
- need for double allocates. */
- unix_path_name = (char *) crealloc (unix_path_name, strlen (win32_path_name) + 1);
- strcpy (unix_path_name, win32_path_name);
- unix_path_name[0] = unix_path_name[4] = '/';
debug_printf ("unix '%s', win32 '%s'", unix_path_name, win32_path_name);
inuse = NULL;
}
#include <errno.h>
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygerrno.h"
#include "sync.h"
#include "pinfo.h"
#include "security.h"
#include "fhandler.h"
-#include "dtable.h"
#include "path.h"
+#include "dtable.h"
#include "cygheap.h"
#include "cygerrno.h"
#include "pwdgrp.h"
#include "shared_info.h"
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
#include "cygerrno.h"
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
#include <sys/termios.h>
#include <assert.h>
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
#include "heap.h"
#include <errno.h>
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygerrno.h"
#include "cygheap.h"
#include "cygerrno.h"
#include "security.h"
#include "fhandler.h"
-#include "dtable.h"
#include "path.h"
+#include "dtable.h"
#include "sync.h"
#include "sigproc.h"
#include "pinfo.h"
syscall_printf ("symlink (%s, %s)", topath, win32_path.get_win32 ());
- if (win32_path.is_device () ||
- win32_path.file_attributes () != (DWORD) -1)
+ if (win32_path.is_device () || win32_path.exists ())
{
set_errno (EEXIST);
goto done;
return -1;
}
- if (pathbuf.file_attributes () == (DWORD) -1)
+ if (!pathbuf.exists ())
{
set_errno (ENOENT);
return -1;
set_errno (EBADF);
return -1;
}
+ SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "fchdir");
int ret = chdir (cygheap->fdtab[fd]->get_name ());
- if (!ret)
+ if (ret == 0)
{
/* The name in the fhandler is explicitely overwritten with the full path.
Otherwise fchmod() to a path originally given as a relative path could
The 2nd fchmod should chdir to the same dir as the first call, not
to it's parent dir. */
- char path[MAX_PATH];
char posix_path[MAX_PATH];
- mount_table->conv_to_posix_path (cygheap->cwd.get (path, 0, 1),
- posix_path, 0);
- cygheap->fdtab[fd]->set_name (path, posix_path);
+ cygheap->fdtab.reset_unix_path_name (fd, cygheap->cwd.get (posix_path, 1, 1));
}
+ ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "fchdir");
syscall_printf ("%d = fchdir (%d)", ret, fd);
return ret;
}
public:
unsigned path_flags;
+ char *known_suffix;
+ int error;
+ DWORD devn;
+ int unit;
+ DWORD fileattr;
+ BOOL case_clash;
int isdisk () const { return path_flags & PATH_ISDISK;}
int isremote () const {return is_remote_drive;}
int issymlink () const {return path_flags & PATH_SYMLINK;}
int issocket () const {return path_flags & PATH_SOCKET;}
int iscygexec () const {return path_flags & PATH_CYGWIN_EXEC;}
+ bool exists () const {return fileattr != (DWORD) -1;}
+ bool has_attribute (DWORD x) const {return exists () && (fileattr & x);}
+ int isdir () const {return has_attribute (FILE_ATTRIBUTE_DIRECTORY);}
executable_states exec_state ()
{
extern int _check_for_executable;
void set_has_acls (int x = 1) {path_flags |= x ? PATH_HASACLS : PATH_NOTHING;}
void set_has_buggy_open (int x = 1) {path_flags |= x ? PATH_HASBUGGYOPEN : PATH_NOTHING;}
- char *known_suffix;
-
- int error;
- DWORD devn;
- int unit;
-
- DWORD fileattr;
-
- BOOL case_clash;
-
void check (const char *src, unsigned opt = PC_SYM_FOLLOW,
const suffix_info *suffixes = NULL) __attribute__ ((regparm(3)));
inline char *get_win32 () { return path; }
operator char *() {return path; }
+ operator DWORD &() {return fileattr; }
+ operator int &() {return (int) fileattr; }
BOOL is_device () {return devn != FH_BAD;}
DWORD get_devn () {return devn == FH_BAD ? (DWORD) FH_DISK : devn;}
short get_unitn () {return devn == FH_BAD ? 0 : unit;}
#include <limits.h>
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygerrno.h"
#include "sync.h"
#include "cygerrno.h"
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
#include "thread.h"
#include <errno.h>
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
#include "cygerrno.h"
#include "cygerrno.h"
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
#include "sync.h"
#include "pinfo.h"
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
#include "heap.h"
#include "pinfo.h"
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
#include "child_info.h"
debug_printf ("prog '%s'", prog);
buf.check (prog, PC_SYM_FOLLOW | PC_FULL, std_suffixes);
- if (buf.file_attributes () & FILE_ATTRIBUTE_DIRECTORY)
+ if (buf.isdir ())
ext = NULL;
else if (buf.known_suffix)
- ext = buf + (buf.known_suffix - buf.get_win32 ());
+ ext = (char *) buf + (buf.known_suffix - buf.get_win32 ());
else
ext = strchr (buf, '\0');
syscall_printf ("_unlink (%s)", win32_name.get_win32 ());
- DWORD atts;
- atts = win32_name.file_attributes ();
- if (atts == 0xffffffff)
+ if (!win32_name.exists ())
{
- syscall_printf ("unlinking a nonexistant file");
+ syscall_printf ("unlinking a nonexistent file");
set_errno (ENOENT);
goto done;
}
-
- if (atts & FILE_ATTRIBUTE_DIRECTORY)
+ else if (win32_name.isdir ())
{
syscall_printf ("unlinking a directory");
set_errno (EPERM);
}
/* Check for shortcut as symlink condition. */
- if (atts & FILE_ATTRIBUTE_READONLY)
+ if (win32_name.has_attribute (FILE_ATTRIBUTE_READONLY))
{
int len = strlen (win32_name);
- if (len > 4 && strcasematch (win32_name + len - 4, ".lnk"))
- SetFileAttributes (win32_name, atts & ~FILE_ATTRIBUTE_READONLY);
+ if (len > 4 && strcasematch ((char *) win32_name + len - 4, ".lnk"))
+ SetFileAttributes (win32_name, (DWORD) win32_name & ~FILE_ATTRIBUTE_READONLY);
}
DWORD lasterr;
return -1;
}
- DWORD atts = win32_name.file_attributes ();
- if (atts != 0xffffffff && atts & FILE_ATTRIBUTE_DIRECTORY)
- return rmdir (ourname);
-
- return _unlink (ourname);
+ return win32_name.isdir () ? rmdir (ourname) : _unlink (ourname);
}
extern "C" pid_t
goto done;
}
- if (real_b.file_attributes () != (DWORD)-1)
+ if (real_b.exists ())
{
syscall_printf ("file '%s' exists?", (char *)real_b);
set_errno (EEXIST);
}
DWORD attrib = 0;
- if (win32_path.file_attributes () & FILE_ATTRIBUTE_DIRECTORY)
+ if (win32_path.isdir ())
attrib |= S_IFDIR;
res = get_file_attribute (win32_path.has_acls (),
win32_path.get_win32 (),
uid = old_uid;
if (gid == (gid_t) -1)
gid = old_gid;
- if (win32_path.file_attributes () & FILE_ATTRIBUTE_DIRECTORY)
+ if (win32_path.isdir())
attrib |= S_IFDIR;
- res = set_file_attribute (win32_path.has_acls (),
- win32_path.get_win32 (),
- uid, gid, attrib,
- cygheap->user.logsrv ());
+ res = set_file_attribute (win32_path.has_acls (), win32_path, uid,
+ gid, attrib, cygheap->user.logsrv ());
}
if (res != 0 && (!win32_path.has_acls () || !allow_ntsec))
{
goto done;
}
- if (win32_path.file_attributes () == (DWORD)-1)
+ if (!win32_path.exists ())
__seterrno ();
else
{
- DWORD attr = win32_path.file_attributes ();
/* temporary erase read only bit, to be able to set file security */
- SetFileAttributesA (win32_path.get_win32 (),
- attr & ~FILE_ATTRIBUTE_READONLY);
+ SetFileAttributes (win32_path, (DWORD) win32_path & ~FILE_ATTRIBUTE_READONLY);
uid_t uid;
gid_t gid;
- if (win32_path.file_attributes () & FILE_ATTRIBUTE_DIRECTORY)
+ if (win32_path.isdir ())
mode |= S_IFDIR;
get_file_attribute (win32_path.has_acls (),
win32_path.get_win32 (),
NULL, &uid, &gid);
- if (win32_path.file_attributes () & FILE_ATTRIBUTE_DIRECTORY)
+ /* FIXME: Do we really need this to be specified twice? */
+ if (win32_path.isdir ())
mode |= S_IFDIR;
- if (!set_file_attribute (win32_path.has_acls (),
- win32_path.get_win32 (),
- uid, gid,
+ if (!set_file_attribute (win32_path.has_acls (), win32_path, uid, gid,
mode, cygheap->user.logsrv ())
&& allow_ntsec)
res = 0;
/* if the mode we want has any write bits set, we can't
be read only. */
if (mode & (S_IWUSR | S_IWGRP | S_IWOTH))
- attr &= ~FILE_ATTRIBUTE_READONLY;
+ (DWORD) win32_path &= ~FILE_ATTRIBUTE_READONLY;
else
- attr |= FILE_ATTRIBUTE_READONLY;
+ (DWORD) win32_path |= FILE_ATTRIBUTE_READONLY;
if (S_ISLNK (mode) || S_ISSOCK (mode))
- attr |= FILE_ATTRIBUTE_SYSTEM;
+ (DWORD) win32_path |= FILE_ATTRIBUTE_SYSTEM;
- if (!SetFileAttributesA (win32_path.get_win32 (), attr))
+ if (!SetFileAttributes (win32_path, win32_path))
__seterrno ();
else
{
int nofollow)
{
int res = -1;
- int oret = 1;
- int atts;
-
- int attribute = 0;
+ int oret;
uid_t uid;
gid_t gid;
-
- UINT dtype;
- fhandler_disk_file fh (NULL);
+ path_conv real_path;
+ fhandler_base *fh = NULL;
MALLOC_CHECK;
+ int open_flags = O_RDONLY | O_BINARY | O_DIROPEN
+ | (nofollow ? O_NOSYMLINK : 0);
debug_printf ("%s (%s, %p)", caller, name, buf);
- path_conv real_path (name, (nofollow ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW) |
- PC_FULL, stat_suffixes);
+ if (check_null_invalid_struct_errno (buf))
+ goto done;
+
+ fh = cygheap->fdtab.build_fhandler (-1, name, NULL, &real_path,
+ (nofollow ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW)
+ | PC_FULL, stat_suffixes);
if (real_path.error)
{
goto done;
}
- if (check_null_invalid_struct_errno (buf))
- goto done;
-
memset (buf, 0, sizeof (struct stat));
if (real_path.is_device ())
return stat_dev (real_path.get_devn (), real_path.get_unitn (),
hash_path_name (0, real_path.get_win32 ()), buf);
- atts = real_path.file_attributes ();
-
- debug_printf ("%d = file_attributes for '%s'", atts, real_path.get_win32 ());
+ debug_printf ("%d = file_attributes for '%s'", (DWORD) real_path,
+ (char *) real_path);
- dtype = real_path.get_drive_type ();
-
- if ((atts == -1 || ! (atts & FILE_ATTRIBUTE_DIRECTORY) ||
- (wincap.can_open_directories ()
- && dtype != DRIVE_NO_ROOT_DIR
- && dtype != DRIVE_UNKNOWN)))
+ if ((oret = fh->open (real_path, open_flags, 0)))
+ /* ok */;
+ else
{
- oret = fh.open (real_path, O_RDONLY | O_BINARY | O_DIROPEN |
- (nofollow ? O_NOSYMLINK : 0), 0);
+ 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. */
- if (!oret)
- {
- fh.set_query_open (TRUE);
- oret = fh.open (real_path, O_RDONLY | O_BINARY | O_DIROPEN |
- (nofollow ? O_NOSYMLINK : 0), 0);
- }
- /* 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. */
- if (!oret && allow_ntsec && get_errno () == EACCES
- && !get_file_attribute (TRUE, real_path, &attribute, &uid, &gid)
- && !attribute && uid == myself->uid && gid == myself->gid)
- {
+ fh->set_query_open (TRUE);
+ if ((oret = fh->open (real_path, open_flags, 0)))
+ /* ok */;
+ else if (allow_ntsec && real_path.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 (real_path, O_RDONLY | O_BINARY | O_DIROPEN |
- (nofollow ? O_NOSYMLINK : 0), 0);
- set_file_attribute (TRUE, real_path.get_win32 (), 0);
- }
- if (oret)
- {
- res = fh.fstat (buf);
- fh.close ();
- /* 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 (atts != -1 && (atts & FILE_ATTRIBUTE_DIRECTORY))
- buf->st_nlink = (dtype == DRIVE_REMOTE
- ? 1
- : num_entries (real_path.get_win32 ()));
- goto done;
- }
- }
- if (atts != -1 && (oret || (!oret && get_errno () != ENOENT
- && get_errno () != ENOSHARE)))
+ oret = fh->open (real_path, 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 (real_path.isdir ())
+ buf->st_nlink = (real_path.isremote ()
+ ? 1 : num_entries (real_path.get_win32 ()));
+ fh->close ();
+ }
+ else if (real_path.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 (atts != -1
- && (atts & FILE_ATTRIBUTE_DIRECTORY)
- && dtype != DRIVE_REMOTE)
+ if (real_path.isdir () && real_path.isremote ())
buf->st_nlink = num_entries (real_path.get_win32 ());
buf->st_dev = FHDEVN (FH_DISK) << 8;
buf->st_ino = hash_path_name (0, real_path.get_win32 ());
- if (atts != -1 && (atts & FILE_ATTRIBUTE_DIRECTORY))
+ if (real_path.isdir ())
buf->st_mode = S_IFDIR;
else if (real_path.issymlink ())
buf->st_mode = S_IFLNK;
&buf->st_uid, &buf->st_gid))
{
buf->st_mode |= STD_RBITS | STD_XBITS;
- if ((atts & FILE_ATTRIBUTE_READONLY) == 0)
+ if (!(real_path.has_attribute (FILE_ATTRIBUTE_READONLY)))
buf->st_mode |= STD_WBITS;
if (real_path.issymlink ())
buf->st_mode |= S_IRWXU | S_IRWXG | S_IRWXO;
}
done:
+ if (fh)
+ delete fh;
MALLOC_CHECK;
syscall_printf ("%d = %s (%s, %p)", res, caller, name, buf);
return res;
return -1;
}
- if (real_old.file_attributes () == (DWORD) -1) /* file to move doesn't exist */
+ if (!real_old.exists ()) /* file to move doesn't exist */
{
syscall_printf ("file to move doesn't exist");
set_errno (ENOENT);
/* Destination file exists and is read only, change that or else
the rename won't work. */
- if (real_new.file_attributes () != (DWORD) -1 &&
- real_new.file_attributes () & FILE_ATTRIBUTE_READONLY)
- SetFileAttributesA (real_new.get_win32 (),
- real_new.file_attributes () & ~FILE_ATTRIBUTE_READONLY);
+ if (real_new.has_attribute (FILE_ATTRIBUTE_READONLY))
+ SetFileAttributes (real_new, (DWORD) real_new & ~FILE_ATTRIBUTE_READONLY);
/* Shortcut hack No. 2, part 1 */
if (!real_old.issymlink () && !real_new.error && real_new.issymlink () &&
{
__seterrno ();
/* Reset R/O attributes if neccessary. */
- if (real_new.file_attributes () != (DWORD) -1 &&
- real_new.file_attributes () & FILE_ATTRIBUTE_READONLY)
- SetFileAttributesA (real_new.get_win32 (), real_new.file_attributes ());
+ if (real_new.has_attribute (FILE_ATTRIBUTE_READONLY))
+ SetFileAttributes (real_new, real_new);
}
else
{
/* make the new file have the permissions of the old one */
- SetFileAttributesA (real_new.get_win32 (), real_old.file_attributes ());
+ SetFileAttributes (real_new, real_old);
/* Shortcut hack, No. 2, part 2 */
/* if the new filename was an existing shortcut, remove it now if the
if (lnk_suffix)
{
*lnk_suffix = '.';
- DeleteFile (real_new.get_win32 ());
+ DeleteFile (real_new);
}
}
- syscall_printf ("%d = rename (%s, %s)", res, real_old.get_win32 (),
- real_new.get_win32 ());
+ syscall_printf ("%d = rename (%s, %s)", res, (char *) real_old,
+ (char *) real_new);
return res;
}
chroot (const char *newroot)
{
sigframe thisframe (mainthread);
- int ret = -1;
path_conv path (newroot, PC_SYM_FOLLOW | PC_FULL);
+ int ret;
if (path.error)
- goto done;
- if (path.file_attributes () == (DWORD)-1)
+ ret = -1;
+ else if (!path.exists ())
{
set_errno (ENOENT);
- goto done;
+ ret = -1;
}
- if (!(path.file_attributes () & FILE_ATTRIBUTE_DIRECTORY))
+ else if (!path.isdir ())
{
set_errno (ENOTDIR);
- goto done;
+ ret = -1;
+ }
+ else
+ {
+ char buf[MAX_PATH];
+ normalize_posix_path (newroot, buf);
+ cygheap->root.set (buf, path);
+ ret = 0;
}
- char buf[MAX_PATH];
- normalize_posix_path (newroot, buf);
- cygheap->root.set (buf, path);
- ret = 0;
-done:
syscall_printf ("%d = chroot (%s)", ret ? get_errno () : 0,
newroot ? newroot : "NULL");
return ret;
#include <ntdef.h>
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
#include "cygerrno.h"
#include <unistd.h>
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygerrno.h"
#include "cygheap.h"
#include "cygerrno.h"
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
#include "cygwin/version.h"
#include "cygerrno.h"
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
#include "sync.h"
#include "pinfo.h"
#include "security.h"
#include "fhandler.h"
+#include "path.h"
#include "dtable.h"
#include "cygheap.h"
#include "registry.h"