📄 vfs-device.c
字号:
if (fd < 0) { g_fprintf(stderr, "Can't open lock file %s: %s\n", name, strerror(errno)); return FALSE; } if (exclusive) { amflock(fd, name); } else { amroflock(fd, name); } if (file < 0) { self->volume_lock_fd = fd; } else { self->file_lock_fd = fd; } return TRUE;*/}/* For now, does it the bad way. */static void promote_volume_lock(VfsDevice * self) { amfunlock(self->volume_lock_fd, self->volume_lock_name); amflock(self->volume_lock_fd, self->volume_lock_name);}static void demote_volume_lock(VfsDevice * self) { amfunlock(self->volume_lock_fd, self->volume_lock_name); amroflock(self->volume_lock_fd, self->volume_lock_name);}/* A SearchDirectoryFunctor */static gboolean update_volume_size_functor(const char * filename, gpointer user_data) { char * full_filename; struct stat stat_buf; VfsDevice * self = user_data; g_return_val_if_fail(IS_VFS_DEVICE(self), FALSE); full_filename = vstralloc(self->dir_name, "/", filename, NULL); if (stat(full_filename, &stat_buf) < 0) { /* Log it and keep going. */ g_fprintf(stderr, "Couldn't stat file %s: %s\n", full_filename, strerror(errno)); amfree(full_filename); return TRUE; } amfree(full_filename); self->volume_bytes += stat_buf.st_size; return TRUE;}static void update_volume_size(VfsDevice * self) { self->volume_bytes = 0; search_directory(self->dir_handle, "^[0-9]+\\.", update_volume_size_functor, self);}static gboolean vfs_device_open_device (Device * pself, char * device_name) { VfsDevice * self; dumpfile_t * rval; self = VFS_DEVICE(pself); g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (device_name != NULL, FALSE); /* We don't have to free this ourselves; it will be freed by * vfs_device_finalize whether we succeed here or not. */ self->dir_name = g_strconcat(device_name, "/data/", NULL); if (!check_is_dir(self->dir_name, TRUE)) { return FALSE; } /* Next open the directory itself. */ self->dir_handle = opendir(self->dir_name); if (self->dir_handle == NULL) { g_fprintf(stderr, "Couldn't open directory %s for reading: %s\n", device_name, strerror(errno)); return FALSE; } if (!open_lock(self, -1, FALSE)) return FALSE; /* Not an error if this fails. Note that we ignore the class hierarchy. */ rval = vfs_device_seek_file(pself, 0); amfree(rval); if (parent_class->open_device) { /* Will call vfs_device_read_label. */ return (parent_class->open_device)(pself, device_name); } else { return TRUE; }}/* A SearchDirectoryFunctor */static gboolean delete_vfs_files_functor(const char * filename, gpointer user_data) { VfsDevice * self; char * path_name; self = VFS_DEVICE(user_data); g_return_val_if_fail(self != NULL, FALSE); /* Skip the volume lock. */ if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0) return TRUE; path_name = vstralloc(self->dir_name, "/", filename, NULL); if (unlink(path_name) != 0) { g_fprintf(stderr, "Error unlinking %s: %s\n", path_name, strerror(errno)); } amfree(path_name); return TRUE;}/* delete_vfs_files deletes all VfsDevice files in the directory except the volume lockfile. */static gboolean delete_vfs_files(VfsDevice * self) { g_assert(self != NULL); g_assert(self->dir_handle != NULL); /* This function assumes that the volume is locked! */ search_directory(self->dir_handle, VFS_DEVICE_FILE_REGEX, delete_vfs_files_functor, self); return TRUE;}/* This is a functor suitable for search_directory. It simply prints a warning. It also dodges the volume lockfile. */static gboolean check_dir_empty_functor(const char * filename, gpointer user_data) { VfsDevice * self; char * path_name; self = VFS_DEVICE(user_data); g_return_val_if_fail(self != NULL, FALSE); if (strcmp(filename, VOLUME_LOCKFILE_NAME) == 0) return TRUE; path_name = vstralloc(self->dir_name, "/", filename, NULL); g_fprintf(stderr, "Found spurious storage file %s\n", path_name); amfree(path_name); return TRUE;}/* This function is used to write volume and dump headers. */static gboolean write_amanda_header(VfsDevice * self, const dumpfile_t * header) { char * label_buffer; IoResult result; g_return_val_if_fail(header != NULL, FALSE); g_return_val_if_fail(self != NULL, FALSE); label_buffer = build_header(header, VFS_DEVICE_LABEL_SIZE); if (strlen(label_buffer)+1 > VFS_DEVICE_LABEL_SIZE) { amfree(label_buffer); g_fprintf(stderr, "Amanda header header won't fit on VFS device!\n"); return FALSE; } result = vfs_device_robust_write(self, label_buffer, VFS_DEVICE_LABEL_SIZE); amfree(label_buffer); return (result == RESULT_SUCCESS);}/* clear_and_label will erase the contents of the directory, and write * this label in its place. This function assumes we already have a volume * label write lock in place (e.g., promote_lock() has been called.) */static gboolean clear_and_prepare_label(VfsDevice * self, char * label, char * timestamp) { dumpfile_t * label_header; release_file(self); /* Delete any extant data, except our volume lock. */ if (!delete_vfs_files(self)) { return FALSE; } /* Print warnings about any remaining files. */ search_directory(self->dir_handle, VFS_DEVICE_FILE_REGEX, check_dir_empty_functor, self); self->file_name = g_strdup_printf("%s/00000.%s", self->dir_name, label); self->open_file_fd = robust_open(self->file_name, O_CREAT | O_EXCL | O_WRONLY, VFS_DEVICE_CREAT_MODE); if (self->open_file_fd < 0) { g_fprintf(stderr, "Can't open file %s: %s\n", self->file_name, strerror(errno)); return FALSE; } label_header = make_tapestart_header(DEVICE(self), label, timestamp); if (write_amanda_header(self, label_header)) { amfree(label_header); self->volume_bytes = VFS_DEVICE_LABEL_SIZE; return TRUE; } else { amfree(label_header); return FALSE; }}static ReadLabelStatusFlags vfs_device_read_label(Device * dself) { dumpfile_t * amanda_header; VfsDevice * self; self = VFS_DEVICE(dself); g_return_val_if_fail(self != NULL, ~READ_LABEL_STATUS_SUCCESS); amanda_header = vfs_device_seek_file(dself, 0); if (amanda_header == NULL) { /* This means an error occured getting locks or opening the header * file. */ return (READ_LABEL_STATUS_DEVICE_ERROR | READ_LABEL_STATUS_VOLUME_ERROR | READ_LABEL_STATUS_VOLUME_UNLABELED); } if (amanda_header->type != F_TAPESTART) { /* This is an error, and should not happen. */ g_fprintf(stderr, "Got a bad volume label\n"); amfree(amanda_header); return READ_LABEL_STATUS_VOLUME_ERROR; } dself->volume_label = g_strdup(amanda_header->name); dself->volume_time = g_strdup(amanda_header->datestamp); amfree(amanda_header); update_volume_size(self); if (parent_class->read_label) { return (parent_class->read_label)(dself); } else { return READ_LABEL_STATUS_SUCCESS; }}static gboolean vfs_device_write_block(Device * pself, guint size, gpointer data, gboolean last_block) { VfsDevice * self = VFS_DEVICE(pself); IoResult result; g_return_val_if_fail(self != NULL, FALSE); g_return_val_if_fail(last_block || size >= (guint)self->block_size, FALSE); g_return_val_if_fail(pself->in_file, FALSE); g_assert(self->open_file_fd >= 0); if (self->volume_limit > 0 && self->volume_bytes + size > self->volume_limit) { /* Simulate EOF. */ pself->is_eof = TRUE; return FALSE; } result = vfs_device_robust_write(self, data, size); if (result == RESULT_SUCCESS) { self->volume_bytes += size; if (parent_class->write_block) { (parent_class->write_block)(pself, size, data, last_block); } return TRUE; } else { return FALSE; }}static intvfs_device_read_block(Device * pself, gpointer data, int * size_req) { VfsDevice * self; int size; IoResult result; self = VFS_DEVICE(pself); g_return_val_if_fail (self != NULL, -1); if (data == NULL || *size_req < self->block_size) { /* Just a size query. */ *size_req = self->block_size; return 0; } size = self->block_size; result = vfs_device_robust_read(self, data, &size); switch (result) { case RESULT_SUCCESS: *size_req = size; return size; case RESULT_NO_DATA: pself->is_eof = TRUE; /* FALLTHROUGH */ default: return -1; } g_assert_not_reached();}static gboolean vfs_device_start(Device * pself, DeviceAccessMode mode, char * label, char * timestamp) { VfsDevice * self; self = VFS_DEVICE(pself); g_return_val_if_fail(self != NULL, FALSE); g_return_val_if_fail(parent_class->start != NULL, FALSE); if (mode == ACCESS_WRITE) { promote_volume_lock(self); if (!clear_and_prepare_label(self, label, timestamp)) { demote_volume_lock(self); return FALSE; } demote_volume_lock(self); } release_file(self); if (parent_class->start) { return parent_class->start(pself, mode, label, timestamp); } else { return TRUE; }}typedef struct { VfsDevice * self; int rval;} glfn_data;/* A SearchDirectoryFunctor. */static gboolean get_last_file_number_functor(const char * filename, gpointer datap) { guint64 file; glfn_data * data = (glfn_data*)datap; g_return_val_if_fail(IS_VFS_DEVICE(data->self), FALSE); file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */ if (file > G_MAXINT) { g_fprintf(stderr, "Super-large device file %s found, ignoring.\n", filename); return TRUE; } /* This condition is needlessly complex due to sign issues. */ if (data->rval < 0 || ((guint)data->rval) < file) { data->rval = file; } return TRUE;}static gint get_last_file_number(VfsDevice * self) { glfn_data data; int count; data.self = self; data.rval = -1; count = search_directory(self->dir_handle, "^[0-9]+\\.", get_last_file_number_functor, &data); if (count <= 0) { /* Somebody deleted something important while we weren't looking. */ g_fprintf(stderr, "Error identifying VFS device contents!\n"); return -1; } else { g_assert(data.rval >= 0); } return data.rval;}typedef struct { VfsDevice * self; guint request; int best_found;} gnfn_data;/* A SearchDirectoryFunctor. */static gboolean get_next_file_number_functor(const char * filename, gpointer datap) { guint file; gnfn_data * data = (gnfn_data*)datap; g_return_val_if_fail(IS_VFS_DEVICE(data->self), FALSE); file = g_ascii_strtoull(filename, NULL, 10); /* Guaranteed to work. */ if (file > G_MAXINT) { g_fprintf(stderr, "Super-large device file %s found, ignoring.\n", filename); return TRUE; } /* This condition is needlessly complex due to sign issues. */ if (file >= data->request && (data->best_found < 0 || file < (guint)data->best_found)) { data->best_found = file; } return TRUE;}/* Returns the file number equal to or greater than the given requested * file number. */static gint get_next_file_number(VfsDevice * self, guint request) { gnfn_data data; int count; data.self = self; data.request = request; data.best_found = -1; count = search_directory(self->dir_handle, "^[0-9]+\\.", get_next_file_number_functor, &data);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -