diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 49d85a0ed..83992f750 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,69 @@ +2010-09-06 Corinna Vinschen + + * Makefile.in (DLL_OFILES): Add fhandler_procsys.o. + * devices.h (enum fh_devices): Add FH_PROCSYS. + * devices.in (dev_procsys_storage): New device. + * devices.cc: Regenerate. + * dtable.cc (build_fh_pc): Add code to allocate fhandler_procsys. + * fhandler.h (proc_len): Convert to size_t. + (procsys): Declare. + (procsys_len): Declare. + (enum virtual_ftype_t): Move here from fhandler_virtual.h. + Add members supported by fhandler_procsys. + (fhandler_virtual::exists): Return virtual_ftype_t. Change + in all derived classes. + (class fhandler_procsys): New class. + (fhandler_union): Add fhandler_procnet and fhandler_procsys members. + * fhandler_disk_file.cc (__DIR_mounts::check_missing_mount): Use + ro_u_proc. + (fhandler_base::fstat_by_handle): Don't copy attributes if file is an + NT device. + (fhandler_base::fstat_by_name): Ditto. + * fhandler_netdrive.cc (fhandler_netdrive::exists): Return + virtual_ftype_t. + * fhandler_proc.cc (proc_tab): Sort alphabetically. Use _VN macro + to store length. + (proc_len): Change to size_t. + (proc_tab_cmp): New static function. + (virt_tab_search): New function to search entry in virt_tab_t + arrays. Use throughout in /proc and sibling classes instead of + loop. + (fhandler_proc::exists): Return virtual_ftype_t. + * fhandler_process.cc (process_tab): Sort alphabetically. Use _VN + macro to store length. + (fhandler_process::exists): Return virtual_ftype_t. + (fhandler_process::open): Simplify code. + * fhandler_procnet.cc (procnet_tab): Sort alphabetically. Use _VN + macro to store length. + (fhandler_procnet::exists): Return virtual_ftype_t. + (fhandler_procnet::open): Simplify. + * fhandler_procsys.cc: New file. + * fhandler_registry.cc (fhandler_registry::exists): Return + virtual_ftype_t. + * fhandler_virtual.cc (fhandler_virtual::exists): Ditto. + * fhandler_virtual.h (enum virtual_ftype_t): Move to fhandler.h. + (virt_tab_t): Add name_len member. + (_VN): New macro. + (virt_tab_search): Declare. + * mount.cc (mount_info::conv_to_win32_path): Fix comment. Backslashify + isprocsys_dev paths. + * ntdll.h (STATUS_OBJECT_TYPE_MISMATCH): Define + (STATUS_INSTANCE_NOT_AVAILABLE): Define. + (STATUS_PIPE_NOT_AVAILABLE): Define. + (STATUS_INVALID_PIPE_STATE): Define. + (STATUS_PIPE_BUSY): Define. + (SYMBOLIC_LINK_QUERY): Define. + (NtOpenSymbolicLinkObject): Declare. + (NtQuerySymbolicLinkObject): Declare. + * path.cc (path_conv::check): Accommodate fact that exists method + returns virtual_ftype_t now. Add cases for new virtual_ftype_t + types. + (cygwin_conv_path): Add GLOBALROOT prefix to native device paths. + Make sure to strip \\?\ prefix only for actual filesystem-based + paths, not for all paths. + * path.h (isproc_dev): Add FH_PROCSYS. + (isprocsys_dev): Define. + 2010-09-04 Corinna Vinschen * mount.cc (mount_info::from_fstab_line): Reorder to make sure all diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in index c48914805..59f229c01 100644 --- a/winsup/cygwin/Makefile.in +++ b/winsup/cygwin/Makefile.in @@ -141,13 +141,14 @@ DLL_OFILES:=assert.o autoload.o bsdlib.o ctype.o cxx.o cygheap.o cygthread.o \ fhandler.o fhandler_clipboard.o fhandler_console.o fhandler_disk_file.o \ fhandler_dsp.o fhandler_fifo.o fhandler_floppy.o fhandler_mailslot.o \ fhandler_mem.o fhandler_netdrive.o fhandler_nodevice.o fhandler_proc.o \ - fhandler_process.o fhandler_procnet.o fhandler_random.o fhandler_raw.o \ - fhandler_registry.o fhandler_serial.o fhandler_socket.o fhandler_tape.o \ - fhandler_termios.o fhandler_tty.o fhandler_virtual.o fhandler_windows.o \ - fhandler_zero.o flock.o fnmatch.o fork.o fts.o ftw.o getopt.o glob.o \ - glob_pattern_p.o globals.o grp.o heap.o hookapi.o inet_addr.o inet_network.o \ - init.o ioctl.o ipc.o kernel32.o libstdcxx_wrapper.o localtime.o lsearch.o \ - malloc_wrapper.o minires-os-if.o minires.o miscfuncs.o mktemp.o mmap.o msg.o \ + fhandler_process.o fhandler_procnet.o fhandler_procsys.o fhandler_random.o \ + fhandler_raw.o fhandler_registry.o fhandler_serial.o fhandler_socket.o \ + fhandler_tape.o fhandler_termios.o fhandler_tty.o fhandler_virtual.o \ + fhandler_windows.o fhandler_zero.o flock.o fnmatch.o fork.o fts.o ftw.o \ + getopt.o glob.o glob_pattern_p.o globals.o grp.o heap.o hookapi.o \ + inet_addr.o inet_network.o init.o ioctl.o ipc.o kernel32.o \ + libstdcxx_wrapper.o localtime.o lsearch.o malloc_wrapper.o \ + minires-os-if.o minires.o miscfuncs.o mktemp.o mmap.o msg.o \ mount.o net.o netdb.o nfs.o nftw.o nlsfuncs.o ntea.o passwd.o path.o \ pinfo.o pipe.o poll.o posix_ipc.o pseudo-reloc.o pthread.o random.o \ regcomp.o regerror.o regexec.o regfree.o registry.o resource.o rexec.o \ diff --git a/winsup/cygwin/devices.cc b/winsup/cygwin/devices.cc index 1f4bb9529..66fe020ff 100644 --- a/winsup/cygwin/devices.cc +++ b/winsup/cygwin/devices.cc @@ -24,6 +24,9 @@ const device dev_proc_storage = const device dev_procnet_storage = {"", {FH_PROCNET}, ""}; +const device dev_procsys_storage = + {"", {FH_PROCSYS}, ""}; + const device dev_netdrive_storage = {"", {FH_NETDRIVE}, ""}; diff --git a/winsup/cygwin/devices.h b/winsup/cygwin/devices.h index d1a76a4ff..60c21a714 100644 --- a/winsup/cygwin/devices.h +++ b/winsup/cygwin/devices.h @@ -1,6 +1,6 @@ /* devices.h - Copyright 2002, 2003, 2004, 2005 Red Hat, Inc. + Copyright 2002, 2003, 2004, 2005, 2007, 2009, 2010 Red Hat, Inc. This file is part of Cygwin. @@ -53,6 +53,7 @@ enum fh_devices FH_DEV = FHDEV (0, 245), FH_PROCNET = FHDEV (0, 244), FH_PROCESSFD = FHDEV (0, 243), + FH_PROCSYS = FHDEV (0, 242), DEV_FLOPPY_MAJOR = 2, FH_FLOPPY = FHDEV (DEV_FLOPPY_MAJOR, 0), diff --git a/winsup/cygwin/devices.in b/winsup/cygwin/devices.in index bbe829683..591225e20 100644 --- a/winsup/cygwin/devices.in +++ b/winsup/cygwin/devices.in @@ -20,6 +20,9 @@ const device dev_proc_storage = const device dev_procnet_storage = {"", {FH_PROCNET}, ""}; +const device dev_procsys_storage = + {"", {FH_PROCSYS}, ""}; + const device dev_netdrive_storage = {"", {FH_NETDRIVE}, ""}; diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc index 332bc7105..6a9d55df1 100644 --- a/winsup/cygwin/dtable.cc +++ b/winsup/cygwin/dtable.cc @@ -540,6 +540,9 @@ build_fh_pc (path_conv& pc, bool set_name) case FH_PROCNET: fh = cnew (fhandler_procnet) (); break; + case FH_PROCSYS: + fh = cnew (fhandler_procsys) (); + break; case FH_NETDRIVE: fh = cnew (fhandler_netdrive) (); break; diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 54e9d0694..3fcfe1cef 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -34,7 +34,9 @@ extern const char *windows_device_names[]; extern struct __cygwin_perfile *perfile_table; #define __fmode (*(user_data->fmode_ptr)) extern const char proc[]; -extern const int proc_len; +extern const size_t proc_len; +extern const char procsys[]; +extern const size_t procsys_len; class select_record; class select_stuff; @@ -99,6 +101,20 @@ enum del_lock_called_from { after_exec }; +enum virtual_ftype_t { + virt_blk = -7, /* Block special */ + virt_chr = -6, /* Character special */ + virt_fsfile = -5, /* FS-based file via /proc/sys */ + virt_socket = -4, /* Socket */ + virt_pipe = -3, /* Pipe */ + virt_symlink = -2, /* Symlink */ + virt_file = -1, /* Regular file */ + virt_none = 0, /* Invalid, Error */ + virt_directory = 1, /* Directory */ + virt_rootdir = 2, /* Root directory of virtual FS */ + virt_fsdir = 3, /* FS-based directory via /proc/sys */ +}; + class fhandler_base { friend class dtable; @@ -1331,7 +1347,7 @@ class fhandler_virtual : public fhandler_base fhandler_virtual (); virtual ~fhandler_virtual(); - virtual int exists(); + virtual virtual_ftype_t exists(); DIR *opendir (int fd) __attribute__ ((regparm (2))); long telldir (DIR *); void seekdir (DIR *, long); @@ -1357,7 +1373,7 @@ class fhandler_proc: public fhandler_virtual { public: fhandler_proc (); - int exists(); + virtual_ftype_t exists(); int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); static DWORD get_proc_fhandler(const char *path); @@ -1366,11 +1382,30 @@ class fhandler_proc: public fhandler_virtual bool fill_filebuf (); }; +class fhandler_procsys: public fhandler_virtual +{ + public: + fhandler_procsys (); + virtual_ftype_t exists(struct __stat64 *buf) __attribute__ ((regparm (2))); + virtual_ftype_t exists(); + DIR *opendir (int fd) __attribute__ ((regparm (2))); + int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); + long telldir (DIR *); + void seekdir (DIR *, long); + int closedir (DIR *); + int open (int flags, mode_t mode = 0); + int close (); + void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3))); + ssize_t __stdcall write (const void *ptr, size_t len); + int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2))); + bool fill_filebuf (); +}; + class fhandler_netdrive: public fhandler_virtual { public: fhandler_netdrive (); - int exists(); + virtual_ftype_t exists(); int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); void seekdir (DIR *, long); void rewinddir (DIR *); @@ -1388,7 +1423,7 @@ class fhandler_registry: public fhandler_proc public: fhandler_registry (); void set_name (path_conv &pc); - int exists(); + virtual_ftype_t exists(); int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); long telldir (DIR *); void seekdir (DIR *, long); @@ -1408,7 +1443,7 @@ class fhandler_process: public fhandler_proc pid_t pid; public: fhandler_process (); - int exists(); + virtual_ftype_t exists(); DIR *opendir (int fd) __attribute__ ((regparm (2))); int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); int open (int flags, mode_t mode = 0); @@ -1421,7 +1456,7 @@ class fhandler_procnet: public fhandler_proc pid_t pid; public: fhandler_procnet (); - int exists(); + virtual_ftype_t exists(); int readdir (DIR *, dirent *) __attribute__ ((regparm (3))); int open (int flags, mode_t mode = 0); int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2))); @@ -1462,6 +1497,8 @@ typedef union char __pipe[sizeof (fhandler_pipe)]; char __proc[sizeof (fhandler_proc)]; char __process[sizeof (fhandler_process)]; + char __procnet[sizeof (fhandler_procnet)]; + char __procsys[sizeof (fhandler_procsys)]; char __pty_master[sizeof (fhandler_pty_master)]; char __registry[sizeof (fhandler_registry)]; char __serial[sizeof (fhandler_serial)]; diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 02ce90e61..1d7675c34 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -118,7 +118,7 @@ public: { found[__DIR_PROC] = true; if (retname) - RtlInitUnicodeString (retname, L"proc"); + *retname = ro_u_proc; return 2; } if (!found[__DIR_CYGDRIVE]) @@ -407,7 +407,9 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) entry, as in other calls to fstat_helper. */ if (pc.is_rep_symlink ()) fi.fbi.FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY; - pc.file_attributes (fi.fbi.FileAttributes); + /* Only copy attributes if not a device root dir. */ + if (!(pc.file_attributes () & FILE_ATTRIBUTE_DEVICE)) + pc.file_attributes (fi.fbi.FileAttributes); return fstat_helper (buf, fi.fbi.ChangeTime.QuadPart ? &fi.fbi.ChangeTime : &fi.fbi.LastWriteTime, @@ -474,7 +476,9 @@ fhandler_base::fstat_by_name (struct __stat64 *buf) entry, as in other calls to fstat_helper. */ if (pc.is_rep_symlink ()) fdi_buf.fdi.FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY; - pc.file_attributes (fdi_buf.fdi.FileAttributes); + /* Only copy attributes if not a device root dir. */ + if (!(pc.file_attributes () & FILE_ATTRIBUTE_DEVICE)) + pc.file_attributes (fdi_buf.fdi.FileAttributes); return fstat_helper (buf, fdi_buf.fdi.ChangeTime.QuadPart ? &fdi_buf.fdi.ChangeTime : &fdi_buf.fdi.LastWriteTime, diff --git a/winsup/cygwin/fhandler_netdrive.cc b/winsup/cygwin/fhandler_netdrive.cc index 47971526a..94071de00 100644 --- a/winsup/cygwin/fhandler_netdrive.cc +++ b/winsup/cygwin/fhandler_netdrive.cc @@ -145,14 +145,14 @@ create_thread_and_wait (int what, PVOID in, PVOID out, DWORD outsize, /* Returns 0 if path doesn't exist, >0 if path is a directory, -1 if path is a file, -2 if it's a symlink. */ -int +virtual_ftype_t fhandler_netdrive::exists () { char *to; const char *from; size_t len = strlen (get_name ()); if (len == 2) - return 1; + return virt_rootdir; char namebuf[len + 1]; for (to = namebuf, from = get_name (); *from; to++, from++) *to = (*from == '/') ? '\\' : *from; @@ -166,7 +166,7 @@ fhandler_netdrive::exists () &nr, &nh, 0, "WNetOpenEnum"); if (nh.dom) WNetCloseEnum (nh.dom); - return ret != NO_ERROR ? 0 : 1; + return ret != NO_ERROR ? virt_none : virt_directory; } fhandler_netdrive::fhandler_netdrive (): diff --git a/winsup/cygwin/fhandler_proc.cc b/winsup/cygwin/fhandler_proc.cc index 3289acb15..df381127a 100644 --- a/winsup/cygwin/fhandler_proc.cc +++ b/winsup/cygwin/fhandler_proc.cc @@ -46,23 +46,24 @@ static _off64_t format_proc_filesystems (void *, char *&); /* names of objects in /proc */ static const virt_tab_t proc_tab[] = { - { ".", FH_PROC, virt_directory, NULL }, - { "..", FH_PROC, virt_directory, NULL }, - { "loadavg", FH_PROC, virt_file, format_proc_loadavg }, - { "meminfo", FH_PROC, virt_file, format_proc_meminfo }, - { "registry", FH_REGISTRY, virt_directory, NULL }, - { "stat", FH_PROC, virt_file, format_proc_stat }, - { "version", FH_PROC, virt_file, format_proc_version }, - { "uptime", FH_PROC, virt_file, format_proc_uptime }, - { "cpuinfo", FH_PROC, virt_file, format_proc_cpuinfo }, - { "partitions", FH_PROC, virt_file, format_proc_partitions }, - { "self", FH_PROC, virt_symlink, format_proc_self }, - { "mounts", FH_PROC, virt_symlink, format_proc_mounts }, - { "registry32", FH_REGISTRY, virt_directory, NULL }, - { "registry64", FH_REGISTRY, virt_directory, NULL }, - { "net", FH_PROCNET, virt_directory, NULL }, - { "filesystems", FH_PROC, virt_file, format_proc_filesystems }, - { NULL, 0, virt_none, NULL } + { _VN ("."), FH_PROC, virt_directory, NULL }, + { _VN (".."), FH_PROC, virt_directory, NULL }, + { _VN ("cpuinfo"), FH_PROC, virt_file, format_proc_cpuinfo }, + { _VN ("filesystems"), FH_PROC, virt_file, format_proc_filesystems }, + { _VN ("loadavg"), FH_PROC, virt_file, format_proc_loadavg }, + { _VN ("meminfo"), FH_PROC, virt_file, format_proc_meminfo }, + { _VN ("mounts"), FH_PROC, virt_symlink, format_proc_mounts }, + { _VN ("net"), FH_PROCNET, virt_directory, NULL }, + { _VN ("partitions"), FH_PROC, virt_file, format_proc_partitions }, + { _VN ("registry"), FH_REGISTRY, virt_directory, NULL }, + { _VN ("registry32"), FH_REGISTRY, virt_directory, NULL }, + { _VN ("registry64"), FH_REGISTRY, virt_directory, NULL }, + { _VN ("self"), FH_PROC, virt_symlink, format_proc_self }, + { _VN ("stat"), FH_PROC, virt_file, format_proc_stat }, + { _VN ("sys"), FH_PROCSYS, virt_directory, NULL }, + { _VN ("uptime"), FH_PROC, virt_file, format_proc_uptime }, + { _VN ("version"), FH_PROC, virt_file, format_proc_version }, + { NULL, 0, 0, virt_none, NULL } }; #define PROC_DIR_COUNT 4 @@ -71,11 +72,37 @@ static const int PROC_LINK_COUNT = (sizeof (proc_tab) / sizeof (virt_tab_t)) - 1 /* name of the /proc filesystem */ const char proc[] = "/proc"; -const int proc_len = sizeof (proc) - 1; +const size_t proc_len = sizeof (proc) - 1; -/* Auxillary function that returns the fhandler associated with the given path - this is where it would be nice to have pattern matching in C - polymorphism - just doesn't cut it. */ +/* bsearch compare function. */ +static int +proc_tab_cmp (const void *key, const void *memb) +{ + int ret = strncmp (((virt_tab_t *) key)->name, ((virt_tab_t *) memb)->name, + ((virt_tab_t *) memb)->name_len); + if (!ret && ((virt_tab_t *) key)->name[((virt_tab_t *) memb)->name_len] != '\0' && ((virt_tab_t *) key)->name[((virt_tab_t *) memb)->name_len] != '/') + return 1; + return ret; +} + +/* Helper function to perform a binary search of the incoming pathname + against the alpha-sorted virtual file table. */ +virt_tab_t * +virt_tab_search (const char *path, bool prefix, const virt_tab_t *table, + size_t nelem) +{ + virt_tab_t key = { path, 0, 0, virt_none, NULL }; + virt_tab_t *entry = (virt_tab_t *) bsearch (&key, table, nelem, + sizeof (virt_tab_t), + proc_tab_cmp); + if (entry && (path[entry->name_len] == '\0' + || (prefix && path[entry->name_len] == '/'))) + return entry; + return NULL; +} + +/* Auxillary function that returns the fhandler associated with the given + path. */ DWORD fhandler_proc::get_proc_fhandler (const char *path) { @@ -91,12 +118,10 @@ fhandler_proc::get_proc_fhandler (const char *path) if (*path == 0) return FH_PROC; - for (int i = 0; proc_tab[i].name; i++) - { - if (path_prefix_p (proc_tab[i].name, path, strlen (proc_tab[i].name), - false)) - return proc_tab[i].fhandler; - } + virt_tab_t *entry = virt_tab_search (path, true, proc_tab, + PROC_LINK_COUNT); + if (entry) + return entry->fhandler; if (pinfo (atoi (path))) return FH_PROCESS; @@ -120,7 +145,7 @@ fhandler_proc::get_proc_fhandler (const char *path) /* Returns 0 if path doesn't exist, >0 if path is a directory, -1 if path is a file, -2 if it's a symlink. */ -int +virtual_ftype_t fhandler_proc::exists () { const char *path = get_name (); @@ -128,12 +153,13 @@ fhandler_proc::exists () path += proc_len; if (*path == 0) return virt_rootdir; - for (int i = 0; proc_tab[i].name; i++) - if (!strcmp (path + 1, proc_tab[i].name)) - { - fileid = i; - return proc_tab[i].type; - } + virt_tab_t *entry = virt_tab_search (path + 1, false, proc_tab, + PROC_LINK_COUNT); + if (entry) + { + fileid = entry - proc_tab; + return entry->type; + } return virt_none; } @@ -163,21 +189,21 @@ fhandler_proc::fstat (struct __stat64 *buf) } else { - path++; - for (int i = 0; proc_tab[i].name; i++) - if (!strcmp (path, proc_tab[i].name)) - { - if (proc_tab[i].type == virt_directory) - buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; - else if (proc_tab[i].type == virt_symlink) - buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; - else - { - buf->st_mode &= NO_X; - buf->st_mode |= S_IFREG; - } - return 0; - } + virt_tab_t *entry = virt_tab_search (path + 1, false, proc_tab, + PROC_LINK_COUNT); + if (entry) + { + if (entry->type == virt_directory) + buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; + else if (entry->type == virt_symlink) + buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; + else + { + buf->st_mode &= NO_X; + buf->st_mode |= S_IFREG; + } + return 0; + } } set_errno (ENOENT); return -1; diff --git a/winsup/cygwin/fhandler_process.cc b/winsup/cygwin/fhandler_process.cc index 83b69b84a..b2fa5f771 100644 --- a/winsup/cygwin/fhandler_process.cc +++ b/winsup/cygwin/fhandler_process.cc @@ -53,28 +53,28 @@ static _off64_t format_process_mounts (void *, char *&); static const virt_tab_t process_tab[] = { - { ".", FH_PROCESS, virt_directory, NULL }, - { "..", FH_PROCESS, virt_directory, NULL }, - { "ppid", FH_PROCESS, virt_file, format_process_ppid }, - { "winpid", FH_PROCESS, virt_file, format_process_winpid }, - { "winexename", FH_PROCESS, virt_file, format_process_winexename }, - { "status", FH_PROCESS, virt_file, format_process_status }, - { "uid", FH_PROCESS, virt_file, format_process_uid }, - { "gid", FH_PROCESS, virt_file, format_process_gid }, - { "pgid", FH_PROCESS, virt_file, format_process_pgid }, - { "sid", FH_PROCESS, virt_file, format_process_sid }, - { "ctty", FH_PROCESS, virt_file, format_process_ctty }, - { "stat", FH_PROCESS, virt_file, format_process_stat }, - { "statm", FH_PROCESS, virt_file, format_process_statm }, - { "cmdline", FH_PROCESS, virt_file, format_process_cmdline }, - { "maps", FH_PROCESS, virt_file, format_process_maps }, - { "fd", FH_PROCESSFD, virt_directory, format_process_fd }, - { "exename", FH_PROCESS, virt_file, format_process_exename }, - { "root", FH_PROCESS, virt_symlink, format_process_root }, - { "exe", FH_PROCESS, virt_symlink, format_process_exename }, - { "cwd", FH_PROCESS, virt_symlink, format_process_cwd }, - { "mounts", FH_PROCESS, virt_file, format_process_mounts }, - { NULL, 0, virt_none, NULL } + { _VN ("."), FH_PROCESS, virt_directory, NULL }, + { _VN (".."), FH_PROCESS, virt_directory, NULL }, + { _VN ("cmdline"), FH_PROCESS, virt_file, format_process_cmdline }, + { _VN ("ctty"), FH_PROCESS, virt_file, format_process_ctty }, + { _VN ("cwd"), FH_PROCESS, virt_symlink, format_process_cwd }, + { _VN ("exe"), FH_PROCESS, virt_symlink, format_process_exename }, + { _VN ("exename"), FH_PROCESS, virt_file, format_process_exename }, + { _VN ("fd"), FH_PROCESSFD, virt_directory, format_process_fd }, + { _VN ("gid"), FH_PROCESS, virt_file, format_process_gid }, + { _VN ("maps"), FH_PROCESS, virt_file, format_process_maps }, + { _VN ("mounts"), FH_PROCESS, virt_file, format_process_mounts }, + { _VN ("pgid"), FH_PROCESS, virt_file, format_process_pgid }, + { _VN ("ppid"), FH_PROCESS, virt_file, format_process_ppid }, + { _VN ("root"), FH_PROCESS, virt_symlink, format_process_root }, + { _VN ("sid"), FH_PROCESS, virt_file, format_process_sid }, + { _VN ("stat"), FH_PROCESS, virt_file, format_process_stat }, + { _VN ("statm"), FH_PROCESS, virt_file, format_process_statm }, + { _VN ("status"), FH_PROCESS, virt_file, format_process_status }, + { _VN ("uid"), FH_PROCESS, virt_file, format_process_uid }, + { _VN ("winexename"), FH_PROCESS, virt_file, format_process_winexename }, + { _VN ("winpid"), FH_PROCESS, virt_file, format_process_winpid }, + { NULL, 0, 0, virt_none, NULL } }; static const int PROCESS_LINK_COUNT = @@ -90,7 +90,7 @@ static bool get_mem_values (DWORD dwProcessId, unsigned long *vmsize, * -1 if path is a file, -2 if path is a symlink, -3 if path is a pipe, * -4 if path is a socket. */ -int +virtual_ftype_t fhandler_process::exists () { const char *path = get_name (); @@ -99,21 +99,20 @@ fhandler_process::exists () while (*path != 0 && !isdirsep (*path)) path++; if (*path == 0) - return 2; + return virt_rootdir; - for (int i = 0; process_tab[i].name; i++) + virt_tab_t *entry = virt_tab_search (path + 1, true, process_tab, + PROCESS_LINK_COUNT); + if (entry) { - if (!strcmp (path + 1, process_tab[i].name)) + if (!path[entry->name_len + 1]) { - fileid = i; - return process_tab[i].type; + fileid = entry - process_tab; + return entry->type; } - if (process_tab[i].type == virt_directory - && !strncmp (path + 1, process_tab[i].name, - strlen (process_tab[i].name)) - && path[1 + strlen (process_tab[i].name)] == '/') + if (entry->type == virt_directory) { - fileid = i; + fileid = entry - process_tab; if (fill_filebuf ()) return virt_symlink; /* Check for nameless device entries. */ @@ -232,8 +231,6 @@ out: int fhandler_process::open (int flags, mode_t mode) { - int process_file_no = -1; - int res = fhandler_virtual::open (flags, mode); if (!res) goto out; @@ -267,29 +264,15 @@ fhandler_process::open (int flags, mode_t mode) } } - process_file_no = -1; - for (int i = 0; process_tab[i].name; i++) + virt_tab_t *entry; + entry = virt_tab_search (path + 1, true, process_tab, PROCESS_LINK_COUNT); + if (!entry) { - if (path_prefix_p (process_tab[i].name, path + 1, - strlen (process_tab[i].name), false)) - process_file_no = i; + set_errno ((flags & O_CREAT) ? EROFS : ENOENT); + res = 0; + goto out; } - if (process_file_no == -1) - { - if (flags & O_CREAT) - { - set_errno (EROFS); - res = 0; - goto out; - } - else - { - set_errno (ENOENT); - res = 0; - goto out; - } - } - if (process_tab[process_file_no].fhandler == FH_PROCESSFD) + if (entry->fhandler == FH_PROCESSFD) { flags |= O_DIROPEN; goto success; @@ -301,7 +284,7 @@ fhandler_process::open (int flags, mode_t mode) goto out; } - fileid = process_file_no; + fileid = entry - process_tab; if (!fill_filebuf ()) { res = 0; diff --git a/winsup/cygwin/fhandler_procnet.cc b/winsup/cygwin/fhandler_procnet.cc index 3cf29dd6c..607c9d4ff 100644 --- a/winsup/cygwin/fhandler_procnet.cc +++ b/winsup/cygwin/fhandler_procnet.cc @@ -39,10 +39,10 @@ static _off64_t format_procnet_ifinet6 (void *, char *&); static const virt_tab_t procnet_tab[] = { - { ".", FH_PROCNET, virt_directory, NULL }, - { "..", FH_PROCNET, virt_directory, NULL }, - { "if_inet6", FH_PROCNET, virt_file, format_procnet_ifinet6 }, - { NULL, 0, virt_none, NULL } + { _VN ("."), FH_PROCNET, virt_directory, NULL }, + { _VN (".."), FH_PROCNET, virt_directory, NULL }, + { _VN ("if_inet6"), FH_PROCNET, virt_file, format_procnet_ifinet6 }, + { NULL, 0, 0, virt_none, NULL } }; static const int PROCNET_LINK_COUNT = @@ -52,7 +52,7 @@ static const int PROCNET_LINK_COUNT = * -1 if path is a file, -2 if path is a symlink, -3 if path is a pipe, * -4 if path is a socket. */ -int +virtual_ftype_t fhandler_procnet::exists () { const char *path = get_name (); @@ -61,20 +61,21 @@ fhandler_procnet::exists () while (*path != 0 && !isdirsep (*path)) path++; if (*path == 0) - return 1; + return virt_rootdir; - for (int i = 0; procnet_tab[i].name; i++) - if (!strcmp (path + 1, procnet_tab[i].name)) - { - if (procnet_tab[i].type == virt_file) - { - if (!wincap.has_gaa_prefixes () - || !get_adapters_addresses (NULL, AF_INET6)) - return virt_none; - } - fileid = i; - return procnet_tab[i].type; - } + virt_tab_t *entry = virt_tab_search (path + 1, false, procnet_tab, + PROCNET_LINK_COUNT); + if (entry) + { + if (entry->type == virt_file) + { + if (!wincap.has_gaa_prefixes () + || !get_adapters_addresses (NULL, AF_INET6)) + return virt_none; + } + fileid = entry - procnet_tab; + return entry->type; + } return virt_none; } @@ -129,8 +130,6 @@ out: int fhandler_procnet::open (int flags, mode_t mode) { - int process_file_no = -1; - int res = fhandler_virtual::open (flags, mode); if (!res) goto out; @@ -163,27 +162,13 @@ fhandler_procnet::open (int flags, mode_t mode) } } - process_file_no = -1; - for (int i = 0; procnet_tab[i].name; i++) + virt_tab_t *entry; + entry = virt_tab_search (path + 1, true, procnet_tab, PROCNET_LINK_COUNT); + if (!entry) { - if (path_prefix_p (procnet_tab[i].name, path + 1, - strlen (procnet_tab[i].name), false)) - process_file_no = i; - } - if (process_file_no == -1) - { - if (flags & O_CREAT) - { - set_errno (EROFS); - res = 0; - goto out; - } - else - { - set_errno (ENOENT); - res = 0; - goto out; - } + set_errno ((flags & O_CREAT) ? EROFS : ENOENT); + res = 0; + goto out; } if (flags & O_WRONLY) { @@ -192,7 +177,7 @@ fhandler_procnet::open (int flags, mode_t mode) goto out; } - fileid = process_file_no; + fileid = entry - procnet_tab; if (!fill_filebuf ()) { res = 0; diff --git a/winsup/cygwin/fhandler_procsys.cc b/winsup/cygwin/fhandler_procsys.cc new file mode 100644 index 000000000..aa0b6b699 --- /dev/null +++ b/winsup/cygwin/fhandler_procsys.cc @@ -0,0 +1,422 @@ +/* fhandler_procsys.cc: fhandler for native NT namespace. + + Copyright 2010 Red Hat, Inc. + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#include "winsup.h" +#include +#include "cygerrno.h" +#include "security.h" +#include "path.h" +#include "fhandler.h" +#include "dtable.h" +#include "cygheap.h" +#include +#include "ntdll.h" +#include "tls_pbuf.h" + +#include + +/* Path of the /proc/sys filesystem */ +const char procsys[] = "/proc/sys"; +const size_t procsys_len = sizeof (procsys) - 1; + +#define mk_unicode_path(p) \ + WCHAR namebuf[strlen (get_name ()) + 1]; \ + { \ + const char *from; \ + PWCHAR to; \ + for (to = namebuf, from = get_name () + procsys_len; *from; \ + to++, from++) \ + /* The NT device namespace is ASCII only. */ \ + *to = (*from == '/') ? L'\\' : (WCHAR) *from; \ + if (to == namebuf) \ + *to++ = L'\\'; \ + *to = L'\0'; \ + RtlInitUnicodeString ((p), namebuf); \ + } + +/* Returns 0 if path doesn't exist, >0 if path is a directory, + -1 if path is a file, -2 if it's a symlink. */ +virtual_ftype_t +fhandler_procsys::exists (struct __stat64 *buf) +{ + UNICODE_STRING path; \ + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + NTSTATUS status; + HANDLE h; + FILE_BASIC_INFORMATION fbi; + virtual_ftype_t file_type = virt_chr; + + if (strlen (get_name ()) == procsys_len) + return virt_rootdir; + mk_unicode_path (&path); + /* First try to open as file/device to get more info. */ + InitializeObjectAttributes (&attr, &path, OBJ_CASE_INSENSITIVE, NULL, NULL); + status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES, &attr, &io, + FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT); + if (status == STATUS_OBJECT_PATH_NOT_FOUND) + return virt_none; + /* If the name isn't found, or we get this dreaded sharing violation, let + the caller try again as normal file. */ + if (status == STATUS_OBJECT_NAME_NOT_FOUND + || status == STATUS_NO_MEDIA_IN_DEVICE + || status == STATUS_SHARING_VIOLATION) + return virt_fsfile; /* Just try again as normal file. */ + /* Check for pipe errors, which make a good hint... */ + if (status >= STATUS_PIPE_NOT_AVAILABLE && status <= STATUS_PIPE_BUSY) + file_type = virt_pipe; + else if (status == STATUS_ACCESS_DENIED) + { + /* Check if this is just some file or dir on a real FS to circumvent + most permission problems. */ + status = NtQueryAttributesFile (&attr, &fbi); + if (NT_SUCCESS (status)) + return (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ? virt_fsdir : virt_fsfile; + } + else if (NT_SUCCESS (status)) + { + NTSTATUS dev_stat; + FILE_FS_DEVICE_INFORMATION ffdi; + + /* If requested, check permissions. */ + if (buf) + get_object_attribute (h, &buf->st_uid, &buf->st_gid, &buf->st_mode); + /* Check for the device type. */ + dev_stat = NtQueryVolumeInformationFile (h, &io, &ffdi, sizeof ffdi, + FileFsDeviceInformation); + /* And check for file attributes. If we get them, we peeked into + a real FS through /proc/sys. */ + status = NtQueryInformationFile (h, &io, &fbi, sizeof fbi, + FileBasicInformation); + NtClose (h); + if (NT_SUCCESS (dev_stat)) + { + if (ffdi.DeviceType == FILE_DEVICE_NAMED_PIPE) + file_type = NT_SUCCESS (status) ? virt_pipe : virt_blk; + else if (NT_SUCCESS (status)) + file_type = (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ? virt_fsdir : virt_fsfile; + else if (ffdi.DeviceType == FILE_DEVICE_DISK + || ffdi.DeviceType == FILE_DEVICE_CD_ROM + || ffdi.DeviceType == FILE_DEVICE_DFS + || ffdi.DeviceType == FILE_DEVICE_VIRTUAL_DISK) + file_type = virt_blk; + } + } + /* Then check if it's a symlink. */ + status = NtOpenSymbolicLinkObject (&h, READ_CONTROL | SYMBOLIC_LINK_QUERY, + &attr); + if (NT_SUCCESS (status)) + { + /* If requested, check permissions. */ + if (buf) + get_object_attribute (h, &buf->st_uid, &buf->st_gid, &buf->st_mode); + NtClose (h); + return virt_symlink; + } + /* Eventually, test if it's an object directory. */ + status = NtOpenDirectoryObject (&h, READ_CONTROL | DIRECTORY_QUERY, &attr); + if (NT_SUCCESS (status)) + { + /* If requested, check permissions. */ + if (buf) + get_object_attribute (h, &buf->st_uid, &buf->st_gid, &buf->st_mode); + NtClose (h); + return virt_directory; + } + else if (status == STATUS_ACCESS_DENIED) + return virt_directory; + /* Give up. Just treat as character device. */ + return file_type; +} + +virtual_ftype_t +fhandler_procsys::exists () +{ + return exists (NULL); +} + +fhandler_procsys::fhandler_procsys (): + fhandler_virtual () +{ +} + +bool +fhandler_procsys::fill_filebuf () +{ + /* The NT device namespace is ASCII only. */ + char *fnamep; + UNICODE_STRING path, target; + OBJECT_ATTRIBUTES attr; + NTSTATUS status; + HANDLE h; + tmp_pathbuf tp; + + mk_unicode_path (&path); + if (path.Buffer[path.Length / sizeof (WCHAR) - 1] == L'\\') + path.Length -= sizeof (WCHAR); + InitializeObjectAttributes (&attr, &path, OBJ_CASE_INSENSITIVE, NULL, NULL); + status = NtOpenSymbolicLinkObject (&h, SYMBOLIC_LINK_QUERY, &attr); + if (!NT_SUCCESS (status)) + return false; + RtlInitEmptyUnicodeString (&target, tp.w_get (), + (NT_MAX_PATH - 1) * sizeof (WCHAR)); + status = NtQuerySymbolicLinkObject (h, &target, NULL); + NtClose (h); + if (!NT_SUCCESS (status)) + return false; + size_t len = sys_wcstombs (NULL, 0, target.Buffer, + target.Length / sizeof (WCHAR)); + filebuf = (char *) crealloc_abort (filebuf, procsys_len + len + 1); + sys_wcstombs (fnamep = stpcpy (filebuf, procsys), len + 1, target.Buffer, + target.Length / sizeof (WCHAR)); + while ((fnamep = strchr (fnamep, '\\'))) + *fnamep = '/'; + return true; +} + +int +fhandler_procsys::fstat (struct __stat64 *buf) +{ + const char *path = get_name (); + debug_printf ("fstat (%s)", path); + + fhandler_base::fstat (buf); + /* Best bet. */ + buf->st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; + buf->st_uid = 544; + buf->st_gid = 18; + buf->st_dev = buf->st_rdev = dev ().devn; + buf->st_ino = get_ino (); + switch (exists (buf)) + { + case virt_directory: + case virt_rootdir: + case virt_fsdir: + buf->st_mode |= S_IFDIR; + if (buf->st_mode & S_IRUSR) + buf->st_mode |= S_IXUSR; + if (buf->st_mode & S_IRGRP) + buf->st_mode |= S_IXGRP; + if (buf->st_mode & S_IROTH) + buf->st_mode |= S_IXOTH; + break; + case virt_file: + case virt_fsfile: + buf->st_mode |= S_IFREG; + break; + case virt_symlink: + buf->st_mode |= S_IFLNK; + break; + case virt_pipe: + buf->st_mode |= S_IFIFO; + break; + case virt_socket: + buf->st_mode |= S_IFSOCK; + break; + case virt_chr: + buf->st_mode |= S_IFCHR; + break; + case virt_blk: + buf->st_mode |= S_IFBLK; + break; + default: + set_errno (ENOENT); + return -1; + } + return 0; +} + +DIR * +fhandler_procsys::opendir (int fd) +{ + UNICODE_STRING path; + OBJECT_ATTRIBUTES attr; + NTSTATUS status; + HANDLE h; + DIR *dir = fhandler_virtual::opendir (fd); + + mk_unicode_path (&path); + InitializeObjectAttributes (&attr, &path, OBJ_CASE_INSENSITIVE, NULL, NULL); + status = NtOpenDirectoryObject (&h, DIRECTORY_QUERY, &attr); + if (!NT_SUCCESS (status)) + { + free (dir); + __seterrno_from_nt_status (status); + return NULL; + } + dir->__handle = h; + return dir; +} + +int +fhandler_procsys::readdir (DIR *dir, dirent *de) +{ + NTSTATUS status; + struct fdbi + { + DIRECTORY_BASIC_INFORMATION dbi; + WCHAR buf[2][NAME_MAX + 1]; + } f; + int res = EBADF; + + if (dir->__handle != INVALID_HANDLE_VALUE) + { + BOOLEAN restart = dir->__d_position ? FALSE : TRUE; + status = NtQueryDirectoryObject (dir->__handle, &f, sizeof f, TRUE, + restart, (PULONG) &dir->__d_position, + NULL); + if (!NT_SUCCESS (status)) + res = ENMFILE; + else + { + sys_wcstombs (de->d_name, NAME_MAX + 1, f.dbi.ObjectName.Buffer, + f.dbi.ObjectName.Length / sizeof (WCHAR)); + de->d_ino = hash_path_name (get_ino (), de->d_name); + de->d_type = 0; + res = 0; + } + } + syscall_printf ("%d = readdir (%p, %p)", res, dir, de); + return res; +} + +long +fhandler_procsys::telldir (DIR *dir) +{ + return dir->__d_position; +} + +void +fhandler_procsys::seekdir (DIR *dir, long pos) +{ + dir->__d_position = pos; +} + +int +fhandler_procsys::closedir (DIR *dir) +{ + if (dir->__handle != INVALID_HANDLE_VALUE) + { + NtClose (dir->__handle); + dir->__handle = INVALID_HANDLE_VALUE; + } + return fhandler_virtual::closedir (dir); +} + +void __stdcall +fhandler_procsys::read (void *ptr, size_t& len) +{ + NTSTATUS status; + IO_STATUS_BLOCK io; + LARGE_INTEGER off = { QuadPart:0LL }; + + status = NtReadFile (get_handle (), NULL, NULL, NULL, &io, ptr, len, + &off, NULL); + if (!NT_SUCCESS (status)) + { + __seterrno_from_nt_status (status); + len = -1; + } + else + len = io.Information; +} + +ssize_t __stdcall +fhandler_procsys::write (const void *ptr, size_t len) +{ + return fhandler_base::raw_write (ptr, len); +} + +int +fhandler_procsys::open (int flags, mode_t mode) +{ + UNICODE_STRING path; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + NTSTATUS status; + HANDLE h; + ULONG access; + ULONG options = FILE_OPEN_FOR_BACKUP_INTENT; + + + int res = fhandler_virtual::open (flags, mode); + if (!res) + goto out; + + if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL) || (flags & O_TRUNC)) + { + set_errno (EINVAL); + res = 0; + goto out; + } + mk_unicode_path (&path); + InitializeObjectAttributes (&attr, &path, OBJ_INHERIT | OBJ_CASE_INSENSITIVE, + NULL, NULL); + switch (exists ()) + { + case virt_directory: + case virt_rootdir: + if ((flags & O_ACCMODE) != O_RDONLY) + { + set_errno (EISDIR); + res = 0; + goto out; + } + nohandle (true); + res = 1; + goto out; + default: + break; + } + if ((flags & O_ACCMODE) == O_RDONLY) + access = GENERIC_READ; + else if ((flags & O_ACCMODE) == O_WRONLY) + access = GENERIC_WRITE | READ_CONTROL | FILE_READ_ATTRIBUTES; + else + access = GENERIC_READ | GENERIC_WRITE; + if (flags & O_SYNC) + options |= FILE_WRITE_THROUGH; + if (flags & O_DIRECT) + options |= FILE_NO_INTERMEDIATE_BUFFERING; + if (!(flags & O_NONBLOCK)) + { + access |= SYNCHRONIZE; + options |= FILE_SYNCHRONOUS_IO_NONALERT; + } + status = NtOpenFile (&h, access, &attr, &io, FILE_SHARE_VALID_FLAGS, options); + if (!NT_SUCCESS (status)) + { + __seterrno_from_nt_status (status); + res = 0; + goto out; + } + set_io_handle (h); + set_open_status (); + res = 1; +out: + syscall_printf ("%d = fhandler_procsys::open (%p, %d)", res, flags, mode); + return res; +} + +int +fhandler_procsys::close () +{ + if (!nohandle ()) + NtClose (get_handle ()); + return fhandler_virtual::close (); +} +#if 0 +int +fhandler_procsys::ioctl (unsigned int cmd, void *) +{ +} +#endif diff --git a/winsup/cygwin/fhandler_registry.cc b/winsup/cygwin/fhandler_registry.cc index 478b9cca4..b9c9a8ea5 100644 --- a/winsup/cygwin/fhandler_registry.cc +++ b/winsup/cygwin/fhandler_registry.cc @@ -268,10 +268,11 @@ multi_wcstombs (char *dst, size_t len, const wchar_t *src, size_t nwc) * final component is there. This gets round the problem of not having security access * to the final key in the path. */ -int +virtual_ftype_t fhandler_registry::exists () { - int file_type = 0, index = 0, pathlen; + virtual_ftype_t file_type = virt_none; + int index = 0, pathlen; DWORD buf_size = NAME_MAX + 1; LONG error; wchar_t buf[buf_size]; @@ -285,7 +286,7 @@ fhandler_registry::exists () path++; else { - file_type = 2; + file_type = virt_rootdir; goto out; } pathlen = strlen (path); @@ -302,7 +303,7 @@ fhandler_registry::exists () if (path_prefix_p (registry_listing[i], path, strlen (registry_listing[i]), true)) { - file_type = 1; + file_type = virt_directory; break; } } @@ -317,12 +318,12 @@ fhandler_registry::exists () if (!val_only) hKey = open_key (path, KEY_READ, wow64, false); if (hKey != (HKEY) INVALID_HANDLE_VALUE || get_errno () == EACCES) - file_type = 1; + file_type = virt_directory; else { hKey = open_key (path, KEY_READ, wow64, true); if (hKey == (HKEY) INVALID_HANDLE_VALUE) - return 0; + return virt_none; if (hKey == HKEY_PERFORMANCE_DATA) { @@ -332,13 +333,14 @@ fhandler_registry::exists () So allow access to the generic names and to (blank separated) lists of counter numbers. Never allow access to "Add", see above comment. */ - for (int i = 0; i < PERF_DATA_FILE_COUNT && file_type == 0; i++) + for (int i = 0; i < PERF_DATA_FILE_COUNT + && file_type == virt_none; i++) { if (strcasematch (perf_data_files[i], file)) - file_type = -1; + file_type = virt_file; } - if (file_type == 0 && !file[strspn (file, " 0123456789")]) - file_type = -1; + if (file_type == virt_none && !file[strspn (file, " 0123456789")]) + file_type = virt_file; goto out; } @@ -351,7 +353,7 @@ fhandler_registry::exists () { if (!wcscasecmp (buf, dec_file)) { - file_type = 1; + file_type = virt_directory; goto out; } buf_size = NAME_MAX + 1; @@ -372,7 +374,7 @@ fhandler_registry::exists () { if (!wcscasecmp (buf, dec_file)) { - file_type = -1; + file_type = virt_file; goto out; } buf_size = NAME_MAX + 1; @@ -418,32 +420,32 @@ fhandler_registry::fstat (struct __stat64 *buf) { fhandler_base::fstat (buf); buf->st_mode &= ~_IFMT & NO_W; - int file_type = exists (); + virtual_ftype_t file_type = exists (); switch (file_type) { - case 0: + case virt_none: set_errno (ENOENT); return -1; - case 1: + case virt_directory: buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; break; - case 2: + case virt_rootdir: buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH; buf->st_nlink = ROOT_KEY_COUNT; break; default: - case -1: + case virt_file: buf->st_mode |= S_IFREG; buf->st_mode &= NO_X; break; } - if (file_type != 0 && file_type != 2) + if (file_type != virt_none && file_type != virt_rootdir) { HKEY hKey; const char *path = get_name () + proc_len + prefix_len + 2; hKey = open_key (path, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE, wow64, - (file_type < 0) ? true : false); + (file_type < virt_none) ? true : false); if (hKey == HKEY_PERFORMANCE_DATA) /* RegQueryInfoKey () always returns write time 0, @@ -461,7 +463,7 @@ fhandler_registry::fstat (struct __stat64 *buf) to_timestruc_t (&ftLastWriteTime, &buf->st_mtim); buf->st_ctim = buf->st_birthtim = buf->st_mtim; time_as_timestruc_t (&buf->st_atim); - if (file_type > 0) + if (file_type > virt_none) buf->st_nlink = subkey_count + 2; else { @@ -508,7 +510,7 @@ fhandler_registry::fstat (struct __stat64 *buf) buf->st_uid = uid; buf->st_gid = gid; buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); - if (file_type > 0) + if (file_type > virt_none) buf->st_mode |= S_IFDIR; else buf->st_mode &= NO_X; diff --git a/winsup/cygwin/fhandler_virtual.cc b/winsup/cygwin/fhandler_virtual.cc index 3becf03e9..6d515a3a7 100644 --- a/winsup/cygwin/fhandler_virtual.cc +++ b/winsup/cygwin/fhandler_virtual.cc @@ -225,10 +225,10 @@ fhandler_virtual::open (int flags, mode_t mode) return 1; } -int +virtual_ftype_t fhandler_virtual::exists () { - return 0; + return virt_none; } bool diff --git a/winsup/cygwin/fhandler_virtual.h b/winsup/cygwin/fhandler_virtual.h index de914eacd..f2f211727 100644 --- a/winsup/cygwin/fhandler_virtual.h +++ b/winsup/cygwin/fhandler_virtual.h @@ -1,6 +1,6 @@ /* fhandler_virtual.h: Header for virtual fhandlers - Copyright 2009 Red Hat, Inc. + Copyright 2009, 2010 Red Hat, Inc. This file is part of Cygwin. @@ -8,20 +8,15 @@ This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ -enum virtual_ftype_t { - virt_socket = -4, - virt_pipe = -3, - virt_symlink = -2, - virt_file = -1, - virt_none = 0, - virt_directory = 1, - virt_rootdir = 2 -}; - struct virt_tab_t { const char *name; + size_t name_len; __dev32_t fhandler; virtual_ftype_t type; _off64_t (*format_func)(void *data, char *&); }; +#define _VN(s) s, sizeof (s) - 1 + +extern virt_tab_t *virt_tab_search (const char *, bool, const virt_tab_t *, + size_t); diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc index da0e744de..0117b43b1 100644 --- a/winsup/cygwin/mount.cc +++ b/winsup/cygwin/mount.cc @@ -520,7 +520,7 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, } MALLOC_CHECK; - /* If the path is on a network drive or a //./ resp.//?/ path prefix, + /* If the path is on a network drive or a //./ resp. //?/ path prefix, bypass the mount table. If it's // or //MACHINE, use the netdrive device. */ if (src_path[1] == '/') @@ -550,7 +550,16 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, if (dev.devn == FH_BAD) return ENOENT; set_flags (flags, PATH_BINARY); - strcpy (dst, src_path); + if (isprocsys_dev (dev.devn)) + { + if (src_path[procsys_len]) + backslashify (src_path + procsys_len, dst, 0); + else /* Avoid empty NT path. */ + stpcpy (dst, "\\"); + set_flags (flags, (unsigned) cygdrive_flags); + } + else + strcpy (dst, src_path); goto out; } /* Check if the cygdrive prefix was specified. If so, just strip diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index 94b17ee51..5c6eb53c2 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -28,6 +28,7 @@ #define STATUS_NO_MEDIA_IN_DEVICE ((NTSTATUS) 0xc0000013) #define STATUS_ACCESS_DENIED ((NTSTATUS) 0xc0000022) #define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xc0000023) +#define STATUS_OBJECT_TYPE_MISMATCH ((NTSTATUS) 0xc0000024) #define STATUS_OBJECT_NAME_INVALID ((NTSTATUS) 0xc0000033) #define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS) 0xc0000034) #define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS) 0xc000003A) @@ -40,6 +41,10 @@ #define STATUS_DELETE_PENDING ((NTSTATUS) 0xc0000056) #define STATUS_DISK_FULL ((NTSTATUS) 0xc000007f) #define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xc00000a1) +#define STATUS_INSTANCE_NOT_AVAILABLE ((NTSTATUS) 0xc00000ab) +#define STATUS_PIPE_NOT_AVAILABLE ((NTSTATUS) 0xc00000ac) +#define STATUS_INVALID_PIPE_STATE ((NTSTATUS) 0xc00000ad) +#define STATUS_PIPE_BUSY ((NTSTATUS) 0xc00000ae) #define STATUS_NOT_SUPPORTED ((NTSTATUS) 0xc00000bb) #define STATUS_BAD_NETWORK_PATH ((NTSTATUS) 0xc00000be) #define STATUS_INVALID_NETWORK_RESPONSE ((NTSTATUS) 0xc00000c3) @@ -208,6 +213,8 @@ typedef struct _FILE_ID_BOTH_DIR_INFORMATION #define DIRECTORY_CREATE_SUBDIRECTORY 8 #define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|0x0f) +#define SYMBOLIC_LINK_QUERY 1 + #define EVENT_QUERY_STATE 1 #define SEMAPHORE_QUERY_STATE 1 @@ -927,6 +934,8 @@ extern "C" NTSTATUS NTAPI NtOpenMutant (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); NTSTATUS NTAPI NtOpenSection (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); NTSTATUS NTAPI NtOpenSemaphore (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES); + NTSTATUS NTAPI NtOpenSymbolicLinkObject (PHANDLE, ACCESS_MASK, + POBJECT_ATTRIBUTES); /* WARNING! Don't rely on the timestamp information returned by NtQueryAttributesFile. Only the DOS file attribute info is reliable. */ NTSTATUS NTAPI NtQueryAttributesFile (POBJECT_ATTRIBUTES, @@ -956,6 +965,7 @@ extern "C" NTSTATUS NTAPI NtQuerySecurityObject (HANDLE, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR, ULONG, PULONG); + NTSTATUS NTAPI NtQuerySymbolicLinkObject (HANDLE, PUNICODE_STRING, PULONG); NTSTATUS NTAPI NtQueryVirtualMemory (HANDLE, PVOID, MEMORY_INFORMATION_CLASS, PVOID, ULONG, PULONG); NTSTATUS NTAPI NtQueryVolumeInformationFile (HANDLE, IO_STATUS_BLOCK *, diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index fe81acd8b..4b8179c8e 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -761,8 +761,8 @@ path_conv::check (const char *src, unsigned opt, { /* FIXME: Calling build_fhandler here is not the right way to handle this. */ fhandler_virtual *fh = (fhandler_virtual *) build_fh_dev (dev, path_copy); - int file_type = fh->exists (); - if (file_type == -2) + virtual_ftype_t file_type = fh->exists (); + if (file_type == virt_symlink) { fh->fill_filebuf (); symlen = sym.set (fh->get_filebuf ()); @@ -770,31 +770,61 @@ path_conv::check (const char *src, unsigned opt, delete fh; switch (file_type) { - case 1: - case 2: + case virt_directory: + case virt_rootdir: if (component == 0) fileattr = FILE_ATTRIBUTE_DIRECTORY; break; - case -1: + case virt_file: if (component == 0) fileattr = 0; break; - case -2: /* /proc/self or /proc//symlinks */ + case virt_symlink: goto is_virtual_symlink; - case -3: /* /proc//fd/pipe:[] */ + case virt_pipe: if (component == 0) { fileattr = 0; dev.parse (FH_PIPE); } break; - case -4: /* /proc//fd/socket:[] */ + case virt_socket: if (component == 0) { fileattr = 0; dev.parse (FH_TCP); } break; + case virt_fsdir: + case virt_fsfile: + /* Access to real file or directory via block device + entry in /proc/sys. Convert to real file and go with + the flow. */ + dev.parse (FH_FS); + goto is_fs_via_procsys; + case virt_blk: + /* Block special device. If the trailing slash has been + requested, the target is the root directory of the + filesystem on this block device. So we convert this to + a real file and attach the backslash. */ + if (component || need_directory) + { + dev.parse (FH_FS); + if (component == 0) + { + strcat (full_path, "\\"); + fileattr = FILE_ATTRIBUTE_DIRECTORY + | FILE_ATTRIBUTE_DEVICE; + } + else + fileattr = 0; + goto out; + } + /*FALLTHRU*/ + case virt_chr: + if (component == 0) + fileattr = FILE_ATTRIBUTE_DEVICE; + break; default: if (component == 0) fileattr = INVALID_FILE_ATTRIBUTES; @@ -841,6 +871,8 @@ path_conv::check (const char *src, unsigned opt, if (is_msdos) sym.pflags |= PATH_NOPOSIX | PATH_NOACL; +is_fs_via_procsys: + symlen = sym.check (full_path, suff, fs, conv_handle); is_virtual_symlink: @@ -2850,6 +2882,14 @@ cygwin_conv_path (cygwin_conv_path_t what, const void *from, void *to, if (buf[1] != ':') /* native UNC path */ *(buf += 2) = '\\'; } + else if (*buf == '\\') + { + /* Device name points to somewhere else in the NT namespace. + Use GLOBALROOT prefix to convert to Win32 path. */ + char *p = stpcpy (buf, "\\\\.\\GLOBALROOT"); + sys_wcstombs (p, NT_MAX_PATH - (p - buf), + up->Buffer, up->Length / sizeof (WCHAR)); + } lsiz = strlen (buf) + 1; /* TODO: Incoming "." is a special case which leads to a trailing backslash ".\\" in the Win32 path. That's a result of the @@ -2891,7 +2931,8 @@ cygwin_conv_path (cygwin_conv_path_t what, const void *from, void *to, quite a bunch of Win32 functions, especially in user32.dll, apparently, which don't grok long path names at all, not even in the UNICODE API. */ - if (lsiz <= MAX_PATH + 4 || (path[5] != L':' && lsiz <= MAX_PATH + 6)) + if ((path[5] == L':' && lsiz <= MAX_PATH + 4) + || (!wcsncmp (path + 4, L"UNC\\", 4) && lsiz <= MAX_PATH + 6)) { path += 4; lsiz -= 4; @@ -2902,6 +2943,13 @@ cygwin_conv_path (cygwin_conv_path_t what, const void *from, void *to, } } } + else if (*path == L'\\') + { + /* Device name points to somewhere else in the NT namespace. + Use GLOBALROOT prefix to convert to Win32 path. */ + to = (void *) wcpcpy ((wchar_t *) to, L"\\\\.\\GLOBALROOT"); + lsiz += sizeof ("\\\\.\\GLOBALROOT") - 1; + } /* TODO: Same ".\\" band-aid as in CCP_POSIX_TO_WIN_A case. */ if (relative && !strcmp ((const char *) from, ".") && !wcscmp (path, L".\\")) @@ -2943,10 +2991,10 @@ cygwin_conv_path (cygwin_conv_path_t what, const void *from, void *to, case CCP_POSIX_TO_WIN_A: case CCP_WIN_A_TO_POSIX: case CCP_WIN_W_TO_POSIX: - strcpy ((char *) to, buf); + stpcpy ((char *) to, buf); break; case CCP_POSIX_TO_WIN_W: - wcscpy ((PWCHAR) to, path); + wcpcpy ((PWCHAR) to, path); break; } return 0; diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h index 947e83530..3650f7688 100644 --- a/winsup/cygwin/path.h +++ b/winsup/cygwin/path.h @@ -18,7 +18,9 @@ details. */ #define isproc_dev(devn) \ (devn == FH_PROC || devn == FH_REGISTRY || devn == FH_PROCESS || \ - devn == FH_PROCNET) + devn == FH_PROCNET || devn == FH_PROCSYS) + +#define isprocsys_dev(devn) (devn == FH_PROCSYS) #define isvirtual_dev(devn) \ (isproc_dev (devn) || devn == FH_CYGDRIVE || devn == FH_NETDRIVE)