Make it so that volumes can be mounted anywhere.
authorcoderain <coderain@sdf.org>
Mon, 27 Feb 2017 05:29:24 +0000 (06:29 +0100)
committercoderain <coderain@sdf.org>
Mon, 27 Feb 2017 05:29:24 +0000 (06:29 +0100)
kernel/include/filesystem.h
kernel/src/device.c
kernel/src/drivers/fs/fat.c
kernel/src/drivers/fs/ram.c
kernel/src/filesystem.c
kernel/src/start.c

index 03c40ed3b91bde0e1ea627b97193b085f0186e4d..88f477386d1d9ea59681313f161a56ab7f9c2657 100644 (file)
@@ -50,7 +50,7 @@ typedef struct mounted_volume mounted_volume_t;
 typedef struct file file_t;
 typedef struct file_instance file_instance_t;
 
-typedef dword_t (*fs_mount_proc_t)(const char *device, dword_t flags);
+typedef dword_t (*fs_mount_proc_t)(const char *device, const char *mountpoint, dword_t flags);
 typedef dword_t (*fs_unmount_proc_t)(mounted_volume_t *volume);
 typedef dword_t (*fs_load_proc_t)(file_t **file);
 typedef dword_t (*fs_unload_proc_t)(file_t *file);
@@ -118,6 +118,7 @@ struct file_instance
 struct mounted_volume
 {
     list_entry_t list;
+    char *mountpoint;
     dword_t flags;
     resource_t resource;
     device_t *device;
@@ -127,10 +128,9 @@ struct mounted_volume
 
 void register_filesystem_driver(fs_driver_t *driver);
 bool_t unregister_filesystem_driver(fs_driver_t *driver);
-mounted_volume_t *get_mounted_volume(const char *name);
 dword_t register_mounted_volume(mounted_volume_t *volume);
 dword_t unregister_mounted_volume(mounted_volume_t *volume);
-dword_t normalize_path(const char *path, mounted_volume_t **volume, char *normalized_path);
+dword_t normalize_path(const char *path, char *normalized_path);
 dword_t open_file_internal(const char *path, file_instance_t **instance, dword_t mode, dword_t attributes);
 dword_t open_file(const char *path, handle_t *handle, dword_t mode, dword_t attributes);
 dword_t delete_file(const char *path);
@@ -139,7 +139,7 @@ dword_t set_file(handle_t handle, file_info_type_t set_type, void *buffer, size_
 dword_t list_directory(handle_t handle, char *filename, bool_t continue_scan);
 dword_t read_file(handle_t handle, void *buffer, qword_t offset, size_t size, size_t *bytes_read);
 dword_t write_file(handle_t handle, const void *buffer, qword_t offset, size_t size, size_t *bytes_written);
-dword_t mount(const char *device, const char *filesystem, dword_t flags);
+dword_t mount(const char *device, const char *mountpoint, const char *filesystem, dword_t flags);
 dword_t unmount(const char *device);
 
 #endif
index 3f4953410d00ddb977c314cf1e76c91b51c13ec8..195cdea008a3af973de322c08c562e8088aa2b7d 100644 (file)
@@ -33,7 +33,7 @@ static lock_t char_dev_driver_list_lock = 0;
 static resource_t block_device_list_res = 0;
 static resource_t char_device_list_res = 0;
 
-dword_t device_mount(const char *device, dword_t flags);
+dword_t device_mount(const char *device, const char *mountpoint, dword_t flags);
 dword_t device_unmount(mounted_volume_t *volume);
 dword_t device_load_file(file_t **file);
 dword_t device_unload_file(file_t *file);
@@ -61,38 +61,23 @@ static fs_driver_t device_fs_driver =
     .set_file    = device_set_file
 };
 
-static device_t block_device_volume_device =
-{
-    .flags  = 0,
-    .driver = NULL,
-    .name   = "BlockDevices",
-    .capacity = 0ULL,
-    .resource = 0
-};
 
 static mounted_volume_t block_device_volume =
 {
+    .mountpoint = "BlockDevices",
     .flags      = 0,
     .resource   = 0,
-    .device     = &block_device_volume_device,
+    .device     = NULL,
     .open_files = 0ULL,
     .driver     = &device_fs_driver
 };
 
-static device_t char_device_volume_device =
-{
-    .flags  = 0,
-    .driver = NULL,
-    .name   = "CharDevices",
-    .capacity = 0ULL,
-    .resource = 0
-};
-
 static mounted_volume_t char_device_volume =
 {
+    .mountpoint = "CharDevices",
     .flags      = 0,
     .resource   = 0,
-    .device     = &char_device_volume_device,
+    .device     = NULL,
     .open_files = 0ULL,
     .driver     = &device_fs_driver
 };
@@ -254,7 +239,7 @@ dword_t unregister_char_device(device_t *device)
     return ERR_SUCCESS;
 }
 
-dword_t device_mount(const char *device, dword_t flags)
+dword_t device_mount(const char *device, const char *mountpoint, dword_t flags)
 {
     return ERR_INVALID;
 }
index dad9ec92f19e1f6401936e59a29b2eb1409dff0d..b59f695556f7a67fd24a187aa77de7ac9ac14f14 100644 (file)
@@ -23,7 +23,7 @@
 #include <exception.h>
 #include <user.h>
 
-static dword_t fatfs_mount(const char *device, dword_t flags);
+static dword_t fatfs_mount(const char *device, const char *mountpoint, dword_t flags);
 static dword_t fatfs_unmount(mounted_volume_t *volume);
 static dword_t fatfs_load_file(file_t **file);
 static dword_t fatfs_unload_file(file_t *file);
@@ -603,7 +603,7 @@ static dword_t fatfs_write_internal(object_t *obj, const void *buffer, qword_t o
     return fatfs_rw_file(obj, (void*)buffer, offset, length, bytes_written, TRUE);
 }
 
-static dword_t fatfs_mount(const char *device, dword_t flags)
+static dword_t fatfs_mount(const char *device, const char *mountpoint, dword_t flags)
 {
     fatfs_bpb_t bpb;
     fat_version_t type;
@@ -638,6 +638,7 @@ static dword_t fatfs_mount(const char *device, dword_t flags)
     if (volume == NULL) return ERR_NOMEMORY;
 
     volume->header.device = get_block_device(device);
+    volume->header.mountpoint = strdup(mountpoint);
     volume->header.driver = &fatfs_driver;
     volume->type = type;
     volume->bytes_per_sector = bpb.bytes_per_sector;
index 5085571494f258dba891a136913b9cd38ca750ee..70c35ccc8f4b96cd07276723736c6240a62773d8 100644 (file)
@@ -21,7 +21,7 @@
 #include <heap.h>
 #include <syscalls.h>
 
-static dword_t ramfs_mount(const char *device, dword_t flags);
+static dword_t ramfs_mount(const char *device, const char *mountpoint, dword_t flags);
 static dword_t ramfs_unmount(mounted_volume_t *volume);
 static dword_t ramfs_load_file(file_t **file);
 static dword_t ramfs_unload_file(file_t *file);
@@ -94,26 +94,11 @@ static void ramfs_purge_file(ramfs_volume_t *volume, ramfs_node_t *node)
     free(node);
 }
 
-static dword_t ramfs_mount(const char *device, dword_t flags)
+static dword_t ramfs_mount(const char *device, const char *mountpoint, dword_t flags)
 {
     char *endptr;
-    char *device_name = strdup(device);
-
-    char *requested_size = strchr(device_name, ':');
-    if (requested_size == NULL)
-    {
-        free(device_name);
-        return ERR_INVALID;
-    }
-
-    *requested_size++ = '\0';
-
-    qword_t size = strtoull(requested_size, &endptr, 10);
-    if (!size)
-    {
-        free(device_name);
-        return ERR_INVALID;
-    }
+    qword_t size = strtoull(device, &endptr, 10);
+    if (!size) return ERR_INVALID;
 
     switch (*endptr)
     {
@@ -130,32 +115,10 @@ static dword_t ramfs_mount(const char *device, dword_t flags)
         break;
     }
 
-    device_t *virtual_device = (device_t*)malloc(sizeof(device_t));
-    if (virtual_device == NULL) return ERR_NOMEMORY;
-
-    virtual_device->flags = 0;
-    virtual_device->driver = NULL;
-    strcpy(virtual_device->name, device_name);
-    virtual_device->capacity = size;
-    virtual_device->resource = 0;
-
-    dword_t ret = register_block_device(virtual_device);
-    if (ret != ERR_SUCCESS)
-    {
-        free(virtual_device);
-        free(device_name);
-        return ret;
-    }
-
     ramfs_volume_t *volume = (ramfs_volume_t*)malloc(sizeof(ramfs_volume_t));
-    if (volume == NULL)
-    {
-        unregister_block_device(virtual_device);
-        free(virtual_device);
-        free(device_name);
-        return ERR_NOMEMORY;
-    }
+    if (volume == NULL) return ERR_NOMEMORY;
 
+    volume->header.mountpoint = strdup(mountpoint);
     volume->header.driver = &ramfs_driver;
     volume->header.device = NULL;
     volume->max_size = size;
@@ -164,16 +127,8 @@ static dword_t ramfs_mount(const char *device, dword_t flags)
     volume->root.attributes = FILE_ATTR_DIRECTORY;
     list_init(&volume->root.files);
 
-    ret = register_mounted_volume(&volume->header);
-
-    if (ret != ERR_SUCCESS)
-    {
-        free(volume);
-        unregister_block_device(virtual_device);
-        free(virtual_device);
-    }
-
-    free(device_name);
+    dword_t ret = register_mounted_volume(&volume->header);
+    if (ret != ERR_SUCCESS) free(volume);
     return ret;
 }
 
index 2339d523b34e86edd21b340e4c135a9557ef0f88..706d7952f5754f6344d7c089bc896bbc4e8f8c6d 100644 (file)
@@ -29,10 +29,11 @@ static DECLARE_LIST(volumes);
 lock_t fs_driver_list_lock = 0;
 resource_t volume_list_res = 0;
 
-static inline char *skip_volume_name(const char *full_path)
+static inline int count_delimiters(const char *string)
 {
-    char *ptr = strchr(full_path, PATH_DELIMITER_CHAR);
-    return ptr ? ptr + 1 : strchr(full_path, '\0');
+    int count = 0;
+    while ((string = strchr(string, PATH_DELIMITER_CHAR)) != NULL) count++;
+    return count;
 }
 
 void file_cleanup(file_t *file)
@@ -76,30 +77,23 @@ bool_t unregister_filesystem_driver(fs_driver_t *driver)
     return TRUE;
 }
 
-mounted_volume_t *get_mounted_volume(const char *name)
-{
-    list_entry_t *i;
-    mounted_volume_t *vol = NULL;
-
-    acquire_resource_shared(&volume_list_res);
-    for (i = volumes.next; i != &volumes; i = i->next)
-    {
-        vol = CONTAINER_OF(i, mounted_volume_t, list);
-        if (vol->device && strcmp(vol->device->name, name) == 0) break;
-    }
-    release_resource(&volume_list_res);
-
-    if (i == &volumes) vol = NULL;
-    return vol;
-}
-
 dword_t register_mounted_volume(mounted_volume_t *volume)
 {
     acquire_resource_exclusive(&volume_list_res);
 
     volume->resource = 0;
     volume->open_files = 0;
-    list_append(&volumes, &volume->list);
+
+    int delimiters = count_delimiters(volume->mountpoint);
+    list_entry_t *ptr;
+
+    for (ptr = volumes.next; ptr != &volumes; ptr = ptr->next)
+    {
+        mounted_volume_t *current = CONTAINER_OF(ptr, mounted_volume_t, list);
+        if (delimiters >= count_delimiters(current->mountpoint)) break;
+    }
+
+    list_put_before(ptr, &volume->list);
 
     release_resource(&volume_list_res);
     return ERR_SUCCESS;
@@ -118,7 +112,29 @@ dword_t unregister_mounted_volume(mounted_volume_t *volume)
     return ERR_SUCCESS;
 }
 
-dword_t normalize_path(const char *path, mounted_volume_t **volume, char *normalized_path)
+mounted_volume_t *get_volume_from_path(const char *path)
+{
+    mounted_volume_t *volume = NULL;
+    list_entry_t *ptr;
+    acquire_resource_shared(&volume_list_res);
+
+    for (ptr = volumes.next; ptr != &volumes; ptr = ptr->next)
+    {
+        mounted_volume_t *vol = CONTAINER_OF(ptr, mounted_volume_t, list);
+
+        if (strstr(path, vol->mountpoint) == path
+            && (path[strlen(vol->mountpoint)] == '\0' || path[strlen(vol->mountpoint)] == PATH_DELIMITER_CHAR))
+        {
+            volume = vol;
+            break;
+        }
+    }
+
+    release_resource(&volume_list_res);
+    return volume;
+}
+
+dword_t normalize_path(const char *path, char *normalized_path)
 {
     static const char *block_dev_prefix = "BlockDevices/";
     static const char *char_dev_prefix = "CharDevices/";
@@ -144,23 +160,12 @@ dword_t normalize_path(const char *path, mounted_volume_t **volume, char *normal
         path_copy = strdup(path);
     }
 
-    char *token = strtok(path_copy, PATH_DELIMITER_STRING, &endptr);
-    if (token == NULL)
-    {
-        ret = ERR_INVALID;
-        goto cleanup;
-    }
-
-    *volume = get_mounted_volume(token);
-    if (*volume == NULL)
-    {
-        ret = ERR_NOTFOUND;
-        goto cleanup;
-    }
-
+    char *token;
     *normalized_path = '\0';
 
-    while (token)
+    for (token = strtok(path_copy, PATH_DELIMITER_STRING, &endptr);
+         token != NULL;
+         token = strtok(NULL, PATH_DELIMITER_STRING, &endptr))
     {
         if (strcmp(token, ".") == 0) continue;
         if (strcmp(token, "..") == 0)
@@ -177,30 +182,30 @@ dword_t normalize_path(const char *path, mounted_volume_t **volume, char *normal
 
         if (normalized_path[0]) strcat(normalized_path, PATH_DELIMITER_STRING);
         strcat(normalized_path, token);
-
-        token = strtok(NULL, PATH_DELIMITER_STRING, &endptr);
     }
 
-cleanup:
     free(path_copy);
     return ret;
 }
 
-dword_t mount(const char *device, const char *filesystem, dword_t flags)
+dword_t mount(const char *device, const char *mountpoint, const char *filesystem, dword_t flags)
 {
     dword_t ret = ERR_NOTFOUND;
     list_entry_t *i;
     char *safe_device;
+    char *safe_mountpoint;
     char *safe_filesystem;
 
     if (get_previous_mode() == USER_MODE)
     {
         safe_device = copy_user_string(device);
+        safe_mountpoint = copy_user_string(mountpoint);
         safe_filesystem = copy_user_string(filesystem);
     }
     else
     {
         safe_device = (char*)device;
+        safe_mountpoint = (char*)mountpoint;
         safe_filesystem = (char*)filesystem;
     }
 
@@ -212,21 +217,41 @@ dword_t mount(const char *device, const char *filesystem, dword_t flags)
 
         if (filesystem == NULL || strcmp(fs->name, safe_filesystem) == 0)
         {
-            ret = fs->mount(safe_device, flags);
+            ret = fs->mount(safe_device, safe_mountpoint, flags);
             if (ret == ERR_SUCCESS) break;
         }
     }
 
     release_lock(&fs_driver_list_lock);
 
-    if (get_previous_mode() == USER_MODE) free(safe_device);
+    if (get_previous_mode() == USER_MODE)
+    {
+        free(safe_device);
+        free(safe_mountpoint);
+        free(safe_filesystem);
+    }
+
     return ret;
 }
 
-dword_t unmount(const char *device)
+dword_t unmount(const char *mountpoint)
 {
-    mounted_volume_t *vol = get_mounted_volume(device);
-    if (vol == NULL) return ERR_NOTFOUND;
+    acquire_resource_exclusive(&volume_list_res);
+    list_entry_t *ptr;
+    mounted_volume_t *vol = NULL;
+
+    for (ptr = volumes.next; ptr != &volumes; ptr = ptr->next)
+    {
+        mounted_volume_t *current = CONTAINER_OF(ptr, mounted_volume_t, list);
+
+        if (strcmp(current->mountpoint, mountpoint) == 0)
+        {
+            vol = current;
+            break;
+        }
+    }
+
+    release_resource(&volume_list_res);
 
     if (vol->open_files) return ERR_BUSY;
     return vol->driver->unmount(vol);
@@ -234,14 +259,17 @@ dword_t unmount(const char *device)
 
 dword_t open_file_internal(const char *path, file_instance_t **file_instance, dword_t mode, dword_t attributes)
 {
-    mounted_volume_t *vol;
     char normalized_path[MAX_PATH];
     file_t *file = NULL;
     file_instance_t *instance = NULL;
 
-    dword_t ret = normalize_path(path, &vol, normalized_path);
+    dword_t ret = normalize_path(path, normalized_path);
     if (ret != ERR_SUCCESS) return ret;
 
+    mounted_volume_t *vol = get_volume_from_path(normalized_path);
+    if (vol == NULL) return ERR_NOTFOUND;
+
+
     if (reference_by_name(normalized_path, OBJECT_FILE, (object_t**)&file))
     {
         if (((file->global_mode ^ mode) & (FILE_MODE_SHARE_READ | FILE_MODE_SHARE_WRITE))
@@ -260,7 +288,10 @@ dword_t open_file_internal(const char *path, file_instance_t **file_instance, dw
         file->header.name = strdup(normalized_path);
         file->header.type = OBJECT_FILE;
         file->volume = vol;
-        file->path = skip_volume_name(file->header.name);
+
+        file->path = &file->header.name[strlen(vol->mountpoint)];
+        if (*file->path == PATH_DELIMITER_CHAR) file->path++;
+
         file->global_mode = mode;
         file->attributes = attributes;
 
@@ -363,7 +394,6 @@ cleanup:
 dword_t delete_file(const char *path)
 {
     dword_t ret = ERR_SUCCESS;
-    mounted_volume_t *vol;
     char normalized_path[MAX_PATH];
     char *safe_path;
 
@@ -377,14 +407,20 @@ dword_t delete_file(const char *path)
         safe_path = (char*)path;
     }
 
-    ret = normalize_path(safe_path, &vol, normalized_path);
+    ret = normalize_path(safe_path, normalized_path);
     if (ret != ERR_SUCCESS) goto cleanup;
 
+    mounted_volume_t *vol = get_volume_from_path(normalized_path);
+    if (vol == NULL) return ERR_NOTFOUND;
+
     acquire_resource_exclusive(&vol->resource);
 
     file_t *file = NULL;
     reference_by_name(normalized_path, OBJECT_FILE, (object_t**)&file);
-    ret = vol->driver->delete_file(vol, skip_volume_name(normalized_path), file == NULL);
+
+    char *relative_path = &normalized_path[strlen(vol->mountpoint)];
+    if (*relative_path == PATH_DELIMITER_CHAR) relative_path++;
+    ret = vol->driver->delete_file(vol, relative_path, file == NULL);
 
     if (ret == ERR_SUCCESS && file != NULL)
     {
index e63f54d0af9a37c39fcce78a0976b0121265066b..e8d3e69795cb666d5e09ac7ea2e02fe43366ea53 100644 (file)
@@ -206,7 +206,7 @@ void kernel_main(multiboot_header_t *mboot, dword_t stack)
     strcat(message, "...");
     printf("%-70s", message);
 
-    dword_t ret = mount(root_disk, NULL, MOUNT_FLAG_READONLY);
+    dword_t ret = mount(root_disk, root_disk, NULL, MOUNT_FLAG_READONLY);
     if (ret != ERR_SUCCESS) KERNEL_CRASH("Cannot mount root disk");
 
     free(root_disk);