diff options
Diffstat (limited to 'winsup/cygwin/fhandler_dev.cc')
-rw-r--r-- | winsup/cygwin/fhandler_dev.cc | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/winsup/cygwin/fhandler_dev.cc b/winsup/cygwin/fhandler_dev.cc new file mode 100644 index 000000000..ad39961e5 --- /dev/null +++ b/winsup/cygwin/fhandler_dev.cc @@ -0,0 +1,145 @@ +/* fhandler_dev.cc, Implement /dev. + + Copyright 2012 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 <stdlib.h> +#include "path.h" +#include "fhandler.h" +#include "shared_info.h" +#include "ntdll.h" +#include "devices.h" + +#define _COMPILING_NEWLIB +#include <dirent.h> + +#define dev_prefix_len (sizeof ("/dev")) + +static int +device_cmp (const void *a, const void *b) +{ + return strcmp (((const device *) a)->name, + ((const device *) b)->name + dev_prefix_len); +} + +int +fhandler_dev::readdir (DIR *dir, dirent *de) +{ + int ret; + + if (dir_exists && !lastrealpos) + { + while ((ret = fhandler_disk_file::readdir (dir, de)) == 0) + { + /* Avoid to print devices for which users have created files under + /dev already, for instance by using the old script from Igor + Peshansky. */ + device dev; + dev.name = de->d_name; + if (!bsearch (&dev, ext_dev_storage, dev_storage_size, sizeof dev, + device_cmp)) + break; + } + if (ret == ENMFILE) + lastrealpos = dir->__d_position; + } + if (!dir_exists || lastrealpos) + { + ret = ENMFILE; + for (size_t idx = dir->__d_position - lastrealpos + 1; + idx < dev_storage_size; + ++idx) + { + struct __stat64 st; + + ++dir->__d_position; + /* Exclude devices which are only available for internal purposes + and devices which are not really existing at this time. */ + switch (ext_dev_storage[idx].d.major) + { + case 0: + if (ext_dev_storage[idx].d.minor == FH_FIFO + || ext_dev_storage[idx].d.minor == FH_PIPE) + continue; + case DEV_PTYM_MAJOR: + if (ext_dev_storage[idx].d.minor + || !strcmp (ext_dev_storage[idx].name, "/dev/ptm0")) + continue; + break; + case DEV_PTYS_MAJOR: + if (cygwin_shared->tty.connect (ext_dev_storage[idx].d.minor) + == -1) + continue; + break; + case DEV_CONS_MAJOR: + if (!iscons_dev (myself->ctty) + || myself->ctty != ext_dev_storage[idx].d.devn_int) + continue; + break; + case DEV_FLOPPY_MAJOR: + case DEV_TAPE_MAJOR: + case DEV_CDROM_MAJOR: + case DEV_SERIAL_MAJOR: + case DEV_SD_MAJOR: + case DEV_SD1_MAJOR: + case DEV_SD2_MAJOR: + case DEV_SD3_MAJOR: + case DEV_SD4_MAJOR: + case DEV_SD5_MAJOR: + case DEV_SD6_MAJOR: + case DEV_SD7_MAJOR: + { + WCHAR wpath[MAX_PATH]; + UNICODE_STRING upath; + OBJECT_ATTRIBUTES attr; + HANDLE h; + NTSTATUS status; + + sys_mbstowcs (wpath, MAX_PATH, ext_dev_storage[idx].native); + RtlInitUnicodeString (&upath, wpath); + InitializeObjectAttributes (&attr, &upath, + OBJ_CASE_INSENSITIVE, NULL, NULL); + /* The native paths are devices, not symlinks, so we expect + a matching error message. */ + status = NtOpenSymbolicLinkObject (&h, SYMBOLIC_LINK_QUERY, + &attr); + switch (status) + { + case STATUS_OBJECT_NAME_NOT_FOUND: + case STATUS_OBJECT_PATH_NOT_FOUND: + continue; + case STATUS_SUCCESS: + NtClose (h); + break; + default: + break; + } + } + break; + } + if (!lstat64 (ext_dev_storage[idx].name, &st)) + { + strcpy (de->d_name, ext_dev_storage[idx].name + dev_prefix_len); + de->d_ino = st.st_ino; + de->d_type = S_ISBLK (st.st_mode) ? DT_BLK : DT_CHR; + ret = 0; + break; + } + } + } + return ret; +} + +void +fhandler_dev::rewinddir (DIR *dir) +{ + lastrealpos = 0; + fhandler_disk_file::rewinddir (dir); +} + |