/* * Copyright 2015 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include #include #include #include #include #include #include #include #include #include "file_type.h" #include "futility.h" /* Description and functions to handle each file type */ struct futil_file_type_s { /* Short name for this type */ const char *name; /* Human-readable description */ const char *desc; /* Functions to identify, display, and sign this type of file. */ enum futil_file_type (*recognize)(uint8_t *buf, uint32_t len); int (*show)(const char *name, uint8_t *buf, uint32_t len, void *data); int (*sign)(const char *name, uint8_t *buf, uint32_t len, void *data); }; /* Populate a list of file types and operator functions. */ static const struct futil_file_type_s futil_file_types[] = { {"unknown", "not something we know about", 0, 0, 0}, #define R_(x) x #define S_(x) x #define NONE 0 #define FILE_TYPE(A, B, C, D, E, F) {B, C, D, E, F}, #include "file_type.inc" #undef FILE_TYPE #undef NONE #undef S_ #undef R_ }; const char * const futil_file_type_name(enum futil_file_type type) { return futil_file_types[type].name; } const char * const futil_file_type_desc(enum futil_file_type type) { return futil_file_types[type].desc; } /* Name to enum. Returns true on success. */ int futil_str_to_file_type(const char *str, enum futil_file_type *type) { int i; for (i = 0; i < NUM_FILE_TYPES; i++) if (!strcasecmp(str, futil_file_types[i].name)) { *type = i; return 1; } *type = FILE_TYPE_UNKNOWN; return 0; } /* Print the list of type names and exit with the given value. */ void print_file_types_and_exit(int retval) { int i; printf("\nValid file types are:\n\n"); for (i = 0; i < NUM_FILE_TYPES; i++) printf(" %-20s%s\n", futil_file_types[i].name, futil_file_types[i].desc); printf("\n"); exit(retval); } /* Try to figure out what we're looking at */ enum futil_file_type futil_file_type_buf(uint8_t *buf, uint32_t len) { enum futil_file_type type; int i; for (i = 0; i < NUM_FILE_TYPES; i++) { if (futil_file_types[i].recognize) { type = futil_file_types[i].recognize(buf, len); if (type != FILE_TYPE_UNKNOWN) return type; } } return FILE_TYPE_UNKNOWN; } enum futil_file_err futil_file_type(const char *filename, enum futil_file_type *type) { int ifd; uint8_t *buf; uint32_t buf_len; struct stat sb; enum futil_file_err err = FILE_ERR_NONE; *type = FILE_TYPE_UNKNOWN; ifd = open(filename, O_RDONLY); if (ifd < 0) { fprintf(stderr, "Can't open %s: %s\n", filename, strerror(errno)); return FILE_ERR_OPEN; } if (0 != fstat(ifd, &sb)) { fprintf(stderr, "Can't stat input file: %s\n", strerror(errno)); close(ifd); return FILE_ERR_STAT; } if (S_ISREG(sb.st_mode) || S_ISBLK(sb.st_mode)) { err = futil_map_file(ifd, MAP_RO, &buf, &buf_len); if (err) { close(ifd); return err; } *type = futil_file_type_buf(buf, buf_len); err = futil_unmap_file(ifd, MAP_RO, buf, buf_len); if (err) { close(ifd); return err; } } else if (S_ISDIR(sb.st_mode)) { err = FILE_ERR_DIR; } else if (S_ISCHR(sb.st_mode)) { err = FILE_ERR_CHR; } else if (S_ISFIFO(sb.st_mode)) { err = FILE_ERR_FIFO; } else if (S_ISSOCK(sb.st_mode)) { err = FILE_ERR_SOCK; } if (close(ifd)) { fprintf(stderr, "Error when closing %s: %s\n", filename, strerror(errno)); return FILE_ERR_CLOSE; } return err; } int futil_file_type_show(enum futil_file_type type, const char *filename, uint8_t *buf, uint32_t len) { if (futil_file_types[type].show) return futil_file_types[type].show(filename, buf, len, 0); fprintf(stderr, "Don't know how to show %s (type %s)\n", filename, futil_file_type_name(type)); return 1; } int futil_file_type_sign(enum futil_file_type type, const char *filename, uint8_t *buf, uint32_t len) { if (futil_file_types[type].sign) return futil_file_types[type].sign(filename, buf, len, 0); fprintf(stderr, "Don't know how to sign %s (type %s)\n", filename, futil_file_type_name(type)); return 1; }