#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;
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, ".");
}
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) {
--- /dev/null
+/******************************************************************************
+ * @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 = ⊃
+
+ 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;
+
+}