Fixed master branch
authorRobert Pengelly <robertapengelly@hotmail.com>
Wed, 8 Oct 2025 15:33:20 +0000 (16:33 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Wed, 8 Oct 2025 15:33:20 +0000 (16:33 +0100)
common.c
common.h
mcopy.c
mcopy.h
mkfs.c
mls.c
mmd.c
mmd.h
msdos.h

index 66cd0c833150c67f77dc5880e57ca37ca99cad88..8fc99f6e16623f2e4481d2bc8c5131b5dd42be2a 100644 (file)
--- a/common.c
+++ b/common.c
@@ -222,8 +222,11 @@ int create_name (struct fat_dirent *dp, const char *path) {
         ;
     }
     
-    if (si > 0 || dp->lfn[si] == '.') {
+    while (dp->lfn[si] == '.') {
+    
         cf |= 3;
+        si++;
+    
     }
     
     while (di > 0 && dp->lfn[di - 1] != '.') {
@@ -708,6 +711,45 @@ unsigned char sum_sfn (unsigned char *dir) {
 
 }
 
+unsigned int mode_con (char *p) {
+
+    unsigned long o1, o2, o3;
+    
+    char c1, c2, c3;
+    unsigned int mode;
+    
+    c1 = *p++;
+    c2 = *p++;
+    c3 = *p++;
+    
+    o1 = *p++ - '0';
+    o2 = *p++ - '0';
+    o3 = *p++ - '0';
+    
+    mode = (o1 << 6) | (o2 << 3) | o3;
+    
+    if (c1 == 'c') {
+        mode |= 0020000;
+    } else if (c1 == 'd') {
+        mode |= 0040000;
+    } else if (c1 == 'b') {
+        mode |= 0060000;
+    } else if (c1 == '-') {
+        mode |= 0100000;
+    }
+    
+    if (c2 == 'u') {
+        mode |= 0004000;
+    }
+    
+    if (c3 == 'g') {
+        mode |= 0002000;
+    }
+    
+    return mode;
+
+}
+
 
 unsigned short generate_datestamp (void) {
 
index 501db4426833142f98516ccd148ee9bad9e10984..5140f74aba3ba39793ff956f8dec0c375cce9df2 100644 (file)
--- a/common.h
+++ b/common.h
@@ -13,13 +13,17 @@ struct fat_dirent {
 
 };
 
+unsigned short generate_datestamp (void);
+unsigned short generate_timestamp (void);
+
+/* Long filenames. */
 int create_name (struct fat_dirent *dp, const char *path);
 void gen_numname (unsigned char *dst, const unsigned char *src, const unsigned short *lfn, unsigned int seq);
 
 int cmp_lfn (const unsigned short *lfnbuf, unsigned char *dir);
 unsigned char sum_sfn (unsigned char *dir);
 
-unsigned short generate_datestamp (void);
-unsigned short generate_timestamp (void);
+/* Unix mode. */
+unsigned int mode_con (char *p);
 
 #endif      /* _COMMON_H */
diff --git a/mcopy.c b/mcopy.c
index 8c8bf46a60c31363e24de748bfbd7bd28cc48415..748006744ca0959a001909969d2aa154b0d37eed 100644 (file)
--- a/mcopy.c
+++ b/mcopy.c
@@ -92,10 +92,14 @@ enum options {
 
     OPTION_IGNORED = 1,
     OPTION_ARCA,
+    OPTION_GID,
     OPTION_HELP,
     OPTION_INPUT,
+    OPTION_MODE,
     OPTION_OFFSET,
-    OPTION_STATUS
+    OPTION_STATUS,
+    OPTION_UID,
+    OPTION_UNIX
 
 };
 
@@ -104,9 +108,13 @@ static struct option opts[] = {
     { "i",          OPTION_INPUT,       OPTION_HAS_ARG  },
     
     { "-arca",      OPTION_ARCA,        OPTION_NO_ARG   },
+    { "-gid",       OPTION_GID,         OPTION_HAS_ARG  },
     { "-help",      OPTION_HELP,        OPTION_NO_ARG   },
+    { "-mode",      OPTION_MODE,        OPTION_HAS_ARG  },
     { "-offset",    OPTION_OFFSET,      OPTION_HAS_ARG  },
     { "-status",    OPTION_STATUS,      OPTION_NO_ARG   },
+    { "-gid",       OPTION_UID,         OPTION_HAS_ARG  },
+    { "-unix",      OPTION_UNIX,        OPTION_NO_ARG  },
     
     { 0,            0,                  0               }
 
@@ -297,6 +305,26 @@ static void parse_args (int *pargc, char ***pargv, int optind) {
             
             }
             
+            case OPTION_GID: {
+            
+                if (!state->unix_extension) {
+                
+                    report_at (program_name, 0, REPORT_WARNING, "--gid is ignored without --unix");
+                    break;
+                
+                }
+                
+                if (!(state->gid = atoi (optarg))) {
+                
+                    report_at (program_name, 0, REPORT_ERROR, "bad number for --gid");
+                    exit (EXIT_FAILURE);
+                
+                }
+                
+                break;
+            
+            }
+            
             case OPTION_HELP: {
             
                 print_help (EXIT_SUCCESS);
@@ -318,6 +346,27 @@ static void parse_args (int *pargc, char ***pargv, int optind) {
             
             }
             
+            case OPTION_MODE: {
+            
+                if (!state->unix_extension) {
+                
+                    report_at (program_name, 0, REPORT_WARNING, "--mode is ignored without --unix");
+                    break;
+                
+                }
+                
+                if (strlen (optarg) != 3) {
+                
+                    report_at (program_name, 0, REPORT_ERROR, "invalid mode provided");
+                    exit (EXIT_FAILURE);
+                
+                }
+                
+                memmove (state->mode + 3, optarg, 3);
+                break;
+            
+            }
+            
             case OPTION_OFFSET: {
             
                 long conversion;
@@ -352,6 +401,33 @@ static void parse_args (int *pargc, char ***pargv, int optind) {
             
             }
             
+            case OPTION_UID: {
+            
+                if (!state->unix_extension) {
+                
+                    report_at (program_name, 0, REPORT_WARNING, "--uid is ignored without --unix");
+                    break;
+                
+                }
+                
+                if (!(state->uid = atoi (optarg))) {
+                
+                    report_at (program_name, 0, REPORT_ERROR, "bad number for --uid");
+                    exit (EXIT_FAILURE);
+                
+                }
+                
+                break;
+            
+            }
+            
+            case OPTION_UNIX: {
+            
+                state->unix_extension = 1;
+                break;
+            
+            }
+            
             default: {
             
                 report_at (program_name, 0, REPORT_ERROR, "unsupported option '%s'", r);
@@ -368,8 +444,8 @@ static void parse_args (int *pargc, char ***pargv, int optind) {
 
 #ifndef     __PDOS__
 /** Get a single character from the terminal. */
-static char getch () {
-    
+static char getch (void) {
+
 #if     defined(_WIN32) && !defined (__PDOS__)
 
     KEY_EVENT_RECORD keyevent;
@@ -641,6 +717,24 @@ static int set_fat_entry (unsigned char *scratch, unsigned int cluster, unsigned
 static unsigned int get_free_fat (unsigned char *scratch);
 static const unsigned char lfn_ofs[] = { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };
 
+static void put_unix_attributes (struct msdos_dirent *de, unsigned char *sfn) {
+
+    unsigned char *p;
+    memset (de, 0, sizeof (*de));
+    
+    de->attr = ATTR_UNIX_MODE | ATTR_LONG_NAME;
+    de->csum = sum_sfn (sfn);
+    
+    p = (unsigned char *) de;
+    p[0] = ATTR_ARCHIVE;
+    
+    write721_to_byte_array (p + 1, mode_con (state->mode));
+    write721_to_byte_array (p + 4, state->uid);
+    
+    p[7] = state->gid;
+
+}
+
 static void put_lfn (const unsigned short *lfn, int ord, int sum, struct msdos_dirent *de) {
 
     unsigned short wc;
@@ -785,12 +879,12 @@ static int copy_file (const char *source, struct file_info *fi, const char *fnam
     
     }
     
-    num_clusters = (flen + clust_size -  1) / clust_size;
+    num_clusters = (flen + clust_size - 1) / clust_size;
     memset (cluster_chain, 0, cluster_count * sizeof (unsigned int));
     
-    for (i = 2, j = 0; i < cluster_count && j < num_clusters; i++) {
+    for (i = (size_fat == 12 ? 3 : 2), j = 0; i < cluster_count && j < num_clusters; i++) {
     
-        if (get_fat_entry (fi->scratch, i) == 0) {
+        if (!(get_fat_entry (fi->scratch, i))) {
             cluster_chain[j++] = i;
         }
     
@@ -823,9 +917,8 @@ static int copy_file (const char *source, struct file_info *fi, const char *fnam
     while ((bytes = fread (buffer, 1, clust_size, ifp)) > 0) {
     
         size += bytes;
-        i = cluster_chain[j++];
         
-        if (i == cluster_count) {
+        if ((i = cluster_chain[j++]) == cluster_count) {
         
             free (cluster_chain);
             free (buffer);
@@ -1133,13 +1226,13 @@ static int follow_path (const char *target, struct dir_info *di) {
                 a = de.attr & 0x3f;
                 c = de.name[0];
                 
-                if (c == 0xe5 || ((a & 0x08) && a != 15)) {
+                if (c == 0xE5 || ((a & 0x08) && a != 15)) {
                     ord = 0xff;
                 } else {
                 
                     if (a == 15) {
                     
-                        if (!(dp.fn[11] & 2)) {
+                        if (!(dp.fn[11] & 0x40)) {
                         
                             if (c & 0x40) {
                             
@@ -1601,7 +1694,7 @@ static int open_file (const char *target, unsigned char *scratch, struct file_in
         
         }
         
-        fi->cluster = 0;
+        /*fi->cluster = 0;*/
         
         if (seekto ((unsigned long) fi->dir_sector * 512) || fread (scratch, 512, 1, ofp) != 1) {
             return -1;
@@ -1643,8 +1736,46 @@ static int open_file (const char *target, unsigned char *scratch, struct file_in
             nent = 1;
         }
         
-        if (dir_alloc ((char *) tmppath, &di, nent) < 0) {
-            return -1;
+        if (state->unix_extension) {
+        
+            unsigned char dir_offset;
+            unsigned int dir_sector;
+            
+            if (dir_alloc ((char *) tmppath, &di, nent + 1) < 0) {
+                return -1;
+            }
+            
+            if (get_free_dirent ((char *) tmppath, &di) < 0) {
+                return -1;
+            }
+            
+            put_unix_attributes (&de, dp.fn);
+            
+            if (di.current_cluster == 0) {
+                dir_sector = root_dir + di.current_sector;
+            } else {
+                dir_sector = data_area + ((di.current_cluster - 2) * sectors_per_cluster) + di.current_sector;
+            }
+            
+            /*fi->dir_offset = di.current_entry - 1;*/
+            dir_offset = di.current_entry;
+            
+            if (seekto ((unsigned long) dir_sector * 512) || fread (scratch, 512, 1, ofp) != 1) {
+                return -1;
+            }
+            
+            memcpy (&(((struct msdos_dirent *) scratch)[dir_offset]), &de, sizeof (de));
+            
+            if (seekto ((unsigned long) dir_sector * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
+                return -1;
+            }
+        
+        } else {
+        
+            if (dir_alloc ((char *) tmppath, &di, nent) < 0) {
+                return -1;
+            }
+        
         }
         
         if (--nent) {
@@ -1709,7 +1840,7 @@ static int open_file (const char *target, unsigned char *scratch, struct file_in
     if (di.current_cluster == 0) {
         fi->dir_sector = root_dir + di.current_sector;
     } else {
-        fi->dir_sector = data_area + ((di.current_cluster - 2) * sectors_per_cluster)  + di.current_sector;
+        fi->dir_sector = data_area + ((di.current_cluster - 2) * sectors_per_cluster) + di.current_sector;
     }
     
     fi->dir_offset = di.current_entry;
@@ -1918,7 +2049,7 @@ static unsigned int get_free_fat (unsigned char *scratch) {
 
     unsigned int i, result;
     
-    for (i = 2; i < cluster_count; i++) {
+    for (i = (size_fat == 12 ? 3 : 2); i < cluster_count; i++) {
     
         if (!(result = get_fat_entry (scratch, i))) {
             return i;
@@ -1977,7 +2108,7 @@ int get_file (const char *source, unsigned char *scratch, struct file_info *fi)
         return -1;
     }
     
-    report_at (program_name, 0, REPORT_WARNING, "get_file: %ls - %.*s", dp.lfn, 11, dp.fn);
+    /*report_at (program_name, 0, REPORT_WARNING, "get_file: %ls - %.*s", dp.lfn, 11, dp.fn);*/
     
     if (p > tmppath) {
         p--;
@@ -2184,6 +2315,11 @@ int main (int argc, char **argv) {
     }
     
     state = xmalloc (sizeof (*state));
+    
+    state->gid = 1;
+    state->uid = 2;
+    
+    state->mode = xstrdup ("---755");
     parse_args (&argc, &argv, 1);
     
     if (!state->outfile || state->nb_files < 2) {
diff --git a/mcopy.h b/mcopy.h
index dee7b925fb2eb7d1b34205c622c4e2542e883e60..90f6271d8a69e2b82d499a70de3d73a9e7419d30 100644 (file)
--- a/mcopy.h
+++ b/mcopy.h
@@ -15,6 +15,12 @@ struct mcopy_state {
     size_t offset;
     
     int chs_align;
+    int unix_extension;
+    
+    unsigned int gid;
+    unsigned int uid;
+    
+    char *mode;
 
 };
 
diff --git a/mkfs.c b/mkfs.c
index d752a9d464d72c702dbd6f972e69eef6586ff8d2..50696eb608ce4989d845db7bbade6a2523fd863c 100644 (file)
--- a/mkfs.c
+++ b/mkfs.c
@@ -397,108 +397,120 @@ static void establish_bpb (void) {
         
             sectors_per_cluster = 2;
             root_entries = 112;
-            media_descriptor = 0xfe;
             sectors_per_track = 8;
             heads_per_cylinder = 1;
+            
+            media_descriptor = 0xFE;
             break;
         
         case 360:                                                               /* 180KB 5.25" */
         
             sectors_per_cluster = 2;
             root_entries = 112;
-            media_descriptor = 0xfc;
             sectors_per_track = 9;
             heads_per_cylinder = 1;
+            
+            media_descriptor = 0xFC;
             break;
         
         case 640:                                                               /* 320KB 5.25" */
         
             sectors_per_cluster = 2;
             root_entries = 112;
-            media_descriptor = 0xff;
             sectors_per_track = 8;
             heads_per_cylinder = 2;
+            
+            media_descriptor = 0xFF;
             break;
         
         case 720:                                                               /* 360KB 5.25" */
         
             sectors_per_cluster = 2;
             root_entries = 112;
-            media_descriptor = 0xfd;
             sectors_per_track = 9;
             heads_per_cylinder = 2;
+            
+            media_descriptor = 0xFD;
             break;
         
         case 1280:                                                              /* 640KB 5.25" / 3.5" */
         
             sectors_per_cluster = 2;
             root_entries = 112;
-            media_descriptor = 0xfb;
             sectors_per_track = 8;
             heads_per_cylinder = 2;
+            
+            media_descriptor = 0xFB;
             break;
         
         case 1440:                                                              /* 720KB 5.25" / 3.5" */
         
             sectors_per_cluster = 2;
             root_entries = 112;
-            media_descriptor = 0xf9;
             sectors_per_track = 9;
             heads_per_cylinder = 2;
+            
+            media_descriptor = 0xF9;
             break;
         
         case 1640:                                                              /* 820KB 3.5" */
         
             sectors_per_cluster = 2;
             root_entries = 112;
-            media_descriptor = 0xf9;
             sectors_per_track = 10;
             heads_per_cylinder = 2;
+            
+            media_descriptor = 0xF9;
             break;
         
         case 2400:                                                              /* 1.20MB 5.25" / 3.5" */
         
             sectors_per_cluster = 1;
             root_entries = 224;
-            media_descriptor = 0xf9;
             sectors_per_track = 15;
             heads_per_cylinder = 2;
+            
+            media_descriptor = 0xF9;
             break;
         
         case 2880:                                                              /* 1.44MB 3.5" */
         
             sectors_per_cluster = 1;
             root_entries = 224;
-            media_descriptor = 0xf0;
             sectors_per_track = 18;
             heads_per_cylinder = 2;
+            
+            media_descriptor = 0xF0;
             break;
         
         case 3360:                                                              /* 1.68MB 3.5" */
         
             sectors_per_cluster = 1;
             root_entries = 224;
-            media_descriptor = 0xf0;
             sectors_per_track = 21;
             heads_per_cylinder = 2;
+            
+            media_descriptor = 0xF0;
             break;
         
         case 3444:                                                              /* 1.72MB 3.5" */
         
             sectors_per_cluster = 1;
             root_entries = 224;
-            media_descriptor = 0xf0;
             sectors_per_track = 21;
             heads_per_cylinder = 2;
+            
+            media_descriptor = 0xF0;
             break;
         
         case 5760:                                                              /* 2.88MB 3.5" */
         
             sectors_per_cluster = 2;
             root_entries = 240;
-            media_descriptor = 0xf0;
             sectors_per_track = 36;
             heads_per_cylinder = 2;
+            
+            media_descriptor = 0xF0;
             break;
     
     }
diff --git a/mls.c b/mls.c
index a53f2c763952a44d10ebed85878fc7ae548a35c8..46db2cff3c77f695e417ef6ef9f4fd4841345a25 100644 (file)
--- a/mls.c
+++ b/mls.c
@@ -965,7 +965,7 @@ int main (int argc, char **argv) {
                 continue;
             }
             
-            if ((de.attr & ATTR_VOLUME_ID) == ATTR_VOLUME_ID || de.attr == ATTR_LONG_NAME) {
+            if ((de.attr & ATTR_VOLUME_ID) == ATTR_VOLUME_ID || (de.attr & 0x80) != 0) {
                 continue;
             }
             
diff --git a/mmd.c b/mmd.c
index edc69fcbf5b8b92015c2aa24759ca508eec5a114..86d956d188b79408dc15cbbf3aca740ad6672d6d 100644 (file)
--- a/mmd.c
+++ b/mmd.c
@@ -64,9 +64,13 @@ enum options {
 
     OPTION_IGNORED = 1,
     OPTION_ARCA,
+    OPTION_GID,
     OPTION_HELP,
     OPTION_INPUT,
-    OPTION_OFFSET
+    OPTION_MODE,
+    OPTION_OFFSET,
+    OPTION_UID,
+    OPTION_UNIX
 
 };
 
@@ -75,8 +79,12 @@ static struct option opts[] = {
     { "i",          OPTION_INPUT,       OPTION_HAS_ARG  },
     
     { "-arca",      OPTION_ARCA,        OPTION_NO_ARG   },
+    { "-gid",       OPTION_GID,         OPTION_HAS_ARG  },
     { "-help",      OPTION_HELP,        OPTION_NO_ARG   },
+    { "-mode",      OPTION_MODE,        OPTION_HAS_ARG  },
     { "-offset",    OPTION_OFFSET,      OPTION_HAS_ARG  },
+    { "-uid",       OPTION_UID,         OPTION_HAS_ARG  },
+    { "-unix",      OPTION_UNIX,        OPTION_NO_ARG  },
     
     { 0,            0,                  0               }
 
@@ -267,6 +275,26 @@ static void parse_args (int *pargc, char ***pargv, int optind) {
             
             }
             
+            case OPTION_GID: {
+            
+                if (!state->unix_extension) {
+                
+                    report_at (program_name, 0, REPORT_WARNING, "--gid is ignored without --unix");
+                    break;
+                
+                }
+                
+                if (!(state->gid = atoi (optarg))) {
+                
+                    report_at (program_name, 0, REPORT_ERROR, "bad number for --gid");
+                    exit (EXIT_FAILURE);
+                
+                }
+                
+                break;
+            
+            }
+            
             case OPTION_HELP: {
             
                 print_help (EXIT_SUCCESS);
@@ -288,6 +316,27 @@ static void parse_args (int *pargc, char ***pargv, int optind) {
             
             }
             
+            case OPTION_MODE: {
+            
+                if (!state->unix_extension) {
+                
+                    report_at (program_name, 0, REPORT_WARNING, "--mode is ignored without --unix");
+                    break;
+                
+                }
+                
+                if (strlen (optarg) != 3) {
+                
+                    report_at (program_name, 0, REPORT_ERROR, "invalid mode provided");
+                    exit (EXIT_FAILURE);
+                
+                }
+                
+                memmove (state->mode + 3, optarg, 3);
+                break;
+            
+            }
+            
             case OPTION_OFFSET: {
             
                 long conversion;
@@ -315,6 +364,33 @@ static void parse_args (int *pargc, char ***pargv, int optind) {
             
             }
             
+            case OPTION_UID: {
+            
+                if (!state->unix_extension) {
+                
+                    report_at (program_name, 0, REPORT_WARNING, "--uid is ignored without --unix");
+                    break;
+                
+                }
+                
+                if (!(state->uid = atoi (optarg))) {
+                
+                    report_at (program_name, 0, REPORT_ERROR, "bad number for --uid");
+                    exit (EXIT_FAILURE);
+                
+                }
+                
+                break;
+            
+            }
+            
+            case OPTION_UNIX: {
+            
+                state->unix_extension = 1;
+                break;
+            
+            }
+            
             default: {
             
                 report_at (program_name, 0, REPORT_ERROR, "unsupported option '%s'", r);
@@ -346,6 +422,24 @@ static int set_fat_entry (unsigned char *scratch, unsigned int cluster, unsigned
 static unsigned int get_free_fat (unsigned char *scratch);
 static const unsigned char lfn_ofs[] = { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };
 
+static void put_unix_attributes (struct msdos_dirent *de, unsigned char *sfn) {
+
+    unsigned char *p;
+    memset (de, 0, sizeof (*de));
+    
+    de->attr = ATTR_UNIX_MODE | ATTR_LONG_NAME;
+    de->csum = sum_sfn (sfn);
+    
+    p = (unsigned char *) de;
+    p[0] = ATTR_DIR;
+    
+    write721_to_byte_array (p + 1, mode_con (state->mode));
+    write721_to_byte_array (p + 4, state->uid);
+    
+    p[7] = state->gid;
+
+}
+
 static void put_lfn (const unsigned short *lfn, int ord, int sum, struct msdos_dirent *de) {
 
     unsigned short wc;
@@ -616,8 +710,50 @@ static int create_dir (const char *target, unsigned char *scratch) {
         nent = 1;
     }
     
-    if (dir_alloc ((char *) tmppath, &di, nent) < 0) {
-        return -1;
+    if (state->unix_extension) {
+    
+        struct msdos_dirent de;
+        struct dir_info udi;
+        
+        unsigned char dir_offset;
+        unsigned int dir_sector;
+        
+        if (dir_alloc ((char *) tmppath, &di, nent + 1) < 0) {
+            return -1;
+        }
+        
+        memcpy (&udi, &di, sizeof (udi));
+        
+        if (get_free_dirent ((char *) tmppath, &udi) < 0) {
+            return -1;
+        }
+        
+        put_unix_attributes (&de, dp.fn);
+        
+        if (di.current_cluster == 0) {
+            dir_sector = root_dir + udi.current_sector;
+        } else {
+            dir_sector = data_area + ((udi.current_cluster - 2) * sectors_per_cluster) + udi.current_sector;
+        }
+        
+        dir_offset = udi.current_entry;
+        
+        if (seekto ((unsigned long) dir_sector * 512) || fread (scratch, 512, 1, ofp) != 1) {
+            return -1;
+        }
+        
+        memcpy (&(((struct msdos_dirent *) scratch)[dir_offset]), &de, sizeof (de));
+        
+        if (seekto ((unsigned long) dir_sector * 512) || fwrite (scratch, 512, 1, ofp) != 1) {
+            return -1;
+        }
+    
+    } else {
+    
+        if (dir_alloc ((char *) tmppath, &di, nent) < 0) {
+            return -1;
+        }
+    
     }
     
     if (--nent) {
@@ -718,8 +854,11 @@ static int create_dir (const char *target, unsigned char *scratch) {
     
     }
     
-    dir_offset = 0;
+    de.type = 0;
+    de.csum = 0;
+    
     dir_sector = data_area + ((cluster - 2) * sectors_per_cluster);
+    dir_offset = 0;
     
     memset (de.name, ' ', 11);
     de.name[0] = '.';
@@ -1109,6 +1248,7 @@ static int get_free_dirent (const char *path, struct dir_info *di) {
 static int get_next_entry (struct dir_info *di, struct msdos_dirent *de) {
 
     unsigned long offset;
+    unsigned int cluster;
     
     if (di->current_entry >= 512 / sizeof (*de)) {
     
@@ -1145,13 +1285,23 @@ static int get_next_entry (struct dir_info *di, struct msdos_dirent *de) {
                 
                 }
                 
-                di->current_cluster = get_fat_entry (di->scratch, di->current_cluster);
+                cluster = get_fat_entry (di->scratch, di->current_cluster);
+                
+                if ((size_fat == 12 && cluster >= 0x0FF8) || (size_fat == 16 && cluster >= 0xFFF8) || (size_fat == 32 && cluster >= 0x0FFFFFF8)) {
+                
+                    cluster = get_free_fat (di->scratch);
+                    
+                    if (cluster == 0x0FFFFFF7 || set_fat_entry (di->scratch, di->current_cluster, cluster) < 0 || set_fat_entry (di->scratch, cluster, 0x0FFFFFF8) < 0) {
+                        return -1;
+                    }
+                
+                }
+                
+                di->current_cluster = cluster;
             
             }
             
-            offset = (unsigned long) data_area;
-            offset += ((di->current_cluster - 2) * sectors_per_cluster);
-            offset += di->current_sector;
+            offset = ((unsigned long) data_area + ((di->current_cluster - 2) * sectors_per_cluster)) + di->current_sector;
             
             if (seekto (offset * 512) || fread (di->scratch, 512, 1, ofp) != 1) {
                 return -1;
@@ -1375,7 +1525,7 @@ static unsigned int get_free_fat (unsigned char *scratch) {
 
     unsigned int i, result = 0xFFFFFFFF;
     
-    for (i = 2; i < cluster_count; i++) {
+    for (i = (size_fat == 12 ? 3 : 2); i < cluster_count; i++) {
     
         result = get_fat_entry (scratch, i);
         
@@ -1452,6 +1602,11 @@ int main (int argc, char **argv) {
     }
     
     state = xmalloc (sizeof (*state));
+    
+    state->gid = 1;
+    state->uid = 2;
+    
+    state->mode = xstrdup ("d--644");
     parse_args (&argc, &argv, 1);
     
     if (!state->outfile || state->nb_dirs == 0) {
diff --git a/mmd.h b/mmd.h
index 02864005fcf9f6481d19f692728157899dfd12b1..030c51ec8db2e49ad9fd18b68bf52384265f47b5 100644 (file)
--- a/mmd.h
+++ b/mmd.h
@@ -13,6 +13,12 @@ struct mmd_state {
     unsigned long offset;
     
     int chs_align;
+    int unix_extension;
+    
+    unsigned int gid;
+    unsigned int uid;
+    
+    char *mode;
 
 };
 
diff --git a/msdos.h b/msdos.h
index b104ea3c7dab2847dbf0b7e885f5696b3855ccbf..35722e9585c96b14a77a20dfa2ead91f49385e02 100644 (file)
--- a/msdos.h
+++ b/msdos.h
 #define     ATTR_VOLUME_ID              0x08
 #define     ATTR_DIR                    0x10
 #define     ATTR_ARCHIVE                0x20
+
+#define     ATTR_UNIX_LINK              0x40
+#define     ATTR_UNIX_MODE              0x80
+
 #define     ATTR_LONG_NAME              (ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID)
 
 struct msdos_volume_info {