📄 cramfs.patch
字号:
+extern char *xreadlink(const char *path)+{ + static const int GROWBY = 80; /* how large we will grow strings by */++ char *buf = NULL; + int bufsize = 0, readsize = 0;++ do {+ buf = xrealloc(buf, bufsize += GROWBY);+ readsize = readlink(path, buf, bufsize); /* 1st try */+ if (readsize == -1) {+ perror_msg("%s:%s", progname, path);+ return NULL;+ }+ } + while (bufsize < readsize + 1);++ buf[readsize] = '\0';++ return buf;+} + static void map_entry(struct entry *entry) { if (entry->path) { entry->fd = open(entry->path, O_RDONLY); if (entry->fd < 0) {- die(MKFS_ERROR, 1, "open failed: %s", entry->path);+ error_msg_and_die("open failed: %s", entry->path); } entry->uncompressed = mmap(NULL, entry->size, PROT_READ, MAP_PRIVATE, entry->fd, 0); if (entry->uncompressed == MAP_FAILED) {- die(MKFS_ERROR, 1, "mmap failed: %s", entry->path);+ error_msg_and_die("mmap failed: %s", entry->path); } } }@@ -174,8 +317,9 @@ { if (entry->path) { if (munmap(entry->uncompressed, entry->size) < 0) {- die(MKFS_ERROR, 1, "munmap failed: %s", entry->path);+ error_msg_and_die("munmap failed: %s", entry->path); }+ entry->uncompressed=NULL; close(entry->fd); } }@@ -204,7 +348,8 @@ find_identical_file(orig->next, newfile)); } -static void eliminate_doubles(struct entry *root, struct entry *orig) {+static void eliminate_doubles(struct entry *root, struct entry *orig) +{ if (orig) { if (orig->size && (orig->path || orig->uncompressed)) find_identical_file(root, orig);@@ -232,10 +377,7 @@ /* Set up the path. */ /* TODO: Reuse the parent's buffer to save memcpy'ing and duplication. */- path = malloc(len + 1 + MAX_INPUT_NAMELEN + 1);- if (!path) {- die(MKFS_ERROR, 1, "malloc failed");- }+ path = xmalloc(len + 1 + MAX_INPUT_NAMELEN + 1); memcpy(path, name, len); endpath = path + len; *endpath = '/';@@ -245,7 +387,7 @@ dircount = scandir(name, &dirlist, 0, cramsort); if (dircount < 0) {- die(MKFS_ERROR, 1, "scandir failed: %s", name);+ error_msg_and_die("scandir failed: %s", name); } /* process directory */@@ -269,25 +411,20 @@ } namelen = strlen(dirent->d_name); if (namelen > MAX_INPUT_NAMELEN) {- die(MKFS_ERROR, 0,- "very long (%u bytes) filename found: %s\n"- "please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile",+ error_msg_and_die(+ "Very long (%u bytes) filename `%s' found.\n"+ " Please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile. Exiting.\n", namelen, dirent->d_name); } memcpy(endpath, dirent->d_name, namelen + 1); if (lstat(path, &st) < 0) {+ perror(endpath); warn_skip = 1; continue; }- entry = calloc(1, sizeof(struct entry));- if (!entry) {- die(MKFS_ERROR, 1, "calloc failed");- }- entry->name = strdup(dirent->d_name);- if (!entry->name) {- die(MKFS_ERROR, 1, "strdup failed");- }+ entry = xcalloc(1, sizeof(struct entry));+ entry->name = xstrdup(dirent->d_name); /* truncate multi-byte UTF-8 filenames on character boundary */ if (namelen > CRAMFS_MAXPATHLEN) { namelen = CRAMFS_MAXPATHLEN;@@ -297,24 +434,25 @@ namelen--; /* are we reasonably certain it was UTF-8 ? */ if (entry->name[namelen] < 0x80 || !namelen) {- die(MKFS_ERROR, 0, "cannot truncate filenames not encoded in UTF-8");+ error_msg_and_die("cannot truncate filenames not encoded in UTF-8"); } } entry->name[namelen] = '\0'; } entry->mode = st.st_mode; entry->size = st.st_size;- entry->uid = st.st_uid;+ entry->uid = opt_squash ? 0 : st.st_uid; if (entry->uid >= 1 << CRAMFS_UID_WIDTH) warn_uid = 1;- entry->gid = st.st_gid;- if (entry->gid >= 1 << CRAMFS_GID_WIDTH)+ entry->gid = opt_squash ? 0 : st.st_gid;+ if (entry->gid >= 1 << CRAMFS_GID_WIDTH) { /* TODO: We ought to replace with a default gid instead of truncating; otherwise there are security problems. Maybe mode should be &= ~070. Same goes for uid once Linux supports >16-bit uids. */ warn_gid = 1;+ } size = sizeof(struct cramfs_inode) + ((namelen + 3) & ~3); *fslen_ub += size; if (S_ISDIR(st.st_mode)) {@@ -325,21 +463,15 @@ warn_skip = 1; continue; }- entry->path = strdup(path);- if (!entry->path) {- die(MKFS_ERROR, 1, "strdup failed");- }+ entry->path = xstrdup(path); if ((entry->size >= 1 << CRAMFS_SIZE_WIDTH)) { warn_size = 1; entry->size = (1 << CRAMFS_SIZE_WIDTH) - 1; } } } else if (S_ISLNK(st.st_mode)) {- entry->uncompressed = malloc(entry->size);+ entry->uncompressed = xreadlink(path); if (!entry->uncompressed) {- die(MKFS_ERROR, 1, "malloc failed");- }- if (readlink(path, entry->uncompressed, entry->size) < 0) { warn_skip = 1; continue; }@@ -351,7 +483,7 @@ if (entry->size & -(1<<CRAMFS_SIZE_WIDTH)) warn_dev = 1; } else {- die(MKFS_ERROR, 0, "bogus file type: %s", entry->name);+ error_msg_and_die("bogus file type: %s", entry->name); } if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {@@ -378,7 +510,9 @@ struct cramfs_super *super = (struct cramfs_super *) base; unsigned int offset = sizeof(struct cramfs_super) + image_length; - offset += opt_pad; /* 0 if no padding */+ if (opt_pad) {+ offset += opt_pad; /* 0 if no padding */+ } super->magic = CRAMFS_MAGIC; super->flags = CRAMFS_FLAG_FSID_VERSION_2 | CRAMFS_FLAG_SORTED_DIRS;@@ -414,10 +548,10 @@ struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset); if ((offset & 3) != 0) {- die(MKFS_ERROR, 0, "illegal offset of %lu bytes", offset);+ error_msg_and_die("illegal offset of %lu bytes", offset); } if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) {- die(MKFS_ERROR, 0, "filesystem too big");+ error_msg_and_die("filesystem too big"); } inode->offset = (offset >> 2); }@@ -429,7 +563,7 @@ */ static void print_node(struct entry *e) {- char info[10];+ char info[12]; char type = '?'; if (S_ISREG(e->mode)) type = 'f';@@ -442,11 +576,11 @@ if (S_ISCHR(e->mode) || (S_ISBLK(e->mode))) { /* major/minor numbers can be as high as 2^12 or 4096 */- snprintf(info, 10, "%4d,%4d", major(e->size), minor(e->size));+ snprintf(info, 11, "%4d,%4d", major(e->size), minor(e->size)); } else { /* size be as high as 2^24 or 16777216 */- snprintf(info, 10, "%9d", e->size);+ snprintf(info, 11, "%9d", e->size); } printf("%c %04o %s %5d:%-3d %s\n",@@ -462,17 +596,9 @@ { int stack_entries = 0; int stack_size = 64;- struct entry **entry_stack;-- entry_stack = malloc(stack_size * sizeof(struct entry *));- if (!entry_stack) {- die(MKFS_ERROR, 1, "malloc failed");- }-- if (opt_verbose) {- printf("root:\n");- }+ struct entry **entry_stack = NULL; + entry_stack = xmalloc(stack_size * sizeof(struct entry *)); for (;;) { int dir_start = stack_entries; while (entry) {@@ -506,10 +632,7 @@ if (entry->child) { if (stack_entries >= stack_size) { stack_size *= 2;- entry_stack = realloc(entry_stack, stack_size * sizeof(struct entry *));- if (!entry_stack) {- die(MKFS_ERROR, 1, "realloc failed");- }+ entry_stack = xrealloc(entry_stack, stack_size * sizeof(struct entry *)); } entry_stack[stack_entries] = entry; stack_entries++;@@ -543,7 +666,7 @@ set_data_offset(entry, base, offset); if (opt_verbose) {- printf("%s:\n", entry->name);+ printf("'%s':\n", entry->name); } entry = entry->child; }@@ -553,16 +676,21 @@ static int is_zero(char const *begin, unsigned len) {- /* Returns non-zero iff the first LEN bytes from BEGIN are all NULs. */- return (len-- == 0 ||- (begin[0] == '\0' &&- (len-- == 0 ||- (begin[1] == '\0' &&- (len-- == 0 ||- (begin[2] == '\0' &&- (len-- == 0 ||- (begin[3] == '\0' &&- memcmp(begin, begin + 4, len) == 0))))))));+ if (opt_holes)+ /* Returns non-zero iff the first LEN bytes from BEGIN are+ all NULs. */+ return (len-- == 0 ||+ (begin[0] == '\0' &&+ (len-- == 0 ||+ (begin[1] == '\0' &&+ (len-- == 0 ||+ (begin[2] == '\0' &&+ (len-- == 0 ||+ (begin[3] == '\0' &&+ memcmp(begin, begin + 4, len) == 0))))))));+ else+ /* Never create holes. */+ return 0; } /*@@ -575,37 +703,34 @@ * Note that size > 0, as a zero-sized file wouldn't ever * have gotten here in the first place. */-static unsigned int do_compress(char *base, unsigned int offset, char const *name, char *uncompressed, unsigned int size)+static unsigned int do_compress(char *base, unsigned int offset, struct entry *entry) {+ unsigned int size = entry->size; unsigned long original_size = size; unsigned long original_offset = offset; unsigned long new_size; unsigned long blocks = (size - 1) / blksize + 1; unsigned long curr = offset + 4 * blocks; int change;+ char *uncompressed = entry->uncompressed; - total_blocks += blocks;+ total_blocks += blocks; do { unsigned long len = 2 * blksize; unsigned int input = size;- int err;- if (input > blksize) input = blksize; size -= input;- if (!(opt_holes && is_zero (uncompressed, input))) {- err = compress2(base + curr, &len, uncompressed, input, Z_BEST_COMPRESSION);- if (err != Z_OK) {- die(MKFS_ERROR, 0, "compression error: %s", zError(err));- }+ if (!is_zero (uncompressed, input)) {+ compress(base + curr, &len, uncompressed, input); curr += len; } uncompressed += input; if (len > blksize*2) { /* (I don't think this can happen with zlib.) */- die(MKFS_ERROR, 0, "AIEEE: block \"compressed\" to > 2*blocklength (%ld)", len);+ error_msg_and_die("AIEEE: block \"compressed\" to > 2*blocklength (%ld)\n", len); } *(u32 *) (base + offset) = curr;@@ -618,10 +743,12 @@ st_blocks * 512. But if you say that then perhaps administrative data should also be included in both. */ change = new_size - original_size;- if (opt_verbose > 1) {- printf("%6.2f%% (%+d bytes)\t%s\n",- (change * 100) / (double) original_size, change, name);+#if 0+ if (opt_verbose) {+ printf("%6.2f%% (%+d bytes)\t%s\n",+ (change * 100) / (double) original_size, change, entry->name); }+#endif return curr; }@@ -644,7 +771,7 @@ set_data_offset(entry, base, offset); entry->offset = offset; map_entry(entry);- offset = do_compress(base, offset, entry->name, entry->uncompressed, entry->size);+ offset = do_compress(base, offset, entry); unmap_entry(entry); } }@@ -660,13 +787,10 @@ int fd; char *buf; - fd = open(file, O_RDONLY);- if (fd < 0) {- die(MKFS_ERROR, 1, "open failed: %s", file);- }+ fd = xopen(file, O_RDONLY, 0); buf = mmap(NULL, image_length, PROT_READ, MAP_PRIVATE, fd, 0); if (buf == MAP_FAILED) {- die(MKFS_ERROR, 1, "mmap failed");+ error_msg_and_die("mmap failed"); } memcpy(base + offset, buf, image_length); munmap(buf, image_length);@@ -679,6 +803,328 @@ return (offset + image_length); } +static struct entry *find_filesystem_entry(struct entry *dir, char *name, mode_t type)+{+ struct entry *e = dir;++ if (S_ISDIR(dir->mode)) {+ e = dir->child;+ }+ while (e) {+ /* Only bother to do the expensive strcmp on matching file types */+ if (type == (e->mode & S_IFMT) && e->name) {+ if (S_ISDIR(e->mode)) {+ int len = strlen(e->name);++ /* Check if we are a parent of the correct path */+ if (strncmp(e->name, name, len) == 0) {+ /* Is this an _exact_ match? */+ if (strcmp(name, e->name) == 0) {+ return (e);+ }+ /* Looks like we found a parent of the correct path */+ if (name[len] == '/') {+ if (e->child) {+ return (find_filesystem_entry (e, name + len + 1, type));+ } else {+ return NULL;+ }+ }+ }+ } else {+ if (strcmp(name, e->name) == 0) {+ return (e);+ }+ }+ }+ e = e->next;+ }+ return (NULL);+}++void modify_entry(char *full_path, unsigned long uid, unsigned long gid,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -