📄 fhandler_tape.cc
字号:
/* fhandler_tape.cc. See fhandler.h for a description of the fhandler classes. Copyright 1999, 2000, 2001, 2002 Red Hat, Inc.This file is part of Cygwin.This software is a copyrighted work licensed under the terms of theCygwin license. Please consult the file "CYGWIN_LICENSE" fordetails. */#include "winsup.h"#include <sys/termios.h>#include <errno.h>#include <unistd.h>#include <sys/mtio.h>#include "cygerrno.h"#include "perprocess.h"#include "security.h"#include "fhandler.h"#include "path.h"#include "dtable.h"#include "cygheap.h"/**********************************************************************//* fhandler_dev_tape */voidfhandler_dev_tape::clear (void){ lasterr = 0; fhandler_dev_raw::clear ();}intfhandler_dev_tape::is_eom (int win_error){ int ret = ((win_error == ERROR_END_OF_MEDIA) || (win_error == ERROR_EOM_OVERFLOW) || (win_error == ERROR_NO_DATA_DETECTED)); if (ret) debug_printf ("end of medium"); return ret;}intfhandler_dev_tape::is_eof (int win_error){ int ret = ((win_error == ERROR_FILEMARK_DETECTED) || (win_error == ERROR_SETMARK_DETECTED)); if (ret) debug_printf ("end of file"); return ret;}fhandler_dev_tape::fhandler_dev_tape (int unit) : fhandler_dev_raw (FH_TAPE, unit){ debug_printf ("unit: %d", unit);}intfhandler_dev_tape::open (path_conv *real_path, int flags, mode_t){ int ret; devbufsiz = 1L; ret = fhandler_dev_raw::open (real_path, flags); if (ret) { struct mtget get; struct mtop op; struct mtpos pos; if (!ioctl (MTIOCGET, &get)) /* Tape drive supports and is set to variable block size. */ if (get.mt_dsreg == 0) devbufsiz = get.mt_maxblksize; else devbufsiz = get.mt_dsreg; varblkop = get.mt_dsreg == 0; if (devbufsiz > 1L) devbuf = new char [devbufsiz]; /* The following rewind in position 0 solves a problem which appears * in case of multi volume archives: The last ReadFile on first medium * returns ERROR_NO_DATA_DETECTED. After media change, all subsequent * ReadFile calls return ERROR_NO_DATA_DETECTED, too. * The call to tape_set_pos seems to reset some internal flags. */ if ((! ioctl (MTIOCPOS, &pos)) && (! pos.mt_blkno)) { op.mt_op = MTREW; ioctl (MTIOCTOP, &op); } if (flags & O_APPEND) { /* In append mode, seek to beginning of next filemark */ op.mt_op = MTFSFM; op.mt_count = 1; ioctl (MTIOCTOP, &op); } } return ret;}intfhandler_dev_tape::close (void){ struct mtop op; int ret = 0; if (is_writing) { ret = writebuf (); if ((has_written) && (! eom_detected)) { /* if last operation was writing, write a filemark */ debug_printf ("writing filemark"); op.mt_op = MTWEOF; op.mt_count = 1; ioctl (MTIOCTOP, &op); } } // To protected reads on signaling (e.g. Ctrl-C) eof_detected = 1; if (is_rewind_device ()) { debug_printf ("rewinding"); op.mt_op = MTREW; ioctl (MTIOCTOP, &op); } if (ret) { fhandler_dev_raw::close (); return ret; } return fhandler_dev_raw::close ();}intfhandler_dev_tape::fstat (struct __stat64 *buf, path_conv *pc){ int ret; if (!(ret = fhandler_base::fstat (buf, pc))) { struct mtget get; if (!ioctl (MTIOCGET, &get)) buf->st_blocks = get.mt_capacity / buf->st_blksize; } return ret;}__off64_tfhandler_dev_tape::lseek (__off64_t offset, int whence){ struct mtop op; struct mtpos pos; debug_printf ("lseek (%s, %d, %d)", get_name (), offset, whence); writebuf (); eom_detected = eof_detected = 0; lastblk_to_read = 0; devbufstart = devbufend = 0; if (ioctl (MTIOCPOS, &pos)) { return ILLEGAL_SEEK; } switch (whence) { case SEEK_END: op.mt_op = MTFSF; op.mt_count = 1; if (ioctl (MTIOCTOP, &op)) return -1; break; case SEEK_SET: if (whence == SEEK_SET && offset < 0) { set_errno (EINVAL); return -1; } break; case SEEK_CUR: break; default: set_errno (EINVAL); return -1; } op.mt_op = MTFSR; op.mt_count = offset / devbufsiz - (whence == SEEK_SET ? pos.mt_blkno : 0); if (op.mt_count < 0) { op.mt_op = MTBSR; op.mt_count = -op.mt_count; } if (ioctl (MTIOCTOP, &op) || ioctl (MTIOCPOS, &pos)) return -1; return (pos.mt_blkno * devbufsiz);}intfhandler_dev_tape::dup (fhandler_base *child){ fhandler_dev_tape *fhc = (fhandler_dev_tape *) child; fhc->lasterr = lasterr; return fhandler_dev_raw::dup (child);}intfhandler_dev_tape::ioctl (unsigned int cmd, void *buf){ int ret = NO_ERROR; unsigned long block; if (cmd == MTIOCTOP) { struct mtop *op = (struct mtop *) buf; if (! op) ret = ERROR_INVALID_PARAMETER; else switch (op->mt_op) { case MTRESET: break; case MTFSF: ret = tape_set_pos (TAPE_SPACE_FILEMARKS, op->mt_count); break; case MTBSF: ret = tape_set_pos (TAPE_SPACE_FILEMARKS, -op->mt_count); break; case MTFSR: ret = tape_set_pos (TAPE_SPACE_RELATIVE_BLOCKS, op->mt_count); break; case MTBSR: ret = tape_set_pos (TAPE_SPACE_RELATIVE_BLOCKS, -op->mt_count); break; case MTWEOF: if (tape_get_feature (TAPE_DRIVE_WRITE_FILEMARKS)) ret = tape_write_marks (TAPE_FILEMARKS, op->mt_count); else if (tape_get_feature (TAPE_DRIVE_WRITE_LONG_FMKS)) ret = tape_write_marks (TAPE_LONG_FILEMARKS, op->mt_count); else ret = tape_write_marks (TAPE_SHORT_FILEMARKS, op->mt_count); break; case MTREW: ret = tape_set_pos (TAPE_REWIND, 0); break; case MTOFFL: ret = tape_prepare (TAPE_UNLOAD); break; case MTNOP: break; case MTRETEN: if (! tape_get_feature (TAPE_DRIVE_END_OF_DATA)) ret = ERROR_INVALID_PARAMETER; else if (! (ret = tape_set_pos (TAPE_REWIND, 0, FALSE))) ret = tape_prepare (TAPE_TENSION); break; case MTBSFM: ret = tape_set_pos (TAPE_SPACE_FILEMARKS, -op->mt_count, TRUE); break; case MTFSFM: ret = tape_set_pos (TAPE_SPACE_FILEMARKS, op->mt_count, TRUE); break; case MTEOM: if (tape_get_feature (TAPE_DRIVE_END_OF_DATA)) ret = tape_set_pos (TAPE_SPACE_END_OF_DATA, 0); else ret = tape_set_pos (TAPE_SPACE_FILEMARKS, 32767); break; case MTERASE: ret = tape_erase (TAPE_ERASE_SHORT); break; case MTRAS1: case MTRAS2: case MTRAS3: ret = ERROR_INVALID_PARAMETER; break; case MTSETBLK: { long min, max; if (! tape_get_feature (TAPE_DRIVE_SET_BLOCK_SIZE)) { ret = ERROR_INVALID_PARAMETER; break; } ret = tape_get_blocksize (&min, NULL, &max, NULL); if (ret) break; if (devbuf && (size_t) op->mt_count == devbufsiz && !varblkop) { ret = 0; break; } if ((op->mt_count == 0 && !tape_get_feature (TAPE_DRIVE_VARIABLE_BLOCK)) || (op->mt_count > 0 && (op->mt_count < min || op->mt_count > max))) { ret = ERROR_INVALID_PARAMETER; break; } if (devbuf && op->mt_count > 0 && (size_t) op->mt_count < devbufend - devbufstart) { ret = ERROR_MORE_DATA; break; } if (! (ret = tape_set_blocksize (op->mt_count))) { size_t size = 0; if (op->mt_count == 0) { struct mtget get; if ((ret = tape_status (&get)) != NO_ERROR) break; size = get.mt_maxblksize; ret = NO_ERROR; } char *buf = NULL; if (size > 1L && !(buf = new char [size])) { ret = ERROR_OUTOFMEMORY; break; } if (devbufsiz > 1L && size > 1L) { memcpy (buf, devbuf + devbufstart, devbufend - devbufstart); devbufend -= devbufstart; } else devbufend = 0; if (devbufsiz > 1L) delete [] devbuf; devbufstart = 0; devbuf = buf; devbufsiz = size; varblkop = op->mt_count == 0; } } break; case MTSETDENSITY: ret = ERROR_INVALID_PARAMETER; break; case MTSEEK: if (tape_get_feature (TAPE_DRIVE_ABSOLUTE_BLK)) { ret = tape_set_pos (TAPE_ABSOLUTE_BLOCK, op->mt_count); break; } if (! (ret = tape_get_pos (&block))) { ret = tape_set_pos (TAPE_SPACE_RELATIVE_BLOCKS, op->mt_count - block); } break; case MTTELL: if (! (ret = tape_get_pos (&block))) op->mt_count = block; break; case MTSETDRVBUFFER: ret = ERROR_INVALID_PARAMETER; break; case MTFSS: ret = tape_set_pos (TAPE_SPACE_SETMARKS, op->mt_count); break; case MTBSS: ret = tape_set_pos (TAPE_SPACE_SETMARKS, -op->mt_count); break; case MTWSM: ret = tape_write_marks (TAPE_SETMARKS, op->mt_count); break; case MTLOCK: ret = tape_prepare (TAPE_LOCK); break; case MTUNLOCK: ret = tape_prepare (TAPE_UNLOCK); break; case MTLOAD: ret = tape_prepare (TAPE_LOAD); break; case MTUNLOAD: ret = tape_prepare (TAPE_UNLOAD); break; case MTCOMPRESSION: ret = tape_compression (op->mt_count); break; case MTSETPART: case MTMKPART: default: ret = ERROR_INVALID_PARAMETER; break; } } else if (cmd == MTIOCGET) ret = tape_status ((struct mtget *) buf); else if (cmd == MTIOCPOS)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -