Added mke2nod master
authorRobert Pengelly <robertapengelly@hotmail.com>
Sun, 31 Aug 2025 21:10:33 +0000 (22:10 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Sun, 31 Aug 2025 21:10:33 +0000 (22:10 +0100)
Makefile.std
Makefile.unix
Makefile.w32
common.c
common.h
e2cp.c
e2md.c
mke2nod.c [new file with mode: 0644]

index 2bdc10c26e6e6c4eb5ed8de0fbbc60de26dc4b49..9d0263d81bd65f719fcf6a6810ee37a652700059 100644 (file)
@@ -8,7 +8,7 @@ LD=pdld --no-insert-timestamp
 COPTS=-S -O2 -fno-common -ansi -I. -I../pdos/pdpclib -D__WIN32__ -D__NOBIVA__ -D__PDOS__
 COBJ=cache.obj common.obj list.obj report.obj
 
-all: clean mke2fs.exe e2cp.exe e2md.exe
+all: clean mke2fs.exe e2cp.exe e2md.exe mke2nod.exe
 
 mke2fs.exe: mke2fs.obj $(COBJ)
   $(LD) -s -o mke2fs.exe ../pdos/pdpclib/w32start.obj mke2fs.obj $(COBJ) ../pdos/pdpclib/msvcrt.lib
@@ -19,6 +19,9 @@ e2cp.exe: e2cp.obj $(COBJ)
 e2md.exe: e2md.obj $(COBJ)
   $(LD) -s -o e2md.exe ../pdos/pdpclib/w32start.obj e2md.obj $(COBJ) ../pdos/pdpclib/msvcrt.lib
 
+mke2nod.exe: mke2nod.obj $(COBJ)
+  $(LD) -s -o mke2nod.exe ../pdos/pdpclib/w32start.obj mke2nod.obj $(COBJ) ../pdos/pdpclib/msvcrt.lib
+
 .c.obj:
   $(CC) $(COPTS) $<
   $(AS) -o $@ $*.s
@@ -29,3 +32,4 @@ clean:
   rm -f mke2fs.exe
   rm -f e2cp.exe
   rm -f e2md.exe
+  rm -f mke2nod.exe
index 538b3a0418c72a45a5a7b8d0c3d337b694af83cf..b5028c0e0f48d42448652459a034f2927785f4b6 100644 (file)
@@ -8,7 +8,7 @@ CC                  :=  gcc
 CFLAGS              :=  -D_FILE_OFFSET_BITS=64 -Wall -Werror -Wextra -std=c90
 
 ifeq ($(OS), Windows_NT)
-all: mke2fs.exe e2md.exe e2cp.exe
+all: mke2fs.exe e2md.exe e2cp.exe mke2nod.exe
 
 mke2fs.exe: mke2fs.c cache.c common.c list.c report.c
 
@@ -21,8 +21,12 @@ e2md.exe: e2md.c cache.c common.c list.c report.c
 e2cp.exe: e2cp.c cache.c common.c list.c report.c
 
        $(CC) $(CFLAGS) -o $@ $^
+
+mke2nod.exe: mke2nod.c cache.c common.c list.c report.c
+
+       $(CC) $(CFLAGS) -o $@ $^
 else
-all: mke2fs e2md e2cp
+all: mke2fs e2md e2cp mke2nod
 
 mke2fs: mke2fs.c cache.c common.c list.c report.c
 
@@ -35,6 +39,10 @@ e2md: e2md.c cache.c common.c list.c report.c
 e2cp: e2cp.c cache.c common.c list.c report.c
 
        $(CC) $(CFLAGS) -o $@ $^
+
+mke2nod: mke2nod.c cache.c common.c list.c report.c
+
+       $(CC) $(CFLAGS) -o $@ $^
 endif
 
 clean:
@@ -47,3 +55,6 @@ clean:
 
        if [ -f e2cp.exe ]; then rm -rf e2cp.exe; fi
        if [ -f e2cp ]; then rm -rf e2cp; fi
+
+       if [ -f mke2nod.exe ]; then rm -rf mke2nod.exe; fi
+       if [ -f mke2nod ]; then rm -rf mke2nod; fi
index 0f48bad10d02ab0e8528e8c1f86e1da421dce3c8..c6a75f2daa8c9c3d7814fe4fc3078f0aac4b2aa8 100644 (file)
@@ -7,7 +7,7 @@ VPATH               :=  $(SRCDIR)
 CC                  :=  gcc
 CFLAGS              :=  -D_FILE_OFFSET_BITS=64 -Wall -Werror -Wextra -std=c90
 
-all: mke2fs.exe e2md.exe e2cp.exe
+all: mke2fs.exe e2md.exe e2cp.exe mke2nod.exe
 
 clean:
 
@@ -20,6 +20,9 @@ clean:
        if exist e2cp.exe ( del /q e2cp.exe )
        if exist e2cp ( del /q e2cp )
 
+       if exist mke2nod.exe ( del /q mke2nod.exe )
+       if exist mke2nod ( del /q mke2nod )
+
 mke2fs.exe: mke2fs.c cache.c common.c list.c report.c
 
        $(CC) $(CFLAGS) -o $@ $^
@@ -31,3 +34,7 @@ e2md.exe: e2md.c cache.c common.c list.c report.c
 e2cp.exe: e2cp.c cache.c common.c list.c report.c
 
        $(CC) $(CFLAGS) -o $@ $^
+
+mke2nod.exe: mke2nod.c cache.c common.c list.c report.c
+
+       $(CC) $(CFLAGS) -o $@ $^
index 23228123a39110a6c66f916b503f3b3d9d8f70d5..6ab1375b88eb6fb4af6be63390381d2dbf0b15e0 100644 (file)
--- a/common.c
+++ b/common.c
@@ -813,7 +813,7 @@ out:
 #define     GRP_GROUP_OF_INODE(fs, nod)                     \
     (((nod) - 1) / byte_array_to_integer ((fs)->sb->s_inodes_per_group, 4))
 
-unsigned long mknod_fs (struct filesystem *fs, unsigned long parent_nod, const char *name, unsigned long mode, unsigned short uid, unsigned short gid, unsigned long ctime, unsigned long mtime) {
+unsigned long mknod_fs (struct filesystem *fs, unsigned long parent_nod, const char *name, unsigned long mode, unsigned short uid, unsigned short gid, unsigned char major, unsigned char minor, unsigned long ctime, unsigned long mtime) {
 
     unsigned long nod, used_dirs_count;
     
@@ -830,6 +830,22 @@ unsigned long mknod_fs (struct filesystem *fs, unsigned long parent_nod, const c
     
     switch (mode & FM_IFMT) {
     
+        case FM_IFBLK:  case FM_IFCHR:
+        
+            if (fs->swapit) {
+            
+                node->i_block[3] = minor;
+                node->i_block[2] = major;
+            
+            } else {
+            
+                node->i_block[0] = minor;
+                node->i_block[1] = major;
+            
+            }
+            
+            break;
+        
         case FM_IFDIR:
         
             add2dir (fs, nod, nod, ".");
@@ -862,7 +878,7 @@ unsigned long mknod_fs (struct filesystem *fs, unsigned long parent_nod, const c
 }
 
 unsigned long mkdir_fs (struct filesystem *fs, unsigned long parent_nod, const char *name, unsigned long mode, unsigned short uid, unsigned short gid, unsigned long ctime, unsigned long mtime) {
-    return mknod_fs (fs, parent_nod, name, mode | FM_IFDIR, uid, gid, ctime, mtime);
+    return mknod_fs (fs, parent_nod, name, mode | FM_IFDIR, uid, gid, 0, 0, ctime, mtime);
 }
 
 unsigned long rndup (unsigned long qty, unsigned long siz) {
index 9dd806c057fb65f0924bfe7d4ebda53946c4089c..58e17d750ce4b98f97523dc9de6964f0648ae2c4 100644 (file)
--- a/common.h
+++ b/common.h
@@ -91,7 +91,9 @@ unsigned long rndup (unsigned long qty, unsigned long siz);
 #define     FM_IFMT                     0170000
 
 #define     FM_IFREG                    0100000
+#define     FM_IFBLK                    0060000
 #define     FM_IFDIR                    0040000
+#define     FM_IFCHR                    0020000
 #define     FM_IRWXU                    0000700
 #define     FM_IRGRP                    0000040
 #define     FM_IXGRP                    0000010
@@ -155,7 +157,7 @@ struct nod_info {
 };
 
 struct filesystem *alloc_fs (void);
-unsigned long mknod_fs (struct filesystem *fs, unsigned long parent_nod, const char *name, unsigned long mode, unsigned short uid, unsigned short gid, unsigned long ctime, unsigned long mtime);
+unsigned long mknod_fs (struct filesystem *fs, unsigned long parent_nod, const char *name, unsigned long mode, unsigned short uid, unsigned short gid, unsigned char major, unsigned char minor, unsigned long ctime, unsigned long mtime);
 
 struct group_descriptor *get_gd (struct filesystem *fs, unsigned long no, struct gd_info **rgi);
 void put_gd (struct gd_info *gi);
diff --git a/e2cp.c b/e2cp.c
index eaa6d45c2c7dc56dc4151f46ae80a8cfd54faaa1..2a0b458d77678eadcb9be5e9719dba033edecab9 100644 (file)
--- a/e2cp.c
+++ b/e2cp.c
@@ -379,7 +379,7 @@ static unsigned long mkfile_fs (struct filesystem *fs, unsigned long parent_nod,
     struct nod_info *ni;
     struct inode *node;
     
-    nod = mknod_fs (fs, parent_nod, name, mode_con (mode), uid, gid, ctime, mtime);
+    nod = mknod_fs (fs, parent_nod, name, mode_con (mode), uid, gid, 0, 0, ctime, mtime);
     node = get_nod (fs, nod, &ni);
     
     inode_pos_init (fs, &ipos, nod, INODE_POS_TRUNCATE, 0);
diff --git a/e2md.c b/e2md.c
index eb8e35419a2c70e78c6c3d57c40c63839af5d452..30db324eac525dfe45474dd3b03ad0b2b010e0db 100644 (file)
--- a/e2md.c
+++ b/e2md.c
@@ -346,7 +346,7 @@ static void walk_dir (struct filesystem *fs, char *dirname) {
     
     }
     
-    mknod_fs (fs, parent_nod, p1, mode_con (mode), 0, 0, timestamp, timestamp);
+    mknod_fs (fs, parent_nod, p1, mode_con (mode), 0, 0, 0, 0, timestamp, timestamp);
 
 }
 
diff --git a/mke2nod.c b/mke2nod.c
new file mode 100644 (file)
index 0000000..03f31b4
--- /dev/null
+++ b/mke2nod.c
@@ -0,0 +1,439 @@
+/******************************************************************************
+ * @file            mke2nod.c
+ *****************************************************************************/
+#include    <ctype.h>
+#include    <errno.h>
+#include    <limits.h>
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+#include    <time.h>
+
+#include    "common.h"
+#include    "inode.h"
+#include    "report.h"
+#include    "super.h"
+
+static char *mode = 0;
+
+#define     OPTION_BIGENDIAN            0x0001
+#define     OPTION_INPUT                0x0002
+#define     OPTION_HELP                 0x0003
+#define     OPTION_MODE                 0x0004
+#define     OPTION_OFFSET               0x0005
+
+struct option {
+
+    const char *name;
+    int index, flags;
+
+};
+
+#define     OPTION_NO_ARG               0x0001
+#define     OPTION_HAS_ARG              0x0002
+
+static struct option opts[] = {
+
+    {   "-i",               OPTION_INPUT,           OPTION_HAS_ARG      },
+    
+    {   "--bigendian",      OPTION_BIGENDIAN,       OPTION_NO_ARG       },
+    {   "--help",           OPTION_HELP,            OPTION_NO_ARG       },
+    {   "--mode",           OPTION_MODE,            OPTION_HAS_ARG      },
+    {   "--offset",         OPTION_OFFSET,          OPTION_HAS_ARG      },
+    
+    {   0,                  0,                      0                   }
+
+};
+
+static char **args = 0;
+static long nb_args = 0;
+
+static int strstart (const char *val, const char **str) {
+
+    const char *p = val;
+    const char *q = *str;
+    
+    while (*p != '\0') {
+    
+        if (*p != *q) {
+            return 0;
+        }
+        
+        ++p;
+        ++q;
+    
+    }
+    
+    *str = q;
+    return 1;
+
+}
+
+static void print_help (void) {
+
+    if (program_name) {
+    
+        fprintf (stderr, "Usage: %s [options] name type major minor\n\n", program_name);
+        fprintf (stderr, "Options:\n\n");
+        
+        fprintf (stderr, "    Short options:\n\n");
+        fprintf (stderr, "        -i                Specify the input target.\n");
+        
+        fprintf (stderr, "\n");
+        
+        fprintf (stderr, "    Long options:\n\n");
+        fprintf (stderr, "        --help            Show this help information then exit.\n");
+        fprintf (stderr, "        --offset SECTOR   Write the filesystem starting at SECTOR.\n");
+    
+    }
+    
+    exit (EXIT_SUCCESS);
+
+}
+
+static void dynarray_add (void *ptab, long *nb_ptr, void *data) {
+
+    int nb, nb_alloc;
+    void **pp;
+    
+    nb = *nb_ptr;
+    pp = *(void ***) ptab;
+    
+    if ((nb & (nb - 1)) == 0) {
+    
+        if (!nb) {
+            nb_alloc = 1;
+        } else {
+            nb_alloc = nb * 2;
+        }
+        
+        pp = xrealloc (pp, nb_alloc * sizeof (void *));
+        *(void ***) ptab = pp;
+    
+    }
+    
+    pp[nb++] = data;
+    *nb_ptr = nb;
+
+}
+
+static void parse_args (int argc, char **argv, int optind) {
+
+    struct option *popt;
+    const char *optarg, *r;
+    
+    if (argc <= optind) {
+        print_help ();
+    }
+    
+    while (optind < argc) {
+    
+        r = argv[optind++];
+        
+        if (r[0] != '-' || r[1] == '\0') {
+        
+            dynarray_add (&args, &nb_args, xstrdup (r));
+            continue;
+        
+        }
+        
+        for (popt = opts; popt; popt++) {
+        
+            const char *p1 = popt->name;
+            const char *r1 = r;
+            
+            if (!p1) {
+            
+                report_at (program_name, 0, REPORT_ERROR, "invalid option -- '%s'", r);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            if (!strstart (p1, &r1)) {
+                continue;
+            }
+            
+            optarg = r1;
+            
+            if (popt->flags & OPTION_HAS_ARG) {
+            
+                if (*optarg == '\0') {
+                
+                    if (optind >= argc) {
+                    
+                        report_at (program_name, 0, REPORT_ERROR, "argument to '%s' is missing", r);
+                        exit (EXIT_FAILURE);
+                    
+                    }
+                    
+                    optarg = argv[optind++];
+                
+                }
+            
+            } else if (*optarg != '\0') {
+                continue;
+            }
+            
+            break;
+        
+        }
+        
+        switch (popt->index) {
+        
+            case OPTION_BIGENDIAN: {
+            
+                bigendian = 1;
+                break;
+            
+            }
+            
+            case OPTION_HELP: {
+            
+                print_help ();
+                break;
+            
+            }
+            
+            case OPTION_INPUT: {
+            
+                if (outfile) {
+                
+                    report_at (program_name, 0, REPORT_ERROR, "multiple output files provided");
+                    exit (EXIT_FAILURE);
+                
+                }
+                
+                outfile = xstrdup (optarg);
+                break;
+            
+            }
+            
+            case OPTION_MODE: {
+            
+                if (strlen (optarg) != 3) {
+                
+                    report_at (program_name, 0, REPORT_ERROR, "invalid mode provided");
+                    exit (EXIT_FAILURE);
+                
+                }
+                
+                memcpy (mode + 3, optarg, 3);
+                break;
+            
+            }
+            
+            case OPTION_OFFSET: {
+            
+                long conversion;
+                char *temp;
+                
+                errno = 0;
+                conversion = strtol (optarg, &temp, 0);
+                
+                if (!*optarg || isspace ((int) *optarg) || errno || *temp) {
+                
+                    report_at (program_name, 0, REPORT_ERROR, "bad number for offset (%s)", optarg);
+                    exit (EXIT_FAILURE);
+                
+                }
+                
+                if (conversion < 0 || conversion > INT_MAX) {
+                
+                    report_at (program_name, 0, REPORT_ERROR, "offset must be between 0 and %u", INT_MAX);
+                    exit (EXIT_FAILURE);
+                
+                }
+                
+                offset = conversion;
+                break;
+            
+            }
+            
+            default: {
+            
+                report_at (program_name, 0, REPORT_ERROR, "unsupported option '%s'", r);
+                exit (EXIT_FAILURE);
+            
+            }
+        
+        }
+    
+    }
+
+}
+
+static void cleanup (void) {
+
+    if (ofp != NULL) {
+        fclose (ofp);
+    }
+
+}
+
+static unsigned long find_entry (struct filesystem *fs, unsigned long nod, const char *name) {
+
+    struct blockwalker bw;
+    unsigned long nlen, bk;
+    
+    nlen = strlen (name);
+    init_bw (&bw);
+    
+    while ((bk = walk_bw (fs, nod, &bw, 0, 0)) != WALK_END) {
+    
+        struct directory *d;
+        struct dirwalker dw;
+        
+        for (d = get_dir (fs, bk, &dw); d; d = next_dir (&dw)) {
+        
+            if (byte_array_to_integer (d->d_inode, 4) && (nlen == byte_array_to_integer (d->d_name_len, 2)) && !strncmp (dir_name (&dw), name, nlen)) {
+            
+                unsigned long result = byte_array_to_integer (d->d_inode, 4);
+                put_dir (&dw);
+                
+                return result;
+            
+            }
+        
+        }
+        
+        put_dir (&dw);
+    
+    }
+    
+    return 0;
+
+}
+
+static void walk_path (struct filesystem *fs, char *path, unsigned char major, unsigned char minor) {
+
+    unsigned long parent_nod = EXT2_ROOT_INO, timestamp = time (0);
+    char *p1 = path, *p2, saved_ch;
+    
+    while (*p1 && (*p1 == '/' || *p1 == '\\')) {
+        p1++;
+    }
+    
+    if (*p1) {
+    
+        for (; (p2 = strchr (p1, '/')) || (p2 = strchr (p1, '\\')); p1 = p2 + 1) {
+        
+            saved_ch = *p2;
+            *p2 = '\0';
+            
+            if (strlen (p1) >= 14) {
+                p1[13] = '\0';
+            }
+            
+            if (!(parent_nod = find_entry (fs, parent_nod, p1))) {
+            
+                report_at (program_name, 0, REPORT_ERROR, "cannot access '%s'", path);
+                
+                *p2 = saved_ch;
+                return;
+            
+            }
+            
+            *p2 = saved_ch;
+        
+        }
+        
+        if (find_entry (fs, parent_nod, p1)) {
+        
+            report_at (program_name, 0, REPORT_ERROR, "'%s' already exists", path);
+            return;
+        
+        }
+    
+    }
+    
+    mknod_fs (fs, parent_nod, p1, mode_con (mode), 0, 0, major, minor, timestamp, timestamp);
+
+}
+
+int main (int argc, char **argv) {
+
+    struct superblock sup = { 0 };
+    struct filesystem *fs;
+    
+    if (argc && *argv) {
+    
+        char *p;
+        program_name = *argv;
+        
+        if ((p = strrchr (program_name, '/')) || (p = strrchr (program_name, '\\'))) {
+            program_name = (p + 1);
+        }
+    
+    }
+    
+    atexit (cleanup);
+    
+    mode = xstrdup ("---666");
+    parse_args (argc, argv, 1);
+    
+    if (!outfile) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "no input file was provided");
+        return EXIT_FAILURE;
+    
+    }
+    
+    if ((ofp = fopen (outfile, "r+b")) == NULL) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "faild to open '%s' for writing", outfile);
+        return EXIT_FAILURE;
+    
+    }
+    
+    seekto (ofp, EXT2_SUPERBLOCK_OFFSET / BLOCKSIZE);
+    
+    if (fread (&sup, sizeof (sup), 1, ofp) != 1) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed to whilst reading '%s'", outfile);
+        exit (EXIT_FAILURE);
+    
+    }
+    
+    if (bigendian) {
+               swap_sb (&sup);
+    }
+    
+    if (sup.s_magic[0] != (EXT2_SUPER_MAGIC & 0xff) || sup.s_magic[1] != ((EXT2_SUPER_MAGIC >> 8) & 0xff)) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "'%s' has a unsupported file system", outfile);
+        exit (EXIT_FAILURE);
+    
+    }
+    
+    fs = alloc_fs ();
+    fs->swapit = bigendian;
+    
+    fs->sb = &sup;
+    
+    if (nb_args != 4) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "invalid number of arguments passed");
+        exit (EXIT_FAILURE);
+    
+    }
+    
+    switch (args[1][0]) {
+    
+        case 'b':   case 'c':   case 'u':   case 'p':
+        
+            mode[0] = args[1][0];
+            break;
+        
+        default:
+        
+            report_at (program_name, 0, REPORT_ERROR, "invalid type provided");
+            exit (EXIT_FAILURE);
+    
+    }
+    
+    walk_path (fs, args[0], atoi (args[2]), atoi (args[3]));
+    
+    finish_fs (fs);
+    return (get_error_count () > 0) ? EXIT_FAILURE : EXIT_SUCCESS;
+
+}