diff options
author | Karel Zak | 2006-12-07 00:27:10 +0100 |
---|---|---|
committer | Karel Zak | 2006-12-07 00:27:10 +0100 |
commit | 19922f22a1f6c4dd27b11f449c4ff86183842303 (patch) | |
tree | 44d3c22adbbfc63f17574734158284abdcdbadf2 /disk-utils | |
parent | Imported from util-linux-2.13-pre4 tarball. (diff) | |
download | kernel-qcow2-util-linux-19922f22a1f6c4dd27b11f449c4ff86183842303.tar.gz kernel-qcow2-util-linux-19922f22a1f6c4dd27b11f449c4ff86183842303.tar.xz kernel-qcow2-util-linux-19922f22a1f6c4dd27b11f449c4ff86183842303.zip |
Imported from util-linux-2.13-pre5 tarball.
Diffstat (limited to 'disk-utils')
-rw-r--r-- | disk-utils/fsck.cramfs.c | 779 | ||||
-rw-r--r-- | disk-utils/mkfs.cramfs.c | 30 |
2 files changed, 449 insertions, 360 deletions
diff --git a/disk-utils/fsck.cramfs.c b/disk-utils/fsck.cramfs.c index d46a56954..68bbf518f 100644 --- a/disk-utils/fsck.cramfs.c +++ b/disk-utils/fsck.cramfs.c @@ -1,7 +1,8 @@ /* * cramfsck - check a cramfs file system * - * Copyright (C) 2000-2001 Transmeta Corporation + * Copyright (C) 2000-2002 Transmeta Corporation + * 2005 Adrian Bunk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,12 +29,16 @@ * 2000/07/11: Daniel Quinlan (file length tests, start at offset 0 or 512, * fsck-compatible exit codes) * 2000/07/15: Daniel Quinlan (initial support for block devices) + * 2002/01/10: Daniel Quinlan (additional checks, test more return codes, + * use read if mmap fails, standardize messages) */ /* compile-time options */ -#define INCLUDE_FS_TESTS /* include cramfs checking and extraction */ +//#define INCLUDE_FS_TESTS /* include cramfs checking and extraction */ +#define _GNU_SOURCE #include <stdio.h> +#include <stdarg.h> #include <unistd.h> #include <dirent.h> #include <stdlib.h> @@ -59,32 +64,34 @@ static const char *progname = "cramfsck"; static int fd; /* ROM image file descriptor */ static char *filename; /* ROM image filename */ -struct cramfs_super *super; /* just find the cramfs superblock once */ +struct cramfs_super super; /* just find the cramfs superblock once */ static int opt_verbose = 0; /* 1 = verbose (-v), 2+ = very verbose (-vv) */ -#ifdef INCLUDE_FS_TESTS -static int opt_extract = 0; /* extract cramfs (-x) */ char *extract_dir = NULL; /* extraction directory (-x) */ -unsigned long start_inode = 1 << 28; /* start of first non-root inode */ -unsigned long end_inode = 0; /* end of the directory structure */ -unsigned long start_data = 1 << 28; /* start of the data (256 MB = max) */ -unsigned long end_data = 0; /* end of the data */ -/* true? cramfs_super < start_inode < end_inode <= start_data <= end_data */ -static uid_t euid; /* effective UID */ +/* Exit codes used by fsck-type programs */ +#define FSCK_OK 0 /* No errors */ +#define FSCK_NONDESTRUCT 1 /* File system errors corrected */ +#define FSCK_REBOOT 2 /* System should be rebooted */ +#define FSCK_UNCORRECTED 4 /* File system errors left uncorrected */ +#define FSCK_ERROR 8 /* Operational error */ +#define FSCK_USAGE 16 /* Usage or syntax error */ +#define FSCK_LIBRARY 128 /* Shared library error */ #define PAD_SIZE 512 -#include <asm/page.h> -#ifdef PAGE_SIZE -#define PAGE_CACHE_SIZE ((int) PAGE_SIZE) -#elif defined __ia64__ -#define PAGE_CACHE_SIZE (16384) -#elif defined __alpha__ -#define PAGE_CACHE_SIZE (8192) -#else -#define PAGE_CACHE_SIZE (4096) -#endif +#ifdef INCLUDE_FS_TESTS + +static int opt_extract = 0; /* extract cramfs (-x) */ + +static uid_t euid; /* effective UID */ + +/* (cramfs_super + start) <= start_dir < end_dir <= start_data <= end_data */ +static unsigned long start_dir = ~0UL; /* start of first non-root inode */ +static unsigned long end_dir = 0; /* end of the directory structure */ +static unsigned long start_data = ~0UL; /* start of the data (256 MB = max) */ +static unsigned long end_data = 0; /* end of the data */ + /* Guarantee access to at least 8kB at a time */ #define ROMBUFFER_BITS 13 @@ -93,12 +100,16 @@ static uid_t euid; /* effective UID */ static char read_buffer[ROMBUFFERSIZE * 2]; static unsigned long read_buffer_block = ~0UL; -/* Uncompressing data structures... */ -static char outbuffer[PAGE_CACHE_SIZE*2]; -z_stream stream; +static z_stream stream; +/* Prototypes */ +static void expand_fs(char *, struct cramfs_inode *); #endif /* INCLUDE_FS_TESTS */ +static char *outbuffer; + +static size_t page_size; + /* Input status of 0 to print help and exit without an error. */ static void usage(int status) { @@ -113,6 +124,157 @@ static void usage(int status) exit(status); } +static void die(int status, int syserr, const char *fmt, ...) +{ + va_list arg_ptr; + int save = errno; + + fflush(0); + va_start(arg_ptr, fmt); + fprintf(stderr, "%s: ", progname); + vfprintf(stderr, fmt, arg_ptr); + if (syserr) { + fprintf(stderr, ": %s", strerror(save)); + } + fprintf(stderr, "\n"); + va_end(arg_ptr); + exit(status); +} + +static void test_super(int *start, size_t *length) { + struct stat st; + + /* find the physical size of the file or block device */ + if (stat(filename, &st) < 0) { + die(FSCK_ERROR, 1, "stat failed: %s", filename); + } + fd = open(filename, O_RDONLY); + if (fd < 0) { + die(FSCK_ERROR, 1, "open failed: %s", filename); + } + if (S_ISBLK(st.st_mode)) { + if (ioctl(fd, BLKGETSIZE, length) < 0) { + die(FSCK_ERROR, 1, "ioctl failed: unable to determine device size: %s", filename); + } + *length = *length * 512; + } + else if (S_ISREG(st.st_mode)) { + *length = st.st_size; + } + else { + die(FSCK_ERROR, 0, "not a block device or file: %s", filename); + } + + if (*length < sizeof(struct cramfs_super)) { + die(FSCK_UNCORRECTED, 0, "file length too short"); + } + + /* find superblock */ + if (read(fd, &super, sizeof(super)) != sizeof(super)) { + die(FSCK_ERROR, 1, "read failed: %s", filename); + } + if (super.magic == CRAMFS_MAGIC) { + *start = 0; + } + else if (*length >= (PAD_SIZE + sizeof(super))) { + lseek(fd, PAD_SIZE, SEEK_SET); + if (read(fd, &super, sizeof(super)) != sizeof(super)) { + die(FSCK_ERROR, 1, "read failed: %s", filename); + } + if (super.magic == CRAMFS_MAGIC) { + *start = PAD_SIZE; + } + } + + /* superblock tests */ + if (super.magic != CRAMFS_MAGIC) { + die(FSCK_UNCORRECTED, 0, "superblock magic not found"); + } + if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) { + die(FSCK_ERROR, 0, "unsupported filesystem features"); + } + if (super.size < page_size) { + die(FSCK_UNCORRECTED, 0, "superblock size (%d) too small", super.size); + } + if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) { + if (super.fsid.files == 0) { + die(FSCK_UNCORRECTED, 0, "zero file count"); + } + if (*length < super.size) { + die(FSCK_UNCORRECTED, 0, "file length too short"); + } + else if (*length > super.size) { + fprintf(stderr, "warning: file extends past end of filesystem\n"); + } + } + else { + fprintf(stderr, "warning: old cramfs format\n"); + } +} + +static void test_crc(int start) +{ + void *buf; + u32 crc; + + if (!(super.flags & CRAMFS_FLAG_FSID_VERSION_2)) { +#ifdef INCLUDE_FS_TESTS + return; +#else /* not INCLUDE_FS_TESTS */ + die(FSCK_USAGE, 0, "unable to test CRC: old cramfs format"); +#endif /* not INCLUDE_FS_TESTS */ + } + + crc = crc32(0L, Z_NULL, 0); + + buf = mmap(NULL, super.size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if (buf == MAP_FAILED) { + buf = mmap(NULL, super.size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (buf != MAP_FAILED) { + lseek(fd, 0, SEEK_SET); + read(fd, buf, super.size); + } + } + if (buf != MAP_FAILED) { + ((struct cramfs_super *) (buf+start))->fsid.crc = crc32(0L, Z_NULL, 0); + crc = crc32(crc, buf+start, super.size-start); + munmap(buf, super.size); + } + else { + int retval; + size_t length = 0; + + buf = malloc(4096); + if (!buf) { + die(FSCK_ERROR, 1, "malloc failed"); + } + lseek(fd, start, SEEK_SET); + for (;;) { + retval = read(fd, buf, 4096); + if (retval < 0) { + die(FSCK_ERROR, 1, "read failed: %s", filename); + } + else if (retval == 0) { + break; + } + if (length == 0) { + ((struct cramfs_super *) buf)->fsid.crc = crc32(0L, Z_NULL, 0); + } + length += retval; + if (length > (super.size-start)) { + crc = crc32(crc, buf, retval - (length - (super.size-start))); + break; + } + crc = crc32(crc, buf, retval); + } + free(buf); + } + + if (crc != super.fsid.crc) { + die(FSCK_UNCORRECTED, 0, "crc error"); + } +} + #ifdef INCLUDE_FS_TESTS static void print_node(char type, struct cramfs_inode *i, char *name) { @@ -148,6 +310,10 @@ static void *romfs_read(unsigned long offset) static struct cramfs_inode *cramfs_iget(struct cramfs_inode * i) { struct cramfs_inode *inode = malloc(sizeof(struct cramfs_inode)); + + if (!inode) { + die(FSCK_ERROR, 1, "malloc failed"); + } *inode = *i; return inode; } @@ -157,29 +323,27 @@ static struct cramfs_inode *iget(unsigned int ino) return cramfs_iget(romfs_read(ino)); } -#if 0 static void iput(struct cramfs_inode *inode) { free(inode); } -#endif /* - * Return the offset of the root directory, - * or 0 if none. + * Return the offset of the root directory */ static struct cramfs_inode *read_super(void) { - unsigned long offset; - - offset = super->root.offset << 2; - if (super->magic != CRAMFS_MAGIC) - return NULL; - if (memcmp(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature)) != 0) - return NULL; - if (offset < sizeof(super)) - return NULL; - return cramfs_iget(&super->root); + unsigned long offset = super.root.offset << 2; + + if (!S_ISDIR(super.root.mode)) + die(FSCK_UNCORRECTED, 0, "root inode is not directory"); + if (!(super.flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) && + ((offset != sizeof(struct cramfs_super)) && + (offset != PAD_SIZE + sizeof(struct cramfs_super)))) + { + die(FSCK_UNCORRECTED, 0, "bad root offset (%lu)", offset); + } + return cramfs_iget(&super.root); } static int uncompress_block(void *src, int len) @@ -190,16 +354,17 @@ static int uncompress_block(void *src, int len) stream.avail_in = len; stream.next_out = (unsigned char *) outbuffer; - stream.avail_out = PAGE_CACHE_SIZE*2; + stream.avail_out = page_size*2; inflateReset(&stream); + if (len > page_size*2) { + die(FSCK_UNCORRECTED, 0, "data block too large"); + } err = inflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { - fprintf(stderr, - _("%s: error %d while decompressing! %p(%d)\n"), - filename, err, src, len); - exit(4); + die(FSCK_UNCORRECTED, 0, "decompression error %p(%d): %s", + zError(err), src, len); } return stream.total_out; } @@ -207,6 +372,51 @@ static int uncompress_block(void *src, int len) #if !HAVE_LCHOWN #define lchown chown #endif +static void do_uncompress(char *path, int fd, unsigned long offset, unsigned long size) +{ + unsigned long curr = offset + 4 * ((size + page_size - 1) / page_size); + + do { + unsigned long out = page_size; + unsigned long next = *(u32 *) romfs_read(offset); + + if (next > end_data) { + end_data = next; + } + + offset += 4; + if (curr == next) { + if (opt_verbose > 1) { + printf(" hole at %ld (%d)\n", curr, page_size); + } + if (size < page_size) + out = size; + memset(outbuffer, 0x00, out); + } + else { + if (opt_verbose > 1) { + printf(" uncompressing block at %ld to %ld (%ld)\n", curr, next, next - curr); + } + out = uncompress_block(romfs_read(curr), next - curr); + } + if (size >= page_size) { + if (out != page_size) { + die(FSCK_UNCORRECTED, 0, "non-block (%ld) bytes", out); + } + } else { + if (out != size) { + die(FSCK_UNCORRECTED, 0, "non-size (%ld vs %ld) bytes", out, size); + } + } + size -= out; + if (opt_extract) { + if (write(fd, outbuffer, out) < 0) { + die(FSCK_ERROR, 1, "write failed: %s", path); + } + } + curr = next; + } while (size); +} static void change_file_status(char *path, struct cramfs_inode *i) { @@ -214,23 +424,114 @@ static void change_file_status(char *path, struct cramfs_inode *i) if (euid == 0) { if (lchown(path, i->uid, i->gid) < 0) { - perror(path); - exit(8); + die(FSCK_ERROR, 1, "lchown failed: %s", path); } if (S_ISLNK(i->mode)) return; if ((S_ISUID | S_ISGID) & i->mode) { if (chmod(path, i->mode) < 0) { - perror(path); - exit(8); + die(FSCK_ERROR, 1, "chown failed: %s", path); } } } if (S_ISLNK(i->mode)) return; if (utime(path, &epoch) < 0) { - perror(path); - exit(8); + die(FSCK_ERROR, 1, "utime failed: %s", path); + } +} + +static void do_directory(char *path, struct cramfs_inode *i) +{ + int pathlen = strlen(path); + int count = i->size; + unsigned long offset = i->offset << 2; + char *newpath = malloc(pathlen + 256); + + if (!newpath) { + die(FSCK_ERROR, 1, "malloc failed"); + } + if (offset == 0 && count != 0) { + die(FSCK_UNCORRECTED, 0, "directory inode has zero offset and non-zero size: %s", path); + } + if (offset != 0 && offset < start_dir) { + start_dir = offset; + } + /* TODO: Do we need to check end_dir for empty case? */ + memcpy(newpath, path, pathlen); + newpath[pathlen] = '/'; + pathlen++; + if (opt_verbose) { + print_node('d', i, path); + } + if (opt_extract) { + if (mkdir(path, i->mode) < 0) { + die(FSCK_ERROR, 1, "mkdir failed: %s", path); + } + change_file_status(path, i); + } + while (count > 0) { + struct cramfs_inode *child = iget(offset); + int size; + int newlen = child->namelen << 2; + + size = sizeof(struct cramfs_inode) + newlen; + count -= size; + + offset += sizeof(struct cramfs_inode); + + memcpy(newpath + pathlen, romfs_read(offset), newlen); + newpath[pathlen + newlen] = 0; + if (newlen == 0) { + die(FSCK_UNCORRECTED, 0, "filename length is zero"); + } + if ((pathlen + newlen) - strlen(newpath) > 3) { + die(FSCK_UNCORRECTED, 0, "bad filename length"); + } + expand_fs(newpath, child); + + offset += newlen; + + if (offset <= start_dir) { + die(FSCK_UNCORRECTED, 0, "bad inode offset"); + } + if (offset > end_dir) { + end_dir = offset; + } + iput(child); /* free(child) */ + } + free(newpath); +} + +static void do_file(char *path, struct cramfs_inode *i) +{ + unsigned long offset = i->offset << 2; + int fd = 0; + + if (offset == 0 && i->size != 0) { + die(FSCK_UNCORRECTED, 0, "file inode has zero offset and non-zero size"); + } + if (i->size == 0 && offset != 0) { + die(FSCK_UNCORRECTED, 0, "file inode has zero size and non-zero offset"); + } + if (offset != 0 && offset < start_data) { + start_data = offset; + } + if (opt_verbose) { + print_node('f', i, path); + } + if (opt_extract) { + fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, i->mode); + if (fd < 0) { + die(FSCK_ERROR, 1, "open failed: %s", path); + } + } + if (i->size) { + do_uncompress(path, fd, offset, i->size); + } + if (opt_extract) { + close(fd); + change_file_status(path, i); } } @@ -241,34 +542,39 @@ static void do_symlink(char *path, struct cramfs_inode *i) unsigned long next = *(u32 *) romfs_read(offset); unsigned long size; + if (offset == 0) { + die(FSCK_UNCORRECTED, 0, "symbolic link has zero offset"); + } + if (i->size == 0) { + die(FSCK_UNCORRECTED, 0, "symbolic link has zero size"); + } + + if (offset < start_data) { + start_data = offset; + } if (next > end_data) { end_data = next; } size = uncompress_block(romfs_read(curr), next - curr); if (size != i->size) { - fprintf(stderr, _("%s: size error in symlink `%s'\n"), - filename, path); - exit(4); + die(FSCK_UNCORRECTED, 0, "size error in symlink: %s", path); } outbuffer[size] = 0; if (opt_verbose) { char *str; - str = malloc(strlen(outbuffer) + strlen(path) + 5); - strcpy(str, path); - strncat(str, " -> ", 4); - strncat(str, outbuffer, size); - + asprintf(&str, "%s -> %s", path, outbuffer); print_node('l', i, str); if (opt_verbose > 1) { - printf(_(" uncompressing block at %ld " - "to %ld (%ld)\n"), - curr, next, next - curr); + printf(" uncompressing block at %ld to %ld (%ld)\n", curr, next, next - curr); } + free(str); } if (opt_extract) { - symlink(outbuffer, path); + if (symlink(outbuffer, path) < 0) { + die(FSCK_ERROR, 1, "symlink failed: %s", path); + } change_file_status(path, i); } } @@ -278,6 +584,9 @@ static void do_special_inode(char *path, struct cramfs_inode *i) dev_t devtype = 0; char type; + if (i->offset) { /* no need to shift offset */ + die(FSCK_UNCORRECTED, 0, "special file has non-zero offset: %s", path); + } if (S_ISCHR(i->mode)) { devtype = i->size; type = 'c'; @@ -286,14 +595,21 @@ static void do_special_inode(char *path, struct cramfs_inode *i) devtype = i->size; type = 'b'; } - else if (S_ISFIFO(i->mode)) + else if (S_ISFIFO(i->mode)) { + if (i->size != 0) { + die(FSCK_UNCORRECTED, 0, "fifo has non-zero size: %s", path); + } type = 'p'; - else if (S_ISSOCK(i->mode)) + } + else if (S_ISSOCK(i->mode)) { + if (i->size != 0) { + die(FSCK_UNCORRECTED, 0, "socket has non-zero size: %s", path); + } type = 's'; + } else { - fprintf(stderr, _("%s: bogus mode on `%s' (%o)\n"), - filename, path, i->mode); - exit(4); + die(FSCK_UNCORRECTED, 0, "bogus mode: %s (%o)", path, i->mode); + return; /* not reached */ } if (opt_verbose) { @@ -302,183 +618,84 @@ static void do_special_inode(char *path, struct cramfs_inode *i) if (opt_extract) { if (mknod(path, i->mode, devtype) < 0) { - perror(path); - exit(8); + die(FSCK_ERROR, 1, "mknod failed: %s", path); } change_file_status(path, i); } } -static void do_uncompress(int fd, unsigned long offset, unsigned long size) +static void expand_fs(char *path, struct cramfs_inode *inode) { - unsigned long curr = offset + 4 * ((size + PAGE_CACHE_SIZE - 1) / PAGE_CACHE_SIZE); - - do { - unsigned long out = PAGE_CACHE_SIZE; - unsigned long next = *(u32 *) romfs_read(offset); - - if (next > end_data) - end_data = next; - - offset += 4; - if (curr == next) { - if (opt_verbose > 1) { - printf(_(" hole at %ld (%d)\n"), - curr, PAGE_CACHE_SIZE); - } - if (size < PAGE_CACHE_SIZE) - out = size; - memset(outbuffer, 0x00, out); - } - else { - if (opt_verbose > 1) { - printf(_(" uncompressing block at %ld " - "to %ld (%ld)\n"), - curr, next, next - curr); - } - out = uncompress_block(romfs_read(curr), next - curr); - } - if (size >= PAGE_CACHE_SIZE) { - if (out != PAGE_CACHE_SIZE) { - fprintf(stderr, - _("%s: Non-block (%ld) bytes\n"), - filename, out); - exit(4); - } - } else { - if (out != size) { - fprintf(stderr, _("%s: Non-size (%ld vs %ld) " - "bytes\n"), - filename, out, size); - exit(4); - } - } - size -= out; - if (opt_extract) { - write(fd, outbuffer, out); - } - curr = next; - } while (size); + if (S_ISDIR(inode->mode)) { + do_directory(path, inode); + } + else if (S_ISREG(inode->mode)) { + do_file(path, inode); + } + else if (S_ISLNK(inode->mode)) { + do_symlink(path, inode); + } + else { + do_special_inode(path, inode); + } } -static void expand_fs(int pathlen, char *path, struct cramfs_inode *inode) +static void test_fs(int start) { - if (S_ISDIR(inode->mode)) { - int count = inode->size; - unsigned long offset = inode->offset << 2; - char *newpath = malloc(pathlen + 256); - - if (count > 0 && offset < start_inode) { - start_inode = offset; - } - /* XXX - need to check end_inode for empty case? */ - memcpy(newpath, path, pathlen); - newpath[pathlen] = '/'; - pathlen++; - if (opt_verbose) { - print_node('d', inode, path); - } - if (opt_extract) { - mkdir(path, inode->mode); - change_file_status(path, inode); - } - while (count > 0) { - struct cramfs_inode *child = iget(offset); - int size; - int newlen = child->namelen << 2; - - size = sizeof(struct cramfs_inode) + newlen; - count -= size; - - offset += sizeof(struct cramfs_inode); - - memcpy(newpath + pathlen, romfs_read(offset), newlen); - newpath[pathlen + newlen] = 0; - if ((pathlen + newlen) - strlen(newpath) > 3) { - fprintf(stderr, - _("%s: invalid cramfs--bad " - "path length\n"), - filename); - exit(4); - } - expand_fs(strlen(newpath), newpath, child); - - offset += newlen; - - if (offset > end_inode) { - end_inode = offset; - } - } - return; - } - if (S_ISREG(inode->mode)) { - int fd = 0; - unsigned long offset = inode->offset << 2; + struct cramfs_inode *root; - if (offset > 0 && offset < start_data) { - start_data = offset; - } - if (opt_verbose) { - print_node('f', inode, path); - } - if (opt_extract) { - fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, inode->mode); - } - if (inode->size) { - do_uncompress(fd, offset, inode->size); + root = read_super(); + umask(0); + euid = geteuid(); + stream.next_in = NULL; + stream.avail_in = 0; + inflateInit(&stream); + expand_fs(extract_dir, root); + inflateEnd(&stream); + if (start_data != ~0UL) { + if (start_data < (sizeof(struct cramfs_super) + start)) { + die(FSCK_UNCORRECTED, 0, "directory data start (%ld) < sizeof(struct cramfs_super) + start (%ld)", start_data, sizeof(struct cramfs_super) + start); } - if (opt_extract) { - close(fd); - change_file_status(path, inode); + if (end_dir != start_data) { + die(FSCK_UNCORRECTED, 0, "directory data end (%ld) != file data start (%ld)", end_dir, start_data); } - return; } - if (S_ISLNK(inode->mode)) { - unsigned long offset = inode->offset << 2; - - if (offset < start_data) { - start_data = offset; + if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) { + if (end_data > super.size) { + die(FSCK_UNCORRECTED, 0, "invalid file data offset"); } - do_symlink(path, inode); - return; - } - else { - do_special_inode(path, inode); - return; } + iput(root); /* free(root) */ } #endif /* INCLUDE_FS_TESTS */ int main(int argc, char **argv) { - void *buf; - size_t length; - struct stat st; - u32 crc_old, crc_new; -#ifdef INCLUDE_FS_TESTS - struct cramfs_inode *root; -#endif /* INCLUDE_FS_TESTS */ int c; /* for getopt */ int start = 0; + size_t length; + + page_size = sysconf(_SC_PAGESIZE); if (argc) progname = argv[0]; + outbuffer = malloc(page_size * 2); + if (!outbuffer) + die(FSCK_ERROR, 1, "failed to allocate outbuffer"); + /* command line options */ while ((c = getopt(argc, argv, "hx:v")) != EOF) { switch (c) { case 'h': - usage(0); + usage(FSCK_OK); case 'x': #ifdef INCLUDE_FS_TESTS opt_extract = 1; - extract_dir = malloc(strlen(optarg) + 1); - strcpy(extract_dir, optarg); + extract_dir = optarg; break; -#else /* not INCLUDE_FS_TESTS */ - fprintf(stderr, _("%s: compiled without -x support\n"), - progname); - exit(16); +#else /* not INCLUDE_FS_TESTS */ + die(FSCK_USAGE, 0, "compiled without -x support"); #endif /* not INCLUDE_FS_TESTS */ case 'v': opt_verbose++; @@ -487,146 +704,18 @@ int main(int argc, char **argv) } if ((argc - optind) != 1) - usage(16); + usage(FSCK_USAGE); filename = argv[optind]; - /* find the physical size of the file or block device */ - if (lstat(filename, &st) < 0) { - perror(filename); - exit(8); - } - fd = open(filename, O_RDONLY); - if (fd < 0) { - perror(filename); - exit(8); - } - if (S_ISBLK(st.st_mode)) { - if (ioctl(fd, BLKGETSIZE, &length) < 0) { - fprintf(stderr, _("%s: warning--unable to determine " - "filesystem size \n"), filename); - exit(4); - } - length = length * 512; - } - else if (S_ISREG(st.st_mode)) { - length = st.st_size; - } - else { - fprintf(stderr, _("%s is not a block device or file\n"), - filename); - exit(8); - } - - if (length < sizeof(struct cramfs_super)) { - fprintf(stderr, _("%s: invalid cramfs--file length " - "too short\n"), filename); - exit(4); - } - - if (S_ISBLK(st.st_mode)) { - /* nasty because mmap of block devices fails */ - buf = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - read(fd, buf, length); - } - else { - /* nice and easy */ - buf = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - } - - /* XXX - this could be cleaner... */ - if (((struct cramfs_super *) buf)->magic == CRAMFS_MAGIC) { - start = 0; - super = (struct cramfs_super *) buf; - } - else if (length >= (PAD_SIZE + sizeof(struct cramfs_super)) && - ((((struct cramfs_super *) (buf + PAD_SIZE))->magic == CRAMFS_MAGIC))) - { - start = PAD_SIZE; - super = (struct cramfs_super *) (buf + PAD_SIZE); - } - else { - fprintf(stderr, _("%s: invalid cramfs--wrong magic\n"), - filename); - exit(4); - } - - if (super->flags & CRAMFS_FLAG_FSID_VERSION_2) { - /* length test */ - if (length < super->size) { - fprintf(stderr, _("%s: invalid cramfs--file length " - "too short\n"), filename); - exit(4); - } - else if (length > super->size) { - fprintf(stderr, _("%s: warning--file length too long, " - "padded image?\n"), filename); - } - - /* CRC test */ - crc_old = super->fsid.crc; - super->fsid.crc = crc32(0L, Z_NULL, 0); - crc_new = crc32(0L, Z_NULL, 0); - crc_new = crc32(crc_new, (unsigned char *) buf+start, super->size - start); - if (crc_new != crc_old) { - fprintf(stderr, _("%s: invalid cramfs--crc error\n"), - filename); - exit(4); - } - } - else { - fprintf(stderr, _("%s: warning--old cramfs image, no CRC\n"), - filename); - } - + test_super(&start, &length); + test_crc(start); #ifdef INCLUDE_FS_TESTS - super = (struct cramfs_super *) malloc(sizeof(struct cramfs_super)); - if (((struct cramfs_super *) buf)->magic == CRAMFS_MAGIC) { - memcpy(super, buf, sizeof(struct cramfs_super)); - } - else if (length >= (PAD_SIZE + sizeof(struct cramfs_super)) && - ((((struct cramfs_super *) (buf + PAD_SIZE))->magic == CRAMFS_MAGIC))) - { - memcpy(super, (buf + PAD_SIZE), sizeof(struct cramfs_super)); - } - - munmap(buf, length); - - /* file format test, uses fake "blocked" accesses */ - root = read_super(); - umask(0); - euid = geteuid(); - if (!root) { - fprintf(stderr, _("%s: invalid cramfs--bad superblock\n"), - filename); - exit(4); - } - stream.next_in = NULL; - stream.avail_in = 0; - inflateInit(&stream); - - if (!extract_dir) - extract_dir = "root"; - - expand_fs(strlen(extract_dir), extract_dir, root); - inflateEnd(&stream); + test_fs(start); +#endif /* INCLUDE_FS_TESTS */ - if (start_data != 1 << 28 && end_inode != start_data) { - fprintf(stderr, - _("%s: invalid cramfs--directory data end " - "(%ld) != file data start (%ld)\n"), - filename, end_inode, start_data); - exit(4); - } - if (super->flags & CRAMFS_FLAG_FSID_VERSION_2) { - if (end_data > super->size) { - fprintf(stderr, - _("%s: invalid cramfs--invalid file " - "data offset\n"), - filename); - exit(4); - } + if (opt_verbose) { + printf("%s: OK\n", filename); } -#endif /* INCLUDE_FS_TESTS */ - exit(0); + exit(FSCK_OK); } diff --git a/disk-utils/mkfs.cramfs.c b/disk-utils/mkfs.cramfs.c index f204364ea..328912857 100644 --- a/disk-utils/mkfs.cramfs.c +++ b/disk-utils/mkfs.cramfs.c @@ -1,7 +1,7 @@ /* * mkcramfs - make a cramfs file system * - * Copyright (C) 1999-2001 Transmeta Corporation + * Copyright (C) 1999-2002 Transmeta Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,27 +35,25 @@ #include <string.h> #include <assert.h> #include <getopt.h> +#include <stdarg.h> #include <zlib.h> #include "cramfs.h" #include "md5.h" #include "nls.h" -#define PAD_SIZE 512 /* only 0 and 512 supported by kernel */ +/* Exit codes used by mkfs-type programs */ +#define MKFS_OK 0 /* No errors */ +#define MKFS_ERROR 8 /* Operational error */ +#define MKFS_USAGE 16 /* Usage or syntax error */ + +/* The kernel only supports PAD_SIZE of 0 and 512. */ +#define PAD_SIZE 512 static const char *progname = "mkcramfs"; static int verbose = 0; -#ifdef __ia64__ -#define PAGE_CACHE_SIZE (16384) -#elif defined __alpha__ -#define PAGE_CACHE_SIZE (8192) -#else -#define PAGE_CACHE_SIZE (4096) -#endif - -/* The kernel assumes PAGE_CACHE_SIZE as block size. */ -static unsigned int blksize = PAGE_CACHE_SIZE; /* settable via -b option */ +static unsigned int blksize; /* settable via -b option */ static long total_blocks = 0, total_nodes = 1; /* pre-count the root node */ static int image_length = 0; @@ -88,7 +86,7 @@ static int warn_uid = 0; /* In-core version of inode / directory entry. */ struct entry { /* stats */ - char *name; + unsigned char *name; unsigned int mode, size, uid, gid; unsigned char md5sum[16]; unsigned char flags; @@ -97,6 +95,7 @@ struct entry { /* FS data */ char *path; + int fd; /* temporarily open files while mmapped */ struct entry *same; /* points to other identical file */ unsigned int offset; /* pointer to compressed data in archive */ unsigned int dir_offset; /* offset of directory entry in archive */ @@ -121,13 +120,13 @@ usage(int status) { FILE *stream = status ? stderr : stdout; fprintf(stream, - _("usage: %s [-h] [-v] [-b blksz] [-e edition] [-i file] " + _("usage: %s [-h] [-v] [-b blksize] [-e edition] [-i file] " "[-n name] dirname outfile\n" " -h print this help\n" " -v be verbose\n" " -E make all warnings errors " "(non-zero exit status)\n" - " -b blksz use this blocksize, must equal page size\n" + " -b blksize use this blocksize, must equal page size\n" " -e edition set edition number (part of fsid)\n" " -i file insert a file image into the filesystem " "(requires >= 2.4.0)\n" @@ -730,6 +729,7 @@ int main(int argc, char **argv) u32 crc = crc32(0L, Z_NULL, 0); int c; + blksize = sysconf(_SC_PAGESIZE); total_blocks = 0; if (argc) { |