blob: b55d13f1de74e1f403b78f96b214646b4e6c5ad1 [file] [log] [blame] [edit]
/* 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;
}