?? cramfsck.c
字號:
/* * cramfsck - check a cramfs file system * * Copyright (C) 2000-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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * 1999/12/03: Linus Torvalds (cramfs tester and unarchive program) * 2000/06/03: Daniel Quinlan (CRC and length checking program) * 2000/06/04: Daniel Quinlan (merged programs, added options, support * for special files, preserve permissions and * ownership, cramfs superblock v2, bogus mode * test, pathname length test, etc.) * 2000/06/06: Daniel Quinlan (support for holes, pretty-printing, * symlink size test) * 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 _GNU_SOURCE#include <sys/types.h>#include <stdio.h>#include <stdarg.h>#include <sys/stat.h>#include <unistd.h>#include <sys/mman.h>#include <fcntl.h>#include <dirent.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <sys/sysmacros.h>#include <utime.h>#include <sys/ioctl.h>#define _LINUX_STRING_H_#include <linux/fs.h>#include <linux/cramfs_fs.h>#include <zlib.h>/* 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#define PAGE_CACHE_SIZE (4096)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 */static int opt_verbose = 0; /* 1 = verbose (-v), 2+ = very verbose (-vv) */#ifdef INCLUDE_FS_TESTSstatic int opt_extract = 0; /* extract cramfs (-x) */static char *extract_dir = "root"; /* extraction directory (-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#define ROMBUFFERSIZE (1 << ROMBUFFER_BITS)#define ROMBUFFERMASK (ROMBUFFERSIZE-1)static char read_buffer[ROMBUFFERSIZE * 2];static unsigned long read_buffer_block = ~0UL;/* Uncompressing data structures... */static char outbuffer[PAGE_CACHE_SIZE*2];static z_stream stream;/* Prototypes */static void expand_fs(char *, struct cramfs_inode *);#endif /* INCLUDE_FS_TESTS *//* Input status of 0 to print help and exit without an error. */static void usage(int status){ FILE *stream = status ? stderr : stdout; fprintf(stream, "usage: %s [-hv] [-x dir] file\n" " -h print this help\n" " -x dir extract into dir\n" " -v be more verbose\n" " file file to test\n", progname); 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_CACHE_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_TESTSstatic void print_node(char type, struct cramfs_inode *i, char *name){ char info[10]; if (S_ISCHR(i->mode) || (S_ISBLK(i->mode))) { /* major/minor numbers can be as high as 2^12 or 4096 */ snprintf(info, 10, "%4d,%4d", major(i->size), minor(i->size)); } else { /* size be as high as 2^24 or 16777216 */ snprintf(info, 10, "%9d", i->size); } printf("%c %04o %s %5d:%-3d %s\n", type, i->mode & ~S_IFMT, info, i->uid, i->gid, name);}/* * Create a fake "blocked" access */static void *romfs_read(unsigned long offset){ unsigned int block = offset >> ROMBUFFER_BITS; if (block != read_buffer_block) { read_buffer_block = block; lseek(fd, block << ROMBUFFER_BITS, SEEK_SET); read(fd, read_buffer, ROMBUFFERSIZE * 2); } return read_buffer + (offset & ROMBUFFERMASK);}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;}static struct cramfs_inode *iget(unsigned int ino){ return cramfs_iget(romfs_read(ino));}static void iput(struct cramfs_inode *inode){ free(inode);}/* * Return the offset of the root directory */static struct cramfs_inode *read_super(void){ 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){ int err; stream.next_in = src; stream.avail_in = len; stream.next_out = (unsigned char *) outbuffer; stream.avail_out = PAGE_CACHE_SIZE*2; inflateReset(&stream); if (len > PAGE_CACHE_SIZE*2) { die(FSCK_UNCORRECTED, 0, "data block too large"); } err = inflate(&stream, Z_FINISH); if (err != Z_STREAM_END) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -