:: commit 6d973a0e00fbccc5f16aa4281cf3049e244ece0e

mintsuki <mintsuki@protonmail.com> — 2022-07-02 08:43

parents: 2f2eda8a64

uri: Add fslabel:// URI scheme as mentioned in #188

diff --git a/common/fs/ext2.h b/common/fs/ext2.h
index baedaa77..ad75a5c3 100644
--- a/common/fs/ext2.h
+++ b/common/fs/ext2.h
@@ -50,7 +50,7 @@ struct ext2_superblock {
     uint32_t s_feature_ro_compat;
 
     uint64_t s_uuid[2];
-    uint64_t s_volume_name[2];
+    uint8_t s_volume_name[16];
 
     uint64_t s_last_mounted[8];
 
@@ -124,6 +124,7 @@ struct ext2_file_handle {
 
 int ext2_check_signature(struct volume *part);
 bool ext2_get_guid(struct guid *guid, struct volume *part);
+char *ext2_get_label(struct volume *part);
 
 bool ext2_open(struct ext2_file_handle *ret, struct volume *part, const char *path);
 void ext2_read(struct ext2_file_handle *file, void *buf, uint64_t loc, uint64_t count);
diff --git a/common/fs/ext2.s2.c b/common/fs/ext2.s2.c
index 9e6ddb6a..d1379764 100644
--- a/common/fs/ext2.s2.c
+++ b/common/fs/ext2.s2.c
@@ -488,3 +488,22 @@ bool ext2_get_guid(struct guid *guid, struct volume *part) {
 
     return true;
 }
+
+char *ext2_get_label(struct volume *part) {
+    struct ext2_superblock sb;
+    volume_read(part, &sb, 1024, sizeof(struct ext2_superblock));
+
+    if (sb.s_magic != EXT2_S_MAGIC) {
+        return NULL;
+    }
+
+    if (sb.s_rev_level < 1) {
+        return NULL;
+    }
+
+    size_t label_len = strlen((char *)sb.s_volume_name);
+    char *ret = ext_mem_alloc(label_len + 1);
+    strcpy(ret, (char *)sb.s_volume_name);
+
+    return ret;
+}
diff --git a/common/fs/fat32.h b/common/fs/fat32.h
index c2cfd928..052bb2cc 100644
--- a/common/fs/fat32.h
+++ b/common/fs/fat32.h
@@ -7,6 +7,7 @@
 struct fat32_context {
     struct volume *part;
     int type;
+    char label[12];
     uint16_t bytes_per_sector;
     uint8_t sectors_per_cluster;
     uint16_t reserved_sectors;
@@ -31,6 +32,7 @@ struct fat32_file_handle {
 };
 
 int fat32_check_signature(struct volume *part);
+char *fat32_get_label(struct volume *part);
 
 bool fat32_open(struct fat32_file_handle *ret, struct volume *part, const char *path);
 void fat32_read(struct fat32_file_handle *file, void *buf, uint64_t loc, uint64_t count);
diff --git a/common/fs/fat32.s2.c b/common/fs/fat32.s2.c
index 38255046..1f75ff91 100644
--- a/common/fs/fat32.s2.c
+++ b/common/fs/fat32.s2.c
@@ -124,6 +124,15 @@ valid:;
         context->type = 32;
     }
 
+    memcpy(context->label, bpb.label, 11);
+    context->label[11] = 0;
+    // remove trailing spaces
+    for (int i = 10; i >= 0; i--) {
+        if (context->label[i] == ' ') {
+            context->label[i] = 0;
+        }
+    }
+
     context->bytes_per_sector = bpb.bytes_per_sector;
     context->sectors_per_cluster = bpb.sectors_per_cluster;
     context->reserved_sectors = bpb.reserved_sectors;
@@ -362,6 +371,23 @@ int fat32_check_signature(struct volume *part) {
     return fat32_init_context(&context, part) == 0;
 }
 
+char *fat32_get_label(struct volume *part) {
+    struct fat32_context context;
+    if (fat32_init_context(&context, part) != 0) {
+        return NULL;
+    }
+
+    size_t label_len = strlen(context.label);
+    if (label_len == 0) {
+        return NULL;
+    }
+
+    char *ret = ext_mem_alloc(label_len + 1);
+    strcpy(ret, context.label);
+
+    return ret;
+}
+
 bool fat32_open(struct fat32_file_handle* ret, struct volume *part, const char* path) {
     struct fat32_context context;
     int r = fat32_init_context(&context, part);
diff --git a/common/fs/file.h b/common/fs/file.h
index a464c34e..62602171 100644
--- a/common/fs/file.h
+++ b/common/fs/file.h
@@ -12,6 +12,7 @@
 #define PATH_MAX 4096
 
 bool fs_get_guid(struct guid *guid, struct volume *part);
+char *fs_get_label(struct volume *part);
 
 struct file_handle {
     bool       is_memfile;
diff --git a/common/fs/file.s2.c b/common/fs/file.s2.c
index f4f099bf..723a91df 100644
--- a/common/fs/file.s2.c
+++ b/common/fs/file.s2.c
@@ -13,6 +13,17 @@
 #include <lib/libc.h>
 #include <pxe/tftp.h>
 
+char *fs_get_label(struct volume *part) {
+    if (fat32_check_signature(part)) {
+        return fat32_get_label(part);
+    }
+    if (ext2_check_signature(part)) {
+        return ext2_get_label(part);
+    }
+
+    return NULL;
+}
+
 bool fs_get_guid(struct guid *guid, struct volume *part) {
     if (echfs_check_signature(part)) {
         return echfs_get_guid(guid, part);
diff --git a/common/lib/part.h b/common/lib/part.h
index f468b7d8..9de453f5 100644
--- a/common/lib/part.h
+++ b/common/lib/part.h
@@ -50,6 +50,8 @@ struct volume {
     struct guid guid;
     bool part_guid_valid;
     struct guid part_guid;
+    bool fslabel_valid;
+    char *fslabel;
 };
 
 void list_volumes(void);
@@ -63,6 +65,7 @@ uint32_t mbr_get_id(struct volume *volume);
 int part_get(struct volume *part, struct volume *volume, int partition);
 
 struct volume *volume_get_by_guid(struct guid *guid);
+struct volume *volume_get_by_fslabel(char *fslabel);
 struct volume *volume_get_by_coord(bool optical, int drive, int partition);
 #if bios == 1
 struct volume *volume_get_by_bios_drive(int drive);
diff --git a/common/lib/part.s2.c b/common/lib/part.s2.c
index 2bceb998..7abd51ee 100644
--- a/common/lib/part.s2.c
+++ b/common/lib/part.s2.c
@@ -221,6 +221,14 @@ static int gpt_get_part(struct volume *ret, struct volume *volume, int partition
         ret->guid = guid;
     }
 
+    char *fslabel = fs_get_label(ret);
+    if (fslabel == NULL) {
+        ret->fslabel_valid = false;
+    } else {
+        ret->fslabel_valid = true;
+        ret->fslabel = fslabel;
+    }
+
     ret->part_guid_valid = true;
     ret->part_guid = entry.unique_partition_guid;
 
@@ -339,6 +347,14 @@ static int mbr_get_logical_part(struct volume *ret, struct volume *extended_part
         ret->guid = guid;
     }
 
+    char *fslabel = fs_get_label(ret);
+    if (fslabel == NULL) {
+        ret->fslabel_valid = false;
+    } else {
+        ret->fslabel_valid = true;
+        ret->fslabel = fslabel;
+    }
+
     ret->part_guid_valid = false;
 
     return 0;
@@ -413,6 +429,14 @@ static int mbr_get_part(struct volume *ret, struct volume *volume, int partition
         ret->guid = guid;
     }
 
+    char *fslabel = fs_get_label(ret);
+    if (fslabel == NULL) {
+        ret->fslabel_valid = false;
+    } else {
+        ret->fslabel_valid = true;
+        ret->fslabel = fslabel;
+    }
+
     ret->part_guid_valid = false;
 
     return 0;
@@ -450,6 +474,17 @@ struct volume *volume_get_by_guid(struct guid *guid) {
     return NULL;
 }
 
+struct volume *volume_get_by_fslabel(char *fslabel) {
+    for (size_t i = 0; i < volume_index_i; i++) {
+        if (volume_index[i]->fslabel_valid
+         && strcmp(volume_index[i]->fslabel, fslabel) == 0) {
+            return volume_index[i];
+        }
+    }
+
+    return NULL;
+}
+
 struct volume *volume_get_by_coord(bool optical, int drive, int partition) {
     for (size_t i = 0; i < volume_index_i; i++) {
         if (volume_index[i]->index == drive
diff --git a/common/lib/uri.c b/common/lib/uri.c
index 055d71d3..3f677224 100644
--- a/common/lib/uri.c
+++ b/common/lib/uri.c
@@ -133,6 +133,15 @@ static struct file_handle *uri_guid_dispatch(char *guid_str, char *path) {
     return fopen(volume, path);
 }
 
+static struct file_handle *uri_fslabel_dispatch(char *fslabel, char *path) {
+    struct volume *volume = volume_get_by_fslabel(fslabel);
+    if (volume == NULL) {
+        return NULL;
+    }
+
+    return fopen(volume, path);
+}
+
 static struct file_handle *uri_fwcfg_dispatch(char *path) {
     struct file_handle *ret = ext_mem_alloc(sizeof(struct file_handle));
     if (!fwcfg_open(ret, path)) {
@@ -216,6 +225,8 @@ struct file_handle *uri_open(char *uri) {
         ret = uri_guid_dispatch(root, path);
     } else if (!strcmp(resource, "uuid")) {
         ret = uri_guid_dispatch(root, path);
+    } else if (!strcmp(resource, "fslabel")) {
+        ret = uri_fslabel_dispatch(root, path);
 #if bios == 1
     } else if (!strcmp(resource, "tftp")) {
         ret = uri_tftp_dispatch(root, path);
tab: 248 wrap: offon