Index: Makefile.in =================================================================== RCS file: /cvs/src/src/winsup/cygwin/Makefile.in,v retrieving revision 1.237 diff -u -p -r1.237 Makefile.in --- Makefile.in 21 Aug 2010 18:57:36 -0000 1.237 +++ Makefile.in 2 Sep 2010 16:13:50 -0000 @@ -142,12 +142,13 @@ DLL_OFILES:=assert.o autoload.o bsdlib.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_registry.o fhandler_serial.o fhandler_socket.o fhandler_sysfs.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 \ Index: devices.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/devices.cc,v retrieving revision 1.31 diff -u -p -r1.31 devices.cc --- devices.cc 3 Jan 2009 05:12:20 -0000 1.31 +++ devices.cc 2 Sep 2010 16:13:51 -0000 @@ -24,6 +24,9 @@ const device dev_proc_storage = const device dev_procnet_storage = {"", {FH_PROCNET}, ""}; +const device dev_sysfs_storage = + {"", {FH_SYSFS}, ""}; + const device dev_netdrive_storage = {"", {FH_NETDRIVE}, ""}; Index: devices.h =================================================================== RCS file: /cvs/src/src/winsup/cygwin/devices.h,v retrieving revision 1.25 diff -u -p -r1.25 devices.h --- devices.h 20 Jan 2009 17:22:11 -0000 1.25 +++ devices.h 2 Sep 2010 16:13:51 -0000 @@ -53,6 +53,8 @@ enum fh_devices FH_DEV = FHDEV (0, 245), FH_PROCNET = FHDEV (0, 244), FH_PROCESSFD = FHDEV (0, 243), + FH_SYSFS = FHDEV (0, 242), + DEV_FLOPPY_MAJOR = 2, FH_FLOPPY = FHDEV (DEV_FLOPPY_MAJOR, 0), @@ -287,6 +289,8 @@ extern const device dev_piper_storage; extern const device dev_pipew_storage; #define pipew_dev (&dev_pipew_storage) extern const device dev_proc_storage; +#define sysfs_dev (&dev_sysfs_storage) +extern const device dev_sysfs_storage; #define proc_dev (&dev_proc_storage) extern const device dev_netdrive_storage; #define netdrive_dev (&dev_netdrive_storage) Index: devices.in =================================================================== RCS file: /cvs/src/src/winsup/cygwin/devices.in,v retrieving revision 1.22 diff -u -p -r1.22 devices.in --- devices.in 3 Jan 2009 05:12:20 -0000 1.22 +++ devices.in 2 Sep 2010 16:13:51 -0000 @@ -20,6 +20,9 @@ const device dev_proc_storage = const device dev_procnet_storage = {"", {FH_PROCNET}, ""}; +const device dev_sysfs_storage = + {"", {FH_SYSFS}, ""}; + const device dev_netdrive_storage = {"", {FH_NETDRIVE}, ""}; Index: dir.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/dir.cc,v retrieving revision 1.126 diff -u -p -r1.126 dir.cc --- dir.cc 5 Jul 2010 16:59:51 -0000 1.126 +++ dir.cc 2 Sep 2010 16:13:51 -0000 @@ -144,7 +144,7 @@ readdir_worker (DIR *dir, dirent *de) ((fhandler_base *) dir->__fh)->pc.get_nt_native_path (); DWORD devn = ((fhandler_base *) dir->__fh)->get_device (); /* Paths below /proc don't have a Win32 pendant. */ - if (isproc_dev (devn)) + if (isproc_dev (devn) || issysfs_dev (devn)) de->d_ino = hash_path_name (de->d_ino, L"/"); else if (w32name->Buffer[w32name->Length / sizeof (WCHAR) - 1] != L'\\') Index: dtable.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/dtable.cc,v retrieving revision 1.216 diff -u -p -r1.216 dtable.cc --- dtable.cc 15 Jun 2010 12:05:14 -0000 1.216 +++ dtable.cc 2 Sep 2010 16:13:51 -0000 @@ -540,6 +540,9 @@ build_fh_pc (path_conv& pc, bool set_nam case FH_PROCNET: fh = cnew (fhandler_procnet) (); break; + case FH_SYSFS: + fh = cnew (fhandler_sysfs) (); + break; case FH_NETDRIVE: fh = cnew (fhandler_netdrive) (); break; Index: fhandler.h =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler.h,v retrieving revision 1.403 diff -u -p -r1.403 fhandler.h --- fhandler.h 5 Jul 2010 16:59:55 -0000 1.403 +++ fhandler.h 2 Sep 2010 16:13:51 -0000 @@ -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 sysfs[]; +extern const size_t sysfs_len; class select_record; class select_stuff; @@ -99,6 +101,22 @@ 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 SYSFS */ + 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_dir_nobs = 3, /* Directory, strip trailing backslash */ + virt_fsdir = 4, /* FS-based directory via SYSFS */ + virt_fsdir_nobs = 5 /* Ditto, strip trailing backslash */ +}; + class fhandler_base { friend class dtable; @@ -1331,7 +1349,7 @@ class fhandler_virtual : public fhandler 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 +1375,7 @@ class fhandler_proc: public fhandler_vir { 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 +1384,30 @@ class fhandler_proc: public fhandler_vir bool fill_filebuf (); }; +class fhandler_sysfs: public fhandler_virtual +{ + public: + fhandler_sysfs (); + 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 +1425,7 @@ class fhandler_registry: public fhandler 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 +1445,7 @@ class fhandler_process: public fhandler_ 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 +1458,7 @@ class fhandler_procnet: public fhandler_ 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))); Index: fhandler_disk_file.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler_disk_file.cc,v retrieving revision 1.334 diff -u -p -r1.334 fhandler_disk_file.cc --- fhandler_disk_file.cc 20 Aug 2010 11:18:58 -0000 1.334 +++ fhandler_disk_file.cc 2 Sep 2010 16:13:51 -0000 @@ -36,11 +36,12 @@ class __DIR_mounts const char *parent_dir; int parent_dir_len; UNICODE_STRING mounts[MAX_MOUNTS]; - bool found[MAX_MOUNTS + 2]; + bool found[MAX_MOUNTS + 3]; UNICODE_STRING cygdrive; #define __DIR_PROC (MAX_MOUNTS) -#define __DIR_CYGDRIVE (MAX_MOUNTS+1) +#define __DIR_SYS (MAX_MOUNTS+1) +#define __DIR_CYGDRIVE (MAX_MOUNTS+2) __ino64_t eval_ino (int idx) { @@ -84,6 +85,11 @@ public: found[__DIR_PROC] = true; return 2; } + if (RtlEqualUnicodeString (fname, &ro_u_sysfs, FALSE)) + { + found[__DIR_SYS] = true; + return 2; + } if (fname->Length / sizeof (WCHAR) == mount_table->cygdrive_len - 2 && RtlEqualUnicodeString (fname, &cygdrive, FALSE)) { @@ -118,7 +124,14 @@ public: { found[__DIR_PROC] = true; if (retname) - RtlInitUnicodeString (retname, L"proc"); + *retname = ro_u_proc; + return 2; + } + if (!found[__DIR_SYS]) + { + found[__DIR_SYS] = true; + if (retname) + *retname = ro_u_sysfs; return 2; } if (!found[__DIR_CYGDRIVE]) @@ -474,7 +487,10 @@ fhandler_base::fstat_by_name (struct __s 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); + /* If basename.Length is 0, the file is a virtual directory. The attributes + from fdi_buf are incorrect, so don't copy. */ + if (basename.Length > 0) + pc.file_attributes (fdi_buf.fdi.FileAttributes); return fstat_helper (buf, fdi_buf.fdi.ChangeTime.QuadPart ? &fdi_buf.fdi.ChangeTime : &fdi_buf.fdi.LastWriteTime, Index: fhandler_netdrive.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler_netdrive.cc,v retrieving revision 1.29 diff -u -p -r1.29 fhandler_netdrive.cc --- fhandler_netdrive.cc 1 Sep 2010 18:24:10 -0000 1.29 +++ fhandler_netdrive.cc 2 Sep 2010 16:13:51 -0000 @@ -145,14 +145,14 @@ create_thread_and_wait (int what, PVOID /* 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 (): Index: fhandler_proc.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler_proc.cc,v retrieving revision 1.92 diff -u -p -r1.92 fhandler_proc.cc --- fhandler_proc.cc 27 Aug 2010 09:08:32 -0000 1.92 +++ fhandler_proc.cc 2 Sep 2010 16:13:52 -0000 @@ -71,7 +71,7 @@ static const int PROC_LINK_COUNT = (size /* 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 @@ -120,7 +120,7 @@ fhandler_proc::get_proc_fhandler (const /* 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 (); Index: fhandler_process.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler_process.cc,v retrieving revision 1.91 diff -u -p -r1.91 fhandler_process.cc --- fhandler_process.cc 18 May 2010 14:30:50 -0000 1.91 +++ fhandler_process.cc 2 Sep 2010 16:13:52 -0000 @@ -90,7 +90,7 @@ static bool get_mem_values (DWORD dwProc * -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,7 +99,7 @@ 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++) { Index: fhandler_procnet.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler_procnet.cc,v retrieving revision 1.11 diff -u -p -r1.11 fhandler_procnet.cc --- fhandler_procnet.cc 20 Jan 2009 18:04:32 -0000 1.11 +++ fhandler_procnet.cc 2 Sep 2010 16:13:52 -0000 @@ -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,7 +61,7 @@ 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)) Index: fhandler_registry.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler_registry.cc,v retrieving revision 1.62 diff -u -p -r1.62 fhandler_registry.cc --- fhandler_registry.cc 1 Sep 2010 10:30:52 -0000 1.62 +++ fhandler_registry.cc 2 Sep 2010 16:13:52 -0000 @@ -268,10 +268,11 @@ multi_wcstombs (char *dst, size_t len, c * 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 __stat6 { 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 __stat6 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 __stat6 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; Index: fhandler_sysfs.cc =================================================================== RCS file: fhandler_sysfs.cc diff -N fhandler_sysfs.cc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ fhandler_sysfs.cc 2 Sep 2010 16:13:52 -0000 @@ -0,0 +1,431 @@ +/* fhandler_sysfs.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 + +/* name of the /sys filesystem */ +const char sysfs[] = "/sys"; +const size_t sysfs_len = sizeof (sysfs) - 1; + +#define mk_unicode_path(p) \ + WCHAR namebuf[strlen (get_name ()) + 1]; \ + { \ + const char *from; \ + PWCHAR to; \ + for (to = namebuf, from = get_name () + sysfs_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_sysfs::exists (struct __stat64 *buf) +{ + UNICODE_STRING path; \ + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + NTSTATUS status; + HANDLE h; + FILE_BASIC_INFORMATION fbi; + bool strip_bs = false; + virtual_ftype_t file_type = virt_chr; + + if (strlen (get_name ()) == sysfs_len) + return virt_rootdir; + mk_unicode_path (&path); + /* First try to open as file/device to get more info. */ + InitializeObjectAttributes (&attr, &path, 0, 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_NAME_INVALID + && path.Buffer[path.Length / sizeof (WCHAR) - 1] == L'\\') + { + /* Strip the trailing backslash and try again. */ + strip_bs = true; + path.Length -= sizeof (WCHAR); + 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_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) + ? (strip_bs ? virt_fsdir_nobs : 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 SYSFS. */ + status = NtQueryInformationFile (h, &io, &fbi, sizeof fbi, + FileBasicInformation); + NtClose (h); + if (NT_SUCCESS (dev_stat)) + { + if (ffdi.DeviceType == FILE_DEVICE_NAMED_PIPE) + { + if (path.Buffer[path.Length / sizeof (WCHAR) - 1] == L'\\') + return virt_fsdir; + file_type = virt_pipe; + } + else if (NT_SUCCESS (status)) + file_type = (fbi.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ? (strip_bs ? virt_fsdir_nobs : virt_fsdir) + : virt_fsfile; + else if (ffdi.DeviceType == FILE_DEVICE_DISK + || ffdi.DeviceType == FILE_DEVICE_CD_ROM + || 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 strip_bs ? virt_dir_nobs : virt_directory; + } + else if (status == STATUS_ACCESS_DENIED) + return strip_bs ? virt_dir_nobs : virt_directory; + /* Give up. Just treat as character device. */ + return file_type; +} + +virtual_ftype_t +fhandler_sysfs::exists () +{ + return exists (NULL); +} + +fhandler_sysfs::fhandler_sysfs (): + fhandler_virtual () +{ +} + +bool +fhandler_sysfs::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, 0, 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, sysfs_len + len + 1); + sys_wcstombs (fnamep = stpcpy (filebuf, sysfs), len + 1, target.Buffer, + target.Length / sizeof (WCHAR)); + while ((fnamep = strchr (fnamep, '\\'))) + *fnamep = '/'; + return true; +} + +int +fhandler_sysfs::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_dir_nobs: + case virt_fsdir: + case virt_fsdir_nobs: + 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_sysfs::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, 0, 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_sysfs::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_sysfs::telldir (DIR *dir) +{ + return dir->__d_position; +} + +void +fhandler_sysfs::seekdir (DIR *dir, long pos) +{ + dir->__d_position = pos; +} + +int +fhandler_sysfs::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_sysfs::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_sysfs::write (const void *ptr, size_t len) +{ + return fhandler_base::raw_write (ptr, len); +} + +int +fhandler_sysfs::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, NULL, NULL); + switch (exists ()) + { + case virt_directory: + case virt_rootdir: + case virt_dir_nobs: + 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_sysfs::open (%p, %d)", res, flags, mode); + return res; +} + +int +fhandler_sysfs::close () +{ + if (!nohandle ()) + NtClose (get_handle ()); + return fhandler_virtual::close (); +} Index: fhandler_virtual.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler_virtual.cc,v retrieving revision 1.52 diff -u -p -r1.52 fhandler_virtual.cc --- fhandler_virtual.cc 5 Jul 2010 16:59:56 -0000 1.52 +++ fhandler_virtual.cc 2 Sep 2010 16:13:52 -0000 @@ -225,10 +225,10 @@ fhandler_virtual::open (int flags, mode_ return 1; } -int +virtual_ftype_t fhandler_virtual::exists () { - return 0; + return virt_none; } bool Index: fhandler_virtual.h =================================================================== RCS file: /cvs/src/src/winsup/cygwin/fhandler_virtual.h,v retrieving revision 1.1 diff -u -p -r1.1 fhandler_virtual.h --- fhandler_virtual.h 20 Jan 2009 17:22:11 -0000 1.1 +++ fhandler_virtual.h 2 Sep 2010 16:13:52 -0000 @@ -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,16 +8,6 @@ This software is a copyrighted work lice 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; __dev32_t fhandler; Index: globals.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/globals.cc,v retrieving revision 1.21 diff -u -p -r1.21 globals.cc --- globals.cc 30 Aug 2010 01:57:36 -0000 1.21 +++ globals.cc 2 Sep 2010 16:13:52 -0000 @@ -99,6 +99,7 @@ UNICODE_STRING _RDATA ro_u_com = _ROU (L UNICODE_STRING _RDATA ro_u_scr = _ROU (L".scr"); UNICODE_STRING _RDATA ro_u_sys = _ROU (L".sys"); UNICODE_STRING _RDATA ro_u_proc = _ROU (L"proc"); +UNICODE_STRING _RDATA ro_u_sysfs = _ROU (L"sys"); UNICODE_STRING _RDATA ro_u_pmem = _ROU (L"\\device\\physicalmemory"); UNICODE_STRING _RDATA ro_u_natp = _ROU (L"\\??\\"); UNICODE_STRING _RDATA ro_u_uncp = _ROU (L"\\??\\UNC\\"); Index: mount.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/mount.cc,v retrieving revision 1.64 diff -u -p -r1.64 mount.cc --- mount.cc 25 Aug 2010 09:20:11 -0000 1.64 +++ mount.cc 2 Sep 2010 16:13:52 -0000 @@ -45,6 +45,9 @@ details. */ #define isproc(path) \ (path_prefix_p (proc, (path), proc_len, false)) +#define issysfs(path) \ + (path_prefix_p (sysfs, (path), sysfs_len, false)) + bool NO_COPY mount_info::got_usr_bin; bool NO_COPY mount_info::got_usr_lib; int NO_COPY mount_info::root_idx = -1; @@ -520,7 +523,7 @@ mount_info::conv_to_win32_path (const ch } 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] == '/') @@ -553,6 +556,13 @@ mount_info::conv_to_win32_path (const ch strcpy (dst, src_path); goto out; } + else if (issysfs (src_path)) + { + dev = *sysfs_dev; + set_flags (flags, PATH_BINARY); + backslashify (src_path + sysfs_len, dst, 0); + goto out; + } /* Check if the cygdrive prefix was specified. If so, just strip off the prefix and transform it into an MS-DOS path. */ else if (iscygdrive (src_path)) Index: ntdll.h =================================================================== RCS file: /cvs/src/src/winsup/cygwin/ntdll.h,v retrieving revision 1.101 diff -u -p -r1.101 ntdll.h --- ntdll.h 27 Aug 2010 17:58:43 -0000 1.101 +++ ntdll.h 2 Sep 2010 16:13:52 -0000 @@ -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_INFORMA #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 *, Index: path.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/path.cc,v retrieving revision 1.605 diff -u -p -r1.605 path.cc --- path.cc 31 Aug 2010 13:48:04 -0000 1.605 +++ path.cc 2 Sep 2010 16:13:53 -0000 @@ -760,9 +760,15 @@ path_conv::check (const char *src, unsig else if (isvirtual_dev (dev.devn)) { /* FIXME: Calling build_fhandler here is not the right way to handle this. */ + char *end = NULL; + if (need_directory && issysfs_dev (dev.devn)) + { + end = strchr (path_copy, '\0'); + stpcpy (end, "/"); + } 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 +776,67 @@ path_conv::check (const char *src, unsig delete fh; switch (file_type) { - case 1: - case 2: + case virt_dir_nobs: + if (end) + *end = '\0'; + /*FALLTHRU*/ + 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: + dev.parse (FH_FS); + if (need_directory) + strcat (full_path, "\\"); + goto is_fs_via_sysfs; + case virt_fsdir_nobs: + if (end) + *end = '\0'; + /*FALLTHRU*/ + case virt_fsfile: + dev.parse (FH_FS); + goto is_fs_via_sysfs; + case virt_blk: + /* If it's a component, and if it has been recognized as + block special device, the target path is definitely + a FS_based path. So we convert this to a FH_FS device. + The current component path is also lacking the trailing + backslash which converts it from a block device to a + file system's root directory. */ + if (component) + { + dev.parse (FH_FS); + strcat (full_path, "\\"); + goto is_fs_via_sysfs; + } + case virt_chr: + if (component == 0) + { + dev.parse (FH_SYSFS); + fileattr = 0; + } + break; default: if (component == 0) fileattr = INVALID_FILE_ATTRIBUTES; @@ -841,6 +883,8 @@ path_conv::check (const char *src, unsig if (is_msdos) sym.pflags |= PATH_NOPOSIX | PATH_NOACL; +is_fs_via_sysfs: + symlen = sym.check (full_path, suff, fs, conv_handle); is_virtual_symlink: @@ -2471,6 +2515,8 @@ restart: } fileattr = 0; } + else if (basename.Length == 0) + fileattr = FILE_ATTRIBUTE_DIRECTORY; else fileattr = fdi_buf.fdi.FileAttributes; } Index: path.h =================================================================== RCS file: /cvs/src/src/winsup/cygwin/path.h,v retrieving revision 1.145 diff -u -p -r1.145 path.h --- path.h 4 Jul 2010 17:12:26 -0000 1.145 +++ path.h 2 Sep 2010 16:13:53 -0000 @@ -20,8 +20,11 @@ details. */ (devn == FH_PROC || devn == FH_REGISTRY || devn == FH_PROCESS || \ devn == FH_PROCNET) +#define issysfs_dev(devn) (devn == FH_SYSFS) + #define isvirtual_dev(devn) \ - (isproc_dev (devn) || devn == FH_CYGDRIVE || devn == FH_NETDRIVE) + (isproc_dev (devn) || issysfs_dev (devn) || \ + devn == FH_CYGDRIVE || devn == FH_NETDRIVE) inline bool has_attribute (DWORD attributes, DWORD attribs_to_test) Index: syscalls.cc =================================================================== RCS file: /cvs/src/src/winsup/cygwin/syscalls.cc,v retrieving revision 1.565 diff -u -p -r1.565 syscalls.cc --- syscalls.cc 25 Aug 2010 08:51:41 -0000 1.565 +++ syscalls.cc 2 Sep 2010 16:13:53 -0000 @@ -688,7 +688,7 @@ unlink (const char *ourname) } devn = win32_name.get_devn (); - if (isproc_dev (devn)) + if (isproc_dev (devn) || issysfs_dev (devn)) { set_errno (EROFS); goto done;