patch-2.3.35 linux/scripts/cramfs/mkcramfs.c
Next file: linux/CREDITS
Previous file: linux/net/unix/af_unix.c
Back to the patch index
Back to the overall index
- Lines: 351
- Date:
Tue Nov 23 17:53:38 1999
- Orig file:
v2.3.34/linux/scripts/cramfs/mkcramfs.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.3.34/linux/scripts/cramfs/mkcramfs.c linux/scripts/cramfs/mkcramfs.c
@@ -0,0 +1,349 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* zlib required.. */
+#include <zlib.h>
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+#include "cramfs.h"
+
+#define PAGE_CACHE_SIZE (4096)
+
+static const char *progname = "mkcramfs";
+
+void usage(void)
+{
+ fprintf(stderr, "Usage: '%s dirname outfile'\n"
+ " where <dirname> is the root of the\n"
+ " filesystem to be compressed.\n", progname);
+ exit(1);
+}
+
+struct entry {
+ /* stats */
+ char *name;
+ unsigned int mode, size, uid, gid;
+
+ /* FS data */
+ void *uncompressed;
+ unsigned int dir_offset; /* Where in the archive is the directory entry? */
+ unsigned int data_offset; /* Where in the archive is the start of the data? */
+
+ /* organization */
+ struct entry *child;
+ struct entry *next;
+};
+
+/*
+ * We should mind about memory leaks and
+ * checking for out-of-memory.
+ *
+ * We don't.
+ */
+static unsigned int parse_directory(const char *name, struct entry **prev)
+{
+ DIR *dir;
+ int count = 0, totalsize = 0;
+ struct dirent *dirent;
+ char *path, *endpath;
+ int len = strlen(name);
+
+ dir = opendir(name);
+ if (!dir) {
+ perror(name);
+ exit(2);
+ }
+ /* Set up the path.. */
+ path = malloc(4096);
+ memcpy(path, name, len);
+ endpath = path + len;
+ *endpath = '/';
+ endpath++;
+
+ while ((dirent = readdir(dir)) != NULL) {
+ struct entry *entry;
+ struct stat st;
+ int fd, size;
+
+ /* Ignore "." and ".." - we won't be adding them to the archive */
+ if (dirent->d_name[0] == '.') {
+ if (dirent->d_name[1] == '\0')
+ continue;
+ if (dirent->d_name[1] == '.') {
+ if (dirent->d_name[2] == '\0')
+ continue;
+ }
+ }
+ strcpy(endpath, dirent->d_name);
+
+ if (lstat(path, &st) < 0) {
+ perror(endpath);
+ continue;
+ }
+ entry = calloc(1, sizeof(struct entry));
+ entry->name = strdup(dirent->d_name);
+ entry->mode = st.st_mode;
+ entry->size = st.st_size;
+ entry->uid = st.st_uid;
+ entry->gid = st.st_gid;
+ size = sizeof(struct cramfs_inode) + (~3 & (strlen(entry->name) + 3));
+ if (S_ISDIR(st.st_mode)) {
+ entry->size = parse_directory(path, &entry->child);
+ } else if (S_ISREG(st.st_mode)) {
+ int fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ perror(path);
+ continue;
+ }
+ if (entry->size)
+ entry->uncompressed = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (-1 == (int) (long) entry->uncompressed) {
+ perror("mmap");
+ exit(5);
+ }
+ close(fd);
+ } else if (S_ISLNK(st.st_mode)) {
+ entry->uncompressed = malloc(st.st_size);
+ if (readlink(path, entry->uncompressed, st.st_size) < 0) {
+ perror(path);
+ continue;
+ }
+ } else {
+ entry->size = st.st_rdev;
+ }
+
+ /* Link it into the list */
+ *prev = entry;
+ prev = &entry->next;
+ count++;
+ totalsize += size;
+ }
+ closedir(dir);
+ free(path);
+ return totalsize;
+}
+
+static void set_random(void *area, int size)
+{
+ int fd = open("/dev/random", O_RDONLY);
+
+ if (fd >= 0) {
+ if (read(fd, area, size) == size)
+ return;
+ }
+ memset(area, 0x00, size);
+}
+
+static unsigned int write_superblock(struct entry *root, char *base)
+{
+ struct cramfs_super *super = (struct cramfs_super *) base;
+ unsigned int offset = sizeof(struct cramfs_super);
+
+ super->magic = CRAMFS_MAGIC;
+ super->flags = 0;
+ super->size = 0x10000;
+ memcpy(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature));
+ set_random(super->fsid, sizeof(super->fsid));
+ strncpy(super->name, "Compressed", sizeof(super->name));
+
+ super->root.mode = root->mode;
+ super->root.uid = root->uid;
+ super->root.gid = root->gid;
+ super->root.size = root->size;
+ super->root.offset = offset >> 2;
+
+ return offset;
+}
+
+static void set_data_offset(struct entry *entry, char *base, unsigned long offset)
+{
+ struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset);
+ inode->offset = (offset >> 2);
+}
+
+
+/*
+ * We do a width-first printout of the directory
+ * entries, using a stack to remember the directories
+ * we've seen.
+ */
+#define MAXENTRIES (100)
+static int stack_entries = 0;
+static struct entry *entry_stack[MAXENTRIES];
+
+static unsigned int write_directory_structure(struct entry *entry, char *base, unsigned int offset)
+{
+ for (;;) {
+ while (entry) {
+ struct cramfs_inode *inode = (struct cramfs_inode *) (base + offset);
+ int len = strlen(entry->name);
+
+ entry->dir_offset = offset;
+ offset += sizeof(struct cramfs_inode);
+
+ inode->mode = entry->mode;
+ inode->uid = entry->uid;
+ inode->gid = entry->gid;
+ inode->size = entry->size;
+ inode->offset = 0; /* Fill in later */
+
+ memcpy(base + offset, entry->name, len);
+ /* Pad up the name to a 4-byte boundary */
+ while (len & 3) {
+ *(base + offset + len) = '\0';
+ len++;
+ }
+ inode->namelen = len >> 2;
+ offset += len;
+
+ printf(" %s\n", entry->name);
+
+ if (entry->child) {
+ entry_stack[stack_entries] = entry;
+ stack_entries++;
+ }
+ entry = entry->next;
+ }
+ if (!stack_entries)
+ break;
+ stack_entries--;
+ entry = entry_stack[stack_entries];
+
+ set_data_offset(entry, base, offset);
+ printf("'%s':\n", entry->name);
+ entry = entry->child;
+ }
+ return offset;
+}
+
+/*
+ * One 4-byte pointer per block and then the actual blocked
+ * output. The first block does not need an offset pointer,
+ * as it will start immediately after the pointer block.
+ *
+ * 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 *uncompressed, unsigned int size)
+{
+ unsigned long original_size = size;
+ unsigned long original_offset = offset;
+ unsigned long new_size;
+ unsigned long blocks = (size - 1) / PAGE_CACHE_SIZE + 1;
+ unsigned long curr = offset + 4 * blocks;
+ int change;
+
+ do {
+ unsigned int input = size;
+ unsigned long len = 8192;
+ if (input > PAGE_CACHE_SIZE)
+ input = PAGE_CACHE_SIZE;
+ compress(base + curr, &len, uncompressed, input);
+ uncompressed += input;
+ size -= input;
+ curr += len;
+
+ if (len > PAGE_CACHE_SIZE*2) {
+ printf("AIEEE: block expanded to > 2*blocklength (%d)\n", len);
+ exit(1);
+ }
+
+ *(u32 *) (base + offset) = curr;
+ offset += 4;
+ } while (size);
+
+ new_size = curr - original_offset;
+ change = new_size - original_size;
+ printf("%4.2f %% (%d bytes)\n", (change * 100) / (double) original_size, change);
+
+ return (curr + 3) & ~3;
+}
+
+static unsigned int write_data(struct entry *entry, char *base, unsigned int offset)
+{
+ do {
+ if (entry->uncompressed) {
+ set_data_offset(entry, base, offset);
+ offset = do_compress(base, offset, entry->uncompressed, entry->size);
+ }
+ if (entry->child)
+ offset = write_data(entry->child, base, offset);
+ entry = entry->next;
+ } while (entry);
+ return offset;
+}
+
+/* This is the maximum rom-image you can create */
+#define MAXROM (64*1024*1024)
+
+/*
+ * Usage:
+ *
+ * mkcramfs directory-name
+ *
+ * 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;
+ struct entry *root_entry;
+ char *rom_image;
+ unsigned int offset, written;
+ int fd;
+
+ if (argc)
+ progname = argv[0];
+ if (argc != 3)
+ usage();
+
+ if (stat(argv[1], &st) < 0) {
+ perror(argv[1]);
+ exit(1);
+ }
+ fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
+
+ root_entry = calloc(1, sizeof(struct entry));
+ root_entry->mode = st.st_mode;
+ root_entry->uid = st.st_uid;
+ root_entry->gid = st.st_gid;
+ root_entry->name = "";
+
+ root_entry->size = parse_directory(argv[1], &root_entry->child);
+
+ rom_image = mmap(NULL, MAXROM, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (-1 == (int) (long) rom_image) {
+ perror("ROM image map");
+ exit(1);
+ }
+ offset = write_superblock(root_entry, rom_image);
+ printf("Super block: %d bytes\n", offset);
+
+ offset = write_directory_structure(root_entry->child, rom_image, offset);
+ printf("Directory data: %d bytes\n", offset);
+
+ offset = write_data(root_entry, rom_image, offset);
+ printf("Everything: %d bytes\n", offset);
+
+ written = write(fd, rom_image, offset);
+ if (written < 0) {
+ perror("rom image");
+ exit(1);
+ }
+ if (offset != written) {
+ fprintf(stderr, "ROM image write failed (%d %d)\n", written, offset);
+ exit(1);
+ }
+ return 0;
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)