aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohan Srinivasan <srmohan@google.com>2016-07-26 15:06:29 -0700
committerDaniel Rosenberg <drosen@google.com>2017-02-08 18:00:20 -0800
commit89ad674ab0175600088acfee8fb90b3d5af4f287 (patch)
tree611b9b4d567c8bd651ec87f0ca289d8e273f2e45
parent4445cd175ee8ed20fdec0537a76a6e3cb65fdb53 (diff)
downloadsquashfs-tools-89ad674ab0175600088acfee8fb90b3d5af4f287.tar.gz
SquashFS whitelist support.
Support for specifying a (whole file) whitelist to mksquashfs, so that frequently read in files will not be compressed. Bug: 28605313 Signed-off-by: Mohan Srinivasan <srmohan@google.com> Change-Id: I34e3dc9369c702ce57713d5284e0d62d3cc0e5f1
-rw-r--r--squashfs-tools/mksquashfs.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/squashfs-tools/mksquashfs.c b/squashfs-tools/mksquashfs.c
index 936ae05..60be156 100644
--- a/squashfs-tools/mksquashfs.c
+++ b/squashfs-tools/mksquashfs.c
@@ -127,6 +127,12 @@ unsigned int id_count = 0;
int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0,
sock_count = 0;
+/* ANDROID CHANGES START*/
+#ifdef ANDROID
+int whitelisted_count = 0;
+#endif
+/* ANDROID CHANGES END */
+
/* write position within data section */
long long bytes = 0, total_bytes = 0;
@@ -330,6 +336,24 @@ void write_filesystem_tables(struct squashfs_super_block *sBlk, int nopad);
unsigned short get_checksum_mem(char *buff, int bytes);
void check_usable_phys_mem(int total_mem);
+/* ANDROID CHANGES START*/
+#ifdef ANDROID
+static int whitelisted(struct stat *buf);
+static void add_whitelist_entry(char *filename, struct stat *buf);
+static int add_whitelist(char *path);
+static void process_whitelist_file(char *argv);
+
+#define WHITELIST_SIZE 8192
+int whitelist = 0;
+
+struct whitelist_info {
+ dev_t st_dev;
+ ino_t st_ino;
+};
+char *whitelist_filename = NULL;
+struct whitelist_info *whitelist_paths = NULL;
+#endif
+/* ANDROID CHANGES END */
void prep_exit()
{
@@ -3078,7 +3102,16 @@ struct inode_info *lookup_inode3(struct stat *buf, int pseudo, int id,
*/
inode->no_fragments = no_fragments;
inode->always_use_fragments = always_use_fragments;
+
+/* ANDROID CHANGES START*/
+#ifdef ANDROID
+ /* Check the whitelist */
+ inode->noD = whitelisted(buf);
+#else
inode->noD = noD;
+#endif
+/* ANDROID CHANGES END */
+
inode->noF = noF;
inode->next = inode_info[ino_hash];
@@ -4762,6 +4795,150 @@ void process_exclude_file(char *argv)
fclose(fd);
}
+/* ANDROID CHANGES START*/
+#ifdef ANDROID
+/*
+ * Return TRUE (don't compress) if the (regular) file is in the
+ * whitelist. Else return the Global noD value.
+ *
+ * Note : These functions are lifted 100% from the existing exclude
+ * file code. For maintainability, I've kept this code separate from
+ * the exclude code instead of having common code for both paths.
+ */
+static int
+whitelisted(struct stat *buf)
+{
+ int i;
+
+ /*
+ * only regular files in the whitelist
+ */
+ if (!S_ISREG(buf->st_mode))
+ return noD;
+ for (i = 0; i < whitelist; i++) {
+ if ((whitelist_paths[i].st_dev == buf->st_dev) &&
+ (whitelist_paths[i].st_ino == buf->st_ino)) {
+ /* Don't compress */
+ whitelisted_count++;
+ return TRUE;
+ }
+ }
+ return noD;
+}
+
+static void
+add_whitelist_entry(char *filename, struct stat *buf)
+{
+ if (!S_ISREG(buf->st_mode)) {
+ BAD_ERROR("Cannot whitelist %s only regular files can be whitelisted",
+ filename);
+ }
+ if (whitelist % WHITELIST_SIZE == 0) {
+ whitelist_paths = realloc(whitelist_paths,
+ (whitelist + WHITELIST_SIZE)
+ * sizeof(struct whitelist_info));
+ if (whitelist_paths == NULL)
+ MEM_ERROR();
+ }
+ whitelist_paths[whitelist].st_dev = buf->st_dev;
+ whitelist_paths[whitelist++].st_ino = buf->st_ino;
+}
+
+static int
+add_whitelist(char *path)
+{
+ int i;
+ char *filename;
+ struct stat buf;
+
+ /* Absolute of (filesystem) relative path */
+ if (path[0] == '/' || strncmp(path, "./", 2) == 0 ||
+ strncmp(path, "../", 3) == 0) {
+ if(lstat(path, &buf) == -1) {
+ BAD_ERROR("Cannot stat whitelist dir/file %s because "
+ "%s", path, strerror(errno));
+ }
+ add_whitelist_entry(path, &buf);
+ return TRUE;
+ }
+
+ /* pathname relative to mksquashfs source dirs */
+ for(i = 0; i < source; i++) {
+ int res = asprintf(&filename, "%s/%s", source_path[i], path);
+ if(res == -1)
+ BAD_ERROR("asprintf failed in add_whitelist\n");
+ if(lstat(filename, &buf) == -1) {
+ if(!(errno == ENOENT || errno == ENOTDIR)) {
+ BAD_ERROR("Cannot stat whitelist dir/file %s "
+ "because %s", filename, strerror(errno));
+ }
+ free(filename);
+ continue;
+ }
+ add_whitelist_entry(filename, &buf);
+ free(filename);
+ }
+ return TRUE;
+}
+
+static void
+process_whitelist_file(char *argv)
+{
+ FILE *fd;
+ char buffer[MAX_LINE + 1]; /* overflow safe */
+ char *filename;
+
+ fd = fopen(argv, "r");
+ if(fd == NULL)
+ BAD_ERROR("Failed to open whitelist file \"%s\" because %s\n",
+ argv, strerror(errno));
+
+ while(fgets(filename = buffer, MAX_LINE + 1, fd) != NULL) {
+ int len = strlen(filename);
+
+ if(len == MAX_LINE && filename[len - 1] != '\n')
+ /* line too large */
+ BAD_ERROR("Line too long when reading "
+ "whitelist file \"%s\", larger than %d "
+ "bytes\n", argv, MAX_LINE);
+
+ /*
+ * Remove '\n' terminator if it exists (the last line
+ * in the file may not be '\n' terminated)
+ */
+ if(len && filename[len - 1] == '\n')
+ filename[len - 1] = '\0';
+
+ /* Skip any leading whitespace */
+ while(isspace(*filename))
+ filename ++;
+
+ /* if comment line, skip */
+ if(*filename == '#')
+ continue;
+
+ /*
+ * check for initial backslash, to accommodate
+ * filenames with leading space or leading # character
+ */
+ if(*filename == '\\')
+ filename ++;
+
+ /* if line is now empty after skipping characters, skip it */
+ if(*filename == '\0')
+ continue;
+
+ add_whitelist(filename);
+ }
+
+ if(ferror(fd))
+ BAD_ERROR("Reading whitelist file \"%s\" failed because %s\n",
+ argv, strerror(errno));
+
+ fclose(fd);
+}
+#endif
+/* ANDROID CHANGES END */
#define RECOVER_ID "Squashfs recovery file v1.0\n"
#define RECOVER_ID_SIZE 28
@@ -5007,6 +5184,9 @@ void write_filesystem_tables(struct squashfs_super_block *sBlk, int nopad)
group->gr_name, id_table[i]->id);
}
}
+
+ printf("Number of whitelisted (uncompressed) files %d\n",
+ whitelisted_count);
}
@@ -5715,6 +5895,12 @@ print_compressor_options:
exit(1);
}
fs_config_file = argv[i];
+ } else if(strcmp(argv[i], "-whitelist") == 0) {
+ if(++i == argc) {
+ ERROR("%s: -whitelist missing filename\n", argv[0]);
+ exit(1);
+ }
+ whitelist_filename = argv[i];
}
else if(strcmp(argv[i], "-t") == 0) {
if(++i == argc) {
@@ -5834,6 +6020,8 @@ printOptions:
"acceptable compression ratio of a block to\n\t\t\t"
"<compress_thresh_per> otherwise don't compress. "
"Default 0%\n");
+ ERROR("-whitelist <file>\tAndroid specific whitelist "
+ "one entry per line (no wildcards)\n");
#endif
/* ANDROID CHANGES END */
ERROR("-noI\t\t\tdo not compress inode table\n");
@@ -5949,6 +6137,8 @@ printOptions:
} else if (mount_point) {
fs_config_func = fs_config;
}
+ if (whitelist_filename)
+ process_whitelist_file(whitelist_filename);
#endif
/* ANDROID CHANGES END */