diff --git a/src/stored/Makefile.in b/src/stored/Makefile.in index 60c953b7d8d..183297e3c4d 100644 --- a/src/stored/Makefile.in +++ b/src/stored/Makefile.in @@ -2,7 +2,7 @@ @MCOMMON@ srcdir = @srcdir@ -VPATH = @srcdir@ +VPATH = @srcdir@:backends .PATH: @srcdir@ sd_group=@sd_group@ @@ -27,48 +27,52 @@ GNUTLS_LIBS_NONSHARED = @GNUTLS_LIBS_NONSHARED@ first_rule: all dummy: +DEVICE_API_SRCS = unix_file_device.c \ + unix_tape_device.c \ + vtape.c + # bareos-sd SDSRCS = acquire.c ansi_label.c append.c askdir.c authenticate.c \ autochanger.c block.c bsr.c butil.c crc32.c dev.c device.c \ dir_cmd.c ebcdic.c fd_cmds.c job.c label.c lock.c mac.c mount.c \ ndmp_tape.c read_record.c read.c record.c reserve.c scan.c sd_cmds.c \ - sd_plugins.c spool.c status.c stored_conf.c stored.c vol_mgr.c vtape.c \ - wait.c unix_device.c + sd_plugins.c spool.c status.c stored_conf.c stored.c vol_mgr.c \ + wait.c $(DEVICE_API_SRCS) SDOBJS = $(SDSRCS:.c=.o) # btape TAPESRCS = acquire.c ansi_label.c autochanger.c block.c btape.c bsr.c \ butil.c crc32.c dev.c device.c ebcdic.c label.c lock.c mount.c \ read_record.c record.c reserve.c scan.c sd_plugins.c spool.c \ - stored_conf.c vol_mgr.c vtape.c wait.c unix_device.c + stored_conf.c vol_mgr.c wait.c $(DEVICE_API_SRCS) TAPEOBJS = $(TAPESRCS:.c=.o) # bls BLSSRCS = acquire.c ansi_label.c autochanger.c block.c bls.c bsr.c \ butil.c crc32.c dev.c device.c ebcdic.c label.c lock.c mount.c \ read_record.c record.c reserve.c scan.c sd_plugins.c spool.c \ - stored_conf.c vol_mgr.c vtape.c wait.c unix_device.c + stored_conf.c vol_mgr.c wait.c $(DEVICE_API_SRCS) BLSOBJS = $(BLSSRCS:.c=.o) # bextract BEXTSRCS = acquire.c ansi_label.c autochanger.c bextract.c block.c bsr.c \ butil.c crc32.c dev.c device.c ebcdic.c label.c lock.c mount.c \ read_record.c record.c reserve.c scan.c sd_plugins.c spool.c \ - stored_conf.c vol_mgr.c vtape.c wait.c unix_device.c + stored_conf.c vol_mgr.c wait.c $(DEVICE_API_SRCS) BEXTOBJS = $(BEXTSRCS:.c=.o) # bscan SCNSRCS = acquire.c ansi_label.c autochanger.c block.c bscan.c bsr.c \ butil.c crc32.c dev.c device.c ebcdic.c label.c lock.c mount.c \ read_record.c record.c reserve.c scan.c sd_plugins.c spool.c \ - stored_conf.c vol_mgr.c vtape.c wait.c unix_device.c + stored_conf.c vol_mgr.c wait.c $(DEVICE_API_SRCS) SCNOBJS = $(SCNSRCS:.c=.o) # bcopy COPYSRCS = acquire.c ansi_label.c autochanger.c bcopy.c block.c bsr.c \ butil.c crc32.c dev.c device.c ebcdic.c label.c lock.c mount.c \ read_record.c record.c reserve.c scan.c sd_plugins.c spool.c \ - stored_conf.c vol_mgr.c vtape.c wait.c unix_device.c + stored_conf.c vol_mgr.c wait.c $(DEVICE_API_SRCS) COPYOBJS = $(COPYSRCS:.c=.o) SD_LIBS += @CAP_LIBS@ diff --git a/src/stored/acquire.c b/src/stored/acquire.c index 84a66671eb7..10f741eec83 100644 --- a/src/stored/acquire.c +++ b/src/stored/acquire.c @@ -291,7 +291,7 @@ bool acquire_device_for_read(DCR *dcr) /* Mount a specific volume and no other */ Dmsg0(rdbglvl, "calling dir_ask_sysop\n"); - if (!dir_ask_sysop_to_mount_volume(dcr, ST_READ)) { + if (!dir_ask_sysop_to_mount_volume(dcr, ST_READREADY)) { goto get_out; /* error return */ } diff --git a/src/stored/askdir.c b/src/stored/askdir.c index 148130181e6..3e63845a1ff 100644 --- a/src/stored/askdir.c +++ b/src/stored/askdir.c @@ -625,7 +625,7 @@ bool dir_ask_sysop_to_mount_volume(DCR *dcr, int mode) if (!dev->poll && (status == W_TIMEOUT || status == W_MOUNT)) { const char *msg; - if (mode == ST_APPEND) { + if (mode == ST_APPENDREADY) { msg = _("Please mount append Volume \"%s\" or label a new one for:\n" " Job: %s\n" " Storage: %s\n" diff --git a/src/stored/backends/unix_file_device.c b/src/stored/backends/unix_file_device.c new file mode 100644 index 00000000000..440729fcdd1 --- /dev/null +++ b/src/stored/backends/unix_file_device.c @@ -0,0 +1,136 @@ +/* + BAREOS® - Backup Archiving REcovery Open Sourced + + Copyright (C) 2013-2013 Bareos GmbH & Co. KG + + This program is Free Software; you can redistribute it and/or + modify it under the terms of version three of the GNU Affero General Public + License as published by the Free Software Foundation and included + in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ +/* + * UNIX File API device abstraction. + * + * Marco van Wieringen, December 2013 + */ + +#include "bareos.h" +#include "stored.h" +#include "unix_file_device.h" + +int unix_file_device::d_open(const char *pathname, int flags, int mode) +{ + return ::open(pathname, flags, mode); +} + +ssize_t unix_file_device::d_read(int fd, void *buffer, size_t count) +{ + return ::read(fd, buffer, count); +} + +ssize_t unix_file_device::d_write(int fd, const void *buffer, size_t count) +{ + return ::write(fd, buffer, count); +} + +int unix_file_device::d_close(int fd) +{ + return ::close(fd); +} + +int unix_file_device::d_ioctl(int fd, ioctl_req_t request, char *op) +{ + return -1; +} + +boffset_t unix_file_device::d_lseek(DCR *dcr, boffset_t offset, int whence) +{ + return ::lseek(m_fd, offset, whence); +} + +bool unix_file_device::d_truncate(DCR *dcr) +{ + struct stat st; + + if (ftruncate(m_fd, 0) != 0) { + berrno be; + + Mmsg2(errmsg, _("Unable to truncate device %s. ERR=%s\n"), print_name(), be.bstrerror()); + return false; + } + + /* + * Check for a successful ftruncate() and issue a work-around for devices + * (mostly cheap NAS) that don't support truncation. + * Workaround supplied by Martin Schmid as a solution to bug #1011. + * 1. close file + * 2. delete file + * 3. open new file with same mode + * 4. change ownership to original + */ + if (fstat(m_fd, &st) != 0) { + berrno be; + + Mmsg2(errmsg, _("Unable to stat device %s. ERR=%s\n"), print_name(), be.bstrerror()); + return false; + } + + if (st.st_size != 0) { /* ftruncate() didn't work */ + POOL_MEM archive_name(PM_FNAME); + + pm_strcpy(archive_name, dev_name); + if (!IsPathSeparator(archive_name.c_str()[strlen(archive_name.c_str())-1])) { + pm_strcat(archive_name, "/"); + } + pm_strcat(archive_name, dcr->VolumeName); + + Mmsg2(errmsg, _("Device %s doesn't support ftruncate(). Recreating file %s.\n"), + print_name(), archive_name.c_str()); + + /* + * Close file and blow it away + */ + ::close(m_fd); + ::unlink(archive_name.c_str()); + + /* + * Recreate the file -- of course, empty + */ + set_mode(CREATE_READ_WRITE); + if ((m_fd = ::open(archive_name.c_str(), oflags, st.st_mode)) < 0) { + berrno be; + + dev_errno = errno; + Mmsg2(errmsg, _("Could not reopen: %s, ERR=%s\n"), archive_name.c_str(), be.bstrerror()); + Dmsg1(100, "reopen failed: %s", errmsg); + Emsg0(M_FATAL, 0, errmsg); + return false; + } + + /* + * Reset proper owner + */ + chown(archive_name.c_str(), st.st_uid, st.st_gid); + } + + return true; +} + +unix_file_device::~unix_file_device() +{ +} + +unix_file_device::unix_file_device() +{ + m_fd = -1; +} diff --git a/src/stored/backends/unix_file_device.h b/src/stored/backends/unix_file_device.h new file mode 100644 index 00000000000..5200974368c --- /dev/null +++ b/src/stored/backends/unix_file_device.h @@ -0,0 +1,47 @@ +/* + BAREOS® - Backup Archiving REcovery Open Sourced + + Copyright (C) 2013-2013 Bareos GmbH & Co. KG + + This program is Free Software; you can redistribute it and/or + modify it under the terms of version three of the GNU Affero General Public + License as published by the Free Software Foundation, which is + listed in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ +/* + * UNIX File API device abstraction. + * + * Marco van Wieringen, December 2013 + */ + +#ifndef UNIX_FILE_DEVICE_H +#define UNIX_FILE_DEVICE_H + +class unix_file_device: public DEVICE { +public: + unix_file_device(); + ~unix_file_device(); + + /* + * Interface from DEVICE + */ + int d_close(int); + int d_open(const char *pathname, int flags, int mode); + int d_ioctl(int fd, ioctl_req_t request, char *mt = NULL); + boffset_t d_lseek(DCR *dcr, boffset_t offset, int whence); + ssize_t d_read(int fd, void *buffer, size_t count); + ssize_t d_write(int fd, const void *buffer, size_t count); + bool d_truncate(DCR *dcr); +}; + +#endif /* UNIX_FILE_DEVICE_H */ diff --git a/src/stored/unix_device.c b/src/stored/backends/unix_tape_device.c similarity index 56% rename from src/stored/unix_device.c rename to src/stored/backends/unix_tape_device.c index 20040c03f77..1eeba92d6a5 100644 --- a/src/stored/unix_device.c +++ b/src/stored/backends/unix_tape_device.c @@ -18,50 +18,59 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/* + * UNIX Tape API device abstraction. + * + * Marco van Wieringen, December 2013 + */ #include "bareos.h" #include "stored.h" -#include "unix_device.h" +#include "unix_tape_device.h" -int unix_device::d_open(const char *pathname, int flags) +int unix_tape_device::d_open(const char *pathname, int flags, int mode) { - return ::open(pathname, flags); + return ::open(pathname, flags, mode); } -ssize_t unix_device::d_read(int fd, void *buffer, size_t count) +ssize_t unix_tape_device::d_read(int fd, void *buffer, size_t count) { return ::read(fd, buffer, count); } -ssize_t unix_device::d_write(int fd, const void *buffer, size_t count) +ssize_t unix_tape_device::d_write(int fd, const void *buffer, size_t count) { return ::write(fd, buffer, count); } -int unix_device::d_close(int fd) +int unix_tape_device::d_close(int fd) { return ::close(fd); } -int unix_device::d_ioctl(int fd, ioctl_req_t request, char *op) +int unix_tape_device::d_ioctl(int fd, ioctl_req_t request, char *op) { return ::ioctl(fd, request, op); } -boffset_t unix_device::lseek(DCR *dcr, boffset_t offset, int whence) +boffset_t unix_tape_device::d_lseek(DCR *dcr, boffset_t offset, int whence) { - switch (dev_type) { - case B_FILE_DEV: - return ::lseek(m_fd, offset, whence); - } return -1; } -unix_device::~unix_device() +bool unix_tape_device::d_truncate(DCR *dcr) +{ + /* + * Maybe we should rewind and write and eof ???? + */ + return true; /* We don't really truncate tapes */ +} + +unix_tape_device::~unix_tape_device() { } -unix_device::unix_device() +unix_tape_device::unix_tape_device() { m_fd = -1; } diff --git a/src/stored/unix_device.h b/src/stored/backends/unix_tape_device.h similarity index 69% rename from src/stored/unix_device.h rename to src/stored/backends/unix_tape_device.h index 7ff77c3294b..a333c1ac240 100644 --- a/src/stored/unix_device.h +++ b/src/stored/backends/unix_tape_device.h @@ -19,25 +19,29 @@ 02110-1301, USA. */ /* + * UNIX API device abstraction. + * + * Marco van Wieringen, December 2013 */ -#ifndef WIN32_DISK_DEVICE_H -#define WIN32_DISK_DEVICE_H +#ifndef UNIX_TAPE_DEVICE_H +#define UNIX_TAPE_DEVICE_H -class unix_device: public DEVICE { +class unix_tape_device: public DEVICE { public: - unix_device(); - ~unix_device(); + unix_tape_device(); + ~unix_tape_device(); /* * Interface from DEVICE */ int d_close(int); - int d_open(const char *pathname, int flags); - int d_ioctl(int fd, ioctl_req_t request, char *mt=NULL); - boffset_t lseek(DCR *dcr, boffset_t offset, int whence); + int d_open(const char *pathname, int flags, int mode); + int d_ioctl(int fd, ioctl_req_t request, char *mt = NULL); + boffset_t d_lseek(DCR *dcr, boffset_t offset, int whence); ssize_t d_read(int fd, void *buffer, size_t count); ssize_t d_write(int fd, const void *buffer, size_t count); + bool d_truncate(DCR *dcr); }; -#endif /* WIN32_DISK_DEVICE_H */ +#endif /* UNIX_TAPE_DEVICE_H */ diff --git a/src/stored/vtape.c b/src/stored/backends/vtape.c similarity index 98% rename from src/stored/vtape.c rename to src/stored/backends/vtape.c index f53b2cec2ac..d1dfaa668d6 100644 --- a/src/stored/vtape.c +++ b/src/stored/backends/vtape.c @@ -25,7 +25,7 @@ Device { Name = Drive-1 # Maximum File Size = 800M Maximum Volume Size = 3G - Device Type = TAPE + Device Type = vtape Archive Device = /tmp/fake Media Type = DLT-8000 AutomaticMount = yes; # when device opened, read it @@ -49,10 +49,10 @@ Device { */ #include "bareos.h" -#include "stored.h" #ifdef USE_VTAPE -#include "vtape.h" +#include "stored.h" +#include "backends/vtape.h" static int dbglevel = 100; #define FILE_OFFSET 30 @@ -702,7 +702,7 @@ int vtape::bsr(int count) return 0; } -boffset_t vtape::lseek(DCR *dcr, boffset_t offset, int whence) +boffset_t vtape::d_lseek(DCR *dcr, boffset_t offset, int whence) { return -1; } @@ -712,6 +712,11 @@ boffset_t vtape::lseek(int fd, off_t offset, int whence) return ::lseek(fd, offset, whence); } +bool vtape::d_truncate(DCR *dcr) +{ + return true; /* we don't really truncate tapes */ +} + /* BSF => just before last EOF * EOF + BSF => just before EOF * file 0 + BSF => BOT + errno @@ -852,7 +857,7 @@ ssize_t vtape::d_read(int, void *buffer, size_t count) return nb; } -int vtape::d_open(const char *pathname, int flags) +int vtape::d_open(const char *pathname, int flags, int mode) { Dmsg2(dbglevel, "vtape::d_open(%s, %i)\n", pathname, flags); diff --git a/src/stored/vtape.h b/src/stored/backends/vtape.h similarity index 95% rename from src/stored/vtape.h rename to src/stored/backends/vtape.h index 5ff0f470a33..e369aa472b3 100644 --- a/src/stored/vtape.h +++ b/src/stored/backends/vtape.h @@ -83,12 +83,13 @@ class vtape: public DEVICE { /* interface from DEVICE */ int d_close(int); - int d_open(const char *pathname, int flags); + int d_open(const char *pathname, int flags, int mode); int d_ioctl(int fd, ioctl_req_t request, char *mt = NULL); ssize_t d_read(int fd, void *buffer, size_t count); ssize_t d_write(int fd, const void *buffer, size_t count); + bool d_truncate(DCR *dcr); - boffset_t lseek(DCR *dcr, off_t offset, int whence); + boffset_t d_lseek(DCR *dcr, off_t offset, int whence); boffset_t lseek(int fd, off_t offset, int whence); int tape_op(struct mtop *mt_com); diff --git a/src/stored/btape.c b/src/stored/btape.c index 84df77ba4dc..cbad84ba2a5 100644 --- a/src/stored/btape.c +++ b/src/stored/btape.c @@ -36,10 +36,6 @@ #include "stored.h" #include "lib/crypto_cache.h" -#ifdef USE_VTAPE -#include "vtape.h" -#endif - /* Dummy functions */ extern bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code); diff --git a/src/stored/dev.c b/src/stored/dev.c index 82f0fb14d29..36fc21f2e72 100644 --- a/src/stored/dev.c +++ b/src/stored/dev.c @@ -73,13 +73,14 @@ #include "bareos.h" #include "stored.h" #ifdef USE_VTAPE -#include "vtape.h" +#include "backends/vtape.h" #endif #ifdef HAVE_WIN32 -#include "win32_tape_device.h" -#include "win32_file_device.h" +#include "backends/win32_tape_device.h" +#include "backends/win32_file_device.h" #else -#include "unix_device.h" +#include "backends/unix_tape_device.h" +#include "backends/unix_file_device.h" #endif #ifndef O_NONBLOCK @@ -89,7 +90,7 @@ /* Forward referenced functions */ void set_os_device_parameters(DCR *dcr); static bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat); -static const char *mode_to_str(int mode); +static const char *mode_to_str(int omode); static DEVICE *m_init_dev(JCR *jcr, DEVRES *device, bool new_init); /* @@ -120,9 +121,13 @@ m_init_dev(JCR *jcr, DEVRES *device, bool new_init) Dmsg1(400, "max_block_size in device res is %u\n", device->max_block_size); - /* If no device type specified, try to guess */ + /* + * If no device type specified, try to guess + */ if (!device->dev_type) { - /* Check that device is available */ + /* + * Check that device is available + */ if (stat(device->device_name, &statp) < 0) { berrno be; Jmsg2(jcr, M_ERROR, 0, _("Unable to stat device %s: ERR=%s\n"), @@ -136,8 +141,8 @@ m_init_dev(JCR *jcr, DEVRES *device, bool new_init) } else if (S_ISFIFO(statp.st_mode)) { device->dev_type = B_FIFO_DEV; #ifdef USE_VTAPE - /* must set DeviceType = Vtape - * in normal mode, autodetection is disabled + /* + * Must set DeviceType = Vtape in normal mode, autodetection is disabled */ } else if (S_ISREG(statp.st_mode)) { device->dev_type = B_VTAPE_DEV; @@ -149,6 +154,7 @@ m_init_dev(JCR *jcr, DEVRES *device, bool new_init) return NULL; } } + switch (device->dev_type) { #ifdef USE_VTAPE case B_VTAPE_DEV: @@ -164,9 +170,11 @@ m_init_dev(JCR *jcr, DEVRES *device, bool new_init) break; #else case B_TAPE_DEV: + dev = New(unix_tape_device); + break; case B_FILE_DEV: case B_FIFO_DEV: - dev = New(unix_device); + dev = New(unix_file_device); break; #endif default: @@ -247,21 +255,19 @@ m_init_dev(JCR *jcr, DEVRES *device, bool new_init) max_bs = dev->max_block_size; } if (dev->min_block_size > max_bs) { - Jmsg(jcr, M_ERROR_TERM, 0, _("Min block size > max on device %s\n"), - dev->print_name()); + Jmsg(jcr, M_ERROR_TERM, 0, _("Min block size > max on device %s\n"), dev->print_name()); } if (dev->max_block_size > MAX_BLOCK_LENGTH) { Jmsg3(jcr, M_ERROR, 0, _("Block size %u on device %s is too large, using default %u\n"), - dev->max_block_size, dev->print_name(), DEFAULT_BLOCK_SIZE); + dev->max_block_size, dev->print_name(), DEFAULT_BLOCK_SIZE); dev->max_block_size = 0; } if (dev->max_block_size % TAPE_BSIZE != 0) { Jmsg3(jcr, M_WARNING, 0, _("Max block size %u not multiple of device %s block size=%d.\n"), - dev->max_block_size, dev->print_name(), TAPE_BSIZE); + dev->max_block_size, dev->print_name(), TAPE_BSIZE); } if (dev->max_volume_size != 0 && dev->max_volume_size < (dev->max_block_size << 4)) { - Jmsg(jcr, M_ERROR_TERM, 0, _("Max Vol Size < 8 * Max Block Size for device %s\n"), - dev->print_name()); + Jmsg(jcr, M_ERROR_TERM, 0, _("Max Vol Size < 8 * Max Block Size for device %s\n"), dev->print_name()); } dev->errmsg = get_pool_memory(PM_EMSG); @@ -273,30 +279,35 @@ m_init_dev(JCR *jcr, DEVRES *device, bool new_init) Mmsg1(dev->errmsg, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } + if ((errstat = pthread_cond_init(&dev->wait, NULL)) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init cond variable: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } + if ((errstat = pthread_cond_init(&dev->wait_next_vol, NULL)) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init cond variable: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } + if ((errstat = pthread_mutex_init(&dev->spool_mutex, NULL)) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init spool mutex: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } + if ((errstat = dev->init_acquire_mutex()) != 0) { berrno be; dev->dev_errno = errstat; Mmsg1(dev->errmsg, _("Unable to init acquire mutex: ERR=%s\n"), be.bstrerror(errstat)); Jmsg0(jcr, M_ERROR_TERM, 0, dev->errmsg); } + if ((errstat = dev->init_read_acquire_mutex()) != 0) { berrno be; dev->dev_errno = errstat; @@ -443,13 +454,13 @@ bool DEVICE::open(DCR *dcr, int omode) { int preserve = 0; if (is_open()) { - if (openmode == omode) { + if (open_mode == omode) { return true; } else { d_close(m_fd); clear_opened(); Dmsg0(100, "Close fd for mode change.\n"); - preserve = state & (ST_LABEL|ST_APPEND|ST_READ); + preserve = state & (ST_LABEL | ST_APPENDREADY | ST_READREADY); } } if (dcr) { @@ -459,7 +470,7 @@ bool DEVICE::open(DCR *dcr, int omode) Dmsg4(100, "open dev: type=%d dev_name=%s vol=%s mode=%s\n", dev_type, print_name(), getVolCatName(), mode_to_str(omode)); - state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF); + state &= ~(ST_LABEL | ST_APPENDREADY | ST_READREADY | ST_EOT | ST_WEOT | ST_EOF); label_type = B_BAREOS_LABEL; if (is_tape() || is_fifo()) { @@ -470,23 +481,24 @@ bool DEVICE::open(DCR *dcr, int omode) } state |= preserve; /* reset any important state info */ Dmsg2(100, "preserve=0x%x fd=%d\n", preserve, m_fd); + return m_fd >= 0; } -void DEVICE::set_mode(int new_mode) +void DEVICE::set_mode(int mode) { - switch (new_mode) { + switch (mode) { case CREATE_READ_WRITE: - mode = O_CREAT | O_RDWR | O_BINARY; + oflags = O_CREAT | O_RDWR | O_BINARY; break; case OPEN_READ_WRITE: - mode = O_RDWR | O_BINARY; + oflags = O_RDWR | O_BINARY; break; case OPEN_READ_ONLY: - mode = O_RDONLY | O_BINARY; + oflags = O_RDONLY | O_BINARY; break; case OPEN_WRITE_ONLY: - mode = O_WRONLY | O_BINARY; + oflags = O_WRONLY | O_BINARY; break; default: Emsg0(M_ABORT, 0, _("Illegal mode given to open dev.\n")); @@ -511,7 +523,7 @@ void DEVICE::open_tape_device(DCR *dcr, int omode) get_autochanger_loaded_slot(dcr); - openmode = omode; + open_mode = omode; set_mode(omode); if (timeout < 1) { @@ -524,30 +536,39 @@ void DEVICE::open_tape_device(DCR *dcr, int omode) } Dmsg2(100, "Try open %s mode=%s\n", print_name(), mode_to_str(omode)); #if defined(HAVE_WIN32) - - /* Windows Code */ - if ((m_fd = d_open(dev_name, mode)) < 0) { + /* + * Windows Code + */ + if ((m_fd = d_open(dev_name, oflags, 0)) < 0) { dev_errno = errno; } - #else - - /* UNIX Code */ - /* If busy retry each second for max_open_wait seconds */ + /* + * UNIX Code + * + * If busy retry each second for max_open_wait seconds + */ for ( ;; ) { - /* Try non-blocking open */ - m_fd = d_open(dev_name, mode+O_NONBLOCK); + /* + * Try non-blocking open + */ + m_fd = d_open(dev_name, oflags | O_NONBLOCK, 0); if (m_fd < 0) { berrno be; dev_errno = errno; - Dmsg5(100, "Open error on %s omode=%d mode=%x errno=%d: ERR=%s\n", - print_name(), omode, mode, errno, be.bstrerror()); + Dmsg5(100, "Open error on %s omode=%d oflags=%x errno=%d: ERR=%s\n", + print_name(), omode, oflags, errno, be.bstrerror()); } else { - /* Tape open, now rewind it */ + /* + * Tape open, now rewind it + */ Dmsg0(100, "Rewind after open\n"); mt_com.mt_op = MTREW; mt_com.mt_count = 1; - /* rewind only if dev is a tape */ + + /* + * Rewind only if dev is a tape + */ if (is_tape() && (d_ioctl(m_fd, MTIOCTOP, (char *)&mt_com) < 0)) { berrno be; dev_errno = errno; /* set error status from rewind */ @@ -555,19 +576,23 @@ void DEVICE::open_tape_device(DCR *dcr, int omode) clear_opened(); Dmsg2(100, "Rewind error on %s close: ERR=%s\n", print_name(), be.bstrerror(dev_errno)); - /* If we get busy, device is probably rewinding, try again */ + /* + * If we get busy, device is probably rewinding, try again + */ if (dev_errno != EBUSY) { break; /* error -- no medium */ } } else { - /* Got fd and rewind worked, so we must have medium in drive */ + /* + * Got fd and rewind worked, so we must have medium in drive + */ d_close(m_fd); - m_fd = d_open(dev_name, mode); /* open normally */ + m_fd = d_open(dev_name, oflags, 0); /* open normally */ if (m_fd < 0) { berrno be; dev_errno = errno; - Dmsg5(100, "Open error on %s omode=%d mode=%x errno=%d: ERR=%s\n", - print_name(), omode, mode, errno, be.bstrerror()); + Dmsg5(100, "Open error on %s omode=%d oflags=%x errno=%d: ERR=%s\n", + print_name(), omode, oflags, errno, be.bstrerror()); break; } dev_errno = 0; @@ -577,7 +602,10 @@ void DEVICE::open_tape_device(DCR *dcr, int omode) } } bmicrosleep(5, 0); - /* Exceed wait time ? */ + + /* + * Exceed wait time ? + */ if (time(NULL) - start_time >= max_open_wait) { break; /* yes, get out */ } @@ -591,7 +619,9 @@ void DEVICE::open_tape_device(DCR *dcr, int omode) Dmsg1(100, "%s", errmsg); } - /* Stop any open() timer we started */ + /* + * Stop any open() timer we started + */ if (tid) { stop_thread_timer(tid); tid = 0; @@ -611,8 +641,8 @@ void DEVICE::open_file_device(DCR *dcr, int omode) /* * Handle opening of File Archive (not a tape) */ - pm_strcpy(archive_name, dev_name); + /* * If this is a virtual autochanger (i.e. changer_res != NULL) * we simply use the device name, assuming it has been @@ -634,24 +664,29 @@ void DEVICE::open_file_device(DCR *dcr, int omode) mount(dcr, 1); /* do mount if required */ - openmode = omode; + open_mode = omode; set_mode(omode); - /* If creating file, give 0640 permissions */ + + /* + * If creating file, give 0640 permissions + */ Dmsg3(100, "open disk: mode=%s open(%s, 0x%x, 0640)\n", mode_to_str(omode), - archive_name.c_str(), mode); - /* Use system open() */ - if ((m_fd = ::open(archive_name.c_str(), mode, 0640)) < 0) { + archive_name.c_str(), oflags); + + if ((m_fd = d_open(archive_name.c_str(), oflags, 0640)) < 0) { berrno be; dev_errno = errno; Mmsg2(errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(), be.bstrerror()); Dmsg1(100, "open failed: %s", errmsg); } + if (m_fd >= 0) { dev_errno = 0; file = 0; file_addr = 0; } + Dmsg1(100, "open dev: disk fd=%d opened\n", m_fd); } @@ -674,6 +709,7 @@ bool DEVICE::rewind(DCR *dcr) if (m_fd < 0) { return false; } + if (is_tape()) { mt_com.mt_op = MTREW; mt_com.mt_count = 1; @@ -695,10 +731,10 @@ bool DEVICE::rewind(DCR *dcr) * So, we close the drive and re-open it. */ if (first && dcr) { - int open_mode = openmode; + int oo_mode = open_mode; d_close(m_fd); clear_opened(); - open(dcr, open_mode); + open(dcr, oo_mode); if (m_fd < 0) { return false; } @@ -731,7 +767,11 @@ bool DEVICE::rewind(DCR *dcr) print_name(), be.bstrerror()); return false; } + } else { + Mmsg1(errmsg, _("Don't know how to rewind device of type %d\n"), dev_type); + return false; } + return true; } @@ -955,6 +995,7 @@ bool DEVICE::update_pos(DCR *dcr) file = (uint32_t)(pos >> 32); } } + return ok; } @@ -1134,7 +1175,7 @@ bool DEVICE::offline() return true; /* device not open */ } - state &= ~(ST_APPEND|ST_READ|ST_EOT|ST_EOF|ST_WEOT); /* remove EOF/EOT flags */ + state &= ~(ST_APPENDREADY | ST_READREADY | ST_EOT | ST_EOF | ST_WEOT); /* remove EOF/EOT flags */ block_num = file = 0; file_size = 0; file_addr = 0; @@ -1853,14 +1894,14 @@ void DEVICE::close(DCR *dcr) /* Clean up device packet so it can be reused */ clear_opened(); - state &= ~(ST_LABEL | ST_READ | ST_APPEND | ST_EOT | ST_WEOT | + state &= ~(ST_LABEL | ST_READREADY | ST_APPENDREADY | ST_EOT | ST_WEOT | ST_EOF | ST_MOUNTED | ST_MEDIA | ST_SHORT); label_type = B_BAREOS_LABEL; file = block_num = 0; file_size = 0; file_addr = 0; EndFile = EndBlock = 0; - openmode = 0; + open_mode = 0; clear_volhdr(); memset(&VolCatInfo, 0, sizeof(VolCatInfo)); if (tid) { @@ -1874,78 +1915,16 @@ void DEVICE::close(DCR *dcr) */ bool DEVICE::truncate(DCR *dcr) { - struct stat st; - DEVICE *dev = this; - Dmsg1(100, "truncate %s\n", print_name()); - switch (dev_type) { - case B_VTL_DEV: - case B_VTAPE_DEV: - case B_TAPE_DEV: - /* maybe we should rewind and write and eof ???? */ - return true; /* we don't really truncate tapes */ - case B_FILE_DEV: - for ( ;; ) { - if (ftruncate(dev->m_fd, 0) != 0) { - berrno be; - Mmsg2(errmsg, _("Unable to truncate device %s. ERR=%s\n"), - print_name(), be.bstrerror()); - return false; - } - - /* - * Check for a successful ftruncate() and issue a work-around for devices - * (mostly cheap NAS) that don't support truncation. - * Workaround supplied by Martin Schmid as a solution to bug #1011. - * 1. close file - * 2. delete file - * 3. open new file with same mode - * 4. change ownership to original - */ - - if (fstat(dev->m_fd, &st) != 0) { - berrno be; - Mmsg2(errmsg, _("Unable to stat device %s. ERR=%s\n"), - print_name(), be.bstrerror()); - return false; - } - - if (st.st_size != 0) { /* ftruncate() didn't work */ - POOL_MEM archive_name(PM_FNAME); - - pm_strcpy(archive_name, dev_name); - if (!IsPathSeparator(archive_name.c_str()[strlen(archive_name.c_str())-1])) { - pm_strcat(archive_name, "/"); - } - pm_strcat(archive_name, dcr->VolumeName); - - Mmsg2(errmsg, _("Device %s doesn't support ftruncate(). Recreating file %s.\n"), - print_name(), archive_name.c_str()); - - /* Close file and blow it away */ - ::close(dev->m_fd); - ::unlink(archive_name.c_str()); - - /* Recreate the file -- of course, empty */ - dev->set_mode(CREATE_READ_WRITE); - if ((dev->m_fd = ::open(archive_name.c_str(), mode, st.st_mode)) < 0) { - berrno be; - dev_errno = errno; - Mmsg2(errmsg, _("Could not reopen: %s, ERR=%s\n"), archive_name.c_str(), - be.bstrerror()); - Dmsg1(100, "reopen failed: %s", errmsg); - Emsg0(M_FATAL, 0, errmsg); - return false; - } + return d_truncate(dcr); +} - /* Reset proper owner */ - chown(archive_name.c_str(), st.st_uid, st.st_gid); - } - break; - } - return true; - } - return false; +/* + * Seek on a volume. + */ +boffset_t DEVICE::lseek(DCR *dcr, boffset_t offset, int whence) +{ + return d_lseek(dcr, offset, whence); } /* diff --git a/src/stored/dev.h b/src/stored/dev.h index fa2061397da..a6dc964f687 100644 --- a/src/stored/dev.h +++ b/src/stored/dev.h @@ -85,7 +85,7 @@ enum { B_FILE_DEV = 1, B_TAPE_DEV, B_FIFO_DEV, - B_VTAPE_DEV, /* change to B_TAPE_DEV after init */ + B_VTAPE_DEV, B_VTL_DEV }; @@ -148,8 +148,8 @@ enum { #define ST_LABEL (1 << 6) /* label found */ #define ST_MALLOC (1 << 7) /* dev packet malloc'ed in init_dev() */ -#define ST_APPEND (1 << 8) /* ready for Bareos append */ -#define ST_READ (1 << 9) /* ready for Bareos read */ +#define ST_APPENDREADY (1 << 8) /* Ready for Bareos append */ +#define ST_READREADY (1 << 9) /* Ready for Bareos read */ #define ST_EOT (1 << 10) /* at end of tape */ #define ST_WEOT (1 << 11) /* Got EOT on write */ #define ST_EOF (1 << 12) /* Read EOF i.e. zero bytes */ @@ -240,9 +240,9 @@ class DEVICE: public SMARTALLOC { int capabilities; /* capabilities mask */ int state; /* state mask */ int dev_errno; /* Our own errno */ - int mode; /* read/write modes */ - int openmode; /* parameter passed to open_dev (useful to reopen the device) */ - int dev_type; /* device type */ + int oflags; /* Read/write flags */ + int open_mode; /* Parameter passed to open_dev (useful to reopen the device) */ + int dev_type; /* Device type */ bool autoselect; /* Autoselect in autochanger */ bool norewindonclose; /* Don't rewind tape drive on close */ bool initiated; /* set when init_dev() called */ @@ -323,11 +323,11 @@ class DEVICE: public SMARTALLOC { int is_part_spooled() const { return state & ST_PART_SPOOLED; } int have_media() const { return state & ST_MEDIA; } int is_short_block() const { return state & ST_SHORT; } - int is_busy() const { return (state & ST_READ) || num_writers || num_reserved(); } + int is_busy() const { return (state & ST_READREADY) || num_writers || num_reserved(); } int at_eof() const { return state & ST_EOF; } int at_eot() const { return state & ST_EOT; } int at_weot() const { return state & ST_WEOT; } - int can_append() const { return state & ST_APPEND; } + int can_append() const { return state & ST_APPENDREADY; } int is_crypto_enabled() const { return state & ST_CRYPTOKEY; } /* * can_write() is meant for checking at the end of a job to see @@ -336,7 +336,7 @@ class DEVICE: public SMARTALLOC { */ int can_write() const { return is_open() && can_append() && is_labeled() && !at_weot(); } - int can_read() const { return state & ST_READ; } + int can_read() const { return state & ST_READREADY; } bool can_steal_lock() const { return m_blocked && (m_blocked == BST_UNMOUNTED || m_blocked == BST_WAITING_FOR_SYSOP || @@ -355,9 +355,9 @@ class DEVICE: public SMARTALLOC { void set_ateot(); /* in dev.c */ void set_eot() { state |= ST_EOT; }; void set_eof() { state |= ST_EOF; }; - void set_append() { state |= ST_APPEND; }; + void set_append() { state |= ST_APPENDREADY; }; void set_labeled() { state |= ST_LABEL; }; - inline void set_read() { state |= ST_READ; }; + inline void set_read() { state |= ST_READREADY; }; void set_offline() { state |= ST_OFFLINE; }; void set_mounted() { state |= ST_MOUNTED; }; void set_media() { state |= ST_MEDIA; }; @@ -371,8 +371,8 @@ class DEVICE: public SMARTALLOC { void set_load() { m_load = true; }; void inc_reserved() { m_num_reserved++; } void dec_reserved() { m_num_reserved--; ASSERT(m_num_reserved>=0); }; - void clear_append() { state &= ~ST_APPEND; }; - void clear_read() { state &= ~ST_READ; }; + void clear_append() { state &= ~ST_APPENDREADY; }; + void clear_read() { state &= ~ST_READREADY; }; void clear_labeled() { state &= ~ST_LABEL; }; void clear_offline() { state &= ~ST_OFFLINE; }; void clear_eot() { state &= ~ST_EOT; }; @@ -429,16 +429,21 @@ class DEVICE: public SMARTALLOC { uint32_t get_block_num() const { return block_num; }; int fd() const { return m_fd; }; - /* low level operations */ + /* + * Low level operations + */ virtual int d_ioctl(int fd, ioctl_req_t request, char *mt_com = NULL) = 0; - virtual int d_open(const char *pathname, int flags) = 0; + virtual int d_open(const char *pathname, int flags, int mode) = 0; virtual int d_close(int fd) = 0; virtual ssize_t d_read(int fd, void *buffer, size_t count) = 0; virtual ssize_t d_write(int fd, const void *buffer, size_t count) = 0; - virtual boffset_t lseek(DCR *dcr, boffset_t offset, int whence) = 0; + virtual boffset_t d_lseek(DCR *dcr, boffset_t offset, int whence) = 0; + virtual bool d_truncate(DCR *dcr) = 0; virtual bool update_pos(DCR *dcr); virtual bool rewind(DCR *dcr); - virtual bool truncate(DCR *dcr); + bool truncate(DCR *dcr); + boffset_t lseek(DCR *dcr, boffset_t offset, int whence); + /* * Locking and blocking calls */ @@ -477,10 +482,11 @@ class DEVICE: public SMARTALLOC { bool is_blocked() const { return m_blocked != BST_NOT_BLOCKED; }; const char *print_blocked() const; /* in dev.c */ +protected: + void set_mode(int mode); /* in dev.c */ private: bool do_tape_mount(DCR *dcr, int mount, int dotimeout); /* in dev.c */ bool do_file_mount(DCR *dcr, int mount, int dotimeout); /* in dev.c */ - void set_mode(int omode); /* in dev.c */ void open_tape_device(DCR *dcr, int omode); /* in dev.c */ void open_file_device(DCR *dcr, int omode); /* in dev.c */ }; diff --git a/src/stored/mount.c b/src/stored/mount.c index ff376564d04..370974a9675 100644 --- a/src/stored/mount.c +++ b/src/stored/mount.c @@ -91,7 +91,7 @@ bool DCR::mount_next_write_volume() */ VolCatInfo.Slot = 0; V(mount_mutex); - if (!dir_ask_sysop_to_mount_volume(dcr, ST_APPEND)) { + if (!dir_ask_sysop_to_mount_volume(dcr, ST_APPENDREADY)) { Jmsg(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"), dev->print_name()); goto no_lock_bail_out; @@ -162,7 +162,7 @@ bool DCR::mount_next_write_volume() if (ask) { V(mount_mutex); dcr->setVolCatInfo(false); /* out of date when Vols unlocked */ - if (!dir_ask_sysop_to_mount_volume(dcr, ST_APPEND)) { + if (!dir_ask_sysop_to_mount_volume(dcr, ST_APPENDREADY)) { Dmsg0(150, "Error return ask_sysop ...\n"); goto no_lock_bail_out; } @@ -608,8 +608,7 @@ void DCR::do_swapping(bool is_writing) } /* - * Check if the current position on the volume corresponds to - * what is in the catalog. + * Check if the current position on the volume corresponds to what is in the catalog. */ bool DCR::is_eod_valid() { @@ -644,6 +643,7 @@ bool DCR::is_eod_valid() } } else if (dev->is_file()) { char ed1[50], ed2[50]; + boffset_t pos; pos = dev->lseek(dcr, (boffset_t)0, SEEK_END); if (dev->VolCatInfo.VolCatBytes == (uint64_t)pos) { @@ -674,7 +674,13 @@ bool DCR::is_eod_valid() mark_volume_in_error(); return false; } + } else { + Mmsg1(jcr->errmsg, _("Don't know how to check if EOD is valid for a device of type %d\n"), dev->dev_type); + Jmsg(jcr, M_ERROR, 0, jcr->errmsg); + Dmsg0(050, jcr->errmsg); + return false; } + return true; } diff --git a/src/stored/reserve.c b/src/stored/reserve.c index eb6ea1e925b..66cc3284a4e 100644 --- a/src/stored/reserve.c +++ b/src/stored/reserve.c @@ -757,7 +757,7 @@ static int reserve_device(RCTX &rctx) } /* - * We "reserve" the drive by setting the ST_READ bit. No one else + * We "reserve" the drive by setting the ST_READREADY bit. No one else * should touch the drive until that is cleared. * This allows the DIR to "reserve" the device before actually * starting the job. @@ -784,9 +784,9 @@ static bool reserve_device_for_read(DCR *dcr) } if (dev->is_busy()) { - Dmsg4(dbglvl, "Device %s is busy ST_READ=%d num_writers=%d reserved=%d.\n", + Dmsg4(dbglvl, "Device %s is busy ST_READREADY=%d num_writers=%d reserved=%d.\n", dev->print_name(), - dev->state & ST_READ?1:0, dev->num_writers, dev->num_reserved()); + dev->state & ST_READREADY ? 1 : 0, dev->num_writers, dev->num_reserved()); Mmsg(jcr->errmsg, _("3602 JobId=%u device %s is busy (already reading/writing).\n"), jcr->JobId, dev->print_name()); queue_reserve_message(jcr); diff --git a/src/win32/stored/Makefile b/src/win32/stored/Makefile index 7d8053daa47..aefa3ee5b04 100644 --- a/src/win32/stored/Makefile +++ b/src/win32/stored/Makefile @@ -18,7 +18,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # -VPATH = .:../../stored:../generic +VPATH = .:../../stored:../generic:backends include ../Makefile.inc @@ -39,30 +39,32 @@ LDLIBS_FIND = ../lib/libbareos.a \ $(MINGW_LIB)/libpthreadGCE2.a \ $(WINSOCKLIB) -lole32 -loleaut32 -luuid -lcomctl32 +DEVICE_API_SRCS = win32_tape_device.c win32_file_device.c + SVRSRCS = acquire.c ansi_label.c append.c askdir.c authenticate.c \ autochanger.c block.c bsr.c butil.c crc32.c dev.c device.c \ dir_cmd.c ebcdic.c fd_cmds.c job.c label.c lock.c mac.c mount.c \ ndmp_tape.c read_record.c read.c record.c reserve.c scan.c sd_cmds.c \ sd_plugins.c spool.c status.c stored_conf.c stored.c vol_mgr.c \ - wait.c win32_tape_device.c win32_file_device.c service.c main.c + wait.c service.c main.c $(DEVICE_API_SRCS) SVROBJS = $(SVRSRCS:.c=.o) TAPESRCS = acquire.c ansi_label.c autochanger.c block.c btape.c bsr.c \ butil.c crc32.c dev.c device.c ebcdic.c label.c lock.c mount.c \ read_record.c record.c reserve.c scan.c sd_plugins.c spool.c \ - stored_conf.c vol_mgr.c wait.c win32_tape_device.c win32_file_device.c + stored_conf.c vol_mgr.c wait.c $(DEVICE_API_SRCS) TAPEOBJS = $(TAPESRCS:.c=.o) BLSSRCS = acquire.c ansi_label.c autochanger.c block.c bls.c bsr.c \ butil.c crc32.c dev.c device.c ebcdic.c label.c lock.c mount.c \ read_record.c record.c reserve.c scan.c sd_plugins.c spool.c \ - stored_conf.c vol_mgr.c wait.c win32_tape_device.c win32_file_device.c + stored_conf.c vol_mgr.c wait.c $(DEVICE_API_SRCS) BLSOBJS = $(BLSSRCS:.c=.o) BEXTSRCS = acquire.c ansi_label.c autochanger.c bextract.c block.c bsr.c \ butil.c crc32.c dev.c device.c ebcdic.c label.c lock.c mount.c \ read_record.c record.c reserve.c scan.c sd_plugins.c spool.c \ - stored_conf.c vol_mgr.c wait.c win32_tape_device.c win32_file_device.c + stored_conf.c vol_mgr.c wait.c $(DEVICE_API_SRCS) BEXTOBJS = $(BEXTSRCS:.c=.o) WINDRESSRCS = storedres.rc diff --git a/src/win32/stored/backends/win32_file_device.c b/src/win32/stored/backends/win32_file_device.c new file mode 100644 index 00000000000..b221c924d0e --- /dev/null +++ b/src/win32/stored/backends/win32_file_device.c @@ -0,0 +1,131 @@ +/* + BAREOS® - Backup Archiving REcovery Open Sourced + + Copyright (C) 2013-2014 Bareos GmbH & Co. KG + + This program is Free Software; you can redistribute it and/or + modify it under the terms of version three of the GNU Affero General Public + License as published by the Free Software Foundation and included + in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include "bareos.h" +#include "stored.h" +#include "win32_file_device.h" + +int win32_file_device::d_open(const char *pathname, int flags, int mode) +{ + return ::open(pathname, flags, mode); +} + +ssize_t win32_file_device::d_read(int fd, void *buffer, size_t count) +{ + return ::read(fd, buffer, count); +} + +ssize_t win32_file_device::d_write(int fd, const void *buffer, size_t count) +{ + return ::write(fd, buffer, count); +} + +int win32_file_device::d_close(int fd) +{ + return ::close(fd); +} + +int win32_file_device::d_ioctl(int fd, ioctl_req_t request, char *op) +{ + return -1; +} + +boffset_t win32_file_device::d_lseek(DCR *dcr, boffset_t offset, int whence) +{ + return ::_lseeki64(m_fd, (__int64)offset, whence); +} + +bool win32_file_device::d_truncate(DCR *dcr) +{ + struct stat st; + + if (ftruncate(m_fd, 0) != 0) { + berrno be; + + Mmsg2(errmsg, _("Unable to truncate device %s. ERR=%s\n"), print_name(), be.bstrerror()); + return false; + } + + /* + * Check for a successful ftruncate() and issue a work-around for devices + * (mostly cheap NAS) that don't support truncation. + * Workaround supplied by Martin Schmid as a solution to bug #1011. + * 1. close file + * 2. delete file + * 3. open new file with same mode + * 4. change ownership to original + */ + if (fstat(m_fd, &st) != 0) { + berrno be; + + Mmsg2(errmsg, _("Unable to stat device %s. ERR=%s\n"), print_name(), be.bstrerror()); + return false; + } + + if (st.st_size != 0) { /* ftruncate() didn't work */ + POOL_MEM archive_name(PM_FNAME); + + pm_strcpy(archive_name, dev_name); + if (!IsPathSeparator(archive_name.c_str()[strlen(archive_name.c_str())-1])) { + pm_strcat(archive_name, "/"); + } + pm_strcat(archive_name, dcr->VolumeName); + + Mmsg2(errmsg, _("Device %s doesn't support ftruncate(). Recreating file %s.\n"), + print_name(), archive_name.c_str()); + + /* + * Close file and blow it away + */ + ::close(m_fd); + ::unlink(archive_name.c_str()); + + /* + * Recreate the file -- of course, empty + */ + set_mode(CREATE_READ_WRITE); + if ((m_fd = ::open(archive_name.c_str(), oflags, st.st_mode)) < 0) { + berrno be; + + dev_errno = errno; + Mmsg2(errmsg, _("Could not reopen: %s, ERR=%s\n"), archive_name.c_str(), be.bstrerror()); + Dmsg1(100, "reopen failed: %s", errmsg); + Emsg0(M_FATAL, 0, errmsg); + return false; + } + + /* + * Reset proper owner + */ + chown(archive_name.c_str(), st.st_uid, st.st_gid); + } + + return true; +} + +win32_file_device::~win32_file_device() +{ +} + +win32_file_device::win32_file_device() +{ + m_fd = -1; +} diff --git a/src/win32/stored/win32_file_device.h b/src/win32/stored/backends/win32_file_device.h similarity index 77% rename from src/win32/stored/win32_file_device.h rename to src/win32/stored/backends/win32_file_device.h index 41173fab3ee..73be64c23b0 100644 --- a/src/win32/stored/win32_file_device.h +++ b/src/win32/stored/backends/win32_file_device.h @@ -1,7 +1,7 @@ /* BAREOS® - Backup Archiving REcovery Open Sourced - Copyright (C) 2013-2013 Bareos GmbH & Co. KG + Copyright (C) 2013-2014 Bareos GmbH & Co. KG This program is Free Software; you can redistribute it and/or modify it under the terms of version three of the GNU Affero General Public @@ -19,6 +19,9 @@ 02110-1301, USA. */ /* + * Windows File API device abstraction. + * + * Marco van Wieringen, December 2013 */ #ifndef WIN32_FILE_DEVICE_H @@ -33,11 +36,12 @@ class win32_file_device: public DEVICE { * Interface from DEVICE */ int d_close(int); - int d_open(const char *pathname, int flags); - int d_ioctl(int fd, ioctl_req_t request, char *mt=NULL); + int d_open(const char *pathname, int flags, int mode); + int d_ioctl(int fd, ioctl_req_t request, char *mt = NULL); ssize_t d_read(int fd, void *buffer, size_t count); ssize_t d_write(int fd, const void *buffer, size_t count); - boffset_t lseek(DCR *dcr, boffset_t offset, int whence); + boffset_t d_lseek(DCR *dcr, boffset_t offset, int whence); + bool d_truncate(DCR *dcr); }; #endif /* WIN32_FILE_DEVICE_H */ diff --git a/src/win32/stored/win32_tape_device.c b/src/win32/stored/backends/win32_tape_device.c similarity index 99% rename from src/win32/stored/win32_tape_device.c rename to src/win32/stored/backends/win32_tape_device.c index 1420e5af92d..4a7634ecfd8 100644 --- a/src/win32/stored/win32_tape_device.c +++ b/src/win32/stored/backends/win32_tape_device.c @@ -152,7 +152,7 @@ TAPE_HANDLE_INFO TapeHandleTable[] = static DWORD GetTapePositionInfo(HANDLE hDevice, PTAPE_POSITION_INFO TapePositionInfo); static DWORD GetDensityBlockSize(HANDLE hDevice, DWORD *pdwDensity, DWORD *pdwBlockSize); -int win32_tape_device::d_open(const char *pathname, int flags) +int win32_tape_device::d_open(const char *pathname, int flags, int mode) { HANDLE hDevice = INVALID_HANDLE_VALUE; char szDeviceName[256] = "\\\\.\\"; @@ -397,11 +397,16 @@ int win32_tape_device::d_ioctl(int fd, ioctl_req_t request, char *op) return result; } -boffset_t win32_tape_device::lseek(DCR *dcr, boffset_t offset, int whence) +boffset_t win32_tape_device::d_lseek(DCR *dcr, boffset_t offset, int whence) { return -1; } +bool win32_tape_device::d_truncate(DCR *dcr) +{ + return true; /* we don't really truncate tapes */ +} + int win32_tape_device::tape_op(struct mtop *mt_com) { DWORD result = NO_ERROR; diff --git a/src/win32/stored/win32_tape_device.h b/src/win32/stored/backends/win32_tape_device.h similarity index 78% rename from src/win32/stored/win32_tape_device.h rename to src/win32/stored/backends/win32_tape_device.h index b8bae98ad97..955b18401a2 100644 --- a/src/win32/stored/win32_tape_device.h +++ b/src/win32/stored/backends/win32_tape_device.h @@ -1,7 +1,7 @@ /* BAREOS® - Backup Archiving REcovery Open Sourced - Copyright (C) 2013-2013 Bareos GmbH & Co. KG + Copyright (C) 2013-2014 Bareos GmbH & Co. KG This program is Free Software; you can redistribute it and/or modify it under the terms of version three of the GNU Affero General Public @@ -19,6 +19,9 @@ 02110-1301, USA. */ /* + * Windows Tape API device abstraction. + * + * Marco van Wieringen, December 2013 */ #ifndef WIN32_TAPE_DEVICE_H @@ -33,11 +36,12 @@ class win32_tape_device: public DEVICE { * Interface from DEVICE */ int d_close(int); - int d_open(const char *pathname, int flags); - int d_ioctl(int fd, ioctl_req_t request, char *mt=NULL); + int d_open(const char *pathname, int flags, int mode); + int d_ioctl(int fd, ioctl_req_t request, char *mt = NULL); ssize_t d_read(int fd, void *buffer, size_t count); ssize_t d_write(int fd, const void *buffer, size_t count); - boffset_t lseek(DCR *dcr, boffset_t offset, int whence); + boffset_t d_lseek(DCR *dcr, boffset_t offset, int whence); + bool d_truncate(DCR *dcr); int tape_op(struct mtop *mt_com); int tape_get(struct mtget *mt_com); diff --git a/src/win32/stored/win32_file_device.c b/src/win32/stored/win32_file_device.c deleted file mode 100644 index 0efd082c9b6..00000000000 --- a/src/win32/stored/win32_file_device.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - BAREOS® - Backup Archiving REcovery Open Sourced - - Copyright (C) 2013-2013 Bareos GmbH & Co. KG - - This program is Free Software; you can redistribute it and/or - modify it under the terms of version three of the GNU Affero General Public - License as published by the Free Software Foundation and included - in the file LICENSE. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#include "bareos.h" -#include "stored.h" -#include "win32_file_device.h" - -int win32_file_device::d_open(const char *pathname, int flags) -{ - return ::open(pathname, flags); -} - -ssize_t win32_file_device::d_read(int fd, void *buffer, size_t count) -{ - return ::read(fd, buffer, count); -} - -ssize_t win32_file_device::d_write(int fd, const void *buffer, size_t count) -{ - return ::write(fd, buffer, count); -} - -int win32_file_device::d_close(int fd) -{ - return ::close(fd); -} - -int win32_file_device::d_ioctl(int fd, ioctl_req_t request, char *op) -{ - return -1; -} - -boffset_t win32_file_device::lseek(DCR *dcr, boffset_t offset, int whence) -{ - return ::_lseeki64(m_fd, (__int64)offset, whence); -} - -win32_file_device::~win32_file_device() -{ -} - -win32_file_device::win32_file_device() -{ - m_fd = -1; -}