From b03a4ebd41af2833d38e3253884949f2241d78e3 Mon Sep 17 00:00:00 2001 From: Robert Pengelly Date: Sat, 26 Oct 2024 03:25:27 +0100 Subject: [PATCH] Initial commit --- LICENSE | 24 ++ Makefile.unix | 53 ++++ Makefile.w32 | 37 +++ README.md | 23 ++ common.c | 404 ++++++++++++++++++++++++++++++ common.h | 68 +++++ inode.h | 27 ++ mcopy.c | 590 ++++++++++++++++++++++++++++++++++++++++++++ mkfs.c | 598 ++++++++++++++++++++++++++++++++++++++++++++ mls.c | 668 ++++++++++++++++++++++++++++++++++++++++++++++++++ mmd.c | 497 +++++++++++++++++++++++++++++++++++++ report.c | 150 ++++++++++++ report.h | 29 +++ super.h | 25 ++ 14 files changed, 3193 insertions(+) create mode 100644 LICENSE create mode 100644 Makefile.unix create mode 100644 Makefile.w32 create mode 100644 README.md create mode 100644 common.c create mode 100644 common.h create mode 100644 inode.h create mode 100644 mcopy.c create mode 100644 mkfs.c create mode 100644 mls.c create mode 100644 mmd.c create mode 100644 report.c create mode 100644 report.h create mode 100644 super.h diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fdddb29 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/Makefile.unix b/Makefile.unix new file mode 100644 index 0000000..c7d5763 --- /dev/null +++ b/Makefile.unix @@ -0,0 +1,53 @@ +#****************************************************************************** +# @file Makefile.unix +#****************************************************************************** +SRCDIR ?= $(CURDIR) +VPATH := $(SRCDIR) + +CC := gcc +CFLAGS := -D_FILE_OFFSET_BITS=64 -Wall -Werror -Wextra -std=c90 + +#CSRC := common.c report.c write7x.c + +ifeq ($(OS), Windows_NT) +all: mkminixfs.exe mmd.exe mls.exe mcopy.exe + +mkminixfs.exe: mkfs.c common.c report.c + $(CC) $(CFLAGS) -o $@ $^ + +mmd.exe: mmd.c common.c report.c + $(CC) $(CFLAGS) -o $@ $^ + +mls.exe: mls.c report.c + $(CC) $(CFLAGS) -o $@ $^ + +mcopy.exe: mcopy.c common.c report.c + $(CC) $(CFLAGS) -o $@ $^ +else +all: mkfs.minix mmd mls mcopy + +mkfs.minix: mkfs.c common.c report.c + $(CC) $(CFLAGS) -o $@ $^ + +mmd: mmd.c common.c report.c + $(CC) $(CFLAGS) -o $@ $^ + +mls: mls.c report.c + $(CC) $(CFLAGS) -o $@ $^ + +mcopy: mcopy.c common.c report.c + $(CC) $(CFLAGS) -o $@ $^ +endif + +clean: + if [ -f mkminixfs.exe ]; then rm -rf mkminixfs.exe; fi + if [ -f mkfs.minix ]; then rm -rf mkfs.minix; fi + + if [ -f mmd.exe ]; then rm -rf mmd.exe; fi + if [ -f mmd ]; then rm -rf mmd; fi + + if [ -f mls.exe ]; then rm -rf mls.exe; fi + if [ -f mls ]; then rm -rf mls; fi + + if [ -f mcopy.exe ]; then rm -rf mcopy.exe; fi + if [ -f mcopy ]; then rm -rf mcopy; fi diff --git a/Makefile.w32 b/Makefile.w32 new file mode 100644 index 0000000..de7a81a --- /dev/null +++ b/Makefile.w32 @@ -0,0 +1,37 @@ +#****************************************************************************** +# @file Makefile.w32 +#****************************************************************************** +SRCDIR ?= $(CURDIR) +VPATH := $(SRCDIR) + +CC := gcc +CFLAGS := -D_FILE_OFFSET_BITS=64 -Wall -Werror -Wextra -std=c90 + +#CSRC := common.c report.c write7x.c + +all: mkminixfs.exe mmd.exe mls.exe mcopy.exe + +clean: + if exist mkminixfs.exe ( del /q mkminixfs.exe ) + if exist mkfs.minix ( del /q mkfs.minix ) + + if exist mmd.exe ( del /q mmd.exe ) + if exist mmd ( del /q mmd ) + + if exist mls.exe ( del /q mls.exe ) + if exist mls ( del /q mls ) + + if exist mcopy.exe ( del /q mcopy.exe ) + if exist mcopy ( del /q mcopy ) + +mkminixfs.exe: mkfs.c common.c report.c + $(CC) $(CFLAGS) -o $@ $^ + +mmd.exe: mmd.c common.c report.c + $(CC) $(CFLAGS) -o $@ $^ + +mls.exe: mmd.c report.c + $(CC) $(CFLAGS) -o $@ $^ + +mcopy.exe: mcopy.c common.c report.c + $(CC) $(CFLAGS) -o $@ $^ diff --git a/README.md b/README.md new file mode 100644 index 0000000..6728a0c --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +All source code is Public Domain. + +## Obtain the source code + + git clone https://git.candlhat.org/unixfstools.git + +## Building + + BSD: + + Make sure you have gcc and gmake installed then run gmake -f Makefile.unix. + + Linux: + + Make sure you have gcc and make installed then run make -f Makefile.unix. + + macOS: + + Make sure you have xcode command line tools installed then run make -f Makefile.unix. + + Windows: + + Make sure you have mingw installed and the location within your PATH variable then run mingw32-make.exe -f Makefile.w32. diff --git a/common.c b/common.c new file mode 100644 index 0000000..15f3d72 --- /dev/null +++ b/common.c @@ -0,0 +1,404 @@ +/****************************************************************************** + * @file common.c + *****************************************************************************/ +#include +#include +#include + +#include "common.h" +#include "inode.h" +#include "report.h" + +/*static char umap[MAX_INIT / 8] = { 0 };*/ + +unsigned long next_inode = 0; +unsigned long next_zone = 0; + +unsigned long offset = 0; + +char *program_name = 0; +char *outfile = 0; + +char buffer[BLOCK_SIZE] = { 0 }; + +unsigned long inode_offset = 0; +unsigned long zone_shift = 0; +unsigned long zone_size = 0; + +unsigned long zone_off = 0; +unsigned long zone_map = 0; + +unsigned long ninodes = 0; +unsigned long nzones = 0; + +/*static int read_and_set (int n) { + + int w, s, mask, r; + + w = n / 8; + s = n % 8; + + mask = 1 << s; + + r = (umap[w] & mask) ? 1 : 0; + umap[w] |= mask; + + return r; + +}*/ + +int seekto (FILE *fp, unsigned long sector) { + return fseek (fp, (offset + sector) * SECTOR_SIZE, SEEK_SET); +} + + +extern int alloc_zone (FILE *fp); + +void add_zone (FILE *fp, int n, int z, unsigned long bytes, unsigned long curr_time) { + + struct inode *p, inode[INODES_PER_BLOCK]; + + unsigned long b, off, blk[NR_INDIRECTS], indir, i; + unsigned long i_size, zone; + + b = ((n - 1) / INODES_PER_BLOCK) + inode_offset; + + memset (inode, 0, sizeof (inode)); + get_block (fp, b, inode); + + off = (n - 1) % INODES_PER_BLOCK; + + p = &inode[off]; + + i_size = ((unsigned long) p->i_size[0]) | (((unsigned long) p->i_size[1]) << 8) | (((unsigned long) p->i_size[2]) << 16) | (((unsigned long) p->i_size[3]) << 24); + i_size += bytes; + + write_to_byte_array (p->i_size, i_size, 4); + write_to_byte_array (p->i_mod_time, curr_time, 4); + + for (i = 0; i < NR_DZONE_NUM * 2; i += 2) { + + zone = ((unsigned long) p->i_zone[i]) | (((unsigned long) p->i_zone[i + 1]) << 8); + + if (!zone) { + + write_to_byte_array (p->i_zone + i, z, 2); + + put_block (fp, b, inode); + return; + + } + + } + + put_block (fp, b, inode); + zone = ((unsigned long) p->i_zone[NR_DZONE_NUM * 2]) | (((unsigned long) p->i_zone[(NR_DZONE_NUM * 2) + 1]) << 8); + + if (!zone) { + + zone = alloc_zone (fp); + write_to_byte_array (p->i_zone + (NR_DZONE_NUM * 2), zone, 2); + + } + + indir = zone; + put_block (fp, b, inode); + + b = indir << zone_shift; + + memset (blk, 0, sizeof (blk)); + get_block (fp, b, blk); + + for (i = 0; i < NR_INDIRECTS; i++) { + + if (!blk[i]) { + + blk[i] = z; + + put_block (fp, b, blk); + return; + + } + + } + + report_at (program_name, 0, REPORT_ERROR, "file has grown beyond single indirect"); + exit (EXIT_FAILURE); + +} + +void enter_dir (FILE *fp, int parent, char *name, int child) { + + struct dirent de[NR_DIR_ENTRIES]; + + unsigned long i, j, k, l, b, off; + unsigned long zone; + + struct inode ino[INODES_PER_BLOCK]; + char *p1, *p2; + + b = ((parent - 1) / INODES_PER_BLOCK) + inode_offset; + + memset (ino, 0, sizeof (ino)); + get_block (fp, b, ino); + + off = (parent - 1) % INODES_PER_BLOCK; + + for (k = 0; k < NR_DZONE_NUM * 2; k += 2) { + + struct inode inode = ino[off]; + zone = ((unsigned long) inode.i_zone[k]) | (((unsigned long) inode.i_zone[k + 1]) << 8); + + if (zone == 0) { + + zone = alloc_zone (fp); + write_to_byte_array (inode.i_zone, zone, 2); + + } + + for (l = 0; l < zone_size; l++) { + + memset (de, 0, sizeof (de)); + get_block (fp, (zone << zone_shift) + l, de); + + for (i = 0; i < NR_DIR_ENTRIES; i++) { + + unsigned long inum = ((unsigned long) de[i].d_inum[0]) | (((unsigned long) de[i].d_inum[1]) << 8); + + if (!inum) { + + write_to_byte_array (de[i].d_inum, child, 2); + + p1 = de[i].d_name; + p2 = name; + + j = 14; + + while (j--) { + + *p1++ = *p2; + + if (*p2 != 0) { + p2++; + } + + } + + put_block (fp, (zone << zone_shift) + l, de); + put_block (fp, b, ino); + + return; + + } + + } + + } + + } + + report_at (program_name, 0, REPORT_ERROR, "directory inode %d beyond direct blocks. could not enter %s", parent, name); + exit (EXIT_FAILURE); + +} + +void get_block (FILE *fp, int n, void *buf) { + + int k; + + /*if (read_and_set (n) == 0) { + + memset (buf, 0, BLOCK_SIZE); + return; + + }*/ + + seekto (fp, n * 2); + + if ((k = fread (buf, BLOCK_SIZE, 1, fp)) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", outfile); + exit (EXIT_FAILURE); + + } + +} + +void incr_link (FILE *fp, int n) { + + struct inode inode[INODES_PER_BLOCK]; + int b, off; + + b = ((n - 1) / INODES_PER_BLOCK) + inode_offset; + + memset (inode, 0, sizeof (inode)); + get_block (fp, b, inode); + + off = (n - 1) % INODES_PER_BLOCK; + + inode[off].i_nlinks++; + put_block (fp, b, inode); + +} + +void incr_size (FILE *fp, int n, unsigned long count) { + + struct inode inode[INODES_PER_BLOCK]; + + unsigned long size; + int b, off; + + b = ((n - 1) / INODES_PER_BLOCK) + inode_offset; + + memset (inode, 0, sizeof (inode)); + get_block (fp, b, inode); + + off = (n - 1) % INODES_PER_BLOCK; + + size = ((unsigned long) inode[off].i_size[0]) | (((unsigned long) inode[off].i_size[1]) << 8); + size += count; + + write_to_byte_array (inode[off].i_size, size, 2); + put_block (fp, b, inode); + +} + + +int get_bit (FILE *fp, unsigned long block, int bit) { + + int w, s; + + memset (buffer, 0, sizeof (buffer)); + get_block (fp, block, buffer); + + w = bit / (8 * sizeof (unsigned short)); + s = bit % (8 * sizeof (unsigned short)); + + return (buffer[w] & (1 << s)); + +} + +void insert_bit (FILE *fp, unsigned long block, int bit) { + + int w, s; + + memset (buffer, 0, sizeof (buffer)); + get_block (fp, block, buffer); + + w = bit / (8 * sizeof (unsigned short)); + s = bit % (8 * sizeof (unsigned short)); + + buffer[w] |= (1 << s); + put_block (fp, block, buffer); + +} + +int mode_con (char *p) { + + unsigned long o1, o2, o3; + + char c1, c2, c3; + 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; + +} + +void put_block (FILE *fp, int n, void *buf) { + + /*if (read_and_set (n) == 0) { + + memset (buf, 0, BLOCK_SIZE); + return; + + }*/ + + seekto (fp, n * 2); + + if (fwrite (buf, BLOCK_SIZE, 1, fp) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst writing to '%s'", outfile); + exit (EXIT_FAILURE); + + } + +} + +void write_to_byte_array (unsigned char *arr, unsigned long value, int size) { + + int i; + + for (i = 0; i < size; i++) { + arr[i] = (value >> (8 * i)) & 0xff; + } + +} + + +char *xstrdup (const char *str) { + + char *ptr = xmalloc (strlen (str) + 1); + strcpy (ptr, str); + + return ptr; + +} + +void *xmalloc (unsigned long size) { + + void *ptr = malloc (size); + + if (ptr == NULL && size) { + + report_at (program_name, 0, REPORT_ERROR, "memory full (malloc)"); + exit (EXIT_FAILURE); + + } + + memset (ptr, 0, size); + return ptr; + +} + +void *xrealloc (void *ptr, unsigned long size) { + + void *new_ptr = realloc (ptr, size); + + if (new_ptr == NULL && size) { + + report_at (program_name, 0, REPORT_ERROR, "memory full (realloc)"); + exit (EXIT_FAILURE); + + } + + return new_ptr; + +} diff --git a/common.h b/common.h new file mode 100644 index 0000000..f22c23e --- /dev/null +++ b/common.h @@ -0,0 +1,68 @@ +/****************************************************************************** + * @file common.h + *****************************************************************************/ +#ifndef _COMMON_H +#define _COMMON_H + +#include + +extern unsigned long offset; + +extern char *outfile; +extern char *program_name; + +int seekto (FILE *fp, unsigned long sector); + +char *xstrdup (const char *str); +void *xmalloc (unsigned long size); +void *xrealloc (void *ptr, unsigned long size); + +void write_to_byte_array (unsigned char *arr, unsigned long value, int size); + +#define SECTOR_SIZE 0x0200 +#define BLOCK_SIZE 0x0400 + +#define N_BLOCKS (1024L * 1024L) +#define N_BLOCKS16 (128L * 1024L) + +#define MAX_INIT (sizeof (char *) == 2 ? N_BLOCKS16 : N_BLOCKS) + +#define NR_INDIRECTS (BLOCK_SIZE / sizeof (unsigned short)) +#define NR_DZONE_NUM (NR_ZONE_NUMS - 2) + +extern char buffer[BLOCK_SIZE]; + +void get_block (FILE *fp, int n, void *buf); +void put_block (FILE *fp, int n, void *buf); + +void add_zone (FILE *fp, int n, int z, unsigned long bytes, unsigned long curr_time); +void enter_dir (FILE *fp, int parent, char *name, int child); + +void incr_size (FILE *fp, int n, unsigned long count); +void incr_link (FILE *fp, int n); + +int get_bit (FILE *fp, unsigned long block, int bit); +void insert_bit (FILE *fp, unsigned long block, int bit); + +int mode_con (char *p); + +struct dirent { + + unsigned char d_inum[2]; + char d_name[14]; + +}; + +#define NR_DIR_ENTRIES (BLOCK_SIZE / sizeof (struct dirent)) + +extern unsigned long ninodes; +extern unsigned long nzones; + +extern unsigned long inode_offset; +extern unsigned long zone_shift; +extern unsigned long zone_size; + +extern unsigned long zone_off; +extern unsigned long zone_map; + +#endif /* _COMMON_H */ diff --git a/inode.h b/inode.h new file mode 100644 index 0000000..6caf1aa --- /dev/null +++ b/inode.h @@ -0,0 +1,27 @@ +/****************************************************************************** + * @file inode.h + *****************************************************************************/ +#ifndef _INODE_H +#define _INODE_H + +#define NR_ZONE_NUMS 9 + +struct inode { + + unsigned char i_mode[2]; + unsigned char uid[2]; + + unsigned char i_size[4]; + unsigned char i_mod_time[4]; + + unsigned char gid; + unsigned char i_nlinks; + + unsigned char i_zone[2 * NR_ZONE_NUMS]; + +}; + +#define INODES_PER_BLOCK (BLOCK_SIZE / sizeof (struct inode)) +#define INODE_MAP 2 + +#endif /* _INODE_H */ diff --git a/mcopy.c b/mcopy.c new file mode 100644 index 0000000..fd0d3da --- /dev/null +++ b/mcopy.c @@ -0,0 +1,590 @@ +/****************************************************************************** + * @file mcopy.c + *****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "inode.h" +#include "report.h" +#include "super.h" + +static char *mode = 0; +static char *root = 0; + +#define OPTION_INPUT 0x0001 +#define OPTION_HELP 0x0002 +#define OPTION_MODE 0x0003 +#define OPTION_OFFSET 0x0004 +#define OPTION_ROOT 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 }, + + { "--help", OPTION_HELP, OPTION_NO_ARG }, + { "--mode", OPTION_MODE, OPTION_HAS_ARG }, + { "--offset", OPTION_OFFSET, OPTION_HAS_ARG }, + { "--root", OPTION_ROOT, OPTION_HAS_ARG }, + + { 0, 0, 0 } + +}; + +static char **files = 0; +static long nb_files = 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] dirname\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 (&files, &nb_files, 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_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); + + } + + fprintf (stderr, "%p: %s\n", mode, mode + 3); + 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; + + } + + case OPTION_ROOT: { + + if (root) { + free (root); + } + + root = xstrdup (optarg); + break; + + } + + default: { + + report_at (program_name, 0, REPORT_ERROR, "unsupported option '%s'", r); + exit (EXIT_FAILURE); + + } + + } + + } + +} + +static char buf[BLOCK_SIZE] = { 0 }; +static FILE *ofp = NULL; + +static void cleanup (void) { + + if (ofp != NULL) { + fclose (ofp); + } + +} + +static unsigned long first_data_zone = 0; +static unsigned long first_inode = 1; + +static int alloc_inode (FILE *fp, int mode, int userid, int groupid) { + + struct inode inode[INODES_PER_BLOCK]; + unsigned long int num, b, off; + + for (num = first_inode; num < ninodes; num++) { + + if (!get_bit (fp, INODE_MAP, num)) { + + b = ((num - 1) / INODES_PER_BLOCK) + inode_offset; + + memset (inode, 0, sizeof (inode)); + get_block (fp, b, inode); + + off = (num - 1) % INODES_PER_BLOCK; + + write_to_byte_array (inode[off].i_mode, mode, 2); + write_to_byte_array (inode[off].uid, userid, 2); + + inode[off].gid = groupid; + put_block (fp, b, inode); + + insert_bit (fp, INODE_MAP, num); + return num; + + } + + } + + report_at (program_name, 0, REPORT_ERROR, "file system does not have enough inodes"); + exit (EXIT_FAILURE); + +} + +int alloc_zone (FILE *fp) { + + unsigned long b, z, i; + + for (z = first_data_zone; z < nzones; z++) { + + if (!get_bit (ofp, zone_map, z - zone_off)) { + + b = z << zone_shift; + + if ((b + zone_size) > nzones) { + goto _zone_error; + } + + memset (buf, 0, BLOCK_SIZE); + + for (i = 0; i < zone_size; i++) { + put_block (fp, b + i, buf); + } + + insert_bit (fp, zone_map, z - zone_off); + return z; + + } + + } + +_zone_error: + + report_at (program_name, 0, REPORT_ERROR, "file system not big enough for all files"); + exit (EXIT_FAILURE); + +} + +static int find_entry (int ino, char *name) { + + struct inode inode[INODES_PER_BLOCK], *p; + struct dirent de[NR_DIR_ENTRIES]; + + unsigned long b, off, i, j, zone; + unsigned long mode; + + b = ((ino - 1) / INODES_PER_BLOCK) + inode_offset; + off = (ino - 1) % INODES_PER_BLOCK; + + memset (inode, 0, sizeof (inode)); + get_block (ofp, b, inode); + + p = &inode[off]; + mode = ((unsigned long) p->i_mode[0]) | (((unsigned long) p->i_mode[1]) << 8); + + if ((mode & 0170000) != 0040000) { + return 0; + } + + for (i = 0; i < NR_DZONE_NUM * 2; i += 2) { + + zone = ((unsigned long) p->i_zone[i]) | (((unsigned long) p->i_zone[1]) << 8); + + if (!zone) { + continue; + } + + memset (de, 0, sizeof (de)); + get_block (ofp, zone, de); + + for (j = 0; j < NR_DIR_ENTRIES; j++) { + + if (strcmp (de[j].d_name, name) == 0) { + return (((unsigned long) de[j].d_inum[0]) | (((unsigned long) de[j].d_inum[1]) << 8)); + } + + } + + } + + return 0; + +} + +static int walk_path (char *dirname) { + + unsigned long ino = first_inode; + char *p1 = dirname, *p2; + + while (*p1 && *p1 == '/') { + p1++; + } + + if (*p1) { + + for (; (p2 = strchr (p1, '/')); p1 = p2 + 1) { + + *p2 = '\0'; + + if (strlen (p1) >= 14) { + p1[13] = '\0'; + } + + if (!(ino = find_entry (ino, p1))) { + + *p2 = '/'; + + report_at (program_name, 0, REPORT_ERROR, "failed to enter '%s'", dirname); + return 0; + + } + + *p2 = '/'; + + } + + if (!(ino = find_entry (ino, p1))) { + + report_at (program_name, 0, REPORT_ERROR, "failed to enter '%s'", dirname); + return 0; + + } + + } + + return ino; + +} + +static void copy_file (FILE *fp, unsigned long parent, char *fn) { + + unsigned long ino, zone, i; + + unsigned long bytes = 0, written = 0, ct = BLOCK_SIZE; + char *basename = fn, buf[BLOCK_SIZE], *p; + + if ((p = strrchr (fn, '/'))) { + basename = (p + 1); + } + + fseek (fp, 0, SEEK_END); + + bytes = ftell (fp); + fseek (fp, 0, SEEK_SET); + + if (bytes < BLOCK_SIZE) { + ct = bytes; + } + + ino = alloc_inode (ofp, mode_con (mode), 2, 1); + enter_dir (ofp, parent, basename, ino); + + incr_size (ofp, parent, 16L); + incr_link (ofp, ino); + + do { + + for (i = 0, written = 0; i < zone_size; i++, written += ct) { + + memset (buf, 0, sizeof (buf)); + + if ((ct = fread (buf, 1, (bytes > BLOCK_SIZE) ? BLOCK_SIZE : bytes, fp)) > 0) { + + if (i == 0) { + zone = alloc_zone (ofp); + } + + put_block (ofp, (zone << zone_shift) + i, buf); + bytes -= ct; + + } + + } + + if (ct) { add_zone (ofp, ino, zone, written, time (0)); } + + } while (ct == BLOCK_SIZE); + +} + +int main (int argc, char **argv) { + + struct super_block sup = { 0 }; + + unsigned long parent_ino = first_inode; + unsigned long s_imap_blocks, s_zmap_blocks; + + FILE *fp = NULL; + long i; + + 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, 2); + + 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 (sup.s_magic[0] != (SUPER_MAGIC & 0xff) || sup.s_magic[1] != ((SUPER_MAGIC >> 8) & 0xff)) { + + report_at (program_name, 0, REPORT_ERROR, "'%s' has a unsupported file system", outfile); + exit (EXIT_FAILURE); + + } + + ninodes = ((unsigned long) sup.s_ninodes[0]) | (((unsigned long) sup.s_ninodes[1]) << 8); + nzones = ((unsigned long) sup.s_nzones[0]) | (((unsigned long) sup.s_nzones[1]) << 8); + + s_imap_blocks = ((unsigned long) sup.s_imap_blocks[0]) | (((unsigned long) sup.s_imap_blocks[1]) << 8); + s_zmap_blocks = ((unsigned long) sup.s_zmap_blocks[0]) | (((unsigned long) sup.s_zmap_blocks[1]) << 8); + + first_data_zone = ((unsigned long) sup.s_first_data_zone[0]) | (((unsigned long) sup.s_first_data_zone[1]) << 8); + inode_offset = s_imap_blocks + s_zmap_blocks + 2; + + zone_shift = ((unsigned long) sup.s_log_zone_size[0]) | (((unsigned long) sup.s_log_zone_size[1]) << 8); + zone_size = 1 << zone_shift; + + zone_map = INODE_MAP + s_imap_blocks; + zone_off = first_data_zone - 1; + + if (root) { + + if (!(parent_ino = walk_path (root))) { + return EXIT_FAILURE; + } + + } + + for (i = 0; i < nb_files; i++) { + + if ((fp = fopen (files[i], "rb")) == NULL) { + + report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for reading", files[i]); + continue; + + } + + copy_file (fp, parent_ino, files[i]); + fclose (fp); + + } + + return EXIT_SUCCESS; + +} diff --git a/mkfs.c b/mkfs.c new file mode 100644 index 0000000..3b52588 --- /dev/null +++ b/mkfs.c @@ -0,0 +1,598 @@ +/****************************************************************************** + * @file mkfs.c + *****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "inode.h" +#include "report.h" +#include "super.h" + +static unsigned long sectors = 0; +static char *boot_sector = 0; + +#define OPTION_BOOT 0x0001 +#define OPTION_HELP 0x0002 +#define OPTION_OFFSET 0x0003 +#define OPTION_SECTORS 0x0004 +#define OPTION_VERBOSE 0x0005 + +struct option { + + const char *name; + int index, flags; + +}; + +#define OPTION_NO_ARG 0x0001 +#define OPTION_HAS_ARG 0x0002 + +static struct option opts[] = { + + { "--boot", OPTION_BOOT, OPTION_HAS_ARG }, + { "--help", OPTION_HELP, OPTION_NO_ARG }, + { "--offset", OPTION_OFFSET, OPTION_HAS_ARG }, + { "--sectors", OPTION_SECTORS, OPTION_HAS_ARG }, + + { 0, 0, 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] outfile\n\n", program_name); + fprintf (stderr, "Options:\n\n"); + + fprintf (stderr, " --boot FILE Use FILE as the boot sector.\n"); + fprintf (stderr, " --help Show this help information then exit.\n"); + fprintf (stderr, " --offset SECTOR Write the filesystem starting at SECTOR.\n"); + fprintf (stderr, " --sectors COUNT Make the filesystem the size of COUNT * 512.\n"); + + } + + exit (EXIT_SUCCESS); + +} + +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') { + + if (outfile) { + + report_at (program_name, 0, REPORT_ERROR, "multiple output files provided"); + exit (EXIT_FAILURE); + + } + + outfile = 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_BOOT: { + + if (boot_sector) { free (boot_sector); } + + boot_sector = xstrdup (optarg); + break; + + } + + case OPTION_HELP: { + + print_help (); + break; + + } + + case OPTION_OFFSET: { + + char *temp; + long conversion; + + errno = 0; + conversion = strtol (optarg, &temp, 0); + + if (!*optarg || isspace ((int) *optarg) || *temp || errno) { + + report_at (program_name, 0, REPORT_ERROR, "bad number for offset"); + 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; + + } + + case OPTION_SECTORS: { + + 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 sectors count"); + exit (EXIT_FAILURE); + + } + + if (conversion < 0) { + + report_at (program_name, 0, REPORT_ERROR, "sectors count must be greater than zero"); + exit (EXIT_FAILURE); + + } + + sectors = conversion; + break; + + } + + default: { + + report_at (program_name, 0, REPORT_ERROR, "unsupported option '%s'", r); + exit (EXIT_FAILURE); + + } + + } + + } + +} + + +static char buf[BLOCK_SIZE] = { 0 }; + +static unsigned long next_inode = 0; +static unsigned long next_zone = 0; + +static int alloc_inode (FILE *fp, int mode, int userid, int groupid) { + + struct inode inode[INODES_PER_BLOCK]; + unsigned long int num, b, off; + + if ((num = next_inode++) >= ninodes) { + + report_at (program_name, 0, REPORT_ERROR, "file system does not have enough inodes"); + exit (EXIT_FAILURE); + + } + + b = ((num - 1) / INODES_PER_BLOCK) + inode_offset; + + memset (inode, 0, sizeof (inode)); + get_block (fp, b, inode); + + off = (num - 1) % INODES_PER_BLOCK; + + write_to_byte_array (inode[off].i_mode, mode, 2); + write_to_byte_array (inode[off].uid, userid, 2); + + inode[off].gid = groupid; + put_block (fp, b, inode); + + insert_bit (fp, INODE_MAP, num); + return num; + +} + +int alloc_zone (FILE *fp) { + + unsigned long b, z, i; + + z = next_zone++; + b = z << zone_shift; + + if ((b + zone_size) > nzones) { + + report_at (program_name, 0, REPORT_ERROR, "file system not big enough for all files"); + exit (EXIT_FAILURE); + + } + + memset (buf, 0, BLOCK_SIZE); + + for (i = 0; i < zone_size; i++) { + put_block (fp, b + i, buf); + } + + insert_bit (fp, zone_map, z - zone_off); + return z; + +} + +#define BIT_MAP_SHIFT 13 + +static unsigned long reserved_sectors = 4; +static FILE *ofp = NULL; + +static void wipe_sectors (unsigned long start, unsigned long end) { + + unsigned long i; + seekto (ofp, start); + + memset (buf, 0, BLOCK_SIZE); + + for (i = start; i < end; i++) { + + if (fwrite (buf, SECTOR_SIZE, 1, ofp) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst writing blank sector"); + exit (EXIT_FAILURE); + + } + + } + + seekto (ofp, start); + +} + +static int bitmapsize (int bits) { + + int nr_blocks = (bits >> BIT_MAP_SHIFT); + + if ((nr_blocks << BIT_MAP_SHIFT) < bits) { + nr_blocks++; + } + + return nr_blocks; + +} + +static void super (unsigned long zones, unsigned long inodes) { + + unsigned long inode_blocks, init_blocks; + unsigned long s_imap_blocks, s_zmap_blocks, s_first_data_zone; + + unsigned long zo; + + struct super_block *sup; + memset (buf, 0, BLOCK_SIZE); + + sup = (struct super_block *) buf; + + write_to_byte_array (sup->s_ninodes, inodes, 2); + write_to_byte_array (sup->s_nzones, zones, 2); + + s_imap_blocks = bitmapsize (1 + inodes); + s_zmap_blocks = bitmapsize (zones); + + write_to_byte_array (sup->s_imap_blocks, s_imap_blocks, 2); + write_to_byte_array (sup->s_zmap_blocks, s_zmap_blocks, 2); + + inode_blocks = (inodes + INODES_PER_BLOCK - 1) / INODES_PER_BLOCK; + inode_offset = s_imap_blocks + s_zmap_blocks + 2; + + init_blocks = inode_offset + inode_blocks; + + s_first_data_zone = (init_blocks + (1 << zone_shift) - 1) >> zone_shift; + write_to_byte_array (sup->s_first_data_zone, s_first_data_zone, 2); + + write_to_byte_array (sup->s_log_zone_size, zone_shift, 2); + write_to_byte_array (sup->s_magic, SUPER_MAGIC, 2); + + zo = 7L + NR_INDIRECTS + (NR_INDIRECTS * NR_INDIRECTS); + write_to_byte_array (sup->s_max_size, zo, 4); + + seekto (ofp, 2); + + if (fwrite (buf, BLOCK_SIZE, 1, ofp) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst writing super block"); + exit (EXIT_FAILURE); + + } + + wipe_sectors (4, init_blocks * 2); + + next_zone = s_first_data_zone; + next_inode = 1; + + zone_map = INODE_MAP + s_imap_blocks; + + insert_bit (ofp, zone_map, 0); + insert_bit (ofp, INODE_MAP, 0); + + zone_size = 1 << zone_shift; + zone_off = s_first_data_zone - 1; + +} + +static void rootdir (int inode) { + + add_zone (ofp, inode, alloc_zone (ofp), 32L, time (0)); + + enter_dir (ofp, inode, ".", inode); + enter_dir (ofp, inode, "..", inode); + + incr_link (ofp, inode); + incr_link (ofp, inode); + +} + +static void cleanup (void) { + + if (ofp != NULL) { fclose (ofp); } + + if (get_error_count () > 0) { + remove (outfile); + } + +} + +int main (int argc, char **argv) { + + unsigned long image_size = 0; + + if (argc && *argv) { + + char *p; + program_name = *argv; + + if ((p = strrchr (program_name, '/')) || (p = strrchr (program_name, '\\'))) { + program_name = (p + 1); + } + + } + + atexit (cleanup); + parse_args (argc, argv, 1); + + if (!outfile) { + + report_at (program_name, 0, REPORT_ERROR, "no output file provided"); + return EXIT_FAILURE; + + } + + image_size = sectors * SECTOR_SIZE; + + if ((nzones = image_size / BLOCK_SIZE) < 5) { + + report_at (program_name, 0, REPORT_ERROR, "block count too small"); + return EXIT_FAILURE; + + } + + if (nzones > N_BLOCKS) { + nzones = N_BLOCKS; + } + + ninodes = nzones / 3; + + if (nzones >= 20000) { + ninodes = nzones / 4; + } + + if (nzones >= 40000) { + ninodes = nzones / 5; + } + + if (nzones >= 60000) { + ninodes = nzones / 6; + } + + if (nzones >= 80000) { + ninodes = nzones / 7; + } + + if (nzones >= 100000) { + ninodes = nzones / 8; + } + + ninodes += INODES_PER_BLOCK; + ninodes = (ninodes / INODES_PER_BLOCK) * INODES_PER_BLOCK; + + if (ninodes < 1) { + + report_at (program_name, 0, REPORT_ERROR, "inode count too small"); + return EXIT_FAILURE; + + } + + if (ninodes >= USHRT_MAX) { + ninodes = USHRT_MAX; + } + + image_size += offset * SECTOR_SIZE; + + if ((ofp = fopen (outfile, "r+b")) == NULL) { + + unsigned long len; + + if ((ofp = fopen (outfile, "w+b")) == NULL) { + + report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", outfile); + return EXIT_FAILURE; + + } + + len = image_size; + + while (len > 0) { + + if (fwrite (buf, SECTOR_SIZE, 1, ofp) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst writing '%s'", outfile); + return EXIT_FAILURE; + + } + + len -= SECTOR_SIZE; + + } + + } + + seekto (ofp, 0); + + if (offset * SECTOR_SIZE > image_size) { + + report_at (program_name, 0, REPORT_ERROR, "size (%lu) of %s is less than the requested offset (%lu)", image_size, outfile, offset * SECTOR_SIZE); + return EXIT_FAILURE; + + } + + image_size -= offset * SECTOR_SIZE; + + if (sectors) { + + if (sectors * SECTOR_SIZE > image_size) { + + report_at (program_name, 0, REPORT_ERROR, "size (%lu) of %s is less than the requested size (%lu)", image_size, outfile, sectors * SECTOR_SIZE); + return EXIT_FAILURE; + + } + + } + + wipe_sectors (0, reserved_sectors); + + if (boot_sector) { + + unsigned long bytes; + FILE *ifp; + + if ((ifp = fopen (boot_sector, "rb")) == NULL) { + + report_at (program_name, 0, REPORT_ERROR, "unable to open %s", boot_sector); + exit (EXIT_FAILURE); + + } + + fseek (ifp, 0, SEEK_END); + + if ((bytes = ftell (ifp)) > BLOCK_SIZE) { + + report_at (program_name, 0, REPORT_ERROR, "boot sector must not exceed 1024 bytes in size"); + + fclose (ifp); + exit (EXIT_FAILURE); + + } + + fseek (ifp, 0, SEEK_SET); + + if (fread (buf, bytes, 1, ifp) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "failed to read %s", boot_sector); + + fclose (ifp); + exit (EXIT_FAILURE); + + } + + fclose (ifp); + + if (fwrite (buf, BLOCK_SIZE, 1, ofp) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "to write boot sector to %s", outfile); + exit (EXIT_FAILURE); + + } + + } + + super (nzones, ninodes); + + rootdir (alloc_inode (ofp, 040777, 2, 2)); + return EXIT_SUCCESS; + +} diff --git a/mls.c b/mls.c new file mode 100644 index 0000000..2b6c960 --- /dev/null +++ b/mls.c @@ -0,0 +1,668 @@ +/****************************************************************************** + * @file mls.c + *****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include + +#include "inode.h" +#include "report.h" +#include "super.h" + +static const char *program_name = 0; +static char *filename = 0; + +#define SECTOR_SIZE 0x0200 +#define BLOCK_SIZE 0x0400 + +struct dirent { + + unsigned char d_inum[2]; + char d_name[14]; + +}; + +#define NR_DIR_ENTRIES (BLOCK_SIZE / sizeof (struct dirent)) +#define NR_DZONE_NUM (NR_ZONE_NUMS - 2) + +unsigned long offset = 0; + +#define OPTION_INPUT 0x0001 +#define OPTION_HELP 0x0002 +#define OPTION_OFFSET 0x0003 + +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 }, + + { "--help", OPTION_HELP, OPTION_NO_ARG }, + { "--offset", OPTION_OFFSET, OPTION_HAS_ARG }, + + { 0, 0, 0 } + +}; + +static char **entries = 0; +static long nb_entries = 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] dirname\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 Print the filesystem starting at SECTOR.\n"); + + } + + exit (EXIT_SUCCESS); + +} + +static void *xmalloc (unsigned long size) { + + void *ptr = malloc (size); + + if (ptr == NULL && size) { + + report_at (program_name, 0, REPORT_ERROR, "memory full (malloc)"); + exit (EXIT_FAILURE); + + } + + memset (ptr, 0, size); + return ptr; + +} + +static void *xrealloc (void *ptr, unsigned long size) { + + void *new_ptr = realloc (ptr, size); + + if (new_ptr == NULL && size) { + + report_at (program_name, 0, REPORT_ERROR, "memory full (realloc)"); + exit (EXIT_FAILURE); + + } + + return new_ptr; + +} + +static char *xstrdup (const char *str) { + + char *ptr = xmalloc (strlen (str) + 1); + strcpy (ptr, str); + + return ptr; + +} + +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 (&entries, &nb_entries, 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_HELP: { + + print_help (); + break; + + } + + case OPTION_INPUT: { + + if (filename) { + + report_at (program_name, 0, REPORT_ERROR, "multiple output files provided"); + exit (EXIT_FAILURE); + + } + + filename = xstrdup (optarg); + 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 FILE *ifp = NULL; + +static void cleanup (void) { + + if (ifp != NULL) { + fclose (ifp); + } + +} + +static int seekto (unsigned long sector) { + return fseek (ifp, (offset + sector) * SECTOR_SIZE, SEEK_SET); +} + +static void get_block (int block, void *buf) { + + seekto (block * 2); + + if (fread (buf, BLOCK_SIZE, 1, ifp) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", filename); + exit (EXIT_FAILURE); + + } + +} + +static unsigned long first_inode = 1; +static unsigned long inode_offset = 0; + +static int find_entry (int ino, char *name) { + + struct inode inode[INODES_PER_BLOCK], *p; + struct dirent de[NR_DIR_ENTRIES]; + + unsigned long b, off, i, j, zone; + + b = ((ino - 1) / INODES_PER_BLOCK) + inode_offset; + off = (ino - 1) % INODES_PER_BLOCK; + + memset (inode, 0, sizeof (inode)); + get_block (b, inode); + + p = &inode[off]; + + for (i = 0; i < NR_DZONE_NUM * 2; i += 2) { + + zone = ((unsigned long) p->i_zone[i]) | (((unsigned long) p->i_zone[1]) << 8); + + if (!zone) { + continue; + } + + memset (de, 0, sizeof (de)); + get_block (zone, de); + + for (j = 0; j < NR_DIR_ENTRIES; j++) { + + if (strcmp (de[j].d_name, name) == 0) { + return (((unsigned long) de[j].d_inum[0]) | (((unsigned long) de[j].d_inum[1]) << 8)); + } + + } + + } + + return 0; + +} + +static char *rwx[] = { + + "---", "--x", "-w-", "-wx", + "r--", "r-x", "rw-", "rwx", + "--s", "--s", "-ws", "-ws", + "r-s", "r-s", "rws", "rws" + +}; + +static int walk_dir (char *dirname, int list, int multi) { + + unsigned long ino = first_inode; + char *p1 = dirname, dt[32], *p2, *m1, *m2, *m3, c; + + struct inode inode[INODES_PER_BLOCK], inode2[INODES_PER_BLOCK]; + struct dirent de[NR_DIR_ENTRIES]; + + struct dirent *dep; + struct inode *ip1, *ip2; + + unsigned long block, i, j, mode, uid, size; + long mod_time, m, prot; + + while (*p1 && *p1 == '/') { + p1++; + } + + if (*p1) { + + for (; (p2 = strchr (p1, '/')); p1 = p2 + 1) { + + *p2 = '\0'; + + if (strlen (p1) >= 14) { + p1[13] = '\0'; + } + + if (!(ino = find_entry (ino, p1))) { + + *p2 = '/'; + + if (!list) { + return 1; + } + + } + + *p2 = '/'; + + } + + if (!(ino = find_entry (ino, p1))) { + + if (!list) { + return 2; + } + + + } + + } + + block = ((ino - 1) / INODES_PER_BLOCK) + inode_offset; + + memset (inode, 0, sizeof (inode)); + get_block (block, inode); + + ip1 = &inode[(ino - 1) % INODES_PER_BLOCK]; + mode = ((unsigned long) ip1->i_mode[0]) | (((unsigned long) ip1->i_mode[1]) << 8); + + if ((mode & 0170000) == 0040000) { + + if (list) { + + if (multi) { printf ("%s:\n\n", dirname); } + + for (i = 0; i < NR_DZONE_NUM * 2; i += 2) { + + unsigned long zone = ((unsigned long) ip1->i_zone[i]) | (((unsigned long) ip1->i_zone[i + 1]) << 8); + + if (!zone) { + continue; + } + + memset (de, 0, sizeof (de)); + get_block (zone, de); + + for (j = 0; j < NR_DIR_ENTRIES; j++) { + + unsigned long ino = ((unsigned long) de[j].d_inum[0]) | (((unsigned long) de[j].d_inum[1]) << 8); + + if (!ino) { + continue; + } + + dep = &de[j]; + + if (multi) { + printf (" "); + } + + block = ((ino - 1) / INODES_PER_BLOCK) + inode_offset; + + memset (inode2, 0, sizeof (inode2)); + get_block (block, inode2); + + ip2 = &inode2[(ino - 1) % INODES_PER_BLOCK]; + + mode = ((unsigned long) ip2->i_mode[0]) | (((unsigned long) ip2->i_mode[1]) << 8); + /*printf (" %06lo", mode);*/ + m = (mode & 0170000); + + if (m == 0020000) { + c = 'd'; + } else if (m == 0040000) { + c = 'd'; + } else if (m == 0060000) { + c = 'b'; + } else { + c = '-'; + } + + m = mode & 07777; + prot = (m >> 6) & 07; + + if (m & 0002000) { + prot += 8; + } + + m1 = rwx[prot]; + prot = (m >> 3) & 07; + + if (m & 0002000) { + prot += 8; + } + + m2 = rwx[prot]; + m3 = rwx[m & 07]; + + printf ("%c%s%s%s %2d", c, m1, m2, m3, ip2->i_nlinks); + + size = ((unsigned long) ip2->i_size[0]) | (((unsigned long) ip2->i_size[1]) << 8) | (((unsigned long) ip2->i_size[2]) << 16) | (((unsigned long) ip2->i_size[3]) << 24); + printf (" %10lu", size); + + uid = ((unsigned long) ip2->uid[0]) | (((unsigned long) ip2->uid[1]) << 8); + printf (" %2ld", uid); + + mod_time = ((unsigned long) ip2->i_mod_time[0]) | (((unsigned long) ip2->i_mod_time[1]) << 8) | (((unsigned long) ip2->i_mod_time[2]) << 16) | (((unsigned long) ip2->i_mod_time[3]) << 24); + strftime (dt, sizeof (dt), "%Y-%m-%d %H:%M:%S", localtime (&mod_time)); + /*strftime (dt, sizeof (dt), "%b %d %Y %H:%M:%S", localtime (&mod_time));*/ + + printf (" %2d %s %s\n", ip2->gid, dt, dep->d_name); + + } + + } + + if (multi) {printf ("\n"); } + + } + + return 0; + + } + + mode = ((unsigned long) ip1->i_mode[0]) | (((unsigned long) ip1->i_mode[1]) << 8); + /*printf (" %06lo", mode);*/ + m = (mode & 0170000); + + if (m == 0020000) { + c = 'd'; + } else if (m == 0040000) { + c = 'd'; + } else if (m == 0060000) { + c = 'b'; + } else { + c = '-'; + } + + m = mode & 07777; + prot = (m >> 6) & 07; + + if (m & 0002000) { + prot += 8; + } + + m1 = rwx[prot]; + prot = (m >> 3) & 07; + + if (m & 0002000) { + prot += 8; + } + + m2 = rwx[prot]; + m3 = rwx[m & 07]; + + printf ("%c%s%s%s %2d", c, m1, m2, m3, ip1->i_nlinks); + + size = ((unsigned long) ip1->i_size[0]) | (((unsigned long) ip1->i_size[1]) << 8) | (((unsigned long) ip1->i_size[2]) << 16) | (((unsigned long) ip1->i_size[3]) << 24); + printf (" %10lu", size); + + uid = ((unsigned long) ip1->uid[0]) | (((unsigned long) ip1->uid[1]) << 8); + printf (" %2ld", uid); + + mod_time = ((unsigned long) ip1->i_mod_time[0]) | (((unsigned long) ip1->i_mod_time[1]) << 8) | (((unsigned long) ip1->i_mod_time[2]) << 16) | (((unsigned long) ip1->i_mod_time[3]) << 24); + strftime (dt, sizeof (dt), "%Y-%m-%d %H:%M:%S", localtime (&mod_time)); + + printf (" %2d %s %s\n", ip1->gid, dt, dirname); + return 3; + +} + +int main (int argc, char **argv) { + + struct super_block sup = { 0 }; + + unsigned long s_imap_blocks, s_zmap_blocks; + long multi = 0, i; + + char **found_entries = 0; + long nb_found_entries = 0; + + if (argc && *argv) { + + char *p; + program_name = *argv; + + if ((p = strrchr (program_name, '/')) || (p = strrchr (program_name, '\\'))) { + program_name = (p + 1); + } + + } + + atexit (cleanup); + parse_args (argc, argv, 1); + + if (!filename) { + + report_at (program_name, 0, REPORT_ERROR, "no input file was provided"); + return EXIT_FAILURE; + + } + + if ((ifp = fopen (filename, "rb")) == NULL) { + + report_at (program_name, 0, REPORT_ERROR, "faild to open '%s' for reading", filename); + return EXIT_FAILURE; + + } + + seekto (2); + + if (fread (&sup, sizeof (sup), 1, ifp) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "failed to whilst reading '%s'", filename); + exit (EXIT_FAILURE); + + } + + if (sup.s_magic[0] != (SUPER_MAGIC & 0xff) || sup.s_magic[1] != ((SUPER_MAGIC >> 8) & 0xff)) { + + report_at (program_name, 0, REPORT_ERROR, "'%s' has a unsupported file system", filename); + exit (EXIT_FAILURE); + + } + + s_imap_blocks = ((unsigned long) sup.s_imap_blocks[0]) | (((unsigned long) sup.s_imap_blocks[1]) << 8); + s_zmap_blocks = ((unsigned long) sup.s_zmap_blocks[0]) | (((unsigned long) sup.s_zmap_blocks[1]) << 8); + + inode_offset = s_imap_blocks + s_zmap_blocks + 2; + + for (i = 0; i < nb_entries; i++) { + + int ret = walk_dir (entries[i], 0, 0); + + if (ret == 0 || ret == 3) { + + if (ret == 0) { + dynarray_add (&found_entries, &nb_found_entries, entries[i]); + } + + multi++; + + } else if (ret == 1) { + report_at (program_name, 0, REPORT_ERROR, "unable to enter '%s'", entries[i]); + } else if (ret == 2) { + report_at (program_name, 0, REPORT_ERROR, "unable to list '%s'", entries[i]); + } + + } + + if (multi > 1) { printf ("\n"); } + + for (i = 0; i < nb_found_entries; i++) { + + if (found_entries[i]) { + walk_dir (found_entries[i], 1, multi > 1); + } + + } + + return EXIT_SUCCESS; + +} diff --git a/mmd.c b/mmd.c new file mode 100644 index 0000000..bc2bf92 --- /dev/null +++ b/mmd.c @@ -0,0 +1,497 @@ +/****************************************************************************** + * @file mmd.c + *****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "inode.h" +#include "report.h" +#include "super.h" + +#define OPTION_INPUT 0x0001 +#define OPTION_HELP 0x0002 +#define OPTION_OFFSET 0x0003 + +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 }, + + { "--help", OPTION_HELP, OPTION_NO_ARG }, + { "--offset", OPTION_OFFSET, OPTION_HAS_ARG }, + + { 0, 0, 0 } + +}; + +static char **dirs = 0; +static long nb_dirs = 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] dirname\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 (&dirs, &nb_dirs, 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_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_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 char buf[BLOCK_SIZE] = { 0 }; +static FILE *ofp = NULL; + +static void cleanup (void) { + + if (ofp != NULL) { + fclose (ofp); + } + +} + +static unsigned long first_data_zone = 0; +static unsigned long first_inode = 1; + +static int alloc_inode (FILE *fp, int mode, int userid, int groupid) { + + struct inode inode[INODES_PER_BLOCK]; + unsigned long int num, b, off; + + for (num = first_inode; num < ninodes; num++) { + + if (!get_bit (fp, INODE_MAP, num)) { + + b = ((num - 1) / INODES_PER_BLOCK) + inode_offset; + + memset (inode, 0, sizeof (inode)); + get_block (fp, b, inode); + + off = (num - 1) % INODES_PER_BLOCK; + + write_to_byte_array (inode[off].i_mode, mode, 2); + write_to_byte_array (inode[off].uid, userid, 2); + + inode[off].gid = groupid; + put_block (fp, b, inode); + + insert_bit (fp, INODE_MAP, num); + return num; + + } + + } + + report_at (program_name, 0, REPORT_ERROR, "file system does not have enough inodes"); + exit (EXIT_FAILURE); + +} + +int alloc_zone (FILE *fp) { + + unsigned long b, z, i; + + for (z = first_data_zone; z < nzones; z++) { + + if (!get_bit (ofp, zone_map, z - zone_off)) { + + b = z << zone_shift; + + if ((b + zone_size) > nzones) { + goto _zone_error; + } + + memset (buf, 0, BLOCK_SIZE); + + for (i = 0; i < zone_size; i++) { + put_block (fp, b + i, buf); + } + + insert_bit (fp, zone_map, z - zone_off); + return z; + + } + + } + +_zone_error: + + report_at (program_name, 0, REPORT_ERROR, "file system not big enough for all files"); + exit (EXIT_FAILURE); + +} + +static int find_entry (int ino, char *name) { + + struct inode inode[INODES_PER_BLOCK], *p; + struct dirent de[NR_DIR_ENTRIES]; + + unsigned long b, off, i, j, zone; + unsigned long mode; + + b = ((ino - 1) / INODES_PER_BLOCK) + inode_offset; + off = (ino - 1) % INODES_PER_BLOCK; + + memset (inode, 0, sizeof (inode)); + get_block (ofp, b, inode); + + p = &inode[off]; + mode = ((unsigned long) p->i_mode[0]) | (((unsigned long) p->i_mode[1]) << 8); + + if ((mode & 0170000) != 0040000) { + return 0; + } + + for (i = 0; i < NR_DZONE_NUM * 2; i += 2) { + + zone = ((unsigned long) p->i_zone[i]) | (((unsigned long) p->i_zone[1]) << 8); + + if (!zone) { + continue; + } + + memset (de, 0, sizeof (de)); + get_block (ofp, zone, de); + + for (j = 0; j < NR_DIR_ENTRIES; j++) { + + if (strcmp (de[j].d_name, name) == 0) { + return (((unsigned long) de[j].d_inum[0]) | (((unsigned long) de[j].d_inum[1]) << 8)); + } + + } + + } + + return 0; + +} + +static void walk_dir (char *dirname) { + + unsigned long parent_ino = first_inode; + + char *p1 = dirname, *p2; + int ino; + + while (*p1 && *p1 == '/') { + p1++; + } + + if (*p1) { + + for (; (p2 = strchr (p1, '/')); p1 = p2 + 1) { + + *p2 = '\0'; + + if (strlen (p1) >= 14) { + p1[13] = '\0'; + } + + if (!(parent_ino = find_entry (parent_ino, p1))) { + + *p2 = '/'; + + report_at (program_name, 0, REPORT_ERROR, "failed to enter '%s'", dirname); + return; + + } + + *p2 = '/'; + + } + + if (find_entry (parent_ino, p1)) { + + report_at (program_name, 0, REPORT_ERROR, "'%s' already exists", dirname); + return; + + } + + } + + ino = alloc_inode (ofp, mode_con ("d--755"), 2, 1); + enter_dir (ofp, parent_ino, p1, ino); + + incr_size (ofp, parent_ino, 16L); + incr_link (ofp, ino); + + add_zone (ofp, ino, alloc_zone (ofp), 32L, time (0)); + + enter_dir (ofp, ino, ".", ino); + enter_dir (ofp, ino, "..", parent_ino); + + incr_link (ofp, parent_ino); + incr_link (ofp, ino); + +} + +int main (int argc, char **argv) { + + struct super_block sup = { 0 }; + + unsigned long s_imap_blocks, s_zmap_blocks; + long i; + + if (argc && *argv) { + + char *p; + program_name = *argv; + + if ((p = strrchr (program_name, '/')) || (p = strrchr (program_name, '\\'))) { + program_name = (p + 1); + } + + } + + atexit (cleanup); + 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, 2); + + 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 (sup.s_magic[0] != (SUPER_MAGIC & 0xff) || sup.s_magic[1] != ((SUPER_MAGIC >> 8) & 0xff)) { + + report_at (program_name, 0, REPORT_ERROR, "'%s' has a unsupported file system", outfile); + exit (EXIT_FAILURE); + + } + + ninodes = ((unsigned long) sup.s_ninodes[0]) | (((unsigned long) sup.s_ninodes[1]) << 8); + nzones = ((unsigned long) sup.s_nzones[0]) | (((unsigned long) sup.s_nzones[1]) << 8); + + s_imap_blocks = ((unsigned long) sup.s_imap_blocks[0]) | (((unsigned long) sup.s_imap_blocks[1]) << 8); + s_zmap_blocks = ((unsigned long) sup.s_zmap_blocks[0]) | (((unsigned long) sup.s_zmap_blocks[1]) << 8); + + first_data_zone = ((unsigned long) sup.s_first_data_zone[0]) | (((unsigned long) sup.s_first_data_zone[1]) << 8); + inode_offset = s_imap_blocks + s_zmap_blocks + 2; + + zone_shift = ((unsigned long) sup.s_log_zone_size[0]) | (((unsigned long) sup.s_log_zone_size[1]) << 8); + zone_size = 1 << zone_shift; + + zone_map = INODE_MAP + s_imap_blocks; + zone_off = first_data_zone - 1; + + for (i = 0; i < nb_dirs; i++) { + walk_dir (dirs[i]); + } + + return EXIT_SUCCESS; + +} diff --git a/report.c b/report.c new file mode 100644 index 0000000..8e128ef --- /dev/null +++ b/report.c @@ -0,0 +1,150 @@ +/****************************************************************************** + * @file report.c + *****************************************************************************/ +#include +#include +#include + +#include "report.h" + +unsigned long errors = 0; + +#ifndef __PDOS__ +#if defined (_WIN32) +# include +static int OriginalConsoleColor = -1; +#endif + +static void reset_console_color (void) { + +#if defined (_WIN32) + + HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE); + + if (OriginalConsoleColor == -1) { return; } + + SetConsoleTextAttribute (hStdError, OriginalConsoleColor); + OriginalConsoleColor = -1; + +#else + + fprintf (stderr, "\033[0m"); + +#endif + +} + +static void set_console_color (int color) { + +#if defined (_WIN32) + + HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE); + WORD wColor; + + if (OriginalConsoleColor == -1) { + + CONSOLE_SCREEN_BUFFER_INFO csbi; + + if (!GetConsoleScreenBufferInfo (hStdError, &csbi)) { + return; + } + + OriginalConsoleColor = csbi.wAttributes; + + } + + wColor = (OriginalConsoleColor & 0xF0) + (color & 0xF); + SetConsoleTextAttribute (hStdError, wColor); + +#else + + fprintf (stderr, "\033[%dm", color); + +#endif + +} +#endif + +static void output_message (const char *filename, unsigned long lineno, unsigned long idx, enum report_type type, const char *fmt, va_list ap) { + + if (filename) { + + if (lineno == 0 && idx == 0) { + fprintf (stderr, "%s: ", filename); + } else { + fprintf (stderr, "%s:", filename); + } + + } + + if (lineno > 0) { + + if (idx == 0) { + fprintf (stderr, "%lu: ", lineno); + } else { + fprintf (stderr, "%lu:", lineno); + } + + } + + if (idx > 0) { + fprintf (stderr, "%lu: ", idx); + } + + if (type == REPORT_ERROR || type == REPORT_FATAL_ERROR) { + +#ifndef __PDOS__ + set_console_color (COLOR_ERROR); +#endif + + if (type == REPORT_ERROR) { + fprintf (stderr, "error:"); + } else { + fprintf (stderr, "fatal error:"); + } + + } else if (type == REPORT_INTERNAL_ERROR) { + +#ifndef __PDOS__ + set_console_color (COLOR_INTERNAL_ERROR); +#endif + + fprintf (stderr, "internal error:"); + + } else if (type == REPORT_WARNING) { + +#ifndef __PDOS__ + set_console_color (COLOR_WARNING); +#endif + + fprintf (stderr, "warning:"); + + } + +#ifndef __PDOS__ + reset_console_color (); +#endif + + fprintf (stderr, " "); + vfprintf (stderr, fmt, ap); + fprintf (stderr, "\n"); + + if (type != REPORT_WARNING) { + ++errors; + } + +} + +unsigned long get_error_count (void) { + return errors; +} + +void report_at (const char *filename, unsigned long lineno, enum report_type type, const char *fmt, ...) { + + va_list ap; + + va_start (ap, fmt); + output_message (filename, lineno, 0, type, fmt, ap); + va_end (ap); + +} diff --git a/report.h b/report.h new file mode 100644 index 0000000..8fc8758 --- /dev/null +++ b/report.h @@ -0,0 +1,29 @@ +/****************************************************************************** + * @file report.h + *****************************************************************************/ +#ifndef _REPORT_H +#define _REPORT_H + +enum report_type { + + REPORT_ERROR = 0, + REPORT_FATAL_ERROR, + REPORT_INTERNAL_ERROR, + REPORT_WARNING + +}; + +#if defined (_WIN32) +# define COLOR_ERROR 12 +# define COLOR_WARNING 13 +# define COLOR_INTERNAL_ERROR 19 +#else +# define COLOR_ERROR 91 +# define COLOR_INTERNAL_ERROR 94 +# define COLOR_WARNING 95 +#endif + +unsigned long get_error_count (void); +void report_at (const char *filename, unsigned long line_number, enum report_type type, const char *fmt, ...); + +#endif /* _REPORT_H */ diff --git a/super.h b/super.h new file mode 100644 index 0000000..1473278 --- /dev/null +++ b/super.h @@ -0,0 +1,25 @@ +/****************************************************************************** + * @file super.h + *****************************************************************************/ +#ifndef _SUPER_H +#define _SUPER_H + +struct super_block { + + unsigned char s_ninodes[2]; + unsigned char s_nzones[2]; + + unsigned char s_imap_blocks[2]; + unsigned char s_zmap_blocks[2]; + + unsigned char s_first_data_zone[2]; + unsigned char s_log_zone_size[2]; + + unsigned char s_max_size[4]; + unsigned char s_magic[2]; + +}; + +#define SUPER_MAGIC 0x137F + +#endif /* SUPER_H */ -- 2.34.1