diff options
Diffstat (limited to 'winsup/cygwin/fhandler/raw.cc')
-rw-r--r-- | winsup/cygwin/fhandler/raw.cc | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/winsup/cygwin/fhandler/raw.cc b/winsup/cygwin/fhandler/raw.cc new file mode 100644 index 000000000..44cb10dfb --- /dev/null +++ b/winsup/cygwin/fhandler/raw.cc @@ -0,0 +1,208 @@ +/* fhandler_raw.cc. See fhandler.h for a description of the fhandler classes. + + 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 <unistd.h> +#include <cygwin/rdevio.h> +#include <sys/mtio.h> +#include <sys/param.h> +#include "cygerrno.h" +#include "path.h" +#include "fhandler.h" + +/**********************************************************************/ +/* fhandler_dev_raw */ + +fhandler_dev_raw::fhandler_dev_raw () + : fhandler_base (), + status () +{ + need_fork_fixup (true); +} + +fhandler_dev_raw::~fhandler_dev_raw () +{ + if (devbufsiz > 1L) + delete [] devbufalloc; +} + +int +fhandler_dev_raw::fstat (struct stat *buf) +{ + debug_printf ("here"); + + fhandler_base::fstat (buf); + if (!dev ().isfs ()) + { + if (get_major () == DEV_TAPE_MAJOR) + buf->st_mode = S_IFCHR | STD_RBITS | STD_WBITS | S_IWGRP | S_IWOTH; + else + buf->st_mode = S_IFBLK | STD_RBITS | STD_WBITS | S_IWGRP | S_IWOTH; + + if (get_major () == DEV_SD_HIGHPART_END && get_minor () == 9999) + buf->st_ino = get_ino (); + buf->st_uid = geteuid (); + buf->st_gid = getegid (); + buf->st_nlink = 1; + buf->st_blksize = PREFERRED_IO_BLKSIZE; + time_as_timestruc_t (&buf->st_ctim); + buf->st_atim = buf->st_mtim = buf->st_birthtim = buf->st_ctim; + } + return 0; +} + +int +fhandler_dev_raw::open (int flags, mode_t) +{ + /* Check for illegal flags. */ + if (get_major () != DEV_TAPE_MAJOR && (flags & O_APPEND)) + { + set_errno (EINVAL); + return 0; + } + + /* Always open a raw device existing and binary. */ + flags &= ~(O_CREAT | O_TRUNC); + flags |= O_BINARY; + + /* Write-only doesn't work well with raw devices */ + if ((flags & O_ACCMODE) == O_WRONLY) + flags = ((flags & ~O_WRONLY) | O_RDWR); + + int res = fhandler_base::open (flags, 0); + + return res; +} + +int +fhandler_dev_raw::dup (fhandler_base *child, int flags) +{ + int ret = fhandler_base::dup (child, flags); + + if (!ret) + { + fhandler_dev_raw *fhc = (fhandler_dev_raw *) child; + + if (devbufsiz > 1L) + { + /* Create sector-aligned buffer */ + fhc->devbufalloc = new char [devbufsiz + devbufalign]; + fhc->devbuf = (char *) roundup2 ((uintptr_t) fhc->devbufalloc, + (uintptr_t) devbufalign); + } + fhc->devbufstart = 0; + fhc->devbufend = 0; + fhc->lastblk_to_read (false); + } + return ret; +} + +void +fhandler_dev_raw::fixup_after_fork (HANDLE parent) +{ + fhandler_base::fixup_after_fork (parent); + devbufstart = 0; + devbufend = 0; + lastblk_to_read (false); +} + +void +fhandler_dev_raw::fixup_after_exec () +{ + if (!close_on_exec ()) + { + if (devbufsiz > 1L) + { + /* Create sector-aligned buffer */ + devbufalloc = new char [devbufsiz + devbufalign]; + devbuf = (char *) roundup2 ((uintptr_t) devbufalloc, + (uintptr_t) devbufalign); + } + devbufstart = 0; + devbufend = 0; + lastblk_to_read (false); + } +} + +int +fhandler_dev_raw::ioctl (unsigned int cmd, void *buf) +{ + int ret = NO_ERROR; + + if (cmd == RDIOCDOP) + { + struct rdop *op = (struct rdop *) buf; + + if (!op) + ret = ERROR_INVALID_PARAMETER; + else + switch (op->rd_op) + { + case RDSETBLK: + if (get_major () == DEV_TAPE_MAJOR) + { + struct mtop mop; + + mop.mt_op = MTSETBLK; + mop.mt_count = op->rd_parm; + ret = ioctl (MTIOCTOP, &mop); + } + else if ((op->rd_parm <= 1 && get_major () != DEV_TAPE_MAJOR) + || (op->rd_parm > 1 && (op->rd_parm % devbufalign)) + || (get_flags () & O_DIRECT)) + /* The conditions for a valid parameter are: + - The new size is either 0 or 1, both indicating unbuffered + I/O, and the device is a tape device. + - Or, the new buffersize must be a multiple of the + required buffer alignment. + - In the O_DIRECT case, the whole request is invalid. */ + ret = ERROR_INVALID_PARAMETER; + else if (!devbuf || op->rd_parm != devbufsiz) + { + char *buf = NULL; + off_t curpos = lseek (0, SEEK_CUR); + + if (op->rd_parm > 1L) + buf = new char [op->rd_parm + devbufalign]; + + if (devbufsiz > 1L) + delete [] devbufalloc; + + devbufalloc = buf; + devbuf = (char *) roundup2 ((uintptr_t) buf, + (uintptr_t) devbufalign); + devbufsiz = op->rd_parm ?: 1L; + devbufstart = devbufend = 0; + lseek (curpos, SEEK_SET); + } + break; + default: + break; + } + } + else if (cmd == RDIOCGET) + { + struct rdget *get = (struct rdget *) buf; + + if (!get) + ret = ERROR_INVALID_PARAMETER; + else + get->bufsiz = devbufsiz; + } + else + return fhandler_base::ioctl (cmd, buf); + + if (ret != NO_ERROR) + { + SetLastError (ret); + __seterrno (); + return -1; + } + return 0; +} |