summaryrefslogtreecommitdiff
path: root/cmd/srv9p/static9p.c
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/srv9p/static9p.c')
-rw-r--r--cmd/srv9p/static9p.c232
1 files changed, 232 insertions, 0 deletions
diff --git a/cmd/srv9p/static9p.c b/cmd/srv9p/static9p.c
new file mode 100644
index 0000000..e20921d
--- /dev/null
+++ b/cmd/srv9p/static9p.c
@@ -0,0 +1,232 @@
+#include <assert.h>
+
+#include "static9p.h"
+
+#define UNUSED(name) /* name __attribute__((unused)) */
+#define p9_str(cstr) ((struct lib9p_s){ .len = strlen(cstr), .utf8 = cstr })
+#define p9_nulstr ((struct lib9p_s){ .len = 0, .utf8 = NULL })
+
+/* common metadata ************************************************************/
+
+static struct lib9p_srv_file *static_metadata_clone(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file *_file) {
+ assert(ctx);
+ struct static_metadata *file = (struct static_metadata *)_file;
+ assert(file);
+
+ return &file->header;
+}
+
+static void static_metadata_free(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file *_file) {
+ assert(ctx);
+ struct static_metadata *file = (struct static_metadata *)_file;
+ assert(file);
+
+ /* do nothing */
+}
+
+static uint32_t static_metadata_io(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file *_file, lib9p_o_t UNUSED(flags)) {
+ assert(ctx);
+ struct static_metadata *file = (struct static_metadata *)_file;
+ assert(file);
+
+ return 0;
+}
+
+static void static_metadata_wstat(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file *_file,
+ struct lib9p_stat UNUSED(new)) {
+ assert(ctx);
+ struct static_metadata *file = (struct static_metadata *)_file;
+ assert(file);
+
+ lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem");
+}
+
+static void static_metadata_remove(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file *_file) {
+ assert(ctx);
+ struct static_metadata *file = (struct static_metadata *)_file;
+ assert(file);
+
+ lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem");
+}
+
+/* dir ************************************************************************/
+
+static struct lib9p_stat static_dir_stat(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file *_file) {
+ assert(ctx);
+ struct static_dir *file = (struct static_dir *)_file;
+ assert(file);
+
+ return (struct lib9p_stat){
+ .kern_type = 0,
+ .kern_dev = 0,
+ .file_qid = {
+ .type = LIB9P_QT_DIR,
+ .vers = 1,
+ .path = file->metadata.pathnum,
+ },
+ .file_mode = LIB9P_DM_DIR | (file->metadata.perm & 0555),
+ .file_atime = file->metadata.atime,
+ .file_mtime = file->metadata.mtime,
+ .file_size = 0,
+ .file_name = p9_str(file->metadata.name),
+ .file_owner_uid = p9_str(file->metadata.u_name),
+ .file_owner_gid = p9_str(file->metadata.g_name),
+ .file_last_modified_uid = p9_str(file->metadata.m_name),
+ .file_extension = p9_nulstr,
+ .file_owner_n_uid = file->metadata.u_num,
+ .file_owner_n_gid = file->metadata.g_num,
+ .file_last_modified_n_uid = file->metadata.m_num,
+ };
+}
+
+static struct lib9p_srv_file *static_dir_dopen(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file *_dir,
+ char *childname) {
+ assert(ctx);
+ struct static_dir *dir = (struct static_dir *)_dir;
+ assert(dir);
+
+ for (size_t i = 0; dir->members[i]; i++) {
+ struct lib9p_srv_file *filep = dir->members[i];
+ struct lib9p_stat stat = filep->vtable->stat(ctx, filep);
+ if (lib9p_ctx_has_error(&ctx->basectx))
+ break;
+ lib9p_assert_stat(stat);
+ if (strcmp(stat.file_name.utf8, childname) == 0)
+ return filep;
+ }
+ lib9p_error(&ctx->basectx,
+ LINUX_ENOENT, "no such file or directory");
+ return NULL;
+}
+
+static struct lib9p_srv_file *static_dir_dcreate(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file *_dir,
+ char *UNUSED(childname),
+ lib9p_dm_t UNUSED(perm), lib9p_o_t UNUSED(flags)) {
+ assert(ctx);
+ struct static_dir *dir = (struct static_dir *)_dir;
+ assert(dir);
+
+ lib9p_error(&ctx->basectx, LINUX_EROFS, "read-only part of filesystem");
+ return NULL;
+}
+
+static size_t static_dir_dread(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file *_dir,
+ uint8_t *buf,
+ uint32_t byte_count,
+ size_t _obj_offset) {
+ assert(ctx);
+ struct static_dir *dir = (struct static_dir *)_dir;
+ assert(dir);
+
+ uint32_t byte_offset = 0;
+ size_t obj_offset = _obj_offset;
+ while (dir->members[obj_offset]) {
+ struct lib9p_srv_file *filep = dir->members[obj_offset];
+ struct lib9p_stat stat = filep->vtable->stat(ctx, filep);
+ if (lib9p_ctx_has_error(&ctx->basectx))
+ break;
+ lib9p_assert_stat(stat);
+ uint32_t nbytes = lib9p_marshal_stat(&ctx->basectx, byte_count-byte_offset, &stat,
+ &buf[byte_offset]);
+ if (!nbytes) {
+ if (obj_offset == _obj_offset)
+ lib9p_error(&ctx->basectx,
+ LINUX_ERANGE, "stat object does not fit into negotiated max message size");
+ break;
+ }
+ byte_offset += nbytes;
+ obj_offset++;
+ }
+ return obj_offset - _obj_offset;
+}
+
+struct lib9p_srv_file_vtable static_dir_vtable = {
+ .clone = static_metadata_clone,
+ .free = static_metadata_free,
+
+ .io = static_metadata_io,
+ .stat = static_dir_stat,
+ .wstat = static_metadata_wstat,
+ .remove = static_metadata_remove,
+
+ .dopen = static_dir_dopen,
+ .dcreate = static_dir_dcreate,
+
+ .dread = static_dir_dread,
+};
+
+/* file ***********************************************************************/
+
+static inline size_t static_file_size(struct static_file *file) {
+ assert(file);
+
+ assert(file->data_start);
+ if (!file->data_end)
+ return file->data_size;
+ return (size_t)((uintptr_t)file->data_end - (uintptr_t)file->data_start);
+}
+
+static struct lib9p_stat static_file_stat(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file *_file) {
+ assert(ctx);
+ struct static_file *file = (struct static_file *)_file;
+ assert(file);
+
+ return (struct lib9p_stat){
+ .kern_type = 0,
+ .kern_dev = 0,
+ .file_qid = {
+ .type = LIB9P_QT_FILE,
+ .vers = 1,
+ .path = file->metadata.pathnum,
+ },
+ .file_mode = file->metadata.perm & 0444,
+ .file_atime = file->metadata.atime,
+ .file_mtime = file->metadata.mtime,
+ .file_size = (uint64_t)static_file_size(file),
+ .file_name = p9_str(file->metadata.name),
+ .file_owner_uid = p9_str(file->metadata.u_name),
+ .file_owner_gid = p9_str(file->metadata.g_name),
+ .file_last_modified_uid = p9_str(file->metadata.m_name),
+ .file_extension = p9_nulstr,
+ .file_owner_n_uid = file->metadata.u_num,
+ .file_owner_n_gid = file->metadata.g_num,
+ .file_last_modified_n_uid = file->metadata.m_num,
+ };
+}
+
+static uint32_t static_file_pread(struct lib9p_srv_ctx *ctx, struct lib9p_srv_file *_file,
+ void *buf,
+ uint32_t byte_count,
+ uint64_t byte_offset) {
+ assert(ctx);
+ struct static_file *file = (struct static_file *)_file;
+ assert(file);
+
+ size_t data_size = static_file_size(file);
+
+ if (byte_offset > (uint64_t)data_size) {
+ lib9p_error(&ctx->basectx,
+ LINUX_EINVAL, "offset is past end-of-file length");
+ return 0;
+ }
+
+ size_t beg_off = (size_t)byte_offset;
+ size_t end_off = beg_off + (size_t)byte_count;
+ if (end_off > data_size)
+ end_off = data_size;
+ memcpy(buf, &file->data_start[beg_off], end_off-beg_off);
+ return (uint32_t)(end_off-beg_off);
+}
+
+struct lib9p_srv_file_vtable static_file_vtable = {
+ .clone = static_metadata_clone,
+ .free = static_metadata_free,
+
+ .io = static_metadata_io,
+ .stat = static_file_stat,
+ .wstat = static_metadata_wstat,
+ .remove = static_metadata_remove,
+
+ .pread = static_file_pread,
+ .pwrite = NULL,
+};