:: commit 984986a64dd022f04915d2b6ab0285c5f31f2fc5

mintsuki <mintsuki@protonmail.com> — 2021-03-20 10:52

parents: cd3a64c9f1

iso9660: Add support for rock ridge and properly handle padded sectors when searching directories

diff --git a/stage23/fs/iso9660.s2.c b/stage23/fs/iso9660.s2.c
index fae145ac..e95ac3e1 100644
--- a/stage23/fs/iso9660.s2.c
+++ b/stage23/fs/iso9660.s2.c
@@ -3,6 +3,8 @@
 #include <lib/libc.h>
 #include <mm/pmm.h>
 
+#include <lib/print.h>
+
 #define ISO9660_FIRST_VOLUME_DESCRIPTOR 0x10
 #define ISO9660_VOLUME_DESCRIPTOR_SIZE ISO9660_SECTOR_SIZE
 #define ROCK_RIDGE_MAX_FILENAME 255
@@ -23,6 +25,7 @@ struct iso9660_directory_entry {
     uint8_t interleaved_gap_size;
     struct BE16_t volume_seq;
     uint8_t filename_size;
+    char name[];
 } __attribute__((packed));
 
 // --- Volume descriptors ---
@@ -123,48 +126,71 @@ static struct iso9660_context *iso9660_get_context(struct volume *vol) {
     return &node->context;
 }
 
-static int iso9660_strcmp(const char *a, const char *b, size_t size) {
-    while (size--) {
-        char ca = *a++;
-        char cb = *b++;
-        if (!(ca == cb || (ca - ('a'-'A')) == cb))
-            return 1;
+static void load_name(char *buf, struct iso9660_directory_entry *entry) {
+    unsigned char* sysarea = ((unsigned char*)entry) + sizeof(struct iso9660_directory_entry) + entry->filename_size;
+    int sysarea_len = entry->length - sizeof(struct iso9660_directory_entry) - entry->filename_size;
+    if ((entry->filename_size & 0x1) == 0) {
+        sysarea++;
+        sysarea_len--;
     }
 
-    return 0;
+    int rrnamelen = 0;
+    while ((sysarea_len >= 4) && ((sysarea[3] == 1) || (sysarea[2] == 2))) {
+        if (sysarea[0] == 'N' && sysarea[1] == 'M') {
+            rrnamelen = sysarea[2] - 5;
+            break;
+        }
+        sysarea_len -= sysarea[2];
+        sysarea += sysarea[2];
+    }
+
+    size_t name_len = 0;
+    if (rrnamelen) {
+        /* rock ridge naming scheme */
+        name_len = rrnamelen;
+        memcpy(buf, sysarea + 5, name_len);
+        buf[name_len] = 0;
+    } else {
+        name_len = entry->filename_size;
+        size_t j;
+        for (j = 0; j < name_len; j++) {
+            if (entry->name[j] == ';')
+                break;
+            if (entry->name[j] == '.' && entry->name[j+1] == ';')
+                break;
+            buf[j] = tolower(entry->name[j]);
+        }
+        buf[j] = 0;
+    }
 }
 
-static struct iso9660_directory_entry *iso9660_find(void *buffer, uint32_t size, const char *filename) {
-    // The file can be either FILENAME or FILENAME;1
-    uint32_t len = strlen(filename);
-    char finalfile[len + 2];
-    strcpy(finalfile, filename);
-    finalfile[len + 0] = ';';
-    finalfile[len + 1] = '1';
-
-    // Now, in case the file doesn't have extension
-    char finalfile_noext[len+3];
-    strcpy(finalfile_noext, filename);
-    finalfile_noext[len + 0] = '.';
-    finalfile_noext[len + 1] = ';';
-    finalfile_noext[len + 2] = '1';
+static struct iso9660_directory_entry *iso9660_find(void *buffer, uint32_t size, const char *_filename) {
+    char filename[strlen(_filename) + 1];
+    size_t i = 0;
+    while (*_filename)
+        filename[i++] = tolower(*_filename++);
+    filename[i] = 0;
 
     while (size) {
         struct iso9660_directory_entry *entry = buffer;
-        char* entry_filename = (char*)entry + sizeof(struct iso9660_directory_entry);
+        char entry_filename[128];
+        load_name(entry_filename, entry);
+
+        if (entry->length == 0) {
+            if (size <= ISO9660_SECTOR_SIZE)
+                return NULL;
+            size_t prev_size = size;
+            size = ALIGN_DOWN(size, ISO9660_SECTOR_SIZE);
+            buffer += prev_size - size;
+            continue;
+        }
 
-        if (!entry->length) {
-            return NULL;
-        } else if (entry->filename_size == len && !iso9660_strcmp(filename, entry_filename, len)) {
+        if (strcmp(filename, entry_filename) == 0) {
             return buffer;
-        } else if (entry->filename_size == len+2 && !iso9660_strcmp(finalfile, entry_filename, len+2)) {
-            return buffer;
-        } else if (entry->filename_size == len+3 && !iso9660_strcmp(finalfile_noext, entry_filename, len+3)) {
-            return buffer;
-        } else {
-            size -= entry->length;
-            buffer += entry->length;
         }
+
+        size -= entry->length;
+        buffer += entry->length;
     }
 
     return NULL;
tab: 248 wrap: offon