/* retoor */ #define FUSE_USE_VERSION 31 #define _GNU_SOURCE #include #include #include #include #include #include #include "operations.h" #include "webdav.h" #include "cache.h" #include "utils.h" static webdav_context_t *g_ctx = NULL; static webdav_context_t *get_context(void) { return g_ctx; } static int fusedav_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) { (void)fi; webdav_context_t *ctx = get_context(); if (!ctx) return -EIO; memset(stbuf, 0, sizeof(struct stat)); if (path_is_root(path)) { stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = 2; stbuf->st_uid = getuid(); stbuf->st_gid = getgid(); return 0; } return webdav_get_stat(ctx, path, stbuf); } static int fusedav_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi, enum fuse_readdir_flags flags) { (void)offset; (void)fi; (void)flags; webdav_context_t *ctx = get_context(); if (!ctx) return -EIO; filler(buf, ".", NULL, 0, 0); filler(buf, "..", NULL, 0, 0); dir_listing_t listing = {0}; int result = webdav_list_directory(ctx, path, &listing); if (result != 0) { return result; } for (int i = 0; i < listing.count; i++) { struct stat st = {0}; st.st_mode = listing.entries[i].is_directory ? (S_IFDIR | 0755) : (S_IFREG | 0644); st.st_size = listing.entries[i].size; st.st_mtime = listing.entries[i].mtime; st.st_atime = listing.entries[i].mtime; st.st_ctime = listing.entries[i].mtime; st.st_uid = getuid(); st.st_gid = getgid(); st.st_nlink = listing.entries[i].is_directory ? 2 : 1; if (filler(buf, listing.entries[i].name, &st, 0, 0) != 0) { break; } } for (int i = 0; i < listing.count; i++) { free(listing.entries[i].name); } free(listing.entries); return 0; } static int fusedav_open(const char *path, struct fuse_file_info *fi) { webdav_context_t *ctx = get_context(); if (!ctx) return -EIO; struct stat st; int result = webdav_get_stat(ctx, path, &st); if (result != 0) { if ((fi->flags & O_CREAT) && result == -ENOENT) { result = webdav_create_file(ctx, path); if (result != 0) return result; } else { return result; } } if (S_ISDIR(st.st_mode)) { return -EISDIR; } file_handle_t *fh = file_handle_create(path); if (!fh) return -ENOMEM; fh->file_size = st.st_size; fh->last_modified = st.st_mtime; fi->fh = (uint64_t)(uintptr_t)fh; return 0; } static int fusedav_create(const char *path, mode_t mode, struct fuse_file_info *fi) { (void)mode; webdav_context_t *ctx = get_context(); if (!ctx) return -EIO; int result = webdav_create_file(ctx, path); if (result != 0) return result; file_handle_t *fh = file_handle_create(path); if (!fh) return -ENOMEM; fh->file_size = 0; fh->last_modified = time(NULL); fi->fh = (uint64_t)(uintptr_t)fh; return 0; } static int fusedav_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { (void)path; webdav_context_t *ctx = get_context(); if (!ctx) return -EIO; file_handle_t *fh = (file_handle_t *)(uintptr_t)fi->fh; const char *read_path = fh ? fh->path : path; ssize_t result = webdav_read_file(ctx, read_path, offset, size, (uint8_t *)buf); return (int)result; } static int fusedav_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { (void)path; webdav_context_t *ctx = get_context(); if (!ctx) return -EIO; file_handle_t *fh = (file_handle_t *)(uintptr_t)fi->fh; if (!fh) return -EBADF; if (fh->write_buffer_pos + size > fh->write_buffer_size) { int result = file_handle_flush(ctx, fh); if (result != 0) return result; if (size > fh->write_buffer_size) { ssize_t written = webdav_write_file(ctx, fh->path, offset, size, (uint8_t *)buf); return (int)written; } } memcpy(fh->write_buffer + fh->write_buffer_pos, buf, size); fh->write_buffer_pos += size; fh->dirty = 1; off_t new_end = offset + (off_t)size; if (new_end > fh->file_size) { fh->file_size = new_end; } return (int)size; } static int fusedav_flush(const char *path, struct fuse_file_info *fi) { (void)path; webdav_context_t *ctx = get_context(); if (!ctx) return -EIO; file_handle_t *fh = (file_handle_t *)(uintptr_t)fi->fh; if (!fh) return 0; return file_handle_flush(ctx, fh); } static int fusedav_fsync(const char *path, int isdatasync, struct fuse_file_info *fi) { (void)isdatasync; return fusedav_flush(path, fi); } static int fusedav_release(const char *path, struct fuse_file_info *fi) { (void)path; webdav_context_t *ctx = get_context(); file_handle_t *fh = (file_handle_t *)(uintptr_t)fi->fh; if (fh) { if (ctx && fh->dirty) { file_handle_flush(ctx, fh); } file_handle_destroy(fh); } fi->fh = 0; return 0; } static int fusedav_mkdir(const char *path, mode_t mode) { (void)mode; webdav_context_t *ctx = get_context(); if (!ctx) return -EIO; return webdav_mkdir(ctx, path); } static int fusedav_unlink(const char *path) { webdav_context_t *ctx = get_context(); if (!ctx) return -EIO; return webdav_delete(ctx, path); } static int fusedav_rmdir(const char *path) { webdav_context_t *ctx = get_context(); if (!ctx) return -EIO; return webdav_delete(ctx, path); } static int fusedav_rename(const char *from, const char *to, unsigned int flags) { (void)flags; webdav_context_t *ctx = get_context(); if (!ctx) return -EIO; return webdav_rename(ctx, from, to); } static int fusedav_truncate(const char *path, off_t size, struct fuse_file_info *fi) { (void)fi; webdav_context_t *ctx = get_context(); if (!ctx) return -EIO; return webdav_truncate(ctx, path, size); } static int fusedav_statfs(const char *path, struct statvfs *stbuf) { (void)path; stbuf->f_bsize = 4096; stbuf->f_frsize = 4096; stbuf->f_blocks = 1000000000; stbuf->f_bfree = 500000000; stbuf->f_bavail = 500000000; stbuf->f_files = 1000000; stbuf->f_ffree = 500000; stbuf->f_favail = 500000; stbuf->f_fsid = 0; stbuf->f_flag = 0; stbuf->f_namemax = 255; return 0; } static int fusedav_utimens(const char *path, const struct timespec tv[2], struct fuse_file_info *fi) { (void)path; (void)tv; (void)fi; return 0; } static int fusedav_access(const char *path, int mask) { (void)mask; webdav_context_t *ctx = get_context(); if (!ctx) return -EIO; if (path_is_root(path)) { return 0; } struct stat st; return webdav_get_stat(ctx, path, &st); } static void *fusedav_init(struct fuse_conn_info *conn, struct fuse_config *cfg) { (void)conn; cfg->kernel_cache = 1; cfg->auto_cache = 1; cfg->entry_timeout = 30.0; cfg->attr_timeout = 30.0; cfg->negative_timeout = 5.0; return NULL; } static void fusedav_destroy(void *private_data) { (void)private_data; webdav_context_t *ctx = get_context(); if (ctx) { cache_clear(ctx->metadata_cache); cache_clear(ctx->dir_cache); } } struct fuse_operations fusedav_operations = { .getattr = fusedav_getattr, .readdir = fusedav_readdir, .open = fusedav_open, .create = fusedav_create, .read = fusedav_read, .write = fusedav_write, .flush = fusedav_flush, .fsync = fusedav_fsync, .release = fusedav_release, .mkdir = fusedav_mkdir, .unlink = fusedav_unlink, .rmdir = fusedav_rmdir, .rename = fusedav_rename, .truncate = fusedav_truncate, .statfs = fusedav_statfs, .utimens = fusedav_utimens, .access = fusedav_access, .init = fusedav_init, .destroy = fusedav_destroy, }; void operations_init(webdav_context_t *ctx) { g_ctx = ctx; }