/* IRCfs - IRC FileServ for *nix. * Copyright (C) 2002 Nick 'Zaf' Clifford * For licensing details, refer to the LICENSE file in the source * code directory. */ #include "module.h" #include #include #include #include #include #include #include "file.h" #include "select.h" #include "debug.h" #include "magic.h" #define MAGIC_UFS_DIR 0xD1DA3876 struct ufs_dir { MAGIC magic; POOL pool; struct dir *dir; char *name; DIR *dh; //char *realpath; char *relativepath; char *rootpath; }; #define MAGIC_UFS_FILE 0xFEA9C72D struct ufs_file { MAGIC magic; POOL pool; struct file *file; char *name; char *realpath, *relativepath; int fd, stats_fd; int eof; enum file_flags flags; file_callback_t callbacks[2]; }; struct dir *ufs_dir_open(struct dir *parent, const char *name); struct dir *ufs_dir_create(struct dir *parent, const char *name); int ufs_dir_close(struct dir *d); int ufs_dir_list_files(struct dir *d, dir_traverse_files_t func, void *appdata); int ufs_dir_list_dirs(struct dir *d, dir_traverse_dirs_t func, void *appdata); struct file *ufs_file_open(struct dir *dir, const char *name, enum file_flags flags); int ufs_file_close(struct file *f); int ufs_file_read(struct file *f, char *buffer, size_t size); int ufs_file_write(struct file *f, char *buffer, size_t size); struct file *ufs_file_create(struct dir *dir, const char *name, enum file_flags flags); int ufs_file_lseek(struct file *file, int whence, u_int32_t pos); int ufs_file_set_callback(struct file *file, enum file_callback_type type, file_callback_t func); int ufs_file_eof(struct file *file); static void ufs_file_select_callback(int fd, enum select_mode mode, void *data); const char *ufs_file_get_name(struct file *file); size_t ufs_file_get_size(struct file *file); int ufs_file_exists(struct dir *dir, const char *name); const char *ufs_dir_get_name(struct dir *dir); const char *ufs_dir_get_full_name(struct dir *dir); const char *ufs_dir_get_relative_name(struct dir *dir); MODULE_NAME("ufs"); MODULE_INIT(ufs_init); MODULE_DESTROY(ufs_destroy); MODULE_DEPENDS("file","select"); MODULE_REGISTER(ufs); DEBUG ufs_debug; struct dir_handler ufs_dir_handler = { .name = "ufs", .get_name = ufs_dir_get_name, .get_full_name = ufs_dir_get_full_name, .get_relative_name = ufs_dir_get_relative_name, .create = ufs_dir_create, .open = ufs_dir_open, .close = ufs_dir_close, .list_files = ufs_dir_list_files, .list_dirs = ufs_dir_list_dirs, .get_app_data = dir_get_app_data, .set_app_data = dir_set_app_data }; struct file_handler ufs_file_handler = { .name = "ufs", .get_app_data = file_get_app_data, .set_app_data = file_set_app_data, .get_name = ufs_file_get_name, // .get_full_name = ufs_file_get_full_name, // .validate_name = ufs_file_validate_name, .create = ufs_file_create, .open = ufs_file_open, .close = ufs_file_close, // .set_str_statistic = ufs_file_set_str_statistic, // .get_str_statistic = ufs_file_get_str_statistic, // .set_int_statistic = ufs_file_set_int_statistic, // .get_int_statistic = ufs_file_get_int_statistic, .get_size = ufs_file_get_size, .read = ufs_file_read, .write = ufs_file_write, .lseek = ufs_file_lseek, // .set_callback = ufs_file_set_callback, .eof = ufs_file_eof, .exists = ufs_file_exists , }; char dirtemp[1024],dirtemp2[1024]; char filetemp[1024]; int ufs_dir_list_dirs(struct dir *d, dir_traverse_dirs_t func, void *appdata) { struct ufs_dir *ud; struct dirent *de; struct stat st; ud = d->data; ASSERT(is_magic(ud,MAGIC_UFS_DIR)); rewinddir(ud->dh); while((de = readdir(ud->dh)) != NULL) { snprintf(dirtemp,sizeof(dirtemp),"%s/%s/%s", ud->rootpath,ud->relativepath,de->d_name); if (stat(dirtemp,&st) == -1) { error(ufs_debug,"stat of %s failed",dirtemp); continue; } if (!S_ISDIR(st.st_mode)) continue; if (func(d,de->d_name,appdata) == -1) break; } return de ? 0 : -1; } int ufs_dir_list_files(struct dir *d, dir_traverse_files_t func, void *appdata) { struct ufs_dir *ud; struct dirent *de; struct stat st; ud = d->data; ASSERT(is_magic(ud,MAGIC_UFS_DIR)); rewinddir(ud->dh); while((de = readdir(ud->dh)) != NULL) { snprintf(dirtemp,sizeof(dirtemp),"%s/%s/%s", ud->rootpath,ud->relativepath,de->d_name); if (stat(dirtemp,&st) == -1) { error(ufs_debug,"stat of %s failed",dirtemp); continue; } if (!S_ISREG(st.st_mode)) continue; if (func(d,de->d_name,appdata) == -1) break; } return de ? 0 : -1; } int ufs_dir_close(struct dir *d) { struct ufs_dir *ud; ud = d->data; ASSERT(is_magic(ud,MAGIC_UFS_DIR)); closedir(ud->dh); pool_destroy(ud->pool); return 0; } struct dir *ufs_dir_create(struct dir *parent, const char *name) { char *rootpath,*relpath; struct ufs_dir *ud; struct dir *d; POOL p; if (parent) { ud = (struct ufs_dir *) parent->data; ASSERT(is_magic(ud,MAGIC_UFS_DIR)); rootpath = ud->rootpath; relpath = ud->relativepath; } else { rootpath = "/"; relpath = "/"; } p = pool_new(NULL); ud = XMALLOC(p,struct ufs_dir); set_magic(ud,MAGIC_UFS_DIR); ud->pool = p; d = XMALLOC(p,struct dir); d->data = ud; ud->dir = d; d->handler = &ufs_dir_handler; /* Save the root path */ if (parent) { ud->rootpath = XSTRDUP(p,rootpath); } else { strncpy(dirtemp,name,sizeof(dirtemp)); clean_path(dirtemp); ud->rootpath = XSTRDUP(p,dirtemp); } /* Calculate the new relative path */ if (name[0] == '/') { /* Its a full path */ snprintf(dirtemp,sizeof(dirtemp),"%s/", name); } else { /* Its a relative path */ snprintf(dirtemp,sizeof(dirtemp),"/%s/%s/", relpath,name); } if (parent == NULL) { strcpy(dirtemp,"/"); } /* Remove the duplicate /'s and extra ./ ../'s etc */ tidy_path(dirtemp); ud->relativepath = XSTRDUP(p,dirtemp); /* Calculate its name */ strncpy(dirtemp,ud->relativepath,sizeof(dirtemp)); clean_path(dirtemp); remove_path(dirtemp); if (*dirtemp == 0) ud->name = XSTRDUP(p,"/"); else ud->name = XSTRDUP(p,dirtemp); debug(ufs_debug,"Creating dir name=%s relpath=%s rootpath=%s", ud->name,ud->relativepath, ud->rootpath); snprintf(dirtemp,sizeof(dirtemp),"%s/%s", ud->rootpath, ud->relativepath); if (mkdir(dirtemp,0775) == -1) { error(ufs_debug,"Failed to create dir"); } ud->dh = opendir(dirtemp); if (ud->dh == NULL) { error(ufs_debug,"Failed to open dir"); pool_destroy(ud->pool); return NULL; } return d; } struct dir *ufs_dir_open(struct dir *parent, const char *name) { char *rootpath,*relpath; struct ufs_dir *ud; struct dir *d; POOL p; if (parent) { ud = (struct ufs_dir *) parent->data; ASSERT(is_magic(ud,MAGIC_UFS_DIR)); rootpath = ud->rootpath; relpath = ud->relativepath; } else { rootpath = "/"; relpath = "/"; } p = pool_new(NULL); ud = XMALLOC(p,struct ufs_dir); set_magic(ud,MAGIC_UFS_DIR); ud->pool = p; d = XMALLOC(p,struct dir); d->data = ud; ud->dir = d; d->handler = &ufs_dir_handler; /* Save the root path */ if (parent) { ud->rootpath = XSTRDUP(p,rootpath); } else { strncpy(dirtemp,name,sizeof(dirtemp)); clean_path(dirtemp); ud->rootpath = XSTRDUP(p,dirtemp); } /* Calculate the new relative path */ if (name[0] == '/') { /* Its a full path */ snprintf(dirtemp,sizeof(dirtemp),"/%s/", name); } else { /* Its a relative path */ snprintf(dirtemp,sizeof(dirtemp),"/%s/%s/", relpath,name); } if (parent == NULL) { strcpy(dirtemp,"/"); } /* Remove the duplicate /'s and extra ./ ../'s etc */ tidy_path(dirtemp); ud->relativepath = XSTRDUP(p,dirtemp); /* Calculate its name */ strncpy(dirtemp,ud->relativepath,sizeof(dirtemp)); clean_path(dirtemp); remove_path(dirtemp); if (*dirtemp == 0) ud->name = XSTRDUP(p,"/"); else ud->name = XSTRDUP(p,dirtemp); snprintf(dirtemp,sizeof(dirtemp),"/%s/%s/", ud->rootpath,ud->relativepath); debug(ufs_debug,"Opening dir name=%s relpath=%s rootpath=%s, opening=%s", ud->name,ud->relativepath, ud->rootpath,dirtemp); ud->dh = opendir(dirtemp); if (ud->dh == NULL) { error(ufs_debug,"Failed to open dir %s",dirtemp); pool_destroy(ud->pool); return NULL; } return d; } const char *ufs_dir_get_name(struct dir *dir) { struct ufs_dir *ud; ud = dir->data; ASSERT(is_magic(ud,MAGIC_UFS_DIR)); return ud->name; } const char *ufs_dir_get_full_name(struct dir *dir) { struct ufs_dir *ud; ud = dir->data; ASSERT(is_magic(ud,MAGIC_UFS_DIR)); snprintf(dirtemp,sizeof(dirtemp),"%s/%s", ud->rootpath,ud->relativepath); return dirtemp; } const char *ufs_dir_get_relative_name(struct dir *dir) { struct ufs_dir *ud; ud = dir->data; ASSERT(is_magic(ud,MAGIC_UFS_DIR)); return ud->relativepath; } /***************************************************************/ /* File Ops */ /***************************************************************/ struct file *ufs_file_create(struct dir *dir, const char *name, enum file_flags flags) { return ufs_file_open(dir,name,flags|file_flag_create|file_flag_nosmash); } int ufs_file_exists(struct dir *dir, const char *name) { char *rootpath,*relpath; struct ufs_dir *ud; char *realpath; struct stat st; if (!dir) { rootpath = "/"; relpath = "/"; } else { ud = (struct ufs_dir *) dir->data; ASSERT(is_magic(ud,MAGIC_UFS_DIR)); rootpath = ud->rootpath; relpath = ud->relativepath; } snprintf(filetemp,sizeof(filetemp),"%s/%s/%s", rootpath,relpath,name); clean_path(filetemp); realpath = filetemp; debug(ufs_debug,"Checking file name=%s realpath=%s", name, realpath); if (stat(realpath,&st) == -1) { return -1; } return 0; } struct file *ufs_file_open(struct dir *dir, const char *name, enum file_flags flags) { char *rootpath,*relpath; struct ufs_file *uf; struct ufs_dir *ud; struct file *f; POOL p; int oflag; int mode; if (!dir) { rootpath = "/"; relpath = "/"; } else { ud = (struct ufs_dir *) dir->data; ASSERT(is_magic(ud,MAGIC_UFS_DIR)); rootpath = ud->rootpath; relpath = ud->relativepath; } p = pool_new(NULL); uf = XMALLOC(p,struct ufs_file); set_magic(uf,MAGIC_UFS_FILE); uf->pool = p; f = XMALLOC(p,struct file); f->data = uf; uf->file = f; f->handler = &ufs_file_handler; uf->flags = flags; strncpy(filetemp,name,sizeof(filetemp)); clean_path(filetemp); remove_path(filetemp); uf->name = XSTRDUP(p,filetemp); snprintf(filetemp,sizeof(filetemp),"%s/%s/%s", rootpath,relpath,name); clean_path(filetemp); uf->realpath = XSTRDUP(p,filetemp); snprintf(filetemp,sizeof(filetemp),"%s/%s", relpath,name); clean_path(filetemp); uf->relativepath = XSTRDUP(p,filetemp); debug(ufs_debug,"Opening file name=%s relpath=%s realpath=%s", uf->name,uf->relativepath, uf->realpath); if (flags & file_flag_readonly) { oflag = O_RDONLY; } else if (flags & file_flag_readwrite) { oflag = O_RDWR; } else { debug(ufs_debug,"Missing flag in open"); } if (flags & file_flag_create) { oflag |= O_CREAT; } if (flags & file_flag_nosmash) { oflag |= O_EXCL; } if (flags & file_flag_smash) { oflag |= O_TRUNC; } oflag |= O_NONBLOCK; mode = 0664; if (flags & file_flag_create) { uf->fd = open(uf->realpath,oflag,mode); } else { uf->fd = open(uf->realpath,oflag); } if (uf->fd == -1) { error(ufs_debug,"Failed to open file"); pool_destroy(uf->pool); return NULL; } return f; } int ufs_file_close(struct file *f) { struct ufs_file *uf; uf = f->data; ASSERT(is_magic(uf,MAGIC_UFS_FILE)); unregister_wait_item(uf->fd, select_mode_any); close(uf->fd); pool_destroy(uf->pool); return 0; } int ufs_file_eof(struct file *f) { struct ufs_file *uf; uf = f->data; ASSERT(is_magic(uf,MAGIC_UFS_FILE)); return uf->eof; } int ufs_file_read(struct file *f, char *buffer, size_t size) { struct ufs_file *uf; int r; uf = f->data; ASSERT(is_magic(uf,MAGIC_UFS_FILE)); r = read(uf->fd, buffer,size); if (r == 0) { uf->eof = 1; return 0; } else if (r == -1 && errno == EAGAIN) { uf->eof = 0; errno = 0; return 0; } else if (r == -1) { return -1; } uf->eof = 0; return r; } int ufs_file_write(struct file *f, char *buffer, size_t size) { struct ufs_file *uf; int r; uf = f->data; ASSERT(is_magic(uf,MAGIC_UFS_FILE)); if (uf->flags == file_flag_readonly) return -1; r = write(uf->fd, buffer,size); if (r == 0) { return 0; } else if (r == -1 && errno == EAGAIN) { errno = 0; return 0; } return r; } int ufs_file_lseek(struct file *file, int whence, u_int32_t pos) { struct ufs_file *uf; uf = file->data; ASSERT(is_magic(uf,MAGIC_UFS_FILE)); return lseek(uf->fd, whence,pos); } void ufs_file_select_callback(int fd, enum select_mode mode, void *data) { struct file *f; struct ufs_file *uf; enum file_callback_type ftype; f = data; uf = f->data; ASSERT(is_magic(uf,MAGIC_UFS_FILE)); switch(mode) { case select_mode_read: ftype = file_can_read; break; case select_mode_write: ftype = file_can_write; break; default: unregister_wait_item(uf->fd, mode); } if (uf->callbacks[ftype] == NULL) { unregister_wait_item(uf->fd, mode); } if (uf->callbacks[ftype](f,ftype) == -1) { unregister_wait_item(uf->fd, mode); } return; } int ufs_file_set_callback(struct file *file, enum file_callback_type type, file_callback_t func) { struct ufs_file *uf; uf = file->data; ASSERT(is_magic(uf,MAGIC_UFS_FILE)); uf->callbacks[type] = func; if (type == file_can_read) { if (func == NULL) { unregister_wait_item(uf->fd, select_mode_read); } else { register_wait_item(uf->fd, select_mode_read, ufs_file_select_callback, file); } } else if (type == file_can_write) { if (func == NULL) { unregister_wait_item(uf->fd, select_mode_write); } else { register_wait_item(uf->fd, select_mode_write, ufs_file_select_callback, file); } } return 0; } const char *ufs_file_get_name(struct file *file) { struct ufs_file *uf; uf = file->data; ASSERT(is_magic(uf,MAGIC_UFS_FILE)); return uf->name; } size_t ufs_file_get_size(struct file *file) { struct stat st; struct ufs_file *uf; uf = file->data; ASSERT(is_magic(uf,MAGIC_UFS_FILE)); if (fstat(uf->fd,&st) == -1) { return -1; } return st.st_size; } int ufs_init() { ufs_debug = debug_register("ufs"); register_file_handler(&ufs_file_handler); register_dir_handler(&ufs_dir_handler); return 0; } int ufs_destroy() { return 0; }