device->dev_type = B_DVD_DEV;
}
}
-
- dev = (DEVICE *)malloc(sizeof(DEVICE));
- memset(dev, 0, sizeof(DEVICE));
+ switch (device->dev_type) {
+ case B_DVD_DEV:
+ Jmsg0(jcr, M_FATAL, 0, _("DVD support is now deprecated\n"));
+ return NULL;
+ case B_VTAPE_DEV:
+ dev = new vtape;
+ break;
+#ifdef USE_FTP
+ case B_FTP_DEV:
+ dev = new ftp_device;
+ break;
+#endif
+#ifdef HAVE_WIN32
+/* TODO: defined in src/win32/stored/mtops.cpp */
+ case B_TAPE_DEV:
+ dev = new win32_tape_device;
+ break;
+ case B_FILE_DEV:
+ dev = new win32_file_device;
+ break;
+#else
+ case B_TAPE_DEV:
+ case B_FILE_DEV:
+ case B_FIFO_DEV:
+ dev = new DEVICE;
+ break;
+#endif
+ default:
+ return NULL;
+ }
dev->clear_slot(); /* unknown */
/* Copy user supplied device parameters from Resource */
dev->drive_index = device->drive_index;
dev->autoselect = device->autoselect;
dev->dev_type = device->dev_type;
- dev->init_backend();
if (dev->is_tape()) { /* No parts on tapes */
dev->max_part_size = 0;
} else {
* - Check that the mount point is available
* - Check that (un)mount commands are defined
*/
- if ((dev->is_file() || dev->is_dvd()) && dev->requires_mount()) {
+ if (dev->is_file() && dev->requires_mount()) {
if (!device->mount_point || stat(device->mount_point, &statp) < 0) {
berrno be;
dev->dev_errno = errno;
Jmsg0(jcr, M_ERROR_TERM, 0, _("Mount and unmount commands must defined for a device which requires mount.\n"));
}
}
- if (dev->is_dvd()) {
- if (!device->write_part_command) {
- Jmsg0(jcr, M_ERROR_TERM, 0, _("Write part command must be defined for a device which requires mount.\n"));
- }
- }
/* Sanity check */
if (dev->max_block_size == 0) {
return dev;
}
-/* Choose the right backend */
-void DEVICE::init_backend()
+/* default primitives are designed for file */
+int DEVICE::d_open(const char *pathname, int flags)
{
+ return ::open(pathname, flags);
+}
-#ifdef HAVE_WIN32
- if (is_tape()) {
- d_open = win32_tape_open;
- d_write = win32_tape_write;
- d_close = win32_tape_close;
- d_ioctl = win32_tape_ioctl;
- d_read = win32_tape_read;
+int DEVICE::d_close(int fd)
+{
+ return ::close(fd);
+}
- } else {
- d_open = ::open;
- d_close = ::close;
- d_ioctl = win32_ioctl; /* dummy function */
- d_write = win32_write; /* win32 read/write are not POSIX */
- d_read = win32_read;
- }
-
-#else /* POSIX / UNIX Interface */
- if (is_vtape()) { /* test backend */
- d_open = vtape_open; /* vtape isn't available for WIN32 or FreeBSD */
- d_write = vtape_write;
- d_close = vtape_close;
- d_ioctl = vtape_ioctl;
- d_read = vtape_read;
-
- } else { /* tape and file are using normal io */
- d_open = ::open;
- d_write = ::write;
- d_close = ::close;
- d_ioctl = ::ioctl;
- d_read = ::read;
- }
-#endif
+int DEVICE::d_ioctl(int fd, ioctl_req_t request, char *mt_com)
+{
+ return ::ioctl(fd, request, mt_com);
+}
+
+ssize_t DEVICE::d_read(int fd, void *buffer, size_t count)
+{
+ return ::read(fd, buffer, count);
+}
+
+ssize_t DEVICE::d_write(int fd, const void *buffer, size_t count)
+{
+ return ::write(fd, buffer, count);
}
/*
print_name(), getVolCatName(), mode_to_str(omode));
state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
label_type = B_BACULA_LABEL;
+
if (is_tape() || is_fifo()) {
open_tape_device(dcr, omode);
- } else if (is_dvd()) {
- Dmsg1(100, "call open_dvd_device mode=%s\n", mode_to_str(omode));
- open_dvd_device(dcr, omode);
+ } else if (is_ftp()) {
+ open_device(dcr, omode);
} else {
Dmsg1(100, "call open_file_device mode=%s\n", mode_to_str(omode));
open_file_device(dcr, omode);
Dmsg1(100, "open dev: tape %d opened\n", m_fd);
}
+void DEVICE::open_device(DCR *dcr, int omode)
+{
+ /* do nothing waiting to split open_file/tape_device */
+}
/*
* Open a file device
m_fd, part, num_dvd_parts, part_size);
}
-/*
- * Open a DVD device. N.B. at this point, dcr->getVolCatName()
- * (NB:??? I think it's getVolCatName() that is right)
- * has the desired Volume name, but there is NO assurance that
- * any other field of VolCatInfo is correct.
- */
-void DEVICE::open_dvd_device(DCR *dcr, int omode)
-{
- POOL_MEM archive_name(PM_FNAME);
- struct stat filestat;
-
- /*
- * Handle opening of DVD Volume
- */
- Dmsg2(100, "Enter: open_dvd_dev: DVD vol=%s mode=%s\n",
- &dcr->VolCatInfo, mode_to_str(omode));
-
- /*
- * For a DVD we must always pull the state info from dcr->VolCatInfo
- * This is a bit ugly, but is necessary because we need to open/close/re-open
- * the dvd file in order to properly mount/unmount and access the
- * DVD. So we store the state of the DVD as far as is known in the
- * catalog in dcr->VolCatInfo, and thus we refresh the dev->VolCatInfo
- * copy here, when opening.
- */
- VolCatInfo = dcr->VolCatInfo; /* structure assignment */
- Dmsg1(100, "Volume=%s\n", getVolCatName());
-
- if (VolCatInfo.VolCatName[0] == 0) {
- Dmsg1(10, "Could not open DVD device %s. No Volume name given.\n",
- print_name());
- Mmsg(errmsg, _("Could not open DVD device %s. No Volume name given.\n"),
- print_name());
- clear_opened();
- return;
- }
-
- if (part == 0) {
- Dmsg0(100, "Set part=1\n");
- part = 1; /* count from 1 */
- file_size = 0;
- }
- part_size = 0;
- if (num_dvd_parts != VolCatInfo.VolCatParts) {
- num_dvd_parts = VolCatInfo.VolCatParts;
- }
-
- /*
- * If we are not trying to access the last part, set mode to
- * OPEN_READ_ONLY as writing would be an error.
- */
- Dmsg2(100, "open DVD part=%d num_dvd_parts=%d\n", part, num_dvd_parts);
- /* Now find the name of the part that we want to access */
- if (part <= num_dvd_parts) {
- omode = OPEN_READ_ONLY;
- make_mounted_dvd_filename(this, archive_name);
- set_part_spooled(false);
- } else {
- omode = OPEN_READ_WRITE;
- make_spooled_dvd_filename(this, archive_name);
- set_part_spooled(true);
- }
- set_mode(omode);
-
- // Clear any previous blank_dvd status - we will recalculate it here
- blank_dvd = false;
-
- Dmsg3(99, "open_dvd_device: part=%d num_dvd_parts=%d, VolCatInfo.VolCatParts=%d\n",
- part, num_dvd_parts, dcr->VolCatInfo.VolCatParts);
-
- if (mount(1)) {
- Dmsg0(99, "DVD device mounted.\n");
- if (num_dvd_parts == 0 && !truncating) {
- /*
- * If we can mount the device, and we are not truncating the DVD,
- * we usually want to abort. There is one exception, if there is
- * only one 0-sized file on the DVD, with the right volume name,
- * we continue (it's the method used by truncate_dvd to truncate a volume).
- */
- if (!check_can_write_on_non_blank_dvd(dcr)) {
- Mmsg(errmsg, _("The DVD in device %s contains data, please blank it before writing.\n"), print_name());
- Emsg0(M_FATAL, 0, errmsg);
- unmount(1); /* Unmount the device, so the operator can change it. */
- clear_opened();
- return;
- }
- blank_dvd = true;
- } else {
- /*
- * Ensure that we have the correct DVD loaded by looking for part1.
- * We only succeed the open if it exists. Failure to do this could
- * leave us trying to add a part to a different DVD!
- */
- uint32_t oldpart = part;
- struct stat statp;
- POOL_MEM part1_name(PM_FNAME);
- part = 1;
- make_mounted_dvd_filename(this, part1_name);
- part = oldpart;
- if (stat(part1_name.c_str(), &statp) < 0) {
- berrno be;
- Mmsg(errmsg, _("Unable to stat DVD part 1 file %s: ERR=%s\n"),
- part1_name.c_str(), be.bstrerror());
- Emsg0(M_FATAL, 0, errmsg);
- clear_opened();
- return;
- }
- if (!S_ISREG(statp.st_mode)) {
- /* It is not a regular file */
- Mmsg(errmsg, _("DVD part 1 is not a regular file %s.\n"),
- part1_name.c_str());
- Emsg0(M_FATAL, 0, errmsg);
- clear_opened();
- return;
- }
- }
- } else {
- Dmsg0(99, "DVD device mount failed.\n");
- /* We cannot mount the device */
- if (num_dvd_parts == 0) {
- /* Run free space, check there is a media. */
- if (!update_freespace()) {
- Emsg0(M_FATAL, 0, errmsg);
- clear_opened();
- return;
- }
- if (have_media()) {
- Dmsg1(100, "Could not mount device %s, this is not a problem (num_dvd_parts == 0), and have media.\n", print_name());
- } else {
- Mmsg(errmsg, _("There is no valid DVD in device %s.\n"), print_name());
- Emsg0(M_FATAL, 0, errmsg);
- clear_opened();
- return;
- }
- } else {
- Mmsg(errmsg, _("Could not mount DVD device %s.\n"), print_name());
- Emsg0(M_FATAL, 0, errmsg);
- clear_opened();
- return;
- }
- }
-
- Dmsg5(100, "open dev: DVD dev=%s mode=%s part=%d npart=%d volcatnparts=%d\n",
- archive_name.c_str(), mode_to_str(omode),
- part, num_dvd_parts, dcr->VolCatInfo.VolCatParts);
- openmode = omode;
- Dmsg2(100, "openmode=%d %s\n", openmode, mode_to_str(openmode));
-
-
- /* If creating file, give 0640 permissions */
- Dmsg3(100, "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) {
- berrno be;
- Mmsg2(errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(),
- be.bstrerror());
- // Should this be set if we try the create/open below
- dev_errno = EIO; /* Interpreted as no device present by acquire.c:acquire_device_for_read(). */
- Dmsg1(100, "open failed: %s", errmsg);
-
- /* Previous open failed. See if we can recover */
- if ((omode == OPEN_READ_ONLY || omode == OPEN_READ_WRITE) &&
- (part > num_dvd_parts)) {
- /* If the last part (on spool), doesn't exist when accessing,
- * create it. In read/write mode a write will be allowed (higher
- * level software thinks that we are extending a pre-existing
- * media. Reads for READ_ONLY will report immediately an EOF
- * Sometimes it is better to finish with an EOF than with an error. */
- Dmsg1(100, "Creating last part on spool: %s\n", archive_name.c_str());
- omode = CREATE_READ_WRITE;
- set_mode(CREATE_READ_WRITE);
- m_fd = ::open(archive_name.c_str(), mode, 0640);
- set_mode(omode);
- }
- }
- Dmsg1(100, "after open fd=%d\n", m_fd);
- if (is_open()) {
- if (omode == OPEN_READ_WRITE || omode == CREATE_READ_WRITE) {
- set_append();
- }
- /* Get size of file */
- if (fstat(m_fd, &filestat) < 0) {
- berrno be;
- dev_errno = errno;
- Mmsg2(errmsg, _("Could not fstat: %s, ERR=%s\n"), archive_name.c_str(),
- be.bstrerror());
- Dmsg1(100, "open failed: %s", errmsg);
- /* Use system close() */
- d_close(m_fd);
- clear_opened();
- } else {
- part_size = filestat.st_size;
- dev_errno = 0;
- update_pos(dcr); /* update position */
- }
- }
-}
-
-
/*
* Rewind the device.
* Returns: true on success
file_size = 0;
file_addr = 0;
if (m_fd < 0) {
- if (!is_dvd()) { /* In case of major error, the fd is not open on DVD, so we don't want to abort. */
- dev_errno = EBADF;
- Mmsg1(errmsg, _("Bad call to rewind. Device %s not open\n"),
- print_name());
- Emsg0(M_ABORT, 0, errmsg);
- }
return false;
}
if (is_tape()) {
}
break;
}
- } else if (is_file() || is_dvd()) {
+ } else if (is_file()) {
if (lseek(dcr, (boffset_t)0, SEEK_SET) < 0) {
berrno be;
dev_errno = errno;
return false;
}
- /* Find out where we are */
- if (is_file() || is_dvd()) {
+ if (is_file()) {
file = 0;
file_addr = 0;
pos = lseek(dcr, (boffset_t)0, SEEK_CUR);
dev_errno = errno;
Pmsg1(000, _("Seek error: ERR=%s\n"), be.bstrerror());
Mmsg2(errmsg, _("lseek error on %s. ERR=%s.\n"),
- print_name(), be.bstrerror());
+ print_name(), be.bstrerror());
ok = false;
} else {
file_addr = pos;
boffset_t DEVICE::lseek(DCR *dcr, boffset_t offset, int whence)
{
switch (dev_type) {
- case B_DVD_DEV:
- return lseek_dvd(dcr, offset, whence);
case B_FILE_DEV:
#if defined(HAVE_WIN32)
return ::_lseeki64(m_fd, (__int64)offset, whence);
case B_TAPE_DEV:
/* maybe we should rewind and write and eof ???? */
return true; /* we don't really truncate tapes */
- case B_DVD_DEV:
- return truncate_dvd(dcr);
case B_FILE_DEV:
if (ftruncate(m_fd, 0) != 0) {
berrno be;
}
break;
case B_FILE_DEV:
- case B_DVD_DEV:
if (requires_mount() && device->mount_command) {
return do_file_mount(1, timeout);
}
if (device) {
device->dev = NULL;
}
- free((char *)this);
+ delete this;
}
/*
B_DVD_DEV,
B_FIFO_DEV,
B_VTAPE_DEV, /* change to B_TAPE_DEV after init */
+ B_FTP_DEV,
B_VTL_DEV
};
char VolCatName[MAX_NAME_LENGTH]; /* Desired volume to mount */
};
-
class DEVRES; /* Device resource defined in stored_conf.h */
class DCR; /* forward reference */
class VOLRES; /* forward reference */
* that device and effects all jobs using the device.
*/
class DEVICE {
-private:
+protected:
int m_fd; /* file descriptor */
+private:
int m_blocked; /* set if we must wait (i.e. change tape) */
int m_count; /* Mutex use count -- DEBUG only */
int m_num_reserved; /* counter of device reservations */
bool m_load; /* set when Volume must be loaded */
public:
+ DEVICE() {};
+ virtual ~DEVICE() {};
DEVICE * volatile swap_dev; /* Swap vol from this device */
dlist *attached_dcrs; /* attached DCR list */
bthread_mutex_t m_mutex; /* access control */
int is_removable() const { return capabilities & CAP_REM; }
int is_tape() const { return (dev_type == B_TAPE_DEV ||
dev_type == B_VTAPE_DEV); }
+ int is_ftp() const { return dev_type == B_FTP_DEV; }
int is_file() const { return dev_type == B_FILE_DEV; }
int is_fifo() const { return dev_type == B_FIFO_DEV; }
int is_dvd() const { return dev_type == B_DVD_DEV; }
void clear_volhdr(); /* in dev.c */
void close(); /* in dev.c */
void close_part(DCR *dcr); /* in dev.c */
- bool truncate(DCR *dcr); /* in dev.c */
int open(DCR *dcr, int mode); /* in dev.c */
void term(void); /* in dev.c */
ssize_t read(void *buf, size_t len); /* in dev.c */
ssize_t write(const void *buf, size_t len); /* in dev.c */
- bool rewind(DCR *dcr); /* in dev.c */
bool mount(int timeout); /* in dev.c */
bool unmount(int timeout); /* in dev.c */
void edit_mount_codes(POOL_MEM &omsg, const char *imsg); /* in dev.c */
bool scan_dir_for_volume(DCR *dcr); /* in scan.c */
bool reposition(DCR *dcr, uint32_t rfile, uint32_t rblock); /* in dev.c */
void clrerror(int func); /* in dev.c */
- boffset_t lseek(DCR *dcr, boffset_t offset, int whence); /* in dev.c */
- bool update_pos(DCR *dcr); /* in dev.c */
void set_slot(int32_t slot); /* in dev.c */
void clear_slot(); /* in dev.c */
int fd() const { return m_fd; };
/* low level operations */
- void init_backend();
- int (*d_open)(const char *pathname, int flags, ...);
- int (*d_close)(int fd);
- int (*d_ioctl)(int fd, ioctl_req_t request, ...);
- ssize_t (*d_read)(int fd, void *buffer, size_t count);
- ssize_t (*d_write)(int fd, const void *buffer, size_t count);
-
+ virtual int d_ioctl(int fd, ioctl_req_t request, char *mt_com);
+ virtual int d_open(const char *pathname, int flags);
+ virtual int d_close(int fd);
+ virtual ssize_t d_read(int fd, void *buffer, size_t count);
+ virtual ssize_t d_write(int fd, const void *buffer, size_t count);
+ virtual boffset_t lseek(DCR *dcr, boffset_t offset, int whence);
+ virtual bool update_pos(DCR *dcr);
+ virtual bool rewind(DCR *dcr);
+ virtual bool truncate(DCR *dcr);
+ virtual void open_device(DCR *dcr, int omode);
/*
* Locking and blocking calls
*/
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 */
- void open_dvd_device(DCR *dcr, int omode); /* in dev.c */
};
inline const char *DEVICE::strerror() const { return errmsg; }
/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
+ Copyright (C) 2008-2010 Free Software Foundation Europe e.V.
The main author of Bacula is Kern Sibbald, with contributions from
many others, a complete list can be found in the file AUTHORS.
static int dbglevel = 100;
#define FILE_OFFSET 30
-vtape *ftape_list[FTAPE_MAX_DRIVE];
-
-static vtape *get_tape(int fd)
-{
- ASSERT(fd >= 0);
-
- if (fd >= FTAPE_MAX_DRIVE) {
- /* error */
- return NULL;
- }
-
- return ftape_list[fd];
-}
-
-static bool put_tape(vtape *ftape)
-{
- ASSERT(ftape != NULL);
-
- int fd = ftape->get_fd();
- if (fd >= FTAPE_MAX_DRIVE) {
- /* error */
- return false;
- }
- ftape_list[fd] = ftape;
- return true;
-}
void vtape_debug(int level)
{
dbglevel = level;
}
-/****************************************************************/
-/* theses function will replace open/read/write/close/ioctl
- * in bacula core
- */
-int vtape_open(const char *pathname, int flags, ...)
+int vtape::d_ioctl(int fd, ioctl_req_t request, char *op)
{
- ASSERT(pathname != NULL);
-
- int fd;
- vtape *tape = new vtape();
- fd = tape->open(pathname, flags);
- if (fd > 0) {
- put_tape(tape);
- }
- return fd;
-}
-
-ssize_t vtape_read(int fd, void *buffer, size_t count)
-{
- vtape *tape = get_tape(fd);
- ASSERT(tape != NULL);
- return tape->read(buffer, count);
-}
-
-ssize_t vtape_write(int fd, const void *buffer, size_t count)
-{
- vtape *tape = get_tape(fd);
- ASSERT(tape != NULL);
- return tape->write(buffer, count);
-}
-
-int vtape_close(int fd)
-{
- vtape *tape = get_tape(fd);
- ASSERT(tape != NULL);
- tape->close();
- delete tape;
- return 0;
-}
-
-int vtape_ioctl(int fd, ioctl_req_t request, ...)
-{
- va_list argp;
int result = 0;
- vtape *t = get_tape(fd);
- if (!t) {
- errno = EBADF;
- return -1;
- }
-
- va_start(argp, request);
-
if (request == MTIOCTOP) {
- result = t->tape_op(va_arg(argp, mtop *));
+ result = tape_op((mtop *)op);
} else if (request == MTIOCGET) {
- result = t->tape_get(va_arg(argp, mtget *));
+ result = tape_get((mtget *)op);
} else if (request == MTIOCPOS) {
- result = t->tape_pos(va_arg(argp, mtpos *));
+ result = tape_pos((mtpos *)op);
} else {
errno = ENOTTY;
result = -1;
}
- va_end(argp);
return result;
}
return 0;
}
+vtape::~vtape()
+{
+}
+
vtape::vtape()
{
fd = -1;
current_block = -1;
max_block = VTAPE_MAX_BLOCK;
-}
-
-vtape::~vtape()
-{
+ Dmsg0(0, "I'm a vtape device\n");
}
int vtape::get_fd()
* vtape_header = sizeof(data)
* if vtape_header == 0, this is a EOF
*/
-ssize_t vtape::write(const void *buffer, size_t count)
+ssize_t vtape::d_write(int, const void *buffer, size_t count)
{
ASSERT(online);
ASSERT(current_file >= 0);
return 0;
}
+boffset_t vtape::lseek(int fd, off_t offset, int whence)
+{
+ return ::lseek(fd, offset, whence);
+}
+
/* BSF => just before last EOF
* EOF + BSF => just before EOF
* file 0 + BSF => BOT + errno
/* A filemark is automatically written to tape if the last tape operation
* before close was a write.
*/
-int vtape::close()
+int vtape::d_close(int)
{
check_eof();
::close(fd);
* by returning zero bytes for two consecutive read calls. The third read
* returns an error.
*/
-ssize_t vtape::read(void *buffer, size_t count)
+ssize_t vtape::d_read(int, void *buffer, size_t count)
{
ASSERT(online);
ASSERT(current_file >= 0);
return nb;
}
-int vtape::open(const char *pathname, int uflags)
+int vtape::d_open(const char *pathname, int uflags)
{
- Dmsg2(dbglevel, "vtape::open(%s, %i)\n", pathname, uflags);
+ Dmsg2(dbglevel, "vtape::d_open(%s, %i)\n", pathname, uflags);
online = true; /* assume that drive contains a tape */
atEOF, atEOT, atEOD, atBOT);
}
-#else /* USE_VTAPE */
-
-int vtape_ioctl(int fd, ioctl_req_t request, ...)
-{
- return -1;
-}
-
-int vtape_open(const char *pathname, int flags, ...)
-{
- return -1;
-}
-
-int vtape_close(int fd)
-{
- return -1;
-}
-
-void vtape_debug(int level)
-{
-}
-
-ssize_t vtape_read(int fd, void *buffer, size_t count)
-{
- return -1;
-}
-
-ssize_t vtape_write(int fd, const void *buffer, size_t count)
-{
- return -1;
-}
-
#endif /* ! USE_VTAPE */