1/* 2 * Create a squashfs filesystem. This is a highly compressed read only filesystem. 3 * 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 5 * Phillip Lougher <phillip@lougher.org.uk> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2, 10 * or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 20 * 21 * sort.c 22 */ 23 24#define TRUE 1 25#define FALSE 0 26 27#include <unistd.h> 28#include <stdio.h> 29#include <sys/types.h> 30#include <sys/stat.h> 31#include <fcntl.h> 32#include <errno.h> 33#include <dirent.h> 34#include <string.h> 35#include <stdlib.h> 36 37#include <linux/squashfs_fs.h> 38#include "global.h" 39#include "sort.h" 40 41#ifdef SQUASHFS_TRACE 42#define TRACE(s, args...) do { \ 43 printf("mksquashfs: "s, ## args); \ 44 } while(0) 45#else 46#define TRACE(s, args...) 47#endif 48 49#define INFO(s, args...) do { \ 50 if(!silent) printf("mksquashfs: "s, ## args); \ 51 } while(0) 52#define ERROR(s, args...) do { \ 53 fprintf(stderr, s, ## args); \ 54 } while(0) 55#define EXIT_MKSQUASHFS() do { \ 56 exit(1); \ 57 } while(0) 58#define BAD_ERROR(s, args...) do {\ 59 fprintf(stderr, "FATAL ERROR:" s, ##args);\ 60 EXIT_MKSQUASHFS();\ 61 } while(0); 62 63int mkisofs_style = -1; 64 65struct sort_info { 66 dev_t st_dev; 67 ino_t st_ino; 68 int priority; 69 struct sort_info *next; 70}; 71 72struct sort_info *sort_info_list[65536]; 73 74struct priority_entry *priority_list[65536]; 75 76extern int silent; 77extern squashfs_inode write_file(squashfs_inode *inode, struct dir_ent *dir_ent, long long size, int *c_size); 78 79 80int add_priority_list(struct dir_ent *dir, int priority) 81{ 82 struct priority_entry *new_priority_entry; 83 84 priority += 32768; 85 if((new_priority_entry = malloc(sizeof(struct priority_entry))) == NULL) { 86 ERROR("Out of memory allocating priority entry\n"); 87 return FALSE; 88 } 89 90 new_priority_entry->dir = dir;; 91 new_priority_entry->next = priority_list[priority]; 92 priority_list[priority] = new_priority_entry; 93 return TRUE; 94} 95 96 97int get_priority(char *filename, struct stat *buf, int priority) 98{ 99 int hash = buf->st_ino & 0xffff; 100 struct sort_info *s; 101 102 for(s = sort_info_list[hash]; s; s = s->next) 103 if((s->st_dev == buf->st_dev) && (s->st_ino == buf->st_ino)) { 104 TRACE("returning priority %d (%s)\n", s->priority, filename); 105 return s->priority; 106 } 107 TRACE("returning priority %d (%s)\n", priority, filename); 108 return priority; 109} 110 111 112#define ADD_ENTRY(buf, priority) {\ 113 int hash = buf.st_ino & 0xffff;\ 114 struct sort_info *s;\ 115 if((s = malloc(sizeof(struct sort_info))) == NULL) {\ 116 ERROR("Out of memory allocating sort list entry\n");\ 117 return FALSE;\ 118 }\ 119 s->st_dev = buf.st_dev;\ 120 s->st_ino = buf.st_ino;\ 121 s->priority = priority;\ 122 s->next = sort_info_list[hash];\ 123 sort_info_list[hash] = s;\ 124 } 125int add_sort_list(char *path, int priority, int source, char *source_path[]) 126{ 127 int i, n; 128 char filename[4096]; 129 struct stat buf; 130 131 TRACE("add_sort_list: filename %s, priority %d\n", path, priority); 132 if(strlen(path) > 1 && strcmp(path + strlen(path) - 2, "/*") == 0) 133 path[strlen(path) - 2] = '\0'; 134 135 TRACE("add_sort_list: filename %s, priority %d\n", path, priority); 136re_read: 137 if(path[0] == '/' || strncmp(path, "./", 2) == 0 || strncmp(path, "../", 3) == 0 || mkisofs_style == 1) { 138 if(lstat(path, &buf) == -1) 139 goto error; 140 TRACE("adding filename %s, priority %d, st_dev %llx, st_ino %llx\n", path, priority, buf.st_dev, buf.st_ino); 141 ADD_ENTRY(buf, priority); 142 return TRUE; 143 } 144 145 for(i = 0, n = 0; i < source; i++) { 146 strcat(strcat(strcpy(filename, source_path[i]), "/"), path); 147 if(lstat(filename, &buf) == -1) { 148 if(!(errno == ENOENT || errno == ENOTDIR)) 149 goto error; 150 continue; 151 } 152 ADD_ENTRY(buf, priority); 153 n ++; 154 } 155 156 if(n == 0 && mkisofs_style == -1 && lstat(path, &buf) != -1) { 157 ERROR("WARNING: Mkisofs style sortlist detected! This is supported but please\n"); 158 ERROR("convert to mksquashfs style sortlist! A sortlist entry "); 159 ERROR("should be\neither absolute (starting with "); 160 ERROR("'/') start with './' or '../' (taken to be\nrelative to $PWD), otherwise it "); 161 ERROR("is assumed the entry is relative to one\nof the source directories, i.e. with "); 162 ERROR("\"mksquashfs test test.sqsh\",\nthe sortlist "); 163 ERROR("entry \"file\" is assumed to be inside the directory test.\n\n"); 164 mkisofs_style = 1; 165 goto re_read; 166 } 167 168 mkisofs_style = 0; 169 170 if(n == 1) 171 return TRUE; 172 if(n > 1) 173 BAD_ERROR(" Ambiguous sortlist entry \"%s\"\n\nIt maps to more than one source entry! Please use an absolute path.\n", path); 174 175error: 176 fprintf(stderr, "Cannot stat sortlist entry \"%s\"\n", path); 177 fprintf(stderr, "This is probably because you're using the wrong file\n"); 178 fprintf(stderr, "path relative to the source directories\n"); 179 return FALSE; 180} 181 182 183void generate_file_priorities(struct dir_info *dir, int priority, struct stat *buf) 184{ 185 priority = get_priority(dir->pathname, buf, priority); 186 187 while(dir->current_count < dir->count) { 188 struct dir_ent *dir_ent = dir->list[dir->current_count++]; 189 struct stat *buf = &dir_ent->inode->buf; 190 if(dir_ent->data) 191 continue; 192 193 switch(buf->st_mode & S_IFMT) { 194 case S_IFREG: 195 add_priority_list(dir_ent, get_priority(dir_ent->pathname, buf, priority)); 196 break; 197 case S_IFDIR: 198 generate_file_priorities(dir_ent->dir, priority, buf); 199 break; 200 } 201 } 202 dir->current_count = 0; 203} 204 205 206int read_sort_file(char *filename, int source, char *source_path[]) 207{ 208 FILE *fd; 209 char sort_filename[16385]; 210 int priority; 211 212 if((fd = fopen(filename, "r")) == NULL) { 213 perror("Could not open sort_list file..."); 214 return FALSE; 215 } 216 while(fscanf(fd, "%s %d", sort_filename, &priority) != EOF) 217 if(priority >= -32768 && priority <= 32767) 218 add_sort_list(sort_filename, priority, source, source_path); 219 else 220 ERROR("Sort file %s, priority %d outside range of -32767:32768 - skipping...\n", sort_filename, priority); 221 fclose(fd); 222 return TRUE; 223} 224 225 226void sort_files_and_write(struct dir_info *dir) 227{ 228 int i; 229 struct priority_entry *entry; 230 squashfs_inode inode; 231 int duplicate_file; 232 233 for(i = 65535; i >= 0; i--) 234 for(entry = priority_list[i]; entry; entry = entry->next) { 235 TRACE("%d: %s\n", i - 32768, entry->dir->pathname); 236 if(entry->dir->inode->inode == SQUASHFS_INVALID_BLK) { 237 if(write_file(&inode, entry->dir, entry->dir->inode->buf.st_size, 238 &duplicate_file)) { 239 INFO("file %s, uncompressed size %lld bytes %s\n", 240 entry->dir->pathname, 241 entry->dir->inode->buf.st_size, 242 duplicate_file ? "DUPLICATE" : ""); 243 entry->dir->inode->inode = inode; 244 entry->dir->inode->type = SQUASHFS_FILE_TYPE; 245 } 246 } else 247 INFO("file %s, uncompressed size %lld bytes LINK\n", 248 entry->dir->pathname, entry->dir->inode->buf.st_size); 249 } 250} 251