📄 vfs-device.c
字号:
if (count <= 0) { /* Somebody deleted something important while we weren't looking. */ g_fprintf(stderr, "Error identifying VFS device contents!\n"); return -1; } /* Could be -1. */ return data.best_found;}/* Finds the file number, acquires a lock, and returns the new file name. */staticchar * make_new_file_name(VfsDevice * self, const dumpfile_t * ji) { char * rval; char *base, *sanitary_base; int fileno; for (;;) { fileno = 1 + get_last_file_number(self); if (fileno <= 0) return NULL; if (open_lock(self, fileno, TRUE)) { break; } else { continue; } } base = g_strdup_printf("%05d.%s.%s.%d", fileno, ji->name, ji->disk, ji->dumplevel); sanitary_base = sanitise_filename(base); amfree(base); rval = g_strdup_printf("%s/%s", self->dir_name, sanitary_base); amfree(sanitary_base); return rval;}static gboolean vfs_device_start_file (Device * pself, const dumpfile_t * ji) { VfsDevice * self; self = VFS_DEVICE(pself); g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (ji != NULL, FALSE); if (self->volume_limit > 0 && self->volume_bytes + VFS_DEVICE_LABEL_SIZE > self->volume_limit) { /* No more room. */ return FALSE; } /* The basic idea here is thus: 1) Try to get a lock on the next filenumber. 2) If that fails, update our idea of "next filenumber" and try again. 3) Then open the file itself. 4) Write the label. 5) Chain up. */ self->file_name = make_new_file_name(self, ji); if (self->file_name == NULL) return FALSE; self->open_file_fd = robust_open(self->file_name, O_CREAT | O_EXCL | O_RDWR, VFS_DEVICE_CREAT_MODE); if (self->open_file_fd < 0) { g_fprintf(stderr, "Can't create file %s: %s\n", self->file_name, strerror(errno)); release_file(self); return FALSE; } if (!write_amanda_header(self, ji)) { release_file(self); return FALSE; } self->volume_bytes += VFS_DEVICE_LABEL_SIZE; if (parent_class->start_file) { parent_class->start_file(pself, ji); } return TRUE;}static gboolean vfs_device_finish_file (Device * pself) { VfsDevice * self; self = VFS_DEVICE(pself); g_return_val_if_fail(self != NULL, FALSE); release_file(self); if (parent_class->finish_file) { return parent_class->finish_file(pself); } else { return TRUE; } g_assert_not_reached();}/* This function is used for two purposes, rather than one. In * addition to its documented behavior, we also use it to open the * volume label for reading at startup. In that second case, we avoid * FdDevice-related side effects. */static dumpfile_t * vfs_device_seek_file (Device * pself, guint requested_file) { VfsDevice * self; int file; dumpfile_t * rval; char header_buffer[VFS_DEVICE_LABEL_SIZE]; int header_buffer_size = sizeof(header_buffer); IoResult result; self = VFS_DEVICE(pself); g_return_val_if_fail (self != NULL, NULL); pself->in_file = FALSE; release_file(self); if (requested_file > 0) { file = get_next_file_number(self, requested_file); } else { file = requested_file; } if (file < 0) { /* Did they request one past the end? */ char * tmp_file_name; tmp_file_name = file_number_to_file_name(self, requested_file - 1); if (tmp_file_name != NULL) { free(tmp_file_name); return make_tapeend_header(); } else { return NULL; } } if (!open_lock(self, file, FALSE)) { return NULL; } self->file_name = file_number_to_file_name(self, file); if (self->file_name == NULL) { release_file(self); return NULL; } self->open_file_fd = robust_open(self->file_name, O_RDONLY, 0); if (self->open_file_fd <= 0) { g_fprintf(stderr, "Couldn't open file %s: %s\n", self->file_name, strerror(errno)); amfree(self->file_name); release_file(self); return NULL; } result = vfs_device_robust_read(self, header_buffer, &header_buffer_size); if (result != RESULT_SUCCESS) { g_fprintf(stderr, "Problem reading Amanda header.\n"); release_file(self); return NULL; } rval = malloc(sizeof(*rval)); parse_file_header(header_buffer, rval, header_buffer_size); if (file > 0) { switch (rval->type) { case F_DUMPFILE: case F_CONT_DUMPFILE: case F_SPLIT_DUMPFILE: /* Chain up. */ if (parent_class->seek_file) { parent_class->seek_file(pself, file); } return rval; default: amfree(rval); release_file(self); return NULL; } } else if (file == 0) { return rval; } else { amfree(rval); return NULL; }}static gboolean vfs_device_seek_block (Device * pself, guint64 block) { VfsDevice * self; off_t result; self = VFS_DEVICE(pself); g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (self->open_file_fd >= 0, FALSE); g_assert(sizeof(off_t) >= sizeof(guint64)); /* Pretty simple. We figure out the blocksize and use that. */ result = lseek(self->open_file_fd, (block) * self->block_size + VFS_DEVICE_LABEL_SIZE, SEEK_SET); return (result != (off_t)(-1));}static gbooleanvfs_device_property_get (Device * pself, DevicePropertyId ID, GValue * val) { VfsDevice * self; self = VFS_DEVICE(pself); g_return_val_if_fail(self != NULL, FALSE); if (ID == PROPERTY_BLOCK_SIZE) { g_value_unset_init(val, G_TYPE_INT); g_value_set_int(val, self->block_size); return TRUE; } else if (ID == PROPERTY_MAX_VOLUME_USAGE) { g_value_unset_init(val, G_TYPE_UINT64); g_value_set_uint64(val, self->volume_limit); return TRUE; } else if (ID == PROPERTY_FREE_SPACE) { QualifiedSize qsize; struct fs_usage fsusage; guint64 bytes_avail; if (get_fs_usage(self->dir_name, NULL, &fsusage) == 0) { if (fsusage.fsu_bavail_top_bit_set) bytes_avail = 0; else bytes_avail = fsusage.fsu_bavail * fsusage.fsu_blocksize; if (self->volume_limit && (guint64)self->volume_limit < bytes_avail / 1024) bytes_avail = (guint64)self->volume_limit * 1024; qsize.accuracy = SIZE_ACCURACY_REAL; qsize.bytes = bytes_avail; } else { g_warning(_("get_fs_usage('%s') failed: %s"), self->dir_name, strerror(errno)); qsize.accuracy = SIZE_ACCURACY_UNKNOWN; qsize.bytes = 0; } g_value_unset_init(val, QUALIFIED_SIZE_TYPE); g_value_set_boxed(val, &qsize); return TRUE; } else { if (parent_class->property_get) { return parent_class->property_get(pself, ID, val); } else { return FALSE; } } g_assert_not_reached();}static gboolean vfs_device_property_set (Device * pself, DevicePropertyId ID, GValue * val) { VfsDevice * self; self = VFS_DEVICE(pself); g_return_val_if_fail(self != NULL, FALSE); if (ID == PROPERTY_BLOCK_SIZE) { int block_size = g_value_get_int(val); g_return_val_if_fail(block_size > 0, FALSE); self->block_size = block_size; return TRUE; } else if (ID == PROPERTY_MAX_VOLUME_USAGE) { self->volume_limit = g_value_get_uint64(val); return TRUE; } else { if (parent_class->property_get) { return parent_class->property_get(pself, ID, val); } else { return FALSE; } } g_assert_not_reached();}static gboolean try_unlink(const char * file) { if (unlink(file) < 0) { g_fprintf(stderr, "Can't unlink file %s: %s\n", file, strerror(errno)); return FALSE; } else { return TRUE; }}static gboolean vfs_device_recycle_file (Device * pself, guint filenum) { VfsDevice * self; struct stat file_status; off_t file_size; self = VFS_DEVICE(pself); g_return_val_if_fail(self != NULL, FALSE); g_return_val_if_fail(!(pself->in_file), FALSE); /* Game Plan: * 1) Get a write lock on the file in question. * 2) Unlink the file in question. * 3) Unlink the lock. * 4) Release the lock. * FIXME: Is it OK to unlink the lockfile? */ self->file_name = file_number_to_file_name(self, filenum); if (self->file_name == NULL) return FALSE; if (!open_lock(self, filenum, TRUE)) return FALSE; if (0 != stat(self->file_name, &file_status)) { fprintf(stderr, "Cannot stat file %s (%s), so not removing.\n", self->file_name, strerror(errno)); return FALSE; } file_size = file_status.st_size; if (!try_unlink(self->file_name) || !try_unlink(self->file_lock_name)) { release_file(self); return FALSE; } self->volume_bytes -= file_size; release_file(self); return TRUE;}static IoResult vfs_device_robust_read(VfsDevice * self, char *buf, int *count) { int fd = self->open_file_fd; int want = *count, got = 0; while (got < want) { int result; result = read(fd, buf + got, want - got); if (result > 0) { got += result; } else if (result == 0) { /* end of file */ if (got == 0) { return RESULT_NO_DATA; } else { *count = got; return RESULT_SUCCESS; } } else if (0#ifdef EAGAIN || errno == EAGAIN#endif#ifdef EWOULDBLOCK || errno == EWOULDBLOCK#endif#ifdef EINTR || errno == EINTR#endif ) { /* Try again. */ continue; } else { /* Error occured. */ g_fprintf(stderr, "Error reading fd %d: %s\n", fd, strerror(errno)); *count = got; return -1; } } *count = got; return RESULT_SUCCESS;}static IoResultvfs_device_robust_write(VfsDevice * self, char *buf, int count) { int fd = self->open_file_fd; int rval = 0; while (rval < count) { int result; result = write(fd, buf + rval, count - rval); if (result > 0) { rval += result; continue; } else if (0#ifdef EAGAIN || errno == EAGAIN#endif#ifdef EWOULDBLOCK || errno == EWOULDBLOCK#endif#ifdef EINTR || errno == EINTR#endif ) { /* Try again. */ continue; } else if (0#ifdef EFBIG || errno == EFBIG#endif#ifdef ENOSPC || errno == ENOSPC#endif ) { /* We are definitely out of space. */ return RESULT_NO_SPACE; } else { /* Error occured. Note that here we handle EIO as an error. */ g_fprintf(stderr, "Error writing device fd %d: %s\n", fd, strerror(errno)); return RESULT_ERROR; } } return RESULT_SUCCESS;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -