Cleanup: unify input file processing code

Signed-off-by: David Oberhollenzer <goliath@infraroot.at>
This commit is contained in:
David Oberhollenzer 2019-01-31 22:09:38 +01:00
parent 6fc871b3ff
commit a32a4cb149
7 changed files with 148 additions and 165 deletions

View File

@ -24,7 +24,7 @@ EXTRA_DIST = autogen.sh
##### commands #####
# pack command
pkg_SOURCES += main/cmd/pack/filelist.c main/cmd/pack/filelist_read.c
pkg_SOURCES += main/cmd/pack/filelist.c
pkg_SOURCES += main/cmd/pack/write_toc.c main/cmd/pack/write_files.c
pkg_SOURCES += main/cmd/pack/pack.h main/cmd/pack/pack.c
pkg_SOURCES += main/cmd/pack/desc.c main/cmd/pack/write_hdr.c

View File

@ -10,10 +10,18 @@ typedef struct {
size_t linenum;
} input_file_t;
int prefetch_line(input_file_t *f);
typedef struct {
const char *name;
int (*handle)(input_file_t *f, void *obj);
} keyword_handler_t;
void cleanup_file(input_file_t *f);
int open_file(input_file_t *f, const char *filename);
int process_file(input_file_t *f, const keyword_handler_t *handlers,
size_t count, void *obj);
void input_file_complain(const input_file_t *f, const char *msg);
#endif /* INPUT_FILE_H */

View File

@ -1,8 +1,9 @@
#include "pack.h"
static int handle_requires(input_file_t *f, pkg_desc_t *desc)
static int handle_requires(input_file_t *f, void *obj)
{
char *ptr = f->line, *end;
pkg_desc_t *desc = obj;
dependency_t *dep;
size_t len;
@ -18,15 +19,13 @@ static int handle_requires(input_file_t *f, pkg_desc_t *desc)
break;
if (len > 0xFF) {
fprintf(stderr, "%s: %zu: dependency name too long\n",
f->filename, f->linenum);
input_file_complain(f, "dependency name too long");
return -1;
}
dep = calloc(1, sizeof(*dep) + len + 1);
if (dep == NULL) {
fprintf(stderr, "%s: %zu: out of memory\n",
f->filename, f->linenum);
input_file_complain(f, "out of memory");
return -1;
}
@ -41,27 +40,25 @@ static int handle_requires(input_file_t *f, pkg_desc_t *desc)
return 0;
}
static int handle_name(input_file_t *f, pkg_desc_t *desc)
static int handle_name(input_file_t *f, void *obj)
{
pkg_desc_t *desc = obj;
if (desc->name != NULL) {
fprintf(stderr, "%s: %zu: name redefined\n",
f->filename, f->linenum);
input_file_complain(f, "name redefined");
return -1;
}
desc->name = strdup(f->line);
if (desc->name == NULL) {
fputs("out of memory\n", stderr);
input_file_complain(f, "out of memory");
return -1;
}
return 0;
}
static const struct {
const char *name;
int (*handle)(input_file_t *f, pkg_desc_t *desc);
} line_hooks[] = {
static const keyword_handler_t line_hooks[] = {
{ "requires", handle_requires },
{ "name", handle_name },
};
@ -71,58 +68,19 @@ static const struct {
int desc_read(const char *path, pkg_desc_t *desc)
{
input_file_t f;
size_t i, len;
char *ptr;
int ret;
memset(desc, 0, sizeof(*desc));
if (open_file(&f, path))
return -1;
for (;;) {
ret = prefetch_line(&f);
if (ret < 0)
goto fail;
if (ret > 0)
break;
ptr = f.line;
for (i = 0; i < NUM_LINE_HOOKS; ++i) {
len = strlen(line_hooks[i].name);
if (strncmp(ptr, line_hooks[i].name, len) != 0)
continue;
if (!isspace(ptr[len]) && ptr[len] != '\0')
continue;
for (ptr += len; isspace(*ptr); ++ptr)
;
memmove(f.line, ptr, strlen(ptr) + 1);
break;
}
if (i == NUM_LINE_HOOKS) {
fprintf(stderr, "%s: %zu: unknown description field\n",
f.filename, f.linenum);
goto fail;
}
ret = line_hooks[i].handle(&f, desc);
if (ret)
goto fail;
}
if (desc->name == NULL) {
fprintf(stderr, "%s: no name given in package description\n",
f.filename);
if (process_file(&f, line_hooks, NUM_LINE_HOOKS, desc)) {
cleanup_file(&f);
return -1;
}
cleanup_file(&f);
return 0;
fail:
cleanup_file(&f);
return -1;
}
void desc_free(pkg_desc_t *desc)

View File

@ -7,14 +7,9 @@ static char *skipspace(char *str)
return str;
}
static void complain(const input_file_t *f, const char *msg)
{
fprintf(stderr, "%s: %zu: %s\n", f->filename, f->linenum, msg);
}
static void oom(input_file_t *f)
{
complain(f, "out of memory");
input_file_complain(f, "out of memory");
}
static image_entry_t *filelist_mkentry(input_file_t *f, mode_t filetype)
@ -34,7 +29,7 @@ static image_entry_t *filelist_mkentry(input_file_t *f, mode_t filetype)
;
if (!isspace(line[i])) {
complain(f, "expected space after file name");
input_file_complain(f, "expected space after file name");
goto fail;
}
@ -46,17 +41,17 @@ static image_entry_t *filelist_mkentry(input_file_t *f, mode_t filetype)
memcpy(ent->name, line, i);
if (canonicalize_name(ent->name)) {
complain(f, "invalid file name");
input_file_complain(f, "invalid file name");
goto fail;
}
if (ent->name[0] == '\0') {
complain(f, "refusing to add entry for '/'");
input_file_complain(f, "refusing to add entry for '/'");
goto fail;
}
if (strlen(ent->name) > 0xFFFF) {
complain(f, "name too long");
input_file_complain(f, "name too long");
goto fail;
}
@ -64,20 +59,20 @@ static image_entry_t *filelist_mkentry(input_file_t *f, mode_t filetype)
/* mode */
if (!isdigit(*line)) {
complain(f, "expected numeric mode after file name");
input_file_complain(f, "expected numeric mode after file name");
goto fail;
}
while (isdigit(*line)) {
if (*line > '7') {
complain(f, "mode must be octal number");
input_file_complain(f, "mode must be octal number");
goto fail;
}
ent->mode = (ent->mode << 3) | (*(line++) - '0');
}
if (!isspace(*line)) {
complain(f, "expected space after file mode");
input_file_complain(f, "expected space after file mode");
goto fail;
}
@ -87,7 +82,7 @@ static image_entry_t *filelist_mkentry(input_file_t *f, mode_t filetype)
/* uid */
if (!isdigit(*line)) {
complain(f, "expected numeric UID after mode");
input_file_complain(f, "expected numeric UID after mode");
goto fail;
}
@ -95,7 +90,7 @@ static image_entry_t *filelist_mkentry(input_file_t *f, mode_t filetype)
ent->uid = (ent->uid * 10) + (*(line++) - '0');
if (!isspace(*line)) {
complain(f, "expected space after UID");
input_file_complain(f, "expected space after UID");
goto fail;
}
@ -103,7 +98,7 @@ static image_entry_t *filelist_mkentry(input_file_t *f, mode_t filetype)
/* gid */
if (!isdigit(*line)) {
complain(f, "expected numeric GID after UID");
input_file_complain(f, "expected numeric GID after UID");
goto fail;
}
@ -121,17 +116,26 @@ fail:
return NULL;
}
image_entry_t *filelist_mkdir(input_file_t *f)
int filelist_mkdir(input_file_t *f, void *obj)
{
return filelist_mkentry(f, S_IFDIR);
}
image_entry_t *filelist_mkslink(input_file_t *f)
{
image_entry_t *ent = filelist_mkentry(f, S_IFLNK);
image_entry_t *ent = filelist_mkentry(f, S_IFDIR);
image_entry_t **listptr = obj;
if (ent == NULL)
return NULL;
return -1;
ent->next = *listptr;
*listptr = ent;
return 0;
}
int filelist_mkslink(input_file_t *f, void *obj)
{
image_entry_t *ent = filelist_mkentry(f, S_IFLNK);
image_entry_t **listptr = obj;
if (ent == NULL)
return -1;
ent->data.symlink.target = strdup(f->line);
if (ent->data.symlink.target == NULL) {
@ -140,23 +144,26 @@ image_entry_t *filelist_mkslink(input_file_t *f)
}
if (strlen(ent->data.symlink.target) > 0xFFFF) {
complain(f, "symlink target too long");
input_file_complain(f, "symlink target too long");
goto fail;
}
return ent;
ent->next = *listptr;
*listptr = ent;
return 0;
fail:
image_entry_free(ent);
return NULL;
return -1;
}
image_entry_t *filelist_mkfile(input_file_t *f)
int filelist_mkfile(input_file_t *f, void *obj)
{
image_entry_t *ent = filelist_mkentry(f, S_IFREG);
image_entry_t **listptr = obj;
struct stat sb;
if (ent == NULL)
return NULL;
return -1;
ent->data.file.location = strdup(f->line);
if (ent->data.file.location == NULL) {
@ -171,13 +178,49 @@ image_entry_t *filelist_mkfile(input_file_t *f)
if (sizeof(off_t) > sizeof(uint64_t) &&
sb.st_size > (off_t)(~((uint64_t)0))) {
complain(f, "input file is too big");
input_file_complain(f, "input file is too big");
goto fail;
}
ent->data.file.size = sb.st_size;
return ent;
ent->next = *listptr;
*listptr = ent;
return 0;
fail:
image_entry_free(ent);
return -1;
}
static const keyword_handler_t line_hooks[] = {
{ "file", filelist_mkfile },
{ "dir", filelist_mkdir },
{ "slink", filelist_mkslink },
};
#define NUM_LINE_HOOKS (sizeof(line_hooks) / sizeof(line_hooks[0]))
image_entry_t *filelist_read(const char *filename)
{
image_entry_t *list = NULL;
input_file_t f;
if (open_file(&f, filename))
return NULL;
if (process_file(&f, line_hooks, NUM_LINE_HOOKS, &list))
goto fail;
if (list == NULL) {
fprintf(stderr, "%s: does not contain any entries\n",
f.filename);
goto fail;
}
cleanup_file(&f);
return list;
fail:
cleanup_file(&f);
image_entry_free_list(list);
return NULL;
}

View File

@ -1,73 +0,0 @@
#include "pack.h"
static const struct {
const char *name;
image_entry_t *(*handle)(input_file_t *f);
} line_hooks[] = {
{ "file", filelist_mkfile },
{ "dir", filelist_mkdir },
{ "slink", filelist_mkslink },
};
#define NUM_LINE_HOOKS (sizeof(line_hooks) / sizeof(line_hooks[0]))
image_entry_t *filelist_read(const char *filename)
{
image_entry_t *ent, *list = NULL;
input_file_t f;
size_t i, len;
char *ptr;
int ret;
if (open_file(&f, filename))
return NULL;
for (;;) {
ret = prefetch_line(&f);
if (ret < 0)
goto fail;
if (ret > 0)
break;
ptr = f.line;
for (i = 0; i < NUM_LINE_HOOKS; ++i) {
len = strlen(line_hooks[i].name);
if (strncmp(ptr, line_hooks[i].name, len) != 0)
continue;
if (!isspace(ptr[len]) && ptr[len] != '\0')
continue;
for (ptr += len; isspace(*ptr); ++ptr)
;
memmove(f.line, ptr, strlen(ptr) + 1);
break;
}
if (i == NUM_LINE_HOOKS) {
fprintf(stderr, "%s: %zu: unknown entry type\n",
f.filename, f.linenum);
goto fail;
}
ent = line_hooks[i].handle(&f);
if (ent == NULL)
goto fail;
ent->next = list;
list = ent;
}
if (list == NULL) {
fprintf(stderr, "%s: does not contain any entries\n",
f.filename);
goto fail;
}
cleanup_file(&f);
return list;
fail:
cleanup_file(&f);
image_entry_free_list(list);
return NULL;
}

View File

@ -33,11 +33,11 @@ typedef struct {
char *name;
} pkg_desc_t;
image_entry_t *filelist_mkdir(input_file_t *f);
int filelist_mkdir(input_file_t *f, void *obj);
image_entry_t *filelist_mkslink(input_file_t *f);
int filelist_mkslink(input_file_t *f, void *obj);
image_entry_t *filelist_mkfile(input_file_t *f);
int filelist_mkfile(input_file_t *f, void *obj);
image_entry_t *filelist_read(const char *filename);

View File

@ -5,7 +5,7 @@
#include "input_file.h"
int prefetch_line(input_file_t *f)
static int prefetch_line(input_file_t *f)
{
char *line, *ptr;
ssize_t ret;
@ -77,3 +77,50 @@ int open_file(input_file_t *f, const char *filename)
return 0;
}
void input_file_complain(const input_file_t *f, const char *msg)
{
fprintf(stderr, "%s: %zu: %s\n", f->filename, f->linenum, msg);
}
int process_file(input_file_t *f, const keyword_handler_t *handlers,
size_t count, void *obj)
{
size_t i, len;
char *ptr;
int ret;
for (;;) {
ret = prefetch_line(f);
if (ret < 0)
return -1;
if (ret > 0)
break;
ptr = f->line;
for (i = 0; i < count; ++i) {
len = strlen(handlers[i].name);
if (strncmp(ptr, handlers[i].name, len) != 0)
continue;
if (!isspace(ptr[len]) && ptr[len] != '\0')
continue;
for (ptr += len; isspace(*ptr); ++ptr)
;
memmove(f->line, ptr, strlen(ptr) + 1);
break;
}
if (i == count) {
fprintf(stderr, "%s: %zu: unknown keyword\n",
f->filename, f->linenum);
return -1;
}
if (handlers[i].handle(f, obj))
return -1;
}
return 0;
}