10 #include <sys/ioctl.h>
29 The Palacios cookie encodes "v3vee" followed by a
30 3 byte version code. There are currently two versions:
32 \0\0\0 => original (no checksum)
36 #define COOKIE "v3vee\0\0\0"
38 #define COOKIE_VERSION_OFFSET 5
39 #define COOKIE_VERSION_LEN 3
41 int version = 1; // default version is now 1
45 struct file_info files[MAX_FILES];
50 int parse_config_input(ezxml_t cfg_input);
51 int write_output(char * filename, ezxml_t cfg_output);
52 int copy_file(int file_index, FILE * data_file);
55 printf("Usage: build_vm <infile> [-v version] [-o outfile]\n");
58 int main(int argc, char ** argv) {
60 char * outfile = NULL;
63 memset((char *)files, 0, sizeof(files));
67 while ((c = getopt(argc, argv, "ho:v:")) != -1) {
73 version = atoi(optarg);
88 if (version != 0 && version != 1) {
89 printf("Only versions 0 and 1 are supported\n");
93 infile = argv[optind];
96 if (outfile == NULL) {
97 char * endptr = rindex(infile, '.');
99 outfile = malloc(strlen(infile) + strlen(".dat") + 1);
101 strncpy(outfile, infile, endptr - infile);
103 sprintf(outfile, "%s.dat", outfile);
108 printf("Input: [%s] ==>> Output: [%s]\n", infile, outfile);
110 ezxml_t cfg_input = ezxml_parse_file(infile);
111 if (strcmp("", ezxml_error(cfg_input)) != 0) {
112 printf("%s\n", ezxml_error(cfg_input));
116 if (cfg_input == NULL) {
117 printf("Could not open configuration input file: %s\n", infile);
125 if (parse_config_input(cfg_input) == -1) {
126 printf("Error parsing configuration input\n");
130 // printf("xml : %s\n", ezxml_toxml(cfg_input));
138 write_output(outfile, cfg_input);
144 char * get_val(ezxml_t cfg, char * tag) {
145 char * attrib = (char *)ezxml_attr(cfg, tag);
146 ezxml_t txt = ezxml_child(cfg, tag);
148 if ((txt != NULL) && (attrib != NULL)) {
149 printf("Invalid Cfg file: Duplicate value for %s (attr=%s, txt=%s)\n",
150 tag, attrib, ezxml_txt(txt));
154 return (attrib == NULL) ? ezxml_txt(txt) : attrib;
159 int parse_config_input(ezxml_t cfg_input) {
160 ezxml_t file_tags = NULL;
161 ezxml_t tmp_file_tag = NULL;
163 // files are transformed into blobs that are slapped to the end of the file
165 file_tags = ezxml_child(cfg_input, "files");
167 tmp_file_tag = ezxml_child(file_tags, "file");
169 while (tmp_file_tag) {
170 char * filename = get_val(tmp_file_tag, "filename");
171 struct stat file_stats;
172 char * id = get_val(tmp_file_tag, "id");
176 if (stat(filename, &file_stats) != 0) {
181 files[num_files].size = (unsigned int)file_stats.st_size;
182 strncpy(files[num_files].id, id, 256);
183 strncpy(files[num_files].filename, filename, 2048);
185 snprintf(index_buf, 256, "%d", num_files);
186 ezxml_set_attr_d(tmp_file_tag, "index", index_buf);
189 tmp_file_tag = ezxml_next(tmp_file_tag);
197 static int generate_file_hashes (char * filename,
198 unsigned long long hdr_offset,
200 unsigned char * file_data;
201 unsigned char * out_data;
202 struct mem_file_hdr * hdrs = NULL;
206 out_fd = open(filename, O_RDWR);
208 fprintf(stderr, "Couldn't open output file %s\n", filename);
213 /* mmap the out file, easy access to file headers */
214 if ((out_data = mmap(0,
216 PROT_READ|PROT_WRITE,
220 fprintf(stderr, "Error mapping output file (%d)\n", errno);
224 hdrs = (struct mem_file_hdr *)(out_data + hdr_offset);
226 /* mmap each file, then update it's hash */
227 for (i = 0; i < num_files; i++) {
229 fd = open(files[i].filename, O_RDONLY);
231 fprintf(stderr, "Error opening file %s\n",
236 if ((file_data = mmap(0,
242 fprintf(stderr, "Could not mmap file for hashing\n");
246 /* generate the hash and save it */
247 hdrs[i].file_hash = v3_hash_buffer(file_data, hdrs[i].file_size);
248 printf("Generating hash for file %s (hash=0x%lx)\n",
249 files[i].filename, hdrs[i].file_hash);
251 munmap(file_data, hdrs[i].file_size);
255 munmap(out_data, st.st_size);
259 void gen_cookie(char *dest)
261 memcpy(dest,COOKIE,COOKIE_LEN);
262 dest[COOKIE_VERSION_OFFSET] = (((unsigned)version) >> 16) & 0xff;
263 dest[COOKIE_VERSION_OFFSET+1] = (((unsigned)version) >> 8) & 0xff;
264 dest[COOKIE_VERSION_OFFSET+2] = (((unsigned)version) >> 0) & 0xff;
268 int write_output(char * filename, ezxml_t cfg_output) {
269 FILE * data_file = fopen(filename, "w+");
270 char * new_cfg_str = ezxml_toxml(cfg_output);
271 unsigned int cfg_len = strlen(new_cfg_str);
272 unsigned long long zero = 0;
274 unsigned long long offset = 0;
275 unsigned long long file_cnt = num_files;
276 unsigned long long hdr_offset = 0;
277 char cookie[COOKIE_LEN];
281 fwrite(cookie, COOKIE_LEN, 1, data_file);
282 offset += COOKIE_LEN;
284 // printf("New config: \n%s\n", new_cfg_str);
286 fwrite(&cfg_len, sizeof(unsigned int), 1, data_file);
287 offset += sizeof(unsigned int);
289 fwrite(new_cfg_str, cfg_len, 1, data_file);
292 fwrite(&zero, 1, 8, data_file);
295 printf("Total number of files: %llu\n", file_cnt);
297 fwrite(&file_cnt, 8, 1, data_file);
302 // for version 0, we simply have the file num, offset, size list
303 // each index entry is 16 bytes long plus end padding
304 offset += (16 * num_files) + 8;
305 } else if (version==1) {
306 // For a version 1, we have the file num, offset, size, and hash list
307 // We need to remember where this begins in the file, though...
310 // each index entry is (16+sizeof(unsigned long)) bytes long plus end padding
311 offset += ((16 + sizeof(unsigned long)) * num_files) + 8;
314 for (i = 0; i < num_files; i++) {
315 fwrite(&i, 4, 1, data_file);
316 fwrite(&(files[i].size), 4, 1, data_file);
317 fwrite(&offset, 8, 1, data_file);
320 /* we can't generate the hash yet, zero for now */
321 fwrite(&zero, sizeof(unsigned long), 1, data_file);
324 offset += files[i].size;
327 fwrite(&zero, 1, 8, data_file);
329 for (i = 0; i < num_files; i++) {
331 copy_file(i, data_file);
338 // We now will go back and place the hashes
339 if (generate_file_hashes(filename,
342 fprintf(stderr, "Error generating file hashes\n");
352 #define XFER_BLK_SIZE 4096
354 int copy_file(int file_index, FILE * data_file) {
355 char xfer_buf[XFER_BLK_SIZE];
356 int bytes_to_read = files[file_index].size;
358 int xfer_len = XFER_BLK_SIZE;
359 FILE * in_file = NULL;
360 char * filename = files[file_index].filename;
367 printf("Copying [%d] -- %s \n",
372 if (ioctl(STDIO_FD, TIOCGWINSZ, &wsz) == -1) {
373 printf("ioctl error on STDIO\n");
378 memset(cons_line, 0, 256);
379 snprintf(cons_line, 256, "\r(%s) [", files[file_index].id);
380 prog_len = wsz.ws_col - (strlen(cons_line) + 11);
384 in_file = fopen(filename, "r");
386 while (bytes_to_read > 0) {
387 struct winsize tmp_wsz;
390 if (ioctl(STDIO_FD, TIOCGWINSZ, &tmp_wsz) == -1) {
391 printf("ioctl error on STDIO\n");
395 ratio = (double)bytes_read / (double)(files[file_index].size);
396 tmp_dots = (int)(ratio * (double)prog_len);
398 if ((tmp_dots != num_dots) || (tmp_wsz.ws_col != wsz.ws_col)) {
405 num_blanks = prog_len - num_dots;
407 memset(cons_line, 0, 256);
408 snprintf(cons_line, 256, "\r(%s) [", files[file_index].id);
410 for (i = 0; i <= num_dots; i++) {
411 strcat(cons_line, "=");
414 for (i = 0; i < num_blanks - 1; i++) {
415 strcat(cons_line, " ");
418 strcat(cons_line, "] ");
420 // printf("console width = %d\n", wsz.ws_col);
421 write(STDIO_FD, cons_line, wsz.ws_col);
426 if (xfer_len > bytes_to_read) {
427 xfer_len = bytes_to_read;
430 if (fread(xfer_buf, xfer_len, 1, in_file) == 0) {
431 printf("Error reading data file %s\n", filename);
435 if (fwrite(xfer_buf, xfer_len, 1, data_file) == 0) {
436 printf("Error writing data file contents");
441 bytes_read += xfer_len;
442 bytes_to_read -= xfer_len;
445 strcat(cons_line, "Done\n");
446 write(STDIO_FD, cons_line, wsz.ws_col);