| /* 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 <errno.h> |
| #include <fcntl.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #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; |
| } |
| |