diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in index 75c73bf92..733678e96 100644 --- a/winsup/cygwin/Makefile.in +++ b/winsup/cygwin/Makefile.in @@ -279,6 +279,7 @@ DLL_OFILES:= \ fhandler.o \ fhandler_clipboard.o \ fhandler_console.o \ + fhandler_cygdrive.o \ fhandler_dev.o \ fhandler_disk_file.o \ fhandler_dsp.o \ diff --git a/winsup/cygwin/fhandler_cygdrive.cc b/winsup/cygwin/fhandler_cygdrive.cc new file mode 100644 index 000000000..508cc3650 --- /dev/null +++ b/winsup/cygwin/fhandler_cygdrive.cc @@ -0,0 +1,158 @@ +/* fhandler_cygdrive.cc + +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 +#include "cygerrno.h" +#include "security.h" +#include "path.h" +#include "fhandler.h" +#include "dtable.h" +#include "cygheap.h" +#include "shared_info.h" + +#define _COMPILING_NEWLIB +#include + +fhandler_cygdrive::fhandler_cygdrive () : + fhandler_disk_file () +{ +} + +int +fhandler_cygdrive::open (int flags, mode_t mode) +{ + if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + { + set_errno (EEXIST); + return 0; + } + if (flags & O_WRONLY) + { + set_errno (EISDIR); + return 0; + } + /* Open a fake handle to \\Device\\Null */ + return open_null (flags); +} + +int +fhandler_cygdrive::fstat (struct stat *buf) +{ + fhandler_base::fstat (buf); + buf->st_ino = 2; + buf->st_mode = S_IFDIR | STD_RBITS | STD_XBITS; + buf->st_nlink = 1; + return 0; +} + +int __reg2 +fhandler_cygdrive::fstatvfs (struct statvfs *sfs) +{ + /* Virtual file system. Just return an empty buffer with a few values + set to something useful. Just as on Linux. */ + memset (sfs, 0, sizeof (*sfs)); + sfs->f_bsize = sfs->f_frsize = 4096; + sfs->f_flag = ST_RDONLY; + sfs->f_namemax = NAME_MAX; + return 0; +} + +#define MAX_DRIVE_BUF_LEN (sizeof ("x:\\") * 26 + 2) + +struct __DIR_drives +{ + char *pdrive; + char pbuf[MAX_DRIVE_BUF_LEN]; +}; + +#define d_drives(d) ((__DIR_drives *) (d)->__d_internal) + +DIR * +fhandler_cygdrive::opendir (int fd) +{ + DIR *dir; + + dir = fhandler_disk_file::opendir (fd); + if (dir) + { + dir->__d_internal = (uintptr_t) new __DIR_drives; + GetLogicalDriveStrings (MAX_DRIVE_BUF_LEN, d_drives(dir)->pbuf); + d_drives(dir)->pdrive = d_drives(dir)->pbuf; + } + + return dir; +} + +int +fhandler_cygdrive::readdir (DIR *dir, dirent *de) +{ + WCHAR drive[] = L"X:"; + + while (true) + { + if (!d_drives(dir)->pdrive || !*d_drives(dir)->pdrive) + { + if (!(dir->__flags & dirent_saw_dot)) + { + de->d_name[0] = '.'; + de->d_name[1] = '\0'; + de->d_ino = 2; + } + return ENMFILE; + } + disk_type dt = get_disk_type ((drive[0] = *d_drives(dir)->pdrive, drive)); + if (dt == DT_SHARE_SMB) + { + /* Calling NetUseGetInfo on SMB drives allows to fetch the + current state of the drive without trying to open a file + descriptor on the share (GetFileAttributes). This avoids + waiting for SMB timeouts. Of course, there's a downside: + If a drive becomes availabe again, it can take a couple of + minutes to recognize it. As long as this didn't happen, + the drive will not show up in the cygdrive dir. */ + PUSE_INFO_1 pui1; + DWORD status; + + if (NetUseGetInfo (NULL, drive, 1, (PBYTE *) &pui1) == NERR_Success) + { + status = pui1->ui1_status; + NetApiBufferFree (pui1); + if (status == USE_OK) + break; + } + } + else if (dt != DT_FLOPPY + && GetFileAttributes (d_drives(dir)->pdrive) != INVALID_FILE_ATTRIBUTES) + break; + d_drives(dir)->pdrive = strchr (d_drives(dir)->pdrive, '\0') + 1; + } + *de->d_name = cyg_tolower (*d_drives(dir)->pdrive); + de->d_name[1] = '\0'; + user_shared->warned_msdos = true; + de->d_ino = readdir_get_ino (d_drives(dir)->pdrive, false); + dir->__d_position++; + d_drives(dir)->pdrive = strchr (d_drives(dir)->pdrive, '\0') + 1; + syscall_printf ("%p = readdir (%p) (%s)", &de, dir, de->d_name); + return 0; +} + +void +fhandler_cygdrive::rewinddir (DIR *dir) +{ + d_drives(dir)->pdrive = d_drives(dir)->pbuf; + dir->__d_position = 0; +} + +int +fhandler_cygdrive::closedir (DIR *dir) +{ + delete d_drives(dir); + return 0; +} diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index e0a196fae..5a8463eff 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -2683,140 +2683,3 @@ fhandler_disk_file::ioctl (unsigned int cmd, void *p) syscall_printf ("%d = ioctl_file(%x, %p)", ret, cmd, p); return ret; } - -fhandler_cygdrive::fhandler_cygdrive () : - fhandler_disk_file () -{ -} - -int -fhandler_cygdrive::open (int flags, mode_t mode) -{ - if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) - { - set_errno (EEXIST); - return 0; - } - if (flags & O_WRONLY) - { - set_errno (EISDIR); - return 0; - } - /* Open a fake handle to \\Device\\Null */ - return open_null (flags); -} - -int -fhandler_cygdrive::fstat (struct stat *buf) -{ - fhandler_base::fstat (buf); - buf->st_ino = 2; - buf->st_mode = S_IFDIR | STD_RBITS | STD_XBITS; - buf->st_nlink = 1; - return 0; -} - -int __reg2 -fhandler_cygdrive::fstatvfs (struct statvfs *sfs) -{ - /* Virtual file system. Just return an empty buffer with a few values - set to something useful. Just as on Linux. */ - memset (sfs, 0, sizeof (*sfs)); - sfs->f_bsize = sfs->f_frsize = 4096; - sfs->f_flag = ST_RDONLY; - sfs->f_namemax = NAME_MAX; - return 0; -} - -#define MAX_DRIVE_BUF_LEN (sizeof ("x:\\") * 26 + 2) - -struct __DIR_drives -{ - char *pdrive; - char pbuf[MAX_DRIVE_BUF_LEN]; -}; - -#define d_drives(d) ((__DIR_drives *) (d)->__d_internal) - -DIR * -fhandler_cygdrive::opendir (int fd) -{ - DIR *dir; - - dir = fhandler_disk_file::opendir (fd); - if (dir) - { - dir->__d_internal = (uintptr_t) new __DIR_drives; - GetLogicalDriveStrings (MAX_DRIVE_BUF_LEN, d_drives(dir)->pbuf); - d_drives(dir)->pdrive = d_drives(dir)->pbuf; - } - - return dir; -} - -int -fhandler_cygdrive::readdir (DIR *dir, dirent *de) -{ - WCHAR drive[] = L"X:"; - - while (true) - { - if (!d_drives(dir)->pdrive || !*d_drives(dir)->pdrive) - { - if (!(dir->__flags & dirent_saw_dot)) - { - de->d_name[0] = '.'; - de->d_name[1] = '\0'; - de->d_ino = 2; - } - return ENMFILE; - } - disk_type dt = get_disk_type ((drive[0] = *d_drives(dir)->pdrive, drive)); - if (dt == DT_SHARE_SMB) - { - /* Calling NetUseGetInfo on SMB drives allows to fetch the - current state of the drive without trying to open a file - descriptor on the share (GetFileAttributes). This avoids - waiting for SMB timeouts. Of course, there's a downside: - If a drive becomes availabe again, it can take a couple of - minutes to recognize it. As long as this didn't happen, - the drive will not show up in the cygdrive dir. */ - PUSE_INFO_1 pui1; - DWORD status; - - if (NetUseGetInfo (NULL, drive, 1, (PBYTE *) &pui1) == NERR_Success) - { - status = pui1->ui1_status; - NetApiBufferFree (pui1); - if (status == USE_OK) - break; - } - } - else if (dt != DT_FLOPPY - && GetFileAttributes (d_drives(dir)->pdrive) != INVALID_FILE_ATTRIBUTES) - break; - d_drives(dir)->pdrive = strchr (d_drives(dir)->pdrive, '\0') + 1; - } - *de->d_name = cyg_tolower (*d_drives(dir)->pdrive); - de->d_name[1] = '\0'; - user_shared->warned_msdos = true; - de->d_ino = readdir_get_ino (d_drives(dir)->pdrive, false); - dir->__d_position++; - d_drives(dir)->pdrive = strchr (d_drives(dir)->pdrive, '\0') + 1; - syscall_printf ("%p = readdir (%p) (%s)", &de, dir, de->d_name); - return 0; -} - -void -fhandler_cygdrive::rewinddir (DIR *dir) -{ - d_drives(dir)->pdrive = d_drives(dir)->pbuf; - dir->__d_position = 0; -} - -int -fhandler_cygdrive::closedir (DIR *dir) -{ - delete d_drives(dir); - return 0; -}