📄 cramfs.patch
字号:
+ unsigned long mode, unsigned long rdev, struct entry *root, loff_t *fslen_ub)+{+ char *name, *path, *full;+ struct entry *curr, *parent, *entry, *prev;+ + full = xstrdup(full_path);+ path = xstrdup(dirname(full));+ name = full_path + strlen(path) + 1;+ free(full);+ if (strcmp(path, "/") == 0) {+ parent = root;+ name = full_path + 1;+ } else {+ if (!(parent = find_filesystem_entry(root, path+1, S_IFDIR)))+ error_msg_and_die("%s/%s: could not find parent\n", path, name);+ }+ if ((entry = find_filesystem_entry(parent, name, (mode & S_IFMT)))) {+ /* its there, just modify permissions */+ entry->mode = mode;+ entry->uid = uid;+ entry->gid = gid;+ } else { /* make a new entry */+ + /* code partially replicated from parse_directory() */+ size_t namelen;+ if (S_ISREG(mode)) {+ error_msg_and_die("%s: regular file from device_table file must exist on disk!", full_path);+ }++ namelen = strlen(name);+ if (namelen > MAX_INPUT_NAMELEN) {+ 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, name);+ }+ entry = xcalloc(1, sizeof(struct entry));+ entry->name = xstrdup(name);+ /* truncate multi-byte UTF-8 filenames on character boundary */+ if (namelen > CRAMFS_MAXPATHLEN) {+ namelen = CRAMFS_MAXPATHLEN;+ warn_namelen = 1;+ /* the first lost byte must not be a trail byte */+ while ((entry->name[namelen] & 0xc0) == 0x80) {+ namelen--;+ /* are we reasonably certain it was UTF-8 ? */+ if (entry->name[namelen] < 0x80 || !namelen) {+ error_msg_and_die("cannot truncate filenames not encoded in UTF-8");+ }+ }+ entry->name[namelen] = '\0';+ }+ entry->mode = mode;+ entry->uid = uid;+ entry->gid = gid;+ entry->size = 0;+ if (S_ISBLK(mode) || S_ISCHR(mode)) {+ entry->size = rdev;+ if (entry->size & -(1<<CRAMFS_SIZE_WIDTH))+ warn_dev = 1;+ }+ + /* ok, now we have to backup and correct the size of all the entries above us */+ *fslen_ub += sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);+ parent->size += sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);++ /* alright, time to link us in */+ curr = parent->child;+ prev = NULL;+ while (curr && strcmp(name, curr->name) > 0) {+ prev = curr;+ curr = curr->next;+ }+ if (!prev) parent->child = entry;+ else prev->next = entry;+ entry->next = curr;+ entry->child = NULL;+ }+ if (entry->uid >= 1 << CRAMFS_UID_WIDTH)+ warn_uid = 1;+ 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;+ }+ free(path);+}++/* the GNU C library has a wonderful scanf("%as", string) which will+ allocate the string with the right size, good to avoid buffer overruns. + the following macros use it if available or use a hacky workaround...+ */++#ifdef __GNUC__+#define SCANF_PREFIX "a"+#define SCANF_STRING(s) (&s)+#define GETCWD_SIZE 0+#else+#define SCANF_PREFIX "511"+#define SCANF_STRING(s) (s = xmalloc(512))+#define GETCWD_SIZE -1+inline int snprintf(char *str, size_t n, const char *fmt, ...)+{+ int ret;+ va_list ap;++ va_start(ap, fmt);+ ret = vsprintf(str, fmt, ap);+ va_end(ap);+ return ret;+}+#endif++/* device table entries take the form of:+ <path> <type> <mode> <uid> <gid> <major> <minor> <start> <inc> <count>+ /dev/mem c 640 0 0 1 1 0 0 -++ type can be one of: + f A regular file+ d Directory+ c Character special device file+ b Block special device file+ p Fifo (named pipe)++ I don't bother with symlinks (permissions are irrelevant), hard+ links (special cases of regular files), or sockets (why bother).++ Regular files must exist in the target root directory. If a char,+ block, fifo, or directory does not exist, it will be created.+*/++static int interpret_table_entry(char *line, struct entry *root, loff_t *fslen_ub)+{+ char type, *name = NULL;+ unsigned long mode = 0755, uid = 0, gid = 0, major = 0, minor = 0;+ unsigned long start = 0, increment = 1, count = 0;++ if (sscanf (line, "%" SCANF_PREFIX "s %c %lo %lu %lu %lu %lu %lu %lu %lu",+ SCANF_STRING(name), &type, &mode, &uid, &gid, &major, &minor,+ &start, &increment, &count) < 0) + {+ return 1;+ }++ if (!strcmp(name, "/")) {+ error_msg_and_die("Device table entries require absolute paths");+ }++ switch (type) {+ case 'd':+ mode |= S_IFDIR;+ modify_entry(name, uid, gid, mode, 0, root, fslen_ub);+ break;+ case 'f':+ mode |= S_IFREG;+ modify_entry(name, uid, gid, mode, 0, root, fslen_ub);+ break;+ case 'p':+ mode |= S_IFIFO;+ modify_entry(name, uid, gid, mode, 0, root, fslen_ub);+ break;+ case 'c':+ case 'b':+ mode |= (type == 'c') ? S_IFCHR : S_IFBLK;+ if (count > 0) {+ char *buf;+ unsigned long i;+ dev_t rdev;++ for (i = start; i < count; i++) {+ asprintf(&buf, "%s%lu", name, i);+ rdev = makedev(major, minor + (i * increment - start));+ modify_entry(buf, uid, gid, mode, rdev, root, fslen_ub);+ free(buf);+ }+ } else {+ dev_t rdev = makedev(major, minor);+ modify_entry(name, uid, gid, mode, rdev, root, fslen_ub);+ }+ break;+ default:+ error_msg_and_die("Unsupported file type");+ }+ free(name);+ return 0;+}++static int parse_device_table(FILE *file, struct entry *root, loff_t *fslen_ub)+{+ char *line;+ int status = 0;+ size_t length = 0;++ /* Turn off squash, since we must ensure that values+ * entered via the device table are not squashed */+ opt_squash = 0;++ /* Looks ok so far. The general plan now is to read in one+ * line at a time, check for leading comment delimiters ('#'),+ * then try and parse the line as a device table. If we fail+ * to parse things, try and help the poor fool to fix their+ * device table with a useful error msg... */+ line = NULL;+ while (getline(&line, &length, file) != -1) {+ /* First trim off any whitespace */+ int len = strlen(line);++ /* trim trailing whitespace */+ while (len > 0 && isspace(line[len - 1]))+ line[--len] = '\0';+ /* trim leading whitespace */+ memmove(line, &line[strspn(line, " \n\r\t\v")], len);++ /* How long are we after trimming? */+ len = strlen(line);++ /* If this is NOT a comment line, try to interpret it */+ if (len && *line != '#') {+ if (interpret_table_entry(line, root, fslen_ub))+ status = 1;+ }++ free(line);+ line = NULL;+ }+ free(line);+ fclose(file);++ return status;+}++void traverse(struct entry *entry, int depth)+{+ struct entry *curr = entry;+ int i;++ while (curr) {+ for (i = 0; i < depth; i++) putchar(' ');+ printf("%s: size=%d mode=%d same=%p\n",+ (curr->name)? (char*)curr->name : "/", + curr->size, curr->mode, curr->same);+ if (curr->child) traverse(curr->child, depth + 4);+ curr = curr->next;+ }+}++static void free_filesystem_entry(struct entry *dir)+{+ struct entry *e = dir, *last;++ if (S_ISDIR(dir->mode)) {+ e = dir->child;+ }+ while (e) {+ if (e->name)+ free(e->name);+ if (e->path)+ free(e->path);+ if (e->uncompressed)+ free(e->uncompressed);+ last = e;+ if (e->child) {+ free_filesystem_entry(e);+ }+ e = e->next;+ free(last);+ }+}+++/*+ * Usage:+ *+ * mkcramfs directory-name outfile+ *+ * where "directory-name" is simply the root of the directory+ * tree that we want to generate a compressed filesystem out+ * of.+ */ int main(int argc, char **argv) { struct stat st; /* used twice... */@@ -692,6 +1138,7 @@ u32 crc; int c; /* for getopt */ char *ep; /* for strtoul */+ FILE *devtable = NULL; total_blocks = 0; @@ -699,7 +1146,7 @@ progname = argv[0]; /* command line options */- while ((c = getopt(argc, argv, "hEe:i:n:psvz")) != EOF) {+ while ((c = getopt(argc, argv, "hEe:i:n:psvzD:q")) != EOF) { switch (c) { case 'h': usage(MKFS_OK);@@ -715,7 +1162,7 @@ case 'i': opt_image = optarg; if (lstat(opt_image, &st) < 0) {- die(MKFS_ERROR, 1, "lstat failed: %s", opt_image);+ error_msg_and_die("lstat failed: %s", opt_image); } image_length = st.st_size; /* may be padded later */ fslen_ub += (image_length + 3); /* 3 is for padding */@@ -736,6 +1183,16 @@ case 'z': opt_holes = 1; break;+ case 'q':+ opt_squash = 1;+ break;+ case 'D':+ devtable = xfopen(optarg, "r");+ if (fstat(fileno(devtable), &st) < 0)+ perror_msg_and_die(optarg);+ if (st.st_size < 10)+ error_msg_and_die("%s: not a proper device table file\n", optarg);+ break; } } @@ -745,25 +1202,23 @@ outfile = argv[optind + 1]; if (stat(dirname, &st) < 0) {- die(MKFS_USAGE, 1, "stat failed: %s", dirname);- }- fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);- if (fd < 0) {- die(MKFS_USAGE, 1, "open failed: %s", outfile);+ error_msg_and_die("stat failed: %s", dirname); }+ fd = xopen(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); - root_entry = calloc(1, sizeof(struct entry));- if (!root_entry) {- die(MKFS_ERROR, 1, "calloc failed");- }+ root_entry = xcalloc(1, sizeof(struct entry)); root_entry->mode = st.st_mode; root_entry->uid = st.st_uid; root_entry->gid = st.st_gid; root_entry->size = parse_directory(root_entry, dirname, &root_entry->child, &fslen_ub); + if (devtable) {+ parse_device_table(devtable, root_entry, &fslen_ub);+ }+ /* always allocate a multiple of blksize bytes because that's- what we're going to write later on */+ what we're going to write later on */ fslen_ub = ((fslen_ub - 1) | (blksize - 1)) + 1; if (fslen_ub > MAXFSLEN) {@@ -790,7 +1245,7 @@ rom_image = mmap(NULL, fslen_ub?fslen_ub:1, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (rom_image == MAP_FAILED) {- die(MKFS_ERROR, 1, "mmap failed");+ error_msg_and_die("mmap failed"); } /* Skip the first opt_pad bytes for boot loader code */@@ -807,6 +1262,7 @@ } offset = write_directory_structure(root_entry->child, rom_image, offset);+ if (opt_verbose) printf("Directory data: %d bytes\n", offset); offset = write_data(root_entry, rom_image, offset);@@ -814,30 +1270,38 @@ /* We always write a multiple of blksize bytes, so that losetup works. */ offset = ((offset - 1) | (blksize - 1)) + 1;+ if (opt_verbose) printf("Everything: %d kilobytes\n", offset >> 10); /* Write the superblock now that we can fill in all of the fields. */ write_superblock(root_entry, rom_image+opt_pad, offset);+ if (opt_verbose) printf("Super block: %d bytes\n", sizeof(struct cramfs_super)); /* Put the checksum in. */ crc = crc32(0L, Z_NULL, 0); crc = crc32(crc, (rom_image+opt_pad), (offset-opt_pad)); ((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = crc;+ if (opt_verbose) printf("CRC: %x\n", crc); /* Check to make sure we allocated enough space. */ if (fslen_ub < offset) {- die(MKFS_ERROR, 0, "not enough space allocated for ROM image (%Ld allocated, %d used)", fslen_ub, offset);+ error_msg_and_die("not enough space allocated for ROM "+ "image (%Ld allocated, %d used)", fslen_ub, offset); } written = write(fd, rom_image, offset); if (written < 0) {- die(MKFS_ERROR, 1, "write failed");+ error_msg_and_die("write failed"); } if (offset != written) {- die(MKFS_ERROR, 0, "ROM image write failed (wrote %d of %d bytes)", written, offset);+ error_msg_and_die("ROM image write failed (wrote %d of %d bytes)", written, offset); }+ + /* Free up memory */+ free_filesystem_entry(root_entry);+ free(root_entry); /* (These warnings used to come at the start, but they scroll off the screen too quickly.) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -