From: Robert Pengelly Date: Sat, 26 Oct 2024 02:25:27 +0000 (+0100) Subject: Initial commit X-Git-Url: https://git.candlhat.org/?a=commitdiff_plain;h=b03a4ebd41af2833d38e3253884949f2241d78e3;p=minixfstools.git Initial commit --- b03a4ebd41af2833d38e3253884949f2241d78e3 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 */