feat: (iso9660) rock ridge extension
authorMinep <zelong56@gmail.com>
Sun, 13 Nov 2022 00:08:59 +0000 (00:08 +0000)
committerMinep <zelong56@gmail.com>
Sun, 13 Nov 2022 00:08:59 +0000 (00:08 +0000)
fix: (pcache) over-reading the page cache

lunaix-os/includes/lunaix/fs.h
lunaix-os/includes/lunaix/fs/iso9660.h
lunaix-os/kernel/fs/iso9660/directory.c
lunaix-os/kernel/fs/iso9660/inode.c
lunaix-os/kernel/fs/iso9660/mount.c
lunaix-os/kernel/fs/iso9660/rockridge.c [new file with mode: 0644]
lunaix-os/kernel/fs/iso9660/utils.c
lunaix-os/kernel/fs/pcache.c

index 024b4ea591ff952d4f94bacbf94c61b7faecccec..075cc017fe33966b0e5b704d4e8b0116f761fd91 100644 (file)
@@ -275,6 +275,7 @@ struct pcache_pg
     void* pg;
     uint32_t flags;
     uint32_t fpos;
+    uint32_t len;
 };
 
 void
index de433d4733b98a062b7f3381c8f6c76fa9a82192..9d16961ddeffa3eb2d85be7df9a72396fde58165 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <lunaix/clock.h>
 #include <lunaix/device.h>
+#include <lunaix/fs.h>
 #include <lunaix/types.h>
 
 #define ISO_SIGNATURE_LO 0x30304443UL
@@ -135,22 +136,24 @@ struct iso_var_mdu
     u8_t content[0];
 } PACKED;
 
+struct iso_datetime2
+{
+    u8_t year;
+    u8_t month;
+    u8_t day;
+    u8_t hour;
+    u8_t min;
+    u8_t sec;
+    u8_t gmt;
+} PACKED;
+
 // (9.1) Directory Record [Embedded into Variable MDU]
 struct iso_drecord
 {
     u8_t xattr_len;
     iso_bbo32_t extent_addr;
     iso_bbo32_t data_size;
-    struct
-    {
-        u8_t year;
-        u8_t month;
-        u8_t day;
-        u8_t hour;
-        u8_t min;
-        u8_t sec;
-        u8_t gmt;
-    } PACKED mktime; // Time the record is made, see 9.1.5
+    struct iso_datetime2 PACKED mktime; // Time the record is made, see 9.1.5
     u8_t flags;
     u8_t fu_sz;  // size of file unit (FU)
     u8_t gap_sz; // size of gap if FU is interleaved.
@@ -158,15 +161,6 @@ struct iso_drecord
     struct iso_var_mdu name;
 } PACKED;
 
-// (9.4) L-Path Table Record. [Embedded into Variable MDU]
-struct iso_precord
-{
-    u8_t xattr_len;
-    u32_t extent_addr;
-    u8_t parent; // indexed into path table
-    u8_t id[0];  // length = iso_var_mdu::len
-} PACKED;
-
 struct iso_xattr
 {
     iso_bbo16_t owner;
@@ -190,20 +184,91 @@ struct iso_xattr
     // It however marked as optional, hence we ignore it.
 } PACKED;
 
-struct iso_ptable
+///
+/// -------- IEEE P1281 SUSP ---------
+///
+
+#define ISOSU_ER 0x5245
+#define ISOSU_ST 0x5453
+
+struct isosu_base
 {
-    u32_t start_lba;
-    u32_t current_lba;
-    u32_t size;
-    u32_t range_lower;
-    u32_t range_upper;
-    void* ptable_part;
-};
+    u16_t signature;
+    u8_t length;
+    u8_t version;
+} PACKED;
+
+struct isosu_er
+{
+    struct isosu_base header;
+    u8_t id_len;
+    u8_t des_len;
+    u8_t src_len;
+    u8_t ext_ver;
+    u8_t id_des_src[0];
+} PACKED;
+
+///
+/// -------- Rock Ridge Extension --------
+///
+
+#define ISORR_PX 0x5850
+#define ISORR_PN 0x4e50
+#define ISORR_SL 0x4c53
+#define ISORR_NM 0x4d4e
+#define ISORR_TF 0x4654
+
+#define ISORR_NM_CONT 0x1
+
+#define ISORR_TF_CTIME 0x1
+#define ISORR_TF_MTIME 0x2
+#define ISORR_TF_ATIME 0x4
+#define ISORR_TF_LONG_FORM 0x80
+
+struct isorr_px
+{
+    struct isosu_base header;
+    iso_bbo32_t mode;
+    iso_bbo32_t link;
+    iso_bbo32_t uid;
+    iso_bbo32_t gid;
+    iso_bbo32_t sn;
+} PACKED;
+
+struct isorr_pn
+{
+    struct isosu_base header;
+    iso_bbo32_t dev_hi;
+    iso_bbo32_t dev_lo;
+} PACKED;
+
+struct isorr_sl
+{
+    struct isosu_base header;
+    u8_t flags;
+    char symlink[0];
+} PACKED;
+
+struct isorr_nm
+{
+    struct isosu_base header;
+    u8_t flags;
+    char name[0];
+} PACKED;
+
+struct isorr_tf
+{
+    struct isosu_base header;
+    u8_t flags;
+    char times[0];
+} PACKED;
+
+///
+/// -------- VFS integration ---------
+///
 
 struct iso_inode
 {
-    time_t ctime;
-    time_t mtime;
     u32_t record_fmt;
     u32_t fu_size;
     u32_t gap_size;
@@ -216,9 +281,13 @@ struct iso_drecache
     u32_t extent_addr;
     u32_t data_size;
     u32_t xattr_len;
+    u32_t fno;
     u32_t fu_size;
     u32_t gap_size;
     u32_t flags;
+    time_t ctime;
+    time_t atime;
+    time_t mtime;
     struct hstr name;
     char name_val[ISO9660_IDLEN];
 };
@@ -238,6 +307,9 @@ iso9660_fill_inode(struct v_inode* inode, struct iso_drecache* dir, int ino);
 time_t
 iso9660_dt2unix(struct iso_datetime* isodt);
 
+time_t
+iso9660_dt22unix(struct iso_datetime2* isodt2);
+
 void
 iso9660_init();
 
@@ -245,7 +317,9 @@ int
 iso9660_setup_dnode(struct v_dnode* dnode, struct v_inode* inode);
 
 void
-iso9660_fill_drecache(struct iso_drecache* cache, struct iso_drecord* drec);
+iso9660_fill_drecache(struct iso_drecache* cache,
+                      struct iso_drecord* drec,
+                      u32_t len);
 
 int
 iso9660_dir_lookup(struct v_inode* this, struct v_dnode* dnode);
@@ -268,4 +342,13 @@ iso9660_write(struct v_inode* inode, void* buffer, size_t len, size_t fpos);
 int
 iso9660_seek(struct v_inode* inode, size_t offset);
 
+int
+isorr_parse_px(struct iso_drecache* cache, void* px_start);
+
+int
+isorr_parse_nm(struct iso_drecache* cache, void* nm_start);
+
+int
+isorr_parse_tf(struct iso_drecache* cache, void* tf_start);
+
 #endif /* __LUNAIX_ISO9660_H */
index 816f6eb6b398e083181267ca162cda7e59303047..e1b37894681a46dfcf6bb51ad0e82210c750dea9 100644 (file)
@@ -10,7 +10,9 @@
 extern struct cake_pile* drec_cache_pile;
 
 void
-iso9660_fill_drecache(struct iso_drecache* cache, struct iso_drecord* drec)
+iso9660_fill_drecache(struct iso_drecache* cache,
+                      struct iso_drecord* drec,
+                      u32_t drec_len)
 {
     *cache = (struct iso_drecache){ .data_size = drec->data_size.le,
                                     .extent_addr = drec->extent_addr.le,
@@ -18,16 +20,44 @@ iso9660_fill_drecache(struct iso_drecache* cache, struct iso_drecord* drec)
                                     .fu_size = drec->fu_sz ? drec->fu_sz : 1,
                                     .gap_size = drec->gap_sz,
                                     .xattr_len = drec->xattr_len };
-    u32_t l = drec->name.len;
-    while (l < (u32_t)-1 && drec->name.content[l--] != ';')
-        ;
-    l++;
-    l = l ? l : drec->name.len;
-    l = MIN(l, ISO9660_IDLEN - 1);
-
-    strncpy(cache->name_val, drec->name.content, l);
-    cache->name = HSTR(cache->name_val, l);
-    hstr_rehash(&cache->name, HSTR_FULL_HASH);
+    u32_t padding = ((drec->name.len + sizeof(drec->name)) % 2) != 0;
+    u32_t su_offset = drec->name.len + sizeof(struct iso_drecord) + padding;
+    int su_len = drec_len - su_offset - 2, i = 0;
+
+    while (i < su_len) {
+        struct isosu_base* su_entry =
+          (struct isosu_base*)((void*)drec + su_offset + i);
+        switch (su_entry->signature) {
+            case ISORR_NM:
+                i += isorr_parse_nm(cache, (void*)su_entry);
+                break;
+            case ISORR_PX:
+                i += isorr_parse_px(cache, (void*)su_entry);
+                break;
+            case ISORR_TF:
+                i += isorr_parse_tf(cache, (void*)su_entry);
+                break;
+            case ISOSU_ST:
+                goto done;
+            default:
+                i += su_entry->length;
+                break;
+        }
+    }
+
+done:
+    if (!cache->name.len) {
+        // Load ISO9660 file id if no NM found.
+        u32_t l = drec->name.len;
+        while (l < (u32_t)-1 && drec->name.content[l--] != ';')
+            ;
+        l = (l + 1) ? l : drec->name.len;
+        l = MIN(l, ISO9660_IDLEN - 1);
+
+        strncpy(cache->name_val, drec->name.content, l);
+        cache->name = HSTR(cache->name_val, l);
+        hstr_rehash(&cache->name, HSTR_FULL_HASH);
+    }
 }
 
 int
@@ -74,7 +104,7 @@ iso9660_setup_dnode(struct v_dnode* dnode, struct v_inode* inode)
 
         struct iso_drecache* cache = cake_grab(drec_cache_pile);
 
-        iso9660_fill_drecache(cache, drec);
+        iso9660_fill_drecache(cache, drec, mdu->len);
         llist_append(lead, &cache->caches);
     cont:
         blk_offset += mdu->len;
index f88eee5e4d0cc684fe060adcdaee6ea4b3ca6a3a..e5649106e46d920cf391de660ddb33d2c37ba0f1 100644 (file)
@@ -62,13 +62,18 @@ iso9660_fill_inode(struct v_inode* inode, struct iso_drecache* dir, int ino)
             return EIO;
         }
         isoino->record_fmt = xattr->record_fmt;
-        isoino->ctime = iso9660_dt2unix(&xattr->ctime);
-        isoino->mtime = iso9660_dt2unix(&xattr->mtime);
+
+        inode->ctime = iso9660_dt2unix(&xattr->ctime);
+        inode->mtime = iso9660_dt2unix(&xattr->mtime);
 
         inode->lb_addr += dir->xattr_len * dir->fu_size;
 
         vfree(xattr);
     }
 
+    inode->ctime = dir->ctime ? dir->ctime : inode->ctime;
+    inode->mtime = dir->mtime ? dir->mtime : inode->mtime;
+    inode->atime = dir->atime ? dir->atime : inode->atime;
+
     return 0;
 }
\ No newline at end of file
index 5d7bb819735d4df7e255df774bba58c3960386ea..51679ca0757913cbcecd6995eb73109e67c431fc 100644 (file)
@@ -57,8 +57,8 @@ iso9660_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
     vsb->ops.read_capacity = iso9660_rd_capacity;
 
     struct v_inode* rootino = vfs_i_alloc(vsb);
-    struct iso_drecord* dir =
-      iso9660_get_drecord((struct iso_var_mdu*)vprim->root_record);
+    struct iso_var_mdu* mdu = (struct iso_var_mdu*)vprim->root_record;
+    struct iso_drecord* dir = iso9660_get_drecord(mdu);
 
     if (!dir) {
         vfree(isovsb);
@@ -67,7 +67,7 @@ iso9660_mount(struct v_superblock* vsb, struct v_dnode* mount_point)
     }
 
     struct iso_drecache drecache;
-    iso9660_fill_drecache(&drecache, dir);
+    iso9660_fill_drecache(&drecache, dir, mdu->len);
 
     if ((errno = iso9660_fill_inode(rootino, &drecache, 0)) < 0) {
         vfree(isovsb);
diff --git a/lunaix-os/kernel/fs/iso9660/rockridge.c b/lunaix-os/kernel/fs/iso9660/rockridge.c
new file mode 100644 (file)
index 0000000..b211fdb
--- /dev/null
@@ -0,0 +1,60 @@
+#include <lunaix/fs/iso9660.h>
+
+int
+isorr_parse_px(struct iso_drecache* cache, void* px_start)
+{
+    struct isorr_px* px = (struct isorr_px*)px_start;
+    cache->fno = px->sn.le;
+    // TODO read other file attributes
+    return px->header.length;
+}
+
+time_t
+isorr_tf_gettime(struct isorr_tf* tf, int* index, u32_t type)
+{
+    time_t t = 0;
+    if ((tf->flags & type)) {
+        if ((tf->flags & ISORR_TF_LONG_FORM)) {
+            t =
+              iso9660_dt2unix((struct iso_datetime*)(tf->times + 17 * *index));
+        } else {
+            t =
+              iso9660_dt22unix((struct iso_datetime2*)(tf->times + 7 * *index));
+        }
+        *index = *index + 1;
+    }
+    return t;
+}
+
+int
+isorr_parse_tf(struct iso_drecache* cache, void* tf_start)
+{
+    struct isorr_tf* tf = (struct isorr_tf*)tf_start;
+    int i = 0;
+    cache->ctime = isorr_tf_gettime(tf, &i, ISORR_TF_CTIME);
+    cache->mtime = isorr_tf_gettime(tf, &i, ISORR_TF_MTIME);
+    cache->atime = isorr_tf_gettime(tf, &i, ISORR_TF_ATIME);
+    // TODO read other file attributes
+    return tf->header.length;
+}
+
+int
+isorr_parse_nm(struct iso_drecache* cache, void* nm_start)
+{
+    u32_t i = 0, adv = 0;
+    struct isorr_nm* nm;
+
+    do {
+        nm = (struct isorr_nm*)(nm_start + adv);
+        u32_t len_name = nm->header.length - sizeof(*nm);
+        memcpy(cache->name_val + i, nm->name, len_name);
+        i += len_name;
+        adv += nm->header.length;
+    } while ((nm->flags & ISORR_NM_CONT) && i < ISO9660_IDLEN - 1);
+
+    cache->name_val[i] = 0;
+    cache->name = HSTR(cache->name_val, i);
+    hstr_rehash(&cache->name, HSTR_FULL_HASH);
+
+    return adv;
+}
\ No newline at end of file
index 748077d28e780e9030fa3d9268b9c800f8c201e4..3b19c957b8bc53192e9f5439c0acddfc7cff8e1a 100644 (file)
@@ -22,3 +22,14 @@ iso9660_dt2unix(struct iso_datetime* isodt)
                        TWO_DIGIT(isodt->min),
                        TWO_DIGIT(isodt->sec));
 }
+
+time_t
+iso9660_dt22unix(struct iso_datetime2* isodt2)
+{
+    return time_tounix(isodt2->year + 1900,
+                       isodt2->month,
+                       isodt2->day,
+                       isodt2->hour,
+                       isodt2->min,
+                       isodt2->sec);
+}
\ No newline at end of file
index 317e491a336284268a6f827ae82d7aec1841e4ae..a6c4c31d34993b9ba9b8da91a195f51b886ad655 100644 (file)
@@ -115,6 +115,7 @@ pcache_write(struct v_inode* inode, void* data, uint32_t len, uint32_t fpos)
 
         pcache_set_dirty(pcache, pg);
 
+        pg->len = pg_off + wr_bytes;
         buf_off += wr_bytes;
         fpos += wr_bytes;
     }
@@ -146,8 +147,13 @@ pcache_read(struct v_inode* inode, void* data, uint32_t len, uint32_t fpos)
             } else if (errno < 0) {
                 break;
             }
+            pg->len = errno;
         }
-        uint32_t rd_bytes = MIN(PG_SIZE - pg_off, len - buf_off);
+        uint32_t rd_bytes = MIN(pg->len - pg_off, len - buf_off);
+
+        if (!rd_bytes)
+            break;
+
         memcpy((data + buf_off), pg->pg + pg_off, rd_bytes);
 
         buf_off += rd_bytes;