/
morgan1
/
it
Обзор
Документация
Войти
/
morgan1
/
it
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
fuse.c
462 строки
12 KB
morgan1
upload files
17 ноя 2024, 21:57
17 ноя 2024, 21:57
aacb24b
Код
Авторство
О чём код?
#include <fuse.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> typedef struct { char* name; mode_t mode; off_t size; char* data; } file_t; typedef enum { FILE_TYPE, DIRECTORY_TYPE } node_type; typedef struct { char* name; node_type type; file_t* file; struct node_t* parent; struct node_t* children; } node_t; node_t* root = NULL; pthread_mutex_t fs_mutex; node_t* create_node(const char* name, node_type type, node_t* parent) { node_t* new_node = malloc(sizeof(node_t)); if (new_node == NULL) { return NULL; } new_node->name = strdup(name); new_node->type = type; new_node->file = NULL; new_node->parent = parent; new_node->children = NULL; return new_node; } void add_child(node_t* parent, node_t* child) { child->parent = parent; child->children = parent->children; parent->children = child; } node_t* find_node(node_t* start, const char* path) { if (path[0] == '/') { path++; } node_t* current = start; char* token = strtok((char*)path, "/"); while (token != NULL) { bool found = false; for (node_t* child = current->children; child != NULL; child = child->children) { if (strcmp(child->name, token) == 0) { current = child; found = true; break; } } if (!found) { return NULL; } token = strtok(NULL, "/"); } return current; } void delete_node(node_t* node) { if (node == NULL) { return; } if (node->type == FILE_TYPE) { free(node->file->data); free(node->file); } for (node_t* child = node->children; child != NULL;) { node_t* next = child->children; delete_node(child); child = next; } free(node->name); free(node); } void init_fs() { root = create_node("/", DIRECTORY_TYPE, NULL); } static int getattr_callback(const char *path, struct stat *stbuf) { pthread_mutex_lock(&fs_mutex); node_t* node = find_node(root, path); if (node == NULL) { pthread_mutex_unlock(&fs_mutex); return -ENOENT; } memset(stbuf, 0, sizeof(struct stat)); if (node->type == FILE_TYPE) { stbuf->st_mode = S_IFREG | node->file->mode; stbuf->st_nlink = 1; stbuf->st_size = node->file->size; } else { stbuf->st_mode = S_IFDIR | node->file->mode; stbuf->st_nlink = 2; } stbuf->st_uid = getuid(); stbuf->st_gid = getgid(); stbuf->st_atime = stbuf->st_mtime = stbuf->st_ctime = time(NULL); pthread_mutex_unlock(&fs_mutex); return 0; } static int readdir_callback(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { pthread_mutex_lock(&fs_mutex); node_t* node = find_node(root, path); if (node == NULL) { pthread_mutex_unlock(&fs_mutex); return -ENOENT; } if (node->type != DIRECTORY_TYPE) { pthread_mutex_unlock(&fs_mutex); return -ENOTDIR; } filler(buf, ".", NULL, 0); filler(buf, "..", NULL, 0); for (node_t* child = node->children; child != NULL; child = child->children) { filler(buf, child->name, NULL, 0); } pthread_mutex_unlock(&fs_mutex); return 0; } // Функция для открытия файла static int open_callback(const char *path, struct fuse_file_info *fi) { pthread_mutex_lock(&fs_mutex); node_t* node = find_node(root, path); if (node == NULL) { pthread_mutex_unlock(&fs_mutex); return -ENOENT; } if (node->type != FILE_TYPE) { pthread_mutex_unlock(&fs_mutex); return -EISDIR; } pthread_mutex_unlock(&fs_mutex); return 0; } static int read_callback(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { pthread_mutex_lock(&fs_mutex); node_t* node = find_node(root, path); if (node == NULL) { pthread_mutex_unlock(&fs_mutex); return -ENOENT; } if (node->type != FILE_TYPE) { pthread_mutex_unlock(&fs_mutex); return -EISDIR; } if (offset < 0 || offset >= node->file->size) { pthread_mutex_unlock(&fs_mutex); return 0; } size_t remaining = node->file->size - offset; if (size > remaining) { size = remaining; } memcpy(buf, node->file->data + offset, size); pthread_mutex_unlock(&fs_mutex); return size; } static int write_callback(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { pthread_mutex_lock(&fs_mutex); node_t* node = find_node(root, path); if (node == NULL) { pthread_mutex_unlock(&fs_mutex); return -ENOENT; } if (node->type != FILE_TYPE) { pthread_mutex_unlock(&fs_mutex); return -EISDIR; } if (offset < 0) { pthread_mutex_unlock(&fs_mutex); return -EINVAL; } if (offset + size > node->file->size) { node->file->data = realloc(node->file->data, offset + size); if (node->file->data == NULL) { pthread_mutex_unlock(&fs_mutex); return -ENOMEM; } memset(node->file->data + node->file->size, 0, offset + size - node->file->size); node->file->size = offset + size; } memcpy(node->file->data + offset, buf, size); pthread_mutex_unlock(&fs_mutex); return size; } static int mknod_callback(const char *path, mode_t mode, dev_t dev) { pthread_mutex_lock(&fs_mutex); char* parent_path = strdup(path); char* file_name = strrchr(parent_path, '/'); if (file_name == NULL) { pthread_mutex_unlock(&fs_mutex); free(parent_path); return -EINVAL; } *file_name = '\0'; file_name++; node_t* parent = find_node(root, parent_path); if (parent == NULL) { pthread_mutex_unlock(&fs_mutex); free(parent_path); return -ENOENT; } if (parent->type != DIRECTORY_TYPE) { pthread_mutex_unlock(&fs_mutex); free(parent_path); return -ENOTDIR; } node_t* new_node = create_node(file_name, (mode & S_IFDIR) ? DIRECTORY_TYPE : FILE_TYPE, parent); if (new_node == NULL) { pthread_mutex_unlock(&fs_mutex); free(parent_path); return -ENOMEM; } if (new_node->type == FILE_TYPE) { new_node->file = malloc(sizeof(file_t)); if (new_node->file == NULL) { pthread_mutex_unlock(&fs_mutex); free(parent_path); delete_node(new_node); return -ENOMEM; } new_node->file->name = strdup(file_name); new_node->file->mode = mode; new_node->file->size = 0; new_node->file->data = NULL; } add_child(parent, new_node); pthread_mutex_unlock(&fs_mutex); free(parent_path); return 0; } static int unlink_callback(const char *path) { pthread_mutex_lock(&fs_mutex); node_t* node = find_node(root, path); if (node == NULL) { pthread_mutex_unlock(&fs_mutex); return -ENOENT; } if (node->type != FILE_TYPE) { pthread_mutex_unlock(&fs_mutex); return -EISDIR; } node_t* parent = node->parent; if (parent == NULL) { pthread_mutex_unlock(&fs_mutex); return -EPERM; } node_t* prev = NULL; for (node_t* child = parent->children; child != NULL; child = child->children) { if (child == node) { if (prev == NULL) { parent->children = child->children; } else { prev->children = child->children; } break; } prev = child; } delete_node(node); pthread_mutex_unlock(&fs_mutex); return 0; } static int rmdir_callback(const char *path) { pthread_mutex_lock(&fs_mutex); node_t* node = find_node(root, path); if (node == NULL) { pthread_mutex_unlock(&fs_mutex); return -ENOENT; } if (node->type != DIRECTORY_TYPE) { pthread_mutex_unlock(&fs_mutex); return -ENOTDIR; } if (node->children != NULL) { pthread_mutex_unlock(&fs_mutex); return -ENOTEMPTY; } node_t* parent = node->parent; if (parent == NULL) { pthread_mutex_unlock(&fs_mutex); return -EPERM; } node_t* prev = NULL; for (node_t* child = parent->children; child != NULL; child = child->children) { if (child == node) { if (prev == NULL) { parent->children = child->children; } else { prev->children = child->children; } break; } prev = child; } delete_node(node); pthread_mutex_unlock(&fs_mutex); return 0; } static int mkdir_callback(const char *path, mode_t mode) { pthread_mutex_lock(&fs_mutex); char* parent_path = strdup(path); char* dir_name = strrchr(parent_path, '/'); if (dir_name == NULL) { pthread_mutex_unlock(&fs_mutex); free(parent_path); return -EINVAL; } *dir_name = '\0'; dir_name++; node_t* parent = find_node(root, parent_path); if (parent == NULL) { pthread_mutex_unlock(&fs_mutex); free(parent_path); return -ENOENT; } if (parent->type != DIRECTORY_TYPE) { pthread_mutex_unlock(&fs_mutex); free(parent_path); return -ENOTDIR; } node_t* new_node = create_node(dir_name, DIRECTORY_TYPE, parent); if (new_node == NULL) { pthread_mutex_unlock(&fs_mutex); free(parent_path); return -ENOMEM; } new_node->file = malloc(sizeof(file_t)); if (new_node->file == NULL) { pthread_mutex_unlock(&fs_mutex); free(parent_path); delete_node(new_node); return -ENOMEM; } new_node->file->name = strdup(dir_name); new_node->file->mode = mode; new_node->file->size = 0; new_node->file->data = NULL; add_child(parent, new_node); pthread_mutex_unlock(&fs_mutex); free(parent_path); return 0; } static int chmod_callback(const char *path, mode_t mode) { pthread_mutex_lock(&fs_mutex); node_t* node = find_node(root, path); if (node == NULL) { pthread_mutex_unlock(&fs_mutex); return -ENOENT; } node->file->mode = mode; pthread_mutex_unlock(&fs_mutex); return 0; } static int access_callback(const char *path, int mask) { pthread_mutex_lock(&fs_mutex); node_t* node = find_node(root, path); if (node == NULL) { pthread_mutex_unlock(&fs_mutex); return -ENOENT; } if (mask & R_OK && !(node->file->mode & S_IRUSR)) { pthread_mutex_unlock(&fs_mutex); return -EACCES; } if (mask & W_OK && !(node->file->mode & S_IWUSR)) { pthread_mutex_unlock(&fs_mutex); return -EACCES; } if (mask & X_OK && !(node->file->mode & S_IXUSR)) { pthread_mutex_unlock(&fs_mutex); return -EACCES; } pthread_mutex_unlock(&fs_mutex); return 0; } static struct fuse_operations fuse_operations = { .getattr = getattr_callback, .readdir = readdir_callback, .open = open_callback, .read = read_callback, .write = write_callback, .mknod = mknod_callback, .unlink = unlink_callback, .rmdir = rmdir_callback, .mkdir = mkdir_callback, .chmod = chmod_callback, .access = access_callback, }; int main(int argc, char *argv[]) { pthread_mutex_init(&fs_mutex, NULL); init_fs(); return fuse_main(argc, argv, &fuse_operations, NULL); }