From e5399fc6cee471ff397e1d590d35093de88e130a Mon Sep 17 00:00:00 2001 From: Nathan Giddings Date: Wed, 21 Feb 2024 19:24:26 -0600 Subject: [PATCH] Initial commit --- Makefile | 15 ++ src/file_tree.c | 178 +++++++++++++++++++ src/file_tree.h | 45 +++++ src/fs454.h | 315 +++++++++++++++++++++++++++++++++ src/fs454.x | 80 +++++++++ src/fs454_clnt.c | 253 +++++++++++++++++++++++++++ src/fs454_fuse.c | 428 +++++++++++++++++++++++++++++++++++++++++++++ src/fs454_server.c | 428 +++++++++++++++++++++++++++++++++++++++++++++ src/fs454_svc.c | 279 +++++++++++++++++++++++++++++ src/fs454_xdr.c | 343 ++++++++++++++++++++++++++++++++++++ src/fsio.c | 77 ++++++++ src/fsio.h | 16 ++ src/inode_tree.c | 120 +++++++++++++ src/inode_tree.h | 34 ++++ 14 files changed, 2611 insertions(+) create mode 100644 Makefile create mode 100644 src/file_tree.c create mode 100644 src/file_tree.h create mode 100644 src/fs454.h create mode 100644 src/fs454.x create mode 100644 src/fs454_clnt.c create mode 100644 src/fs454_fuse.c create mode 100644 src/fs454_server.c create mode 100644 src/fs454_svc.c create mode 100644 src/fs454_xdr.c create mode 100644 src/fsio.c create mode 100644 src/fsio.h create mode 100644 src/inode_tree.c create mode 100644 src/inode_tree.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..26b370e --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +CFLAGS += -Wall -ggdb -I/usr/include/tirpc + +.PHONY: all +all: fs454-client fs454-server + $(CC) -Wall $^ -lfuse3 -lpthread -o $@ + +fs454-client: src/fs454_fuse.o src/fs454_clnt.o src/fs454_xdr.o + $(CC) -ggdb -Wall $^ -ltirpc -lfuse3 -lpthread -o $@ + +fs454-server: src/fs454_server.o src/fs454_svc.o src/fs454_xdr.o src/file_tree.o src/inode_tree.o src/fsio.o + $(CC) -Wall $^ -ltirpc -o $@ + +.PHONY: clean +clean: + rm -f src/*.o fs454-client fs454-server \ No newline at end of file diff --git a/src/file_tree.c b/src/file_tree.c new file mode 100644 index 0000000..76607fa --- /dev/null +++ b/src/file_tree.c @@ -0,0 +1,178 @@ +#include +#include +#include +#include "file_tree.h" + +directory_list *file_tree_new() { + directory_list *list = malloc(sizeof(directory_list)); + if(list != NULL) { + list->first = NULL; + list->last = NULL; + list->count = 0; + } + return list; +} + +directory_entry *file_tree_lookup(directory_list *list, long parent, const char *name) { + directory_list_node *node = file_tree_list_dir(list, parent); + if(node == NULL) { + return NULL; + } + dirent_list_node *dirent_node = node->directory.first; + while(dirent_node != NULL) { + if(strcmp(dirent_node->entry.name, name) == 0) { + break; + } else { + dirent_node = dirent_node->next; + } + } + if(dirent_node != NULL) { + return &dirent_node->entry; + } else { + return NULL; + } +} + +directory_list_node *file_tree_list_dir(directory_list *list, long directory) { + directory_list_node *node = list->first; + while(node != NULL) { + if(node->self.inode == directory) { + break; + } else { + node = node->next; + } + } + return node; +} + +int file_tree_insert_root(directory_list *list) { + directory_list_node *newnode = malloc(sizeof(directory_list_node)); + newnode->next = NULL; + newnode->directory.count = 0; + newnode->directory.first = NULL; + newnode->directory.last = NULL; + newnode->self.inode = 1; + newnode->self.parent = 0; + newnode->self.name = malloc(strlen("") + 1); + newnode->self.name[0] = (char) 0; + list->first = newnode; + list->last = newnode; + list->count = 1; + return 0; +} + +int file_tree_insert(directory_list *list, long parent, const char *name, long inode) { + directory_list_node *node = file_tree_list_dir(list, parent); + if(node == NULL) { + /* Parent directory not found */ + return -1; + } + dirent_list_node *newnode = malloc(sizeof(dirent_list_node)); + newnode->next = NULL; + unsigned int namelen = strlen(name) + 1; + newnode->entry.name = malloc(namelen); + strcpy(newnode->entry.name, name); + newnode->entry.inode = inode; + newnode->entry.parent = parent; + if(node->directory.last != NULL) { + node->directory.last->next = newnode; + node->directory.last = newnode; + } else { + node->directory.first = newnode; + node->directory.last = newnode; + } + node->directory.count++; + return 0; +} + +int file_tree_insert_dir(directory_list *list, long parent, const char *name, long inode) { + if(file_tree_list_dir(list, inode) != NULL) { + /* We can't have several hardlinks to the same directory */ + return -1; + } else if(file_tree_insert(list, parent, name, inode) != 0) { + /* Parent directory not found */ + return -1; + } + directory_list_node *newnode = malloc(sizeof(directory_list_node)); + newnode->next = NULL; + newnode->self.inode = inode; + unsigned int namelen = strlen(name) + 1; + newnode->self.name = malloc(namelen); + strcpy(newnode->self.name, name); + newnode->self.parent = parent; + newnode->directory.first = NULL; + newnode->directory.last = NULL; + newnode->directory.count = 0; + list->last->next = newnode; + list->last = newnode; + list->count++; + return 0; +} + +int file_tree_remove(directory_list *list, long parent, const char *name) { + directory_entry *entry = file_tree_lookup(list, parent, name); + if(entry == NULL) { + return -1; + } + directory_list_node *dir_list = file_tree_list_dir(list, entry->inode); + if(dir_list != NULL && dir_list->directory.count > 0) { + return -1; + } else if(dir_list != NULL && dir_list->directory.count == 0) { + directory_list_node *prev = NULL; + directory_list_node *curr = list->first; + while(curr != NULL) { + if(curr->self.inode == entry->inode) { + break; + } else { + prev = curr; + curr = curr->next; + } + } + if(curr != NULL) { + if(prev != NULL) { + prev->next = curr->next; + if(prev->next == NULL) { + list->last = prev; + } + } else if(list->first == list->last) { + list->first = list->last = NULL; + } else { + list->first = curr->next; + } + free(curr->self.name); + free(curr); + list->count--; + } else { + return -1; + } + } + directory_list_node *parent_list = file_tree_list_dir(list, parent); + dirent_list_node *prev = NULL; + dirent_list_node *curr = parent_list->directory.first; + while (curr != NULL) { + if (curr->entry.inode == entry->inode){ + break; + } else { + prev = curr; + curr = curr->next; + } + } + if (curr != NULL) { + if (prev != NULL) { + prev->next = curr->next; + if (prev->next == NULL) { + parent_list->directory.last = prev; + } + } else if (parent_list->directory.first == parent_list->directory.last) { + parent_list->directory.first = parent_list->directory.last = NULL; + } else { + parent_list->directory.first = curr->next; + } + free(curr->entry.name); + free(curr); + parent_list->directory.count--; + } else { + return -1; + } + return 0; +} \ No newline at end of file diff --git a/src/file_tree.h b/src/file_tree.h new file mode 100644 index 0000000..c96ddce --- /dev/null +++ b/src/file_tree.h @@ -0,0 +1,45 @@ +#ifndef FS454_FILE_TREE +#define FS454_FILE_TREE + +typedef struct directory_entry_t { + long inode; + long parent; + char *name; +} directory_entry; + +typedef struct dirent_list_node_t { + struct dirent_list_node_t *next; + directory_entry entry; +} dirent_list_node; + +typedef struct dirent_list_t { + dirent_list_node *first, *last; + long count; +} dirent_list; + +typedef struct directory_list_node_t { + struct directory_list_node_t *next; + directory_entry self; + dirent_list directory; +} directory_list_node; + +typedef struct directory_list_t { + directory_list_node *first, *last; + long count; +} directory_list; + +directory_list *file_tree_new(); + +directory_entry *file_tree_lookup(directory_list *list, long parent, const char *name); + +directory_list_node *file_tree_list_dir(directory_list *list, long directory); + +int file_tree_insert_root(directory_list *list); + +int file_tree_insert(directory_list *list, long parent, const char *name, long inode); + +int file_tree_insert_dir(directory_list *list, long parent, const char *name, long inode); + +int file_tree_remove(directory_list *list, long parent, const char *name); + +#endif \ No newline at end of file diff --git a/src/fs454.h b/src/fs454.h new file mode 100644 index 0000000..502ea39 --- /dev/null +++ b/src/fs454.h @@ -0,0 +1,315 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _FS454_H_RPCGEN +#define _FS454_H_RPCGEN + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +struct file_attributes { + long id; + long link_count; + long filesize; + long owner; + long mode; + long last_access; + long last_modify; + long last_change; +}; +typedef struct file_attributes file_attributes; + +struct dir_entry { + struct { + u_int name_len; + char *name_val; + } name; + struct file_attributes attributes; + struct dir_entry *next; +}; +typedef struct dir_entry dir_entry; + +enum error_code { + FS454_ENONE = 0, + FS454_ENOINODE = 0 + 1, + FS454_EINVAL = 0 + 2, + FS454_EIO = 0 + 3, + FS454_EBADF = 0 + 4, + FS454_EACCESS = 0 + 5, + FS454_ENOTDIR = 0 + 6, + FS454_ENOTEMPTY = 0 + 7, +}; +typedef enum error_code error_code; + +typedef dir_entry *entry_list; + +typedef struct { + u_int byte_buffer_len; + u_char *byte_buffer_val; +} byte_buffer; + + +struct attribute_res { + error_code err; + union { + file_attributes attributes; + } attribute_res_u; +}; +typedef struct attribute_res attribute_res; + +struct string_res { + error_code err; + union { + char *str; + } string_res_u; +}; +typedef struct string_res string_res; + +struct readdir_res { + error_code err; + union { + entry_list entries; + } readdir_res_u; +}; +typedef struct readdir_res readdir_res; + +struct buffer_res { + error_code err; + union { + byte_buffer buffer; + } buffer_res_u; +}; +typedef struct buffer_res buffer_res; + +struct allocate_1_argument { + long arg1; + long arg2; +}; +typedef struct allocate_1_argument allocate_1_argument; + +struct link_1_argument { + long arg1; + char *arg2; + long arg3; +}; +typedef struct link_1_argument link_1_argument; + +struct lookup_1_argument { + char *arg1; + long arg2; +}; +typedef struct lookup_1_argument lookup_1_argument; + +struct mkdir_1_argument { + char *arg1; + long arg2; + long arg3; +}; +typedef struct mkdir_1_argument mkdir_1_argument; + +struct mknod_1_argument { + char *arg1; + long arg2; + long arg3; +}; +typedef struct mknod_1_argument mknod_1_argument; + +struct read_1_argument { + long arg1; + long arg2; + long arg3; +}; +typedef struct read_1_argument read_1_argument; + +struct setattr_1_argument { + long arg1; + long arg2; + struct file_attributes arg3; +}; +typedef struct setattr_1_argument setattr_1_argument; + +struct symlink_1_argument { + char *arg1; + long arg2; + char *arg3; +}; +typedef struct symlink_1_argument symlink_1_argument; + +struct unlink_1_argument { + long arg1; + char *arg2; +}; +typedef struct unlink_1_argument unlink_1_argument; + +struct write_1_argument { + long arg1; + byte_buffer arg2; + long arg3; + long arg4; +}; +typedef struct write_1_argument write_1_argument; + +struct copy_1_argument { + long arg1; + long arg2; + long arg3; + long arg4; + long arg5; +}; +typedef struct copy_1_argument copy_1_argument; + +#define FS454 0x33764824 +#define MESSAGEVERS 1 + +#if defined(__STDC__) || defined(__cplusplus) +#define ALLOCATE 1 +extern error_code * allocate_1(long , long , CLIENT *); +extern error_code * allocate_1_svc(long , long , struct svc_req *); +#define GETATTR 2 +extern attribute_res * getattr_1(long , CLIENT *); +extern attribute_res * getattr_1_svc(long , struct svc_req *); +#define LINK 3 +extern attribute_res * link_1(long , char *, long , CLIENT *); +extern attribute_res * link_1_svc(long , char *, long , struct svc_req *); +#define LOOKUP 4 +extern attribute_res * lookup_1(char *, long , CLIENT *); +extern attribute_res * lookup_1_svc(char *, long , struct svc_req *); +#define MKDIR 5 +extern attribute_res * mkdir_1(char *, long , long , CLIENT *); +extern attribute_res * mkdir_1_svc(char *, long , long , struct svc_req *); +#define MKNOD 6 +extern attribute_res * mknod_1(char *, long , long , CLIENT *); +extern attribute_res * mknod_1_svc(char *, long , long , struct svc_req *); +#define READ 7 +extern buffer_res * read_1(long , long , long , CLIENT *); +extern buffer_res * read_1_svc(long , long , long , struct svc_req *); +#define READDIR 8 +extern readdir_res * readdir_1(long , CLIENT *); +extern readdir_res * readdir_1_svc(long , struct svc_req *); +#define READLINK 9 +extern string_res * readlink_1(long , CLIENT *); +extern string_res * readlink_1_svc(long , struct svc_req *); +#define SETATTR 10 +extern attribute_res * setattr_1(long , long , struct file_attributes , CLIENT *); +extern attribute_res * setattr_1_svc(long , long , struct file_attributes , struct svc_req *); +#define SYMLINK 11 +extern attribute_res * symlink_1(char *, long , char *, CLIENT *); +extern attribute_res * symlink_1_svc(char *, long , char *, struct svc_req *); +#define UNLINK 12 +extern error_code * unlink_1(long , char *, CLIENT *); +extern error_code * unlink_1_svc(long , char *, struct svc_req *); +#define WRITE 13 +extern error_code * write_1(long , byte_buffer , long , long , CLIENT *); +extern error_code * write_1_svc(long , byte_buffer , long , long , struct svc_req *); +#define COPY 14 +extern error_code * copy_1(long , long , long , long , long , CLIENT *); +extern error_code * copy_1_svc(long , long , long , long , long , struct svc_req *); +extern int fs454_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t); + +#else /* K&R C */ +#define ALLOCATE 1 +extern error_code * allocate_1(); +extern error_code * allocate_1_svc(); +#define GETATTR 2 +extern attribute_res * getattr_1(); +extern attribute_res * getattr_1_svc(); +#define LINK 3 +extern attribute_res * link_1(); +extern attribute_res * link_1_svc(); +#define LOOKUP 4 +extern attribute_res * lookup_1(); +extern attribute_res * lookup_1_svc(); +#define MKDIR 5 +extern attribute_res * mkdir_1(); +extern attribute_res * mkdir_1_svc(); +#define MKNOD 6 +extern attribute_res * mknod_1(); +extern attribute_res * mknod_1_svc(); +#define READ 7 +extern buffer_res * read_1(); +extern buffer_res * read_1_svc(); +#define READDIR 8 +extern readdir_res * readdir_1(); +extern readdir_res * readdir_1_svc(); +#define READLINK 9 +extern string_res * readlink_1(); +extern string_res * readlink_1_svc(); +#define SETATTR 10 +extern attribute_res * setattr_1(); +extern attribute_res * setattr_1_svc(); +#define SYMLINK 11 +extern attribute_res * symlink_1(); +extern attribute_res * symlink_1_svc(); +#define UNLINK 12 +extern error_code * unlink_1(); +extern error_code * unlink_1_svc(); +#define WRITE 13 +extern error_code * write_1(); +extern error_code * write_1_svc(); +#define COPY 14 +extern error_code * copy_1(); +extern error_code * copy_1_svc(); +extern int fs454_1_freeresult (); +#endif /* K&R C */ + +/* the xdr functions */ + +#if defined(__STDC__) || defined(__cplusplus) +extern bool_t xdr_file_attributes (XDR *, file_attributes*); +extern bool_t xdr_dir_entry (XDR *, dir_entry*); +extern bool_t xdr_error_code (XDR *, error_code*); +extern bool_t xdr_entry_list (XDR *, entry_list*); +extern bool_t xdr_byte_buffer (XDR *, byte_buffer*); +extern bool_t xdr_file_attributes (XDR *, file_attributes*); +extern bool_t xdr_attribute_res (XDR *, attribute_res*); +extern bool_t xdr_string_res (XDR *, string_res*); +extern bool_t xdr_readdir_res (XDR *, readdir_res*); +extern bool_t xdr_buffer_res (XDR *, buffer_res*); +extern bool_t xdr_allocate_1_argument (XDR *, allocate_1_argument*); +extern bool_t xdr_link_1_argument (XDR *, link_1_argument*); +extern bool_t xdr_lookup_1_argument (XDR *, lookup_1_argument*); +extern bool_t xdr_mkdir_1_argument (XDR *, mkdir_1_argument*); +extern bool_t xdr_mknod_1_argument (XDR *, mknod_1_argument*); +extern bool_t xdr_read_1_argument (XDR *, read_1_argument*); +extern bool_t xdr_setattr_1_argument (XDR *, setattr_1_argument*); +extern bool_t xdr_symlink_1_argument (XDR *, symlink_1_argument*); +extern bool_t xdr_unlink_1_argument (XDR *, unlink_1_argument*); +extern bool_t xdr_write_1_argument (XDR *, write_1_argument*); +extern bool_t xdr_copy_1_argument (XDR *, copy_1_argument*); + +#else /* K&R C */ +extern bool_t xdr_file_attributes (); +extern bool_t xdr_dir_entry (); +extern bool_t xdr_error_code (); +extern bool_t xdr_entry_list (); +extern bool_t xdr_byte_buffer (); +extern bool_t xdr_file_attributes (); +extern bool_t xdr_attribute_res (); +extern bool_t xdr_string_res (); +extern bool_t xdr_readdir_res (); +extern bool_t xdr_buffer_res (); +extern bool_t xdr_allocate_1_argument (); +extern bool_t xdr_link_1_argument (); +extern bool_t xdr_lookup_1_argument (); +extern bool_t xdr_mkdir_1_argument (); +extern bool_t xdr_mknod_1_argument (); +extern bool_t xdr_read_1_argument (); +extern bool_t xdr_setattr_1_argument (); +extern bool_t xdr_symlink_1_argument (); +extern bool_t xdr_unlink_1_argument (); +extern bool_t xdr_write_1_argument (); +extern bool_t xdr_copy_1_argument (); + +#endif /* K&R C */ + +#ifdef __cplusplus +} +#endif + +#endif /* !_FS454_H_RPCGEN */ diff --git a/src/fs454.x b/src/fs454.x new file mode 100644 index 0000000..45576bb --- /dev/null +++ b/src/fs454.x @@ -0,0 +1,80 @@ +struct file_attributes { + long id; + long link_count; + long filesize; + long owner; + long mode; + long last_access; + long last_modify; + long last_change; +}; + +struct dir_entry { + char name<>; + struct file_attributes attributes; + struct dir_entry *next; +}; + +enum error_code { + FS454_ENONE = 0, + FS454_ENOINODE, + FS454_EINVAL, + FS454_EIO, + FS454_EBADF, + FS454_EACCESS, + FS454_ENOTDIR, + FS454_ENOTEMPTY +}; + +typedef struct dir_entry *entry_list; + +typedef unsigned char byte_buffer<>; + +typedef struct file_attributes file_attributes; + +union attribute_res switch(error_code err) { +case FS454_ENONE: + file_attributes attributes; +default: + void; +}; + +union string_res switch(error_code err) { +case FS454_ENONE: + string str<>; +default: + void; +}; + +union readdir_res switch(error_code err) { +case FS454_ENONE: + entry_list entries; +default: + void; +}; + +union buffer_res switch(error_code err) { +case FS454_ENONE: + byte_buffer buffer; +default: + void; +}; + +program FS454 { + version MESSAGEVERS { + error_code ALLOCATE(long, long) = 1; + attribute_res GETATTR(long) = 2; + attribute_res LINK(long, string, long) = 3; + attribute_res LOOKUP(string, long) = 4; + attribute_res MKDIR(string, long, long) = 5; + attribute_res MKNOD(string, long, long) = 6; + buffer_res READ(long, long, long) = 7; + readdir_res READDIR(long) = 8; + string_res READLINK(long) = 9; + attribute_res SETATTR(long, long, struct file_attributes) = 10; + attribute_res SYMLINK(string, long, string) = 11; + error_code UNLINK(long, string) = 12; + error_code WRITE(long, byte_buffer, long, long) = 13; + error_code COPY(long, long, long, long, long) = 14; + } = 1; +} = 0x33764824; \ No newline at end of file diff --git a/src/fs454_clnt.c b/src/fs454_clnt.c new file mode 100644 index 0000000..1f0cdaf --- /dev/null +++ b/src/fs454_clnt.c @@ -0,0 +1,253 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include /* for memset */ +#include "fs454.h" + +/* Default timeout can be changed using clnt_control() */ +static struct timeval TIMEOUT = { 25, 0 }; + +error_code * +allocate_1(long arg1, long arg2, CLIENT *clnt) +{ + allocate_1_argument arg; + static error_code clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + arg.arg1 = arg1; + arg.arg2 = arg2; + if (clnt_call (clnt, ALLOCATE, (xdrproc_t) xdr_allocate_1_argument, (caddr_t) &arg, + (xdrproc_t) xdr_error_code, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +attribute_res * +getattr_1(long arg1, CLIENT *clnt) +{ + static attribute_res clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call (clnt, GETATTR, + (xdrproc_t) xdr_long, (caddr_t) &arg1, + (xdrproc_t) xdr_attribute_res, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +attribute_res * +link_1(long arg1, char *arg2, long arg3, CLIENT *clnt) +{ + link_1_argument arg; + static attribute_res clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + arg.arg1 = arg1; + arg.arg2 = arg2; + arg.arg3 = arg3; + if (clnt_call (clnt, LINK, (xdrproc_t) xdr_link_1_argument, (caddr_t) &arg, + (xdrproc_t) xdr_attribute_res, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +attribute_res * +lookup_1(char *arg1, long arg2, CLIENT *clnt) +{ + lookup_1_argument arg; + static attribute_res clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + arg.arg1 = arg1; + arg.arg2 = arg2; + if (clnt_call (clnt, LOOKUP, (xdrproc_t) xdr_lookup_1_argument, (caddr_t) &arg, + (xdrproc_t) xdr_attribute_res, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +attribute_res * +mkdir_1(char *arg1, long arg2, long arg3, CLIENT *clnt) +{ + mkdir_1_argument arg; + static attribute_res clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + arg.arg1 = arg1; + arg.arg2 = arg2; + arg.arg3 = arg3; + if (clnt_call (clnt, MKDIR, (xdrproc_t) xdr_mkdir_1_argument, (caddr_t) &arg, + (xdrproc_t) xdr_attribute_res, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +attribute_res * +mknod_1(char *arg1, long arg2, long arg3, CLIENT *clnt) +{ + mknod_1_argument arg; + static attribute_res clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + arg.arg1 = arg1; + arg.arg2 = arg2; + arg.arg3 = arg3; + if (clnt_call (clnt, MKNOD, (xdrproc_t) xdr_mknod_1_argument, (caddr_t) &arg, + (xdrproc_t) xdr_attribute_res, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +buffer_res * +read_1(long arg1, long arg2, long arg3, CLIENT *clnt) +{ + read_1_argument arg; + static buffer_res clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + arg.arg1 = arg1; + arg.arg2 = arg2; + arg.arg3 = arg3; + if (clnt_call (clnt, READ, (xdrproc_t) xdr_read_1_argument, (caddr_t) &arg, + (xdrproc_t) xdr_buffer_res, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +readdir_res * +readdir_1(long arg1, CLIENT *clnt) +{ + static readdir_res clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call (clnt, READDIR, + (xdrproc_t) xdr_long, (caddr_t) &arg1, + (xdrproc_t) xdr_readdir_res, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +string_res * +readlink_1(long arg1, CLIENT *clnt) +{ + static string_res clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call (clnt, READLINK, + (xdrproc_t) xdr_long, (caddr_t) &arg1, + (xdrproc_t) xdr_string_res, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +attribute_res * +setattr_1(long arg1, long arg2, struct file_attributes arg3, CLIENT *clnt) +{ + setattr_1_argument arg; + static attribute_res clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + arg.arg1 = arg1; + arg.arg2 = arg2; + arg.arg3 = arg3; + if (clnt_call (clnt, SETATTR, (xdrproc_t) xdr_setattr_1_argument, (caddr_t) &arg, + (xdrproc_t) xdr_attribute_res, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +attribute_res * +symlink_1(char *arg1, long arg2, char *arg3, CLIENT *clnt) +{ + symlink_1_argument arg; + static attribute_res clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + arg.arg1 = arg1; + arg.arg2 = arg2; + arg.arg3 = arg3; + if (clnt_call (clnt, SYMLINK, (xdrproc_t) xdr_symlink_1_argument, (caddr_t) &arg, + (xdrproc_t) xdr_attribute_res, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +error_code * +unlink_1(long arg1, char *arg2, CLIENT *clnt) +{ + unlink_1_argument arg; + static error_code clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + arg.arg1 = arg1; + arg.arg2 = arg2; + if (clnt_call (clnt, UNLINK, (xdrproc_t) xdr_unlink_1_argument, (caddr_t) &arg, + (xdrproc_t) xdr_error_code, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +error_code * +write_1(long arg1, byte_buffer arg2, long arg3, long arg4, CLIENT *clnt) +{ + write_1_argument arg; + static error_code clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + arg.arg1 = arg1; + arg.arg2 = arg2; + arg.arg3 = arg3; + arg.arg4 = arg4; + if (clnt_call (clnt, WRITE, (xdrproc_t) xdr_write_1_argument, (caddr_t) &arg, + (xdrproc_t) xdr_error_code, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +error_code * +copy_1(long arg1, long arg2, long arg3, long arg4, long arg5, CLIENT *clnt) +{ + copy_1_argument arg; + static error_code clnt_res; + + memset((char *)&clnt_res, 0, sizeof(clnt_res)); + arg.arg1 = arg1; + arg.arg2 = arg2; + arg.arg3 = arg3; + arg.arg4 = arg4; + arg.arg5 = arg5; + if (clnt_call (clnt, COPY, (xdrproc_t) xdr_copy_1_argument, (caddr_t) &arg, + (xdrproc_t) xdr_error_code, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} diff --git a/src/fs454_fuse.c b/src/fs454_fuse.c new file mode 100644 index 0000000..6943c5a --- /dev/null +++ b/src/fs454_fuse.c @@ -0,0 +1,428 @@ +#define FUSE_USE_VERSION 34 + +#include "fuse3/fuse_lowlevel.h" +#include "fs454.h" +#include +#include +#include +#include +#include +#include + +CLIENT *rpc_client; + +struct buffer_t +{ + char *ptr; + size_t size; +}; + +void fill_stat(struct stat *dest, file_attributes *src) { + memset(dest, 0, sizeof(struct stat)); + dest->st_ino = src->id; + dest->st_size = src->filesize; + dest->st_uid = src->owner; + dest->st_gid = 0; + dest->st_mode = src->mode; + dest->st_nlink = src->link_count; + dest->st_atime = src->last_access; + dest->st_ctime = src->last_change; + dest->st_mtime = src->last_modify; +} + +int buffer_resize(struct buffer_t *buffer, size_t size) { + if(buffer != NULL) { + buffer->ptr = realloc(buffer->ptr, size); + if(buffer->ptr == NULL) { + buffer->size = 0; + return 1; + } else { + buffer->size = size; + return 0; + } + } else { + return 1; + } +} + +void buffer_free(struct buffer_t *buffer) { + if(buffer != NULL) { + if(buffer->ptr != NULL) { + free(buffer->ptr); + buffer->ptr = NULL; + } + buffer->size = 0; + } +} + +int append_dirent(fuse_req_t request, struct buffer_t *buffer, const char *name, struct stat *attr) { + size_t prev_size = buffer->size; + if(buffer_resize(buffer, prev_size + fuse_add_direntry(request, NULL, 0, name, NULL, 0))) { + return 1; + } + fuse_add_direntry(request, buffer->ptr + prev_size, buffer->size - prev_size, name, attr, buffer->size); + return 0; +} + +void fs454_access(fuse_req_t req, fuse_ino_t ino, int mask) { + fuse_reply_err(req, ENOSYS); +} + +void fs454_copy_file_range(fuse_req_t req, fuse_ino_t ino_in, off_t off_in, struct fuse_file_info *fi_in, fuse_ino_t ino_out, off_t off_out, struct fuse_file_info *fi_out, size_t len, int flags) { + fuse_reply_err(req, ENOSYS); +} + +void fs454_fallocate(fuse_req_t request, fuse_ino_t inode, int mode, off_t offset, off_t length, struct fuse_file_info *fi) { + if(mode == 0) { + error_code *result = allocate_1(inode, offset + length, rpc_client); + if(result == NULL) { + fuse_reply_err(request, EIO); + } else if(*result == FS454_ENONE) { + fuse_reply_err(request, 0); + } else { + fuse_reply_err(request, ENOENT); + } + } else { + fuse_reply_err(request, EOPNOTSUPP); + } +} + +void fs454_getattr(fuse_req_t request, ino_t inode, struct fuse_file_info *info) { + attribute_res *result = getattr_1(inode, rpc_client); + if(result == NULL) { + fuse_reply_err(request, EIO); + } else if(result->err == FS454_ENONE) { + struct stat s; + fill_stat(&s, &result->attribute_res_u.attributes); + fuse_reply_attr(request, &s, 0); + } else { + printf("\terror %i in getattr\n", result->err); + fuse_reply_err(request, ENOENT); + } +} + +void fs454_link(fuse_req_t request, fuse_ino_t inode, fuse_ino_t newparent, const char *newname) { + attribute_res *result = link_1(inode, newname, newparent, rpc_client); + if(result == NULL) { + fuse_reply_err(request, EIO); + } else if(result->err != FS454_ENONE) { + printf("link %i/%s -> %i failed with error %i\n", newparent, newname, inode, result->err); + fuse_reply_err(request, ENOENT); + } else { + struct fuse_entry_param entry = { + .attr_timeout = 0, + .entry_timeout = 0, + .generation = 0, + .ino = result->attribute_res_u.attributes.id + }; + fill_stat(&entry.attr, &result->attribute_res_u.attributes); + fuse_reply_entry(request, &entry); + } +} + +void fs454_lookup(fuse_req_t request, fuse_ino_t parent, const char *name) { + attribute_res *result = lookup_1(name, parent, rpc_client); + if(result == NULL) { + fuse_reply_err(request, EIO); + } else if(result->err == FS454_ENONE) { + struct fuse_entry_param entry = { + .attr_timeout = 0, + .entry_timeout = 0, + .generation = 0, + .ino = result->attribute_res_u.attributes.id + }; + fill_stat(&entry.attr, &result->attribute_res_u.attributes); + fuse_reply_entry(request, &entry); + } else { + fuse_reply_err(request, ENOENT); + } +} + +void fs454_mknod(fuse_req_t request, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev) { + attribute_res *result = mknod_1(name, parent, mode, rpc_client); + if(result == NULL) { + fuse_reply_err(request, EIO); + } else if(result->err == FS454_ENONE) { + struct fuse_entry_param entry = { + .attr_timeout = 0, + .entry_timeout = 0, + .generation = 0, + .ino = result->attribute_res_u.attributes.id + }; + fill_stat(&entry.attr, &result->attribute_res_u.attributes); + fuse_reply_entry(request, &entry); + } else { + fuse_reply_err(request, EINVAL); + } +} + +void fs454_mkdir(fuse_req_t request, fuse_ino_t parent, const char *name, mode_t mode) { + attribute_res *result = mkdir_1(name, parent, mode, rpc_client); + if(result == NULL) { + fuse_reply_err(request, EIO); + } else if(result->err == FS454_ENONE) { + struct fuse_entry_param entry = { + .attr_timeout = 0, + .entry_timeout = 0, + .generation = 0, + .ino = result->attribute_res_u.attributes.id + }; + fill_stat(&entry.attr, &result->attribute_res_u.attributes); + fuse_reply_entry(request, &entry); + } else { + printf("mkdir failed error %i\n", result->err); + fuse_reply_err(request, EINVAL); + } +} + +void fs454_open(fuse_req_t request, fuse_ino_t inode, struct fuse_file_info *finfo) { + finfo->keep_cache = 0; + fuse_reply_open(request, finfo); +} + +void fs454_read(fuse_req_t request, fuse_ino_t inode, size_t size, off_t off, struct fuse_file_info *info) { + buffer_res *result = read_1(inode, off, size, rpc_client); + if(result == NULL) { + fuse_reply_err(request, EIO); + } else if(result->err == FS454_ENONE) { + fuse_reply_buf(request, result->buffer_res_u.buffer.byte_buffer_val, result->buffer_res_u.buffer.byte_buffer_len); + } else { + printf("read failed error %i\n", result->err); + fuse_reply_err(request, ENOENT); + } +} + +void fs454_readdir(fuse_req_t request, fuse_ino_t inode, size_t size, off_t off, struct fuse_file_info *info) { + readdir_res *result = readdir_1(inode, rpc_client); + if(result == NULL) { + fuse_reply_err(request, EIO); + } else if(result->err == FS454_ENONE) { + struct buffer_t buffer = {0}; + struct dir_entry *entry = result->readdir_res_u.entries; + while(entry != NULL) { + struct stat attr; + fill_stat(&attr, &entry->attributes); + append_dirent(request, &buffer, entry->name.name_val, &attr); + entry = entry->next; + } + if(off < buffer.size) { + if(buffer.size - off < size) { + fuse_reply_buf(request, buffer.ptr + off, buffer.size - off); + } else { + fuse_reply_buf(request, buffer.ptr + off, size); + } + } else { + fuse_reply_buf(request, NULL, 0); + } + } else { + printf("readdir failed error %i\n", result->err); + fuse_reply_err(request, EINVAL); + } +} + +void fs454_readlink(fuse_req_t request, fuse_ino_t inode) { + string_res *link = readlink_1(inode, rpc_client); + if(link == NULL) { + fuse_reply_err(request, EIO); + } else { + fuse_reply_readlink(request, link->string_res_u.str); + } +} + +void fs454_rename(fuse_req_t request, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname, unsigned int flags) { + if(parent == newparent && strcmp(name, newname) == 0) { + fuse_reply_err(request, 0); + return; + } + attribute_res *oldattr = lookup_1(name, parent, rpc_client); + if(oldattr == NULL) { + fuse_reply_err(request, EIO); + return; + } else if(oldattr->err != FS454_ENONE) { + fuse_reply_err(request, ENOENT); + } + attribute_res *link_result = link_1(oldattr->attribute_res_u.attributes.id, newname, newparent, rpc_client); + if(link_result == NULL) { + fuse_reply_err(request, EIO); + } else if(link_result->err != FS454_ENONE) { + printf("rename failed to link with error %i\n", link_result->err); + fuse_reply_err(request, EIO); + } else { + error_code *unlink_result = unlink_1(parent, name, rpc_client); + if(*unlink_result != FS454_ENONE) { + printf("rename failed to unlink with error %i\n", link_result->err); + fuse_reply_err(request, EIO); + } else { + fuse_reply_err(request, 0); + } + } +} + +void fs454_rmdir(fuse_req_t request, fuse_ino_t parent, const char *name) { + error_code *result = unlink_1(parent, name, rpc_client); + if(result == NULL) { + fuse_reply_err(request, EIO); + } else { + fuse_reply_err(request, *result == FS454_ENONE ? 0 : EINVAL); + } +} + +void fs454_setattr(fuse_req_t request, fuse_ino_t inode, struct stat *attr, int to_set, struct fuse_file_info *fi) { + file_attributes attributes = { + .id = inode, + .filesize = attr->st_size, + .owner = attr->st_uid, + .mode = attr->st_mode, + .last_access = attr->st_atime, + .last_change = attr->st_ctime, + .last_modify = attr->st_mtime + }; + attribute_res *result = setattr_1(inode, to_set, attributes, rpc_client); + if(result == NULL) { + fuse_reply_err(request, EIO); + } else if(result->err == FS454_ENONE) { + struct stat s; + fill_stat(&s, &result->attribute_res_u.attributes); + fuse_reply_attr(request, &s, 0); + } else { + printf("setattr error %i\n", result->err); + fuse_reply_err(request, EINVAL); + } +} + +void fs454_symlink(fuse_req_t request, const char *link, fuse_ino_t parent, const char *name) { + attribute_res *result = symlink_1(link, parent, name, rpc_client); + if(result == NULL) { + fuse_reply_err(request, EIO); + } else { + file_attributes *attr = &result->attribute_res_u.attributes; + struct stat n; + struct fuse_entry_param entry = { + .attr_timeout = 0, + .entry_timeout = 0, + .generation = 0, + .ino = attr->id + }; + fill_stat(&entry.attr, attr); + fuse_reply_entry(request, &entry); + } +} + +void fs454_unlink(fuse_req_t request, fuse_ino_t parent, const char *name) { + error_code *result = unlink_1(parent, name, rpc_client); + if(result == NULL) { + fuse_reply_err(request, EIO); + } else { + fuse_reply_err(request, (int) (*result == FS454_ENONE ? 0 : ENOENT)); + } +} + +void fs454_write(fuse_req_t request, fuse_ino_t inode, const char *buffer, size_t size, off_t offset, struct fuse_file_info *fi) { + char *copy = malloc(size); + memcpy(copy, buffer, size); + byte_buffer arg_buffer = { + .byte_buffer_len = size, + .byte_buffer_val = copy + }; + error_code *result = write_1(inode, arg_buffer, offset, size, rpc_client); + if(result == NULL) { + fuse_reply_err(request, EIO); + } else if(*result == FS454_ENONE) { + fuse_reply_write(request, size); + } else { + printf("write failed error %i\n", *result); + fuse_reply_write(request, ENOENT); + } +} + +int main(int argc, char** argv) { + const struct fuse_lowlevel_ops fs454_ops = { + .access = fs454_access, + .copy_file_range = fs454_copy_file_range, + .fallocate = fs454_fallocate, + .getattr = fs454_getattr, + .link = fs454_link, + .lookup = fs454_lookup, + .mknod = fs454_mknod, + .mkdir = fs454_mkdir, + .open = fs454_open, + .read = fs454_read, + .readdir = fs454_readdir, + .readlink = fs454_readlink, + .rename = fs454_rename, + .rmdir = fs454_rmdir, + .setattr = fs454_setattr, + .symlink = fs454_symlink, + .unlink = fs454_unlink, + .write = fs454_write + }; + + const char *host = NULL; + if(argc > 2) { + host = argv[argc - 1]; + argc--; + } else { + printf("Please specify a host. Usage: %s [fuse options] [host]\n", argv[0]); + return 0; + } + + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + struct fuse_cmdline_opts opts; + struct fuse_loop_config cfg; + struct fuse_session *session; + + if(fuse_parse_cmdline(&args, &opts) != 0) { + return 1; + } + + if(opts.show_help) { + fuse_cmdline_help(); + fuse_lowlevel_help(); + } + + if(opts.mountpoint == NULL) { + fuse_opt_free_args(&args); + return 1; + } + + printf("Connecting to '%s'...\n", host); + + rpc_client = clnt_create(host, FS454, MESSAGEVERS, "tcp"); + if(rpc_client == NULL) { + clnt_pcreateerror(host); + exit(1); + } + + printf("Connected.\n"); + + session = fuse_session_new(&args, &fs454_ops, sizeof(fs454_ops), NULL); + + if(fuse_set_signal_handlers(session) != 0) { + fuse_session_destroy(session); + fuse_opt_free_args(&args); + return 1; + } + + if(fuse_session_mount(session, opts.mountpoint) != 0) { + fuse_remove_signal_handlers(session); + fuse_session_destroy(session); + fuse_opt_free_args(&args); + return 1; + } + + int status = 0; + fuse_daemonize(opts.foreground); + if(opts.singlethread) { + status = fuse_session_loop(session); + } else { + cfg.clone_fd = opts.clone_fd; + cfg.max_idle_threads = opts.max_idle_threads; + status = fuse_session_loop_mt(session, &cfg); + } + + fuse_session_unmount(session); + fuse_remove_signal_handlers(session); + fuse_session_destroy(session); + fuse_opt_free_args(&args); + return status; +} \ No newline at end of file diff --git a/src/fs454_server.c b/src/fs454_server.c new file mode 100644 index 0000000..e15c4d8 --- /dev/null +++ b/src/fs454_server.c @@ -0,0 +1,428 @@ +#include "inode_tree.h" +#include "file_tree.h" +#include "fsio.h" +#include "fs454.h" +#include +#include +#include + +#define SET_MODE (1 << 0) +#define SET_OWNER (1 << 1) +#define SET_SIZE (1 << 3) +#define SET_ACCESS (1 << 4) +#define SET_MODIFY (1 << 5) +#define SET_ACCESS_NOW (1 << 7) +#define SET_MODIFY_NOW (1 << 8) +#define SET_CHANGE (1 << 10) + +extern inode_tree *inodes; +extern directory_list *directories; + +/** + * @brief Manually check supported bits and copy them to a new mode + * value. This ensures only valid file modes can be given to the filesystem. + * If the input mode indicates the use of unsupported features, this function + * shall return 0 indicating the input mode is illegal. + * + * @param mode file mode to sanitize + * @return long a sanitized file mode + */ +long sanitize_mode(long mode) { + long newmode = 0; + + /* Test file type. Only files, directories, and links allowed. */ + if(S_ISBLK(mode)) { + return 0; + } else if(S_ISCHR(mode)) { + return 0; + } else if(S_ISDIR(mode)) { + newmode |= __S_IFDIR; + } else if(S_ISFIFO(mode)) { + return 0; + } else if(S_ISREG(mode)) { + newmode |= __S_IFREG; + } else if(S_ISLNK(mode)) { + newmode |= __S_IFLNK; + } + + /* Build a bitmask for supported permissions. Execute permissions are disabled. */ + long permission_mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + newmode |= mode & permission_mask; + + return newmode; +} + +error_code *allocate_1_svc(long inode, long length, struct svc_req *rqstp) +{ + static error_code result; + file_descriptor *desc = inode_tree_find(inodes, inode); + if(desc == NULL) { + result = FS454_ENOINODE; + } else if(length < 0 || length > (1 << 30)) { + result = FS454_EINVAL; + } else if(desc->attributes.filesize >= length) { + result = FS454_ENONE; + } else { + if(do_allocate(desc->location, length) != 0) { + result = FS454_EIO; + } else { + desc->attributes.filesize = length; + desc->attributes.last_change = time(0); + result = FS454_ENONE; + } + } + return &result; +} + +attribute_res *getattr_1_svc(long inode, struct svc_req *rqstp) +{ + static attribute_res result; + file_descriptor *desc = inode_tree_find(inodes, inode); + if(desc == NULL) { + result.err = FS454_ENOINODE; + } else { + result.attribute_res_u.attributes = desc->attributes; + result.err = FS454_ENONE; + } + return &result; +} + +attribute_res *link_1_svc(long inode, char *newname, long newparent, struct svc_req *rqstp) +{ + static attribute_res result; + if(inode <= 0 || newparent <= 0 || newname == NULL) { + result.err = FS454_EINVAL; + } + file_descriptor *descriptor = NULL; + file_descriptor *parent_descriptor = NULL; + if((descriptor = inode_tree_find(inodes, inode)) == NULL) { + result.err = FS454_ENOINODE; + } else if((descriptor = inode_tree_find(inodes, newparent)) == NULL) { + result.err = FS454_ENOINODE; + } else if(!S_ISDIR(parent_descriptor->attributes.mode)) { + result.err = FS454_ENOTDIR; + } else if(!S_ISREG(descriptor->attributes.mode)) { + result.err = FS454_EBADF; + } else if(file_tree_insert(directories, newparent, newname, descriptor->attributes.id) != 0) { + result.err = FS454_EIO; + } else { + result.err = FS454_ENONE; + descriptor->attributes.link_count++; + result.attribute_res_u.attributes = descriptor->attributes; + } + return &result; +} + +attribute_res *lookup_1_svc(char *name, long parent, struct svc_req *rqstp) +{ + static attribute_res result; + if(name == NULL || parent <= 0) { + result.err = FS454_EINVAL; + return &result; + } + directory_entry *entry = file_tree_lookup(directories, parent, name); + if(entry == NULL) { + result.err = FS454_ENOINODE; + } else { + file_descriptor *descriptor = inode_tree_find(inodes, entry->inode); + if(descriptor == NULL) { + /* There's a serious problem; this lookup should not fail. */ + fprintf(stderr, "WARNING: Broken link %ld->%ld stored in directory table.\n", parent, entry->inode); + result.err = FS454_EIO; + } else { + result.attribute_res_u.attributes = descriptor->attributes; + result.err = FS454_ENONE; + } + } + return &result; +} + +attribute_res *mkdir_1_svc(char *name, long parent, long mode, struct svc_req *rqstp) +{ + static attribute_res result; + if(name == NULL) { + result.err = FS454_EINVAL; + } else if((mode = sanitize_mode(mode)) == 0 || S_ISREG(mode) || S_ISLNK(mode)) { + result.err = FS454_EINVAL; + } else if(parent <= 0) { + result.err = FS454_EINVAL; + } else { + file_descriptor *parent_descriptor = inode_tree_find(inodes, parent); + file_descriptor *descriptor = NULL; + if(parent_descriptor == NULL) { + result.err = FS454_ENOINODE; + } else if(!S_ISDIR(parent_descriptor->attributes.mode)) { + result.err = FS454_ENOTDIR; + } else if((descriptor = inode_tree_create(inodes)) == NULL) { + result.err = FS454_EIO; + } else if(file_tree_insert_dir(directories, parent, name, descriptor->attributes.id) != 0) { + /* There's a serious problem; if a directory is stored in the inode table, inserting a new node should not fail. */ + fprintf(stderr, "WARNING: Failed to insert a new node %s under %ld into the file tree.\n", name, parent); + if(inode_tree_remove(inodes, descriptor->attributes.id) != 0) { + /* There's a really serious problem. This inode is known to exist; why can't we remove it? */ + fprintf(stderr, "WARNING: Failed to clean up orphaned inode %ld\n", descriptor->attributes.id); + /* No obvious way to recover... */ + } + result.err = FS454_EIO; + } else { + descriptor->location = 0; + descriptor->attributes.mode = mode | __S_IFDIR; + result.err = FS454_ENONE; + result.attribute_res_u.attributes = descriptor->attributes; + } + } + return &result; +} + +attribute_res *mknod_1_svc(char *name, long parent, long mode, struct svc_req *rqstp) +{ + static attribute_res result; + if(name == NULL) { + result.err = FS454_EINVAL; + } else if((mode = sanitize_mode(mode)) == 0 || S_ISDIR(mode) || S_ISLNK(mode)) { + result.err = FS454_EINVAL; + } else if(parent <= 0) { + result.err = FS454_EINVAL; + } else { + file_descriptor *parent_descriptor = inode_tree_find(inodes, parent); + file_descriptor *descriptor = NULL; + if(parent_descriptor == NULL) { + result.err = FS454_ENOINODE; + } else if(!S_ISDIR(parent_descriptor->attributes.mode)) { + result.err = FS454_ENOTDIR; + } else if((descriptor = inode_tree_create(inodes)) == NULL) { + result.err = FS454_EIO; + } else if(file_tree_insert(directories, parent, name, descriptor->attributes.id) != 0) { + /* There's a serious problem; if a directory is stored in the inode table, inserting a new node should not fail. */ + fprintf(stderr, "WARNING: Failed to insert a new node %s under %ld into the file tree.\n", name, parent); + if(inode_tree_remove(inodes, descriptor->attributes.id) != 0) { + /* There's a really serious problem. This inode is known to exist; why can't we remove it? */ + fprintf(stderr, "WARNING: Failed to clean up orphaned inode %ld\n", descriptor->attributes.id); + /* No obvious way to recover... */ + } + result.err = FS454_EIO; + } else { + descriptor->location = do_mknod(); + descriptor->attributes.mode = mode | __S_IFREG; + result.err = FS454_ENONE; + result.attribute_res_u.attributes = descriptor->attributes; + fprintf(stderr, "INFO: Made new inode %ld at location %ld.\n", descriptor->attributes.id, descriptor->location); + } + } + return &result; +} + +buffer_res *read_1_svc(long inode, long offset, long len, struct svc_req *rqstp) +{ + static buffer_res result; + file_descriptor *desc = inode_tree_find(inodes, inode); + if(desc == NULL) { + result.err = FS454_ENOINODE; + } else if(desc->location == 0) { + result.err = FS454_EBADF; + } else if(len < 0 || offset < 0 || offset >= desc->attributes.filesize) { + result.err = FS454_EINVAL; + } else { + if(offset + len > desc->attributes.filesize) { + len = desc->attributes.filesize - offset; + } + result.buffer_res_u.buffer.byte_buffer_val = malloc(len); + result.buffer_res_u.buffer.byte_buffer_len = len; + if(do_read(desc->location, result.buffer_res_u.buffer.byte_buffer_val, offset, len) != 0) { + result.err = FS454_EIO; + free(result.buffer_res_u.buffer.byte_buffer_val); + result.buffer_res_u.buffer.byte_buffer_val = NULL; + result.buffer_res_u.buffer.byte_buffer_len = 0; + } else { + desc->attributes.last_access = time(0); + result.err = FS454_ENONE; + } + } + return &result; +} + +readdir_res *readdir_1_svc(long inode, struct svc_req *rqstp) +{ + static readdir_res result; + directory_list_node *entry_list = file_tree_list_dir(directories, inode); + if(entry_list == NULL) { + result.err = FS454_ENOINODE; + } else { + xdr_free(xdr_readdir_res, &result); + file_descriptor *dir_desc = inode_tree_find(inodes, entry_list->self.inode); + file_descriptor *parent_desc = NULL; + if(entry_list->self.parent > 0) { + parent_desc = inode_tree_find(inodes, entry_list->self.parent); + } else { + parent_desc = dir_desc; + } + result.readdir_res_u.entries = malloc(sizeof(dir_entry)); + dir_entry *current_entry = result.readdir_res_u.entries; + current_entry->name.name_val = malloc(2); + strcpy(current_entry->name.name_val, "."); + current_entry->name.name_len = strlen(".") + 1; + current_entry->attributes = dir_desc->attributes; + current_entry->next = malloc(sizeof(dir_entry)); + current_entry = current_entry->next; + current_entry->name.name_val = malloc(3); + strcpy(current_entry->name.name_val, ".."); + current_entry->name.name_len = strlen("..") + 1; + current_entry->attributes = parent_desc->attributes; + dirent_list_node *node = entry_list->directory.first; + while(node != NULL) { + current_entry->next = malloc(sizeof(dir_entry)); + current_entry = current_entry->next; + u_int namelen = strlen(node->entry.name) + 1; + current_entry->name.name_val = malloc(namelen); + strcpy(current_entry->name.name_val, node->entry.name); + current_entry->name.name_len = namelen; + current_entry->attributes = inode_tree_find(inodes, node->entry.inode)->attributes; + current_entry->next = NULL; + node = node->next; + } + result.err = FS454_ENONE; + } + return &result; +} + +string_res *readlink_1_svc(long arg1, struct svc_req *rqstp) +{ + static string_res result; + result.err = FS454_EINVAL; + return &result; +} + +attribute_res *setattr_1_svc(long inode, long to_set, struct file_attributes attributes, struct svc_req *rqstp) +{ + static attribute_res result; + file_descriptor *descriptor = NULL; + if(to_set & SET_SIZE) { + fprintf(stderr, "INFO: Received request to change file size\n"); + result.err = FS454_EINVAL; + } else if((attributes.mode = sanitize_mode(attributes.mode)) == 0 && (to_set & SET_MODE)) { + fprintf(stderr, "INFO: Received invalid file mode\n"); + result.err = FS454_EINVAL; + } else if(/*(S_ISREG(attributes.mode) || S_ISDIR(attributes.mode) || S_ISLNK(attributes.mode)) && (to_set & SET_MODE)*/ 0) { + fprintf(stderr, "INFO: Received request to change file type\n"); + result.err = FS454_EINVAL; + } else if((descriptor = inode_tree_find(inodes, inode)) == NULL) { + result.err = FS454_ENOINODE; + } else { + if(to_set & SET_MODE) + descriptor->attributes.mode = attributes.mode; + if(to_set & SET_OWNER) + descriptor->attributes.owner = attributes.owner; + if(to_set & SET_CHANGE) + descriptor->attributes.last_change = attributes.last_change; + if(to_set & SET_ACCESS) + descriptor->attributes.last_access = attributes.last_access; + if(to_set & SET_MODIFY) + descriptor->attributes.last_modify = attributes.last_modify; + if(to_set & SET_ACCESS_NOW) + descriptor->attributes.last_access = time(0); + if(to_set & SET_MODIFY_NOW) + descriptor->attributes.last_modify = time(0); + result.attribute_res_u.attributes = descriptor->attributes; + result.err = FS454_ENONE; + } + return &result; +} + +attribute_res *symlink_1_svc(char *arg1, long arg2, char *arg3, struct svc_req *rqstp) +{ + static attribute_res result; + result.err = FS454_EINVAL; + return &result; +} + +error_code *unlink_1_svc(long parent, char *name, struct svc_req *rqstp) +{ + static error_code result; + directory_entry *entry = NULL; + file_descriptor *descriptor = NULL; + if(parent <= 0 || name == NULL) { + result = FS454_EINVAL; + } else if((entry = file_tree_lookup(directories, parent, name)) == NULL) { + result = FS454_ENOINODE; + } else if((descriptor = inode_tree_find(inodes, entry->inode)) == NULL) { + /* There's a serious problem; this lookup should not fail. */ + fprintf(stderr, "WARNING: Broken link %ld->%ld stored in directory table.\n", parent, entry->inode); + result = FS454_EIO; + } else if(S_ISDIR(descriptor->attributes.mode)) { + /* We should only delete empty directories */ + directory_list_node *entry_list = file_tree_list_dir(directories, descriptor->attributes.id); + if(entry_list == NULL) { + /* This is a problem. There exists a directory with no entry list stored in the filesystem. */ + fprintf(stderr, "WARNING: Count not find entry list for directory %ld.\n", descriptor->attributes.id); + result = FS454_EIO; + } else if(entry_list->directory.count > 0) { + result = FS454_ENOTEMPTY; + } else if(file_tree_remove(directories, parent, name) != 0) { + /* There's a serious problem; this node was found in a lookup, and has no children; why can't we remove it? */ + fprintf(stderr, "WARNING: Failed to remove empty directory node %ld->%s.\n", parent, name); + result = FS454_EIO; + } else if(inode_tree_remove(inodes, descriptor->attributes.id) != 0) { + /* This is a more serious problem; we've removed the link, but can't remove the inode. */ + fprintf(stderr, "WARNING: Failed to remove inode %ld from filesystem.\n", descriptor->attributes.id); + result = FS454_ENONE; + } else { + result = FS454_ENONE; + } + } else { + if(file_tree_remove(directories, parent, name) != 0) { + /* There's a serious problem; this node was found in a lookup; why can't we remove it? */ + fprintf(stderr, "WARNING: Failed to remove file node %ld->%s.\n", parent, name); + result = FS454_EIO; + } else if((descriptor->attributes.link_count--) == 0) { + /* Neither of the two following functions should ever fail. */ + if(do_rmnod(descriptor->location) != 0) { + fprintf(stderr, "WARNING: Failed to delete location %ld from disk.\n", descriptor->location); + } + if(inode_tree_remove(inodes, descriptor->attributes.id) != 0) { + fprintf(stderr, "WARNING: Failed to remove inode %ld from filesystem.\n", descriptor->attributes.id); + } + result = FS454_ENONE; + } else { + result = FS454_ENONE; + } + } + + return &result; +} + +error_code *write_1_svc(long inode, byte_buffer buffer, long offset, long length, struct svc_req *rqstp) +{ + static error_code result; + file_descriptor *desc = inode_tree_find(inodes, inode); + if(desc == NULL) { + result = FS454_ENOINODE; + } else if(desc->location == 0) { + result = FS454_EBADF; + } else if(offset < 0 || length < 0 || length > (1 << 30) || offset > (1 << 30)) { + result = FS454_EINVAL; + } else if(length == 0) { + result = FS454_ENONE; + } else if(length > buffer.byte_buffer_len) { + result = FS454_EINVAL; + } else if(!(desc->attributes.mode & S_IWUSR)) { + result = FS454_EACCESS; + } else if(do_write(desc->location, buffer.byte_buffer_val, offset, length) != 0) { + result = FS454_EIO; + } else { + if(offset + length > desc->attributes.filesize) { + desc->attributes.filesize = offset + length; + desc->attributes.last_access = time(0); + desc->attributes.last_modify = time(0); + desc->attributes.last_change = time(0); + } + result = FS454_ENONE; + } + return &result; +} + +error_code *copy_1_svc(long arg1, long arg2, long arg3, long arg4, long arg5, struct svc_req *rqstp) +{ + static error_code result; + result = FS454_EINVAL; + return &result; +} diff --git a/src/fs454_svc.c b/src/fs454_svc.c new file mode 100644 index 0000000..903c01f --- /dev/null +++ b/src/fs454_svc.c @@ -0,0 +1,279 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "fs454.h" +#include +#include +#include +#include +#include +#include +#include +#include "inode_tree.h" +#include "file_tree.h" +#include "fsio.h" + +#ifndef SIG_PF +#define SIG_PF void(*)(int) +#endif + +inode_tree *inodes; +directory_list *directories; + +static error_code * +_allocate_1 (allocate_1_argument *argp, struct svc_req *rqstp) +{ + return (allocate_1_svc(argp->arg1, argp->arg2, rqstp)); +} + +static attribute_res * +_getattr_1 (long *argp, struct svc_req *rqstp) +{ + return (getattr_1_svc(*argp, rqstp)); +} + +static attribute_res * +_link_1 (link_1_argument *argp, struct svc_req *rqstp) +{ + return (link_1_svc(argp->arg1, argp->arg2, argp->arg3, rqstp)); +} + +static attribute_res * +_lookup_1 (lookup_1_argument *argp, struct svc_req *rqstp) +{ + return (lookup_1_svc(argp->arg1, argp->arg2, rqstp)); +} + +static attribute_res * +_mkdir_1 (mkdir_1_argument *argp, struct svc_req *rqstp) +{ + return (mkdir_1_svc(argp->arg1, argp->arg2, argp->arg3, rqstp)); +} + +static attribute_res * +_mknod_1 (mknod_1_argument *argp, struct svc_req *rqstp) +{ + return (mknod_1_svc(argp->arg1, argp->arg2, argp->arg3, rqstp)); +} + +static buffer_res * +_read_1 (read_1_argument *argp, struct svc_req *rqstp) +{ + return (read_1_svc(argp->arg1, argp->arg2, argp->arg3, rqstp)); +} + +static readdir_res * +_readdir_1 (long *argp, struct svc_req *rqstp) +{ + return (readdir_1_svc(*argp, rqstp)); +} + +static string_res * +_readlink_1 (long *argp, struct svc_req *rqstp) +{ + return (readlink_1_svc(*argp, rqstp)); +} + +static attribute_res * +_setattr_1 (setattr_1_argument *argp, struct svc_req *rqstp) +{ + return (setattr_1_svc(argp->arg1, argp->arg2, argp->arg3, rqstp)); +} + +static attribute_res * +_symlink_1 (symlink_1_argument *argp, struct svc_req *rqstp) +{ + return (symlink_1_svc(argp->arg1, argp->arg2, argp->arg3, rqstp)); +} + +static error_code * +_unlink_1 (unlink_1_argument *argp, struct svc_req *rqstp) +{ + return (unlink_1_svc(argp->arg1, argp->arg2, rqstp)); +} + +static error_code * +_write_1 (write_1_argument *argp, struct svc_req *rqstp) +{ + return (write_1_svc(argp->arg1, argp->arg2, argp->arg3, argp->arg4, rqstp)); +} + +static error_code * +_copy_1 (copy_1_argument *argp, struct svc_req *rqstp) +{ + return (copy_1_svc(argp->arg1, argp->arg2, argp->arg3, argp->arg4, argp->arg5, rqstp)); +} + +static void +fs454_1(struct svc_req *rqstp, register SVCXPRT *transp) +{ + union { + allocate_1_argument allocate_1_arg; + long getattr_1_arg; + link_1_argument link_1_arg; + lookup_1_argument lookup_1_arg; + mkdir_1_argument mkdir_1_arg; + mknod_1_argument mknod_1_arg; + read_1_argument read_1_arg; + long readdir_1_arg; + long readlink_1_arg; + setattr_1_argument setattr_1_arg; + symlink_1_argument symlink_1_arg; + unlink_1_argument unlink_1_arg; + write_1_argument write_1_arg; + copy_1_argument copy_1_arg; + } argument; + char *result; + xdrproc_t _xdr_argument, _xdr_result; + char *(*local)(char *, struct svc_req *); + + switch (rqstp->rq_proc) { + case NULLPROC: + (void) svc_sendreply (transp, (xdrproc_t) xdr_void, (char *)NULL); + return; + + case ALLOCATE: + _xdr_argument = (xdrproc_t) xdr_allocate_1_argument; + _xdr_result = (xdrproc_t) xdr_error_code; + local = (char *(*)(char *, struct svc_req *)) _allocate_1; + break; + + case GETATTR: + _xdr_argument = (xdrproc_t) xdr_long; + _xdr_result = (xdrproc_t) xdr_attribute_res; + local = (char *(*)(char *, struct svc_req *)) _getattr_1; + break; + + case LINK: + _xdr_argument = (xdrproc_t) xdr_link_1_argument; + _xdr_result = (xdrproc_t) xdr_attribute_res; + local = (char *(*)(char *, struct svc_req *)) _link_1; + break; + + case LOOKUP: + _xdr_argument = (xdrproc_t) xdr_lookup_1_argument; + _xdr_result = (xdrproc_t) xdr_attribute_res; + local = (char *(*)(char *, struct svc_req *)) _lookup_1; + break; + + case MKDIR: + _xdr_argument = (xdrproc_t) xdr_mkdir_1_argument; + _xdr_result = (xdrproc_t) xdr_attribute_res; + local = (char *(*)(char *, struct svc_req *)) _mkdir_1; + break; + + case MKNOD: + _xdr_argument = (xdrproc_t) xdr_mknod_1_argument; + _xdr_result = (xdrproc_t) xdr_attribute_res; + local = (char *(*)(char *, struct svc_req *)) _mknod_1; + break; + + case READ: + _xdr_argument = (xdrproc_t) xdr_read_1_argument; + _xdr_result = (xdrproc_t) xdr_buffer_res; + local = (char *(*)(char *, struct svc_req *)) _read_1; + break; + + case READDIR: + _xdr_argument = (xdrproc_t) xdr_long; + _xdr_result = (xdrproc_t) xdr_readdir_res; + local = (char *(*)(char *, struct svc_req *)) _readdir_1; + break; + + case READLINK: + _xdr_argument = (xdrproc_t) xdr_long; + _xdr_result = (xdrproc_t) xdr_string_res; + local = (char *(*)(char *, struct svc_req *)) _readlink_1; + break; + + case SETATTR: + _xdr_argument = (xdrproc_t) xdr_setattr_1_argument; + _xdr_result = (xdrproc_t) xdr_attribute_res; + local = (char *(*)(char *, struct svc_req *)) _setattr_1; + break; + + case SYMLINK: + _xdr_argument = (xdrproc_t) xdr_symlink_1_argument; + _xdr_result = (xdrproc_t) xdr_attribute_res; + local = (char *(*)(char *, struct svc_req *)) _symlink_1; + break; + + case UNLINK: + _xdr_argument = (xdrproc_t) xdr_unlink_1_argument; + _xdr_result = (xdrproc_t) xdr_error_code; + local = (char *(*)(char *, struct svc_req *)) _unlink_1; + break; + + case WRITE: + _xdr_argument = (xdrproc_t) xdr_write_1_argument; + _xdr_result = (xdrproc_t) xdr_error_code; + local = (char *(*)(char *, struct svc_req *)) _write_1; + break; + + case COPY: + _xdr_argument = (xdrproc_t) xdr_copy_1_argument; + _xdr_result = (xdrproc_t) xdr_error_code; + local = (char *(*)(char *, struct svc_req *)) _copy_1; + break; + + default: + svcerr_noproc (transp); + return; + } + memset ((char *)&argument, 0, sizeof (argument)); + if (!svc_getargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { + svcerr_decode (transp); + return; + } + result = (*local)((char *)&argument, rqstp); + if (result != NULL && !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) { + svcerr_systemerr (transp); + } + if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)) { + fprintf (stderr, "%s", "unable to free arguments"); + exit (1); + } + return; +} + +int +main (int argc, char **argv) +{ + register SVCXPRT *transp; + + inodes = inode_tree_new(); + directories = file_tree_new(); + + inode_tree_insert_root(inodes); + file_tree_insert_root(directories); + fsio_init(); + + pmap_unset (FS454, MESSAGEVERS); + + transp = svcudp_create(RPC_ANYSOCK); + if (transp == NULL) { + fprintf (stderr, "%s", "cannot create udp service."); + exit(1); + } + if (!svc_register(transp, FS454, MESSAGEVERS, fs454_1, IPPROTO_UDP)) { + fprintf (stderr, "%s", "unable to register (FS454, MESSAGEVERS, udp)."); + exit(1); + } + + transp = svctcp_create(RPC_ANYSOCK, 0, 0); + if (transp == NULL) { + fprintf (stderr, "%s", "cannot create tcp service."); + exit(1); + } + if (!svc_register(transp, FS454, MESSAGEVERS, fs454_1, IPPROTO_TCP)) { + fprintf (stderr, "%s", "unable to register (FS454, MESSAGEVERS, tcp)."); + exit(1); + } + + svc_run (); + fprintf (stderr, "%s", "svc_run returned"); + exit (1); + /* NOTREACHED */ +} diff --git a/src/fs454_xdr.c b/src/fs454_xdr.c new file mode 100644 index 0000000..3ab9745 --- /dev/null +++ b/src/fs454_xdr.c @@ -0,0 +1,343 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#include "fs454.h" + +bool_t +xdr_file_attributes (XDR *xdrs, file_attributes *objp) +{ + register int32_t *buf; + + + if (xdrs->x_op == XDR_ENCODE) { + buf = XDR_INLINE (xdrs, 8 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_long (xdrs, &objp->id)) + return FALSE; + if (!xdr_long (xdrs, &objp->link_count)) + return FALSE; + if (!xdr_long (xdrs, &objp->filesize)) + return FALSE; + if (!xdr_long (xdrs, &objp->owner)) + return FALSE; + if (!xdr_long (xdrs, &objp->mode)) + return FALSE; + if (!xdr_long (xdrs, &objp->last_access)) + return FALSE; + if (!xdr_long (xdrs, &objp->last_modify)) + return FALSE; + if (!xdr_long (xdrs, &objp->last_change)) + return FALSE; + } else { + IXDR_PUT_LONG(buf, objp->id); + IXDR_PUT_LONG(buf, objp->link_count); + IXDR_PUT_LONG(buf, objp->filesize); + IXDR_PUT_LONG(buf, objp->owner); + IXDR_PUT_LONG(buf, objp->mode); + IXDR_PUT_LONG(buf, objp->last_access); + IXDR_PUT_LONG(buf, objp->last_modify); + IXDR_PUT_LONG(buf, objp->last_change); + } + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + buf = XDR_INLINE (xdrs, 8 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_long (xdrs, &objp->id)) + return FALSE; + if (!xdr_long (xdrs, &objp->link_count)) + return FALSE; + if (!xdr_long (xdrs, &objp->filesize)) + return FALSE; + if (!xdr_long (xdrs, &objp->owner)) + return FALSE; + if (!xdr_long (xdrs, &objp->mode)) + return FALSE; + if (!xdr_long (xdrs, &objp->last_access)) + return FALSE; + if (!xdr_long (xdrs, &objp->last_modify)) + return FALSE; + if (!xdr_long (xdrs, &objp->last_change)) + return FALSE; + } else { + objp->id = IXDR_GET_LONG(buf); + objp->link_count = IXDR_GET_LONG(buf); + objp->filesize = IXDR_GET_LONG(buf); + objp->owner = IXDR_GET_LONG(buf); + objp->mode = IXDR_GET_LONG(buf); + objp->last_access = IXDR_GET_LONG(buf); + objp->last_modify = IXDR_GET_LONG(buf); + objp->last_change = IXDR_GET_LONG(buf); + } + return TRUE; + } + + if (!xdr_long (xdrs, &objp->id)) + return FALSE; + if (!xdr_long (xdrs, &objp->link_count)) + return FALSE; + if (!xdr_long (xdrs, &objp->filesize)) + return FALSE; + if (!xdr_long (xdrs, &objp->owner)) + return FALSE; + if (!xdr_long (xdrs, &objp->mode)) + return FALSE; + if (!xdr_long (xdrs, &objp->last_access)) + return FALSE; + if (!xdr_long (xdrs, &objp->last_modify)) + return FALSE; + if (!xdr_long (xdrs, &objp->last_change)) + return FALSE; + return TRUE; +} + +bool_t +xdr_dir_entry (XDR *xdrs, dir_entry *objp) +{ + register int32_t *buf; + + if (!xdr_array (xdrs, (char **)&objp->name.name_val, (u_int *) &objp->name.name_len, ~0, + sizeof (char), (xdrproc_t) xdr_char)) + return FALSE; + if (!xdr_file_attributes (xdrs, &objp->attributes)) + return FALSE; + if (!xdr_pointer (xdrs, (char **)&objp->next, sizeof (dir_entry), (xdrproc_t) xdr_dir_entry)) + return FALSE; + return TRUE; +} + +bool_t +xdr_error_code (XDR *xdrs, error_code *objp) +{ + register int32_t *buf; + + if (!xdr_enum (xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t +xdr_entry_list (XDR *xdrs, entry_list *objp) +{ + register int32_t *buf; + + if (!xdr_pointer (xdrs, (char **)objp, sizeof (dir_entry), (xdrproc_t) xdr_dir_entry)) + return FALSE; + return TRUE; +} + +bool_t +xdr_byte_buffer (XDR *xdrs, byte_buffer *objp) +{ + register int32_t *buf; + + if (!xdr_array (xdrs, (char **)&objp->byte_buffer_val, (u_int *) &objp->byte_buffer_len, ~0, + sizeof (u_char), (xdrproc_t) xdr_u_char)) + return FALSE; + return TRUE; +} + +bool_t +xdr_attribute_res (XDR *xdrs, attribute_res *objp) +{ + register int32_t *buf; + + if (!xdr_error_code (xdrs, &objp->err)) + return FALSE; + switch (objp->err) { + case FS454_ENONE: + if (!xdr_file_attributes (xdrs, &objp->attribute_res_u.attributes)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_string_res (XDR *xdrs, string_res *objp) +{ + register int32_t *buf; + + if (!xdr_error_code (xdrs, &objp->err)) + return FALSE; + switch (objp->err) { + case FS454_ENONE: + if (!xdr_string (xdrs, &objp->string_res_u.str, ~0)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_readdir_res (XDR *xdrs, readdir_res *objp) +{ + register int32_t *buf; + + if (!xdr_error_code (xdrs, &objp->err)) + return FALSE; + switch (objp->err) { + case FS454_ENONE: + if (!xdr_entry_list (xdrs, &objp->readdir_res_u.entries)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_buffer_res (XDR *xdrs, buffer_res *objp) +{ + register int32_t *buf; + + if (!xdr_error_code (xdrs, &objp->err)) + return FALSE; + switch (objp->err) { + case FS454_ENONE: + if (!xdr_byte_buffer (xdrs, &objp->buffer_res_u.buffer)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t +xdr_allocate_1_argument (XDR *xdrs, allocate_1_argument *objp) +{ + if (!xdr_long (xdrs, &objp->arg1)) + return FALSE; + if (!xdr_long (xdrs, &objp->arg2)) + return FALSE; + return TRUE; +} + +bool_t +xdr_link_1_argument (XDR *xdrs, link_1_argument *objp) +{ + if (!xdr_long (xdrs, &objp->arg1)) + return FALSE; + if (!xdr_string (xdrs, &objp->arg2, ~0)) + return FALSE; + if (!xdr_long (xdrs, &objp->arg3)) + return FALSE; + return TRUE; +} + +bool_t +xdr_lookup_1_argument (XDR *xdrs, lookup_1_argument *objp) +{ + if (!xdr_string (xdrs, &objp->arg1, ~0)) + return FALSE; + if (!xdr_long (xdrs, &objp->arg2)) + return FALSE; + return TRUE; +} + +bool_t +xdr_mkdir_1_argument (XDR *xdrs, mkdir_1_argument *objp) +{ + if (!xdr_string (xdrs, &objp->arg1, ~0)) + return FALSE; + if (!xdr_long (xdrs, &objp->arg2)) + return FALSE; + if (!xdr_long (xdrs, &objp->arg3)) + return FALSE; + return TRUE; +} + +bool_t +xdr_mknod_1_argument (XDR *xdrs, mknod_1_argument *objp) +{ + if (!xdr_string (xdrs, &objp->arg1, ~0)) + return FALSE; + if (!xdr_long (xdrs, &objp->arg2)) + return FALSE; + if (!xdr_long (xdrs, &objp->arg3)) + return FALSE; + return TRUE; +} + +bool_t +xdr_read_1_argument (XDR *xdrs, read_1_argument *objp) +{ + if (!xdr_long (xdrs, &objp->arg1)) + return FALSE; + if (!xdr_long (xdrs, &objp->arg2)) + return FALSE; + if (!xdr_long (xdrs, &objp->arg3)) + return FALSE; + return TRUE; +} + +bool_t +xdr_setattr_1_argument (XDR *xdrs, setattr_1_argument *objp) +{ + if (!xdr_long (xdrs, &objp->arg1)) + return FALSE; + if (!xdr_long (xdrs, &objp->arg2)) + return FALSE; + if (!xdr_file_attributes (xdrs, &objp->arg3)) + return FALSE; + return TRUE; +} + +bool_t +xdr_symlink_1_argument (XDR *xdrs, symlink_1_argument *objp) +{ + if (!xdr_string (xdrs, &objp->arg1, ~0)) + return FALSE; + if (!xdr_long (xdrs, &objp->arg2)) + return FALSE; + if (!xdr_string (xdrs, &objp->arg3, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_unlink_1_argument (XDR *xdrs, unlink_1_argument *objp) +{ + if (!xdr_long (xdrs, &objp->arg1)) + return FALSE; + if (!xdr_string (xdrs, &objp->arg2, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_write_1_argument (XDR *xdrs, write_1_argument *objp) +{ + if (!xdr_long (xdrs, &objp->arg1)) + return FALSE; + if (!xdr_byte_buffer (xdrs, &objp->arg2)) + return FALSE; + if (!xdr_long (xdrs, &objp->arg3)) + return FALSE; + if (!xdr_long (xdrs, &objp->arg4)) + return FALSE; + return TRUE; +} + +bool_t +xdr_copy_1_argument (XDR *xdrs, copy_1_argument *objp) +{ + if (!xdr_long (xdrs, &objp->arg1)) + return FALSE; + if (!xdr_long (xdrs, &objp->arg2)) + return FALSE; + if (!xdr_long (xdrs, &objp->arg3)) + return FALSE; + if (!xdr_long (xdrs, &objp->arg4)) + return FALSE; + if (!xdr_long (xdrs, &objp->arg5)) + return FALSE; + return TRUE; +} diff --git a/src/fsio.c b/src/fsio.c new file mode 100644 index 0000000..ea9fd4b --- /dev/null +++ b/src/fsio.c @@ -0,0 +1,77 @@ +#include "fsio.h" +#include +#include +#include +#include +#include + +long next_location; + +void get_filename(char *dest, long location) { + mkdir("data/", 0700); + sprintf(dest, "data/%ld", location); +} + +void fsio_init() { + next_location = 1; +} + +long do_mknod() { + long location = next_location; + next_location++; + char filename[80]; + get_filename(filename, location); + FILE *fd = fopen(filename, "wx"); + if(fd != NULL) { + fclose(fd); + return location; + } else { + return 0; + } +} + +int do_rmnod(long location) { + char filename[80]; + get_filename(filename, location); + remove(filename); + return 0; +} + +int do_read(long location, unsigned char *buffer, long offset, long length) { + printf("do_read %i %i %i %p\n", location, length, offset, buffer); + char filename[80]; + get_filename(filename, location); + int fd = open(filename, O_RDONLY); + if(fd > 0) { + lseek(fd, offset, SEEK_SET); + read(fd, buffer, length); + close(fd); + return 0; + } else { + return -1; + } +} + +int do_write(long location, const unsigned char *buffer, long offset, long length) { + printf("do_write %i %i %i %p\n", location, length, offset, buffer); + char filename[80]; + get_filename(filename, location); + int fd = open(filename, O_WRONLY); + if(fd > 0) { + lseek(fd, offset, SEEK_SET); + write(fd, buffer, length); + close(fd); + return 0; + } else { + return -1; + } +} + +int do_allocate(long location, long size) { + char filename[80]; + get_filename(filename, location); + int fd = open(filename, O_RDWR); + posix_fallocate(fd, 0, size); + close(fd); + return 0; +} \ No newline at end of file diff --git a/src/fsio.h b/src/fsio.h new file mode 100644 index 0000000..5eefd31 --- /dev/null +++ b/src/fsio.h @@ -0,0 +1,16 @@ +#ifndef FS454_IO +#define FS454_IO + +void fsio_init(); + +long do_mknod(); + +int do_rmnod(long location); + +int do_read(long location, unsigned char *buffer, long offset, long length); + +int do_write(long location, const unsigned char *buffer, long offset, long length); + +int do_allocate(long location, long size); + +#endif \ No newline at end of file diff --git a/src/inode_tree.c b/src/inode_tree.c new file mode 100644 index 0000000..2d1b768 --- /dev/null +++ b/src/inode_tree.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include "inode_tree.h" + +inode_tree *inode_tree_new() { + inode_tree *tree = malloc(sizeof(inode_tree)); + if(tree != NULL) { + tree->first = NULL; + tree->last = NULL; + tree->count = 0; + tree->next_inode = 2; + } + return tree; +} + +file_descriptor *inode_tree_create(inode_tree *tree) { + inode_tree_node *newnode = malloc(sizeof(inode_tree_node)); + newnode->descriptor = malloc(sizeof(file_descriptor)); + newnode->next = NULL; + newnode->descriptor->location = 0; + newnode->descriptor->attributes.id = tree->next_inode; + newnode->descriptor->attributes.link_count = 1; + newnode->descriptor->attributes.owner = 0; + newnode->descriptor->attributes.mode = 0; + newnode->descriptor->attributes.last_access = time(0); + newnode->descriptor->attributes.last_modify = time(0); + newnode->descriptor->attributes.last_change = time(0); + if(tree->last != NULL) { + tree->last->next = newnode; + tree->last = newnode; + } else { + tree->first = newnode; + tree->last = newnode; + } + tree->count++; + tree->next_inode++; + return newnode->descriptor; +} + +file_descriptor *inode_tree_find(inode_tree *tree, long inode) { + inode_tree_node *node = tree->first; + while(node != NULL) { + if(node->descriptor->attributes.id == inode) { + break; + } else { + node = node->next; + } + } + if(node != NULL) { + return node->descriptor; + } else { + return NULL; + } +} + +int inode_tree_insert_root(inode_tree *tree) { + file_descriptor *root = malloc(sizeof(file_descriptor)); + root->location = 0; + root->attributes.id = 1; + root->attributes.filesize = 0; + root->attributes.last_access = time(0); + root->attributes.last_change = time(0); + root->attributes.last_modify = time(0); + root->attributes.owner = 0; + root->attributes.mode = __S_IFDIR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH; + return inode_tree_insert(tree, root); +} + +int inode_tree_insert(inode_tree *tree, file_descriptor *descriptor) { + inode_tree_node *node = malloc(sizeof(inode_tree_node)); + if(node != NULL) { + node->next = NULL; + node->descriptor = descriptor; + if(tree->last != NULL) { + tree->last->next = node; + tree->last = node; + } else { + tree->first = node; + tree->last = node; + } + tree->count++; + return 0; + } else { + return -1; + } +} + +int inode_tree_remove(inode_tree *tree, long inode) { + inode_tree_node *prev = NULL; + inode_tree_node *node = tree->first; + while(node != NULL) { + if(node->descriptor->attributes.id == inode) { + break; + } else { + prev = node; + node = node->next; + } + } + if(node != NULL) { + if(prev != NULL) { + prev->next = node->next; + if(prev->next == NULL) { + tree->last = prev; + } + } else { + if(tree->first == tree->last) { + tree->first = tree->last = NULL; + } else { + tree->first = node->next; + } + } + free(node->descriptor); + free(node); + tree->count--; + return 0; + } else { + return -1; + } +} \ No newline at end of file diff --git a/src/inode_tree.h b/src/inode_tree.h new file mode 100644 index 0000000..219e0ae --- /dev/null +++ b/src/inode_tree.h @@ -0,0 +1,34 @@ +#ifndef FS454_INODE_TREE +#define FS454_INODE_TREE + +#include "fs454.h" + +typedef struct file_descriptor_t { + struct file_attributes attributes; + long location; +} file_descriptor; + +typedef struct inode_tree_node_t { + struct inode_tree_node_t *next; + file_descriptor *descriptor; +} inode_tree_node; + +typedef struct inode_tree_t { + inode_tree_node *first, *last; + long count; + long next_inode; +} inode_tree; + +inode_tree *inode_tree_new(); + +file_descriptor *inode_tree_create(inode_tree *tree); + +file_descriptor *inode_tree_find(inode_tree *tree, long inode); + +int inode_tree_insert_root(inode_tree *tree); + +int inode_tree_insert(inode_tree *tree, file_descriptor *descriptor); + +int inode_tree_remove(inode_tree *tree, long inode); + +#endif \ No newline at end of file