#include "common.h"
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include "nitroarc.h"
static FILE *s_logfile = NULL;
void progput(FILE *stream, const char *fmt, va_list args) {
fputs(PROGRAM ": ", stream);
vfprintf(stream, fmt, args);
fputc('\n', stream);
}
void progerr(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
progput(stderr, fmt, args);
va_end(args);
}
void proglog(const char *fmt, ...) {
if (s_logfile) {
va_list args;
va_start(args, fmt);
progput(stdout, fmt, args);
va_end(args);
}
}
int open_file(const char *path, const char *mode, FILE **out_f) {
assert(out_f);
FILE *f = fopen(path, mode);
if (f == NULL) {
progerr("could not open file '%s': %s", path, strerror(errno));
return PROGRAM_EFILEIO;
}
*out_f = f;
return PROGRAM_ENONE;
}
int load_file(const char *path, char **out_buf, size_t *out_size) {
assert(out_buf);
assert(out_size);
if (path == NULL) return PROGRAM_ENONE;
FILE *f = NULL;
char *buf = NULL;
int errc = open_file(path, "rb", &f);
if (errc) return errc;
if (!f) return PROGRAM_EGENERAL;
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
if (fsize == 0) { fclose(f); return PROGRAM_ENONE; }
if (fsize < 0) {
progerr("negative size for file '%s': %s", path, strerror(errno));
errc = PROGRAM_EFILEIO;
goto cleanup;
}
if ((buf = calloc(fsize + 1, 1)) == NULL) {
progerr("alloc failure for file '%s': %s", path, strerror(errno));
errc = PROGRAM_EALLOC;
goto cleanup;
}
long nread = fread(buf, 1, fsize, f);
if (nread != fsize) {
progerr("I/O failure for file '%s': %s", path, strerror(errno));
errc = PROGRAM_EFILEIO;
goto cleanup;
}
*out_buf = buf;
*out_size = fsize;
fclose(f);
return PROGRAM_ENONE;
cleanup:
free(buf);
fclose(f);
return errc;
}
int read_archive(const char *data, size_t size, nitroarc_t *narc) {
assert(data);
assert(narc);
if (size > UINT32_MAX) {
progerr("input data is too large to be an archive");
return PROGRAM_EGENERAL;
}
int errc = nitroarc_read(data, (uint32_t)size, narc);
if (errc) {
progerr("archive format error: %s", nitroarc_errs(errc));
return PROGRAM_ELIBERROR;
}
return PROGRAM_ENONE;
}
int set_logfile(bool verbose) {
s_logfile = verbose ? stderr : NULL;
return PROGRAM_ENONE;
}
int ensure_mkdir(const char *path) {
if (path == NULL || path[0] == 0) return PROGRAM_ENONE;
if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == -1) {
if (errno != EEXIST) {
progerr("could not create directory '%s': %s", path, strerror(errno));
return PROGRAM_EGENERAL;
}
errno = 0;
} else {
proglog("created new directory '%s'", path);
}
return PROGRAM_ENONE;
}
int set_workdir(const char *path) {
int errc = ensure_mkdir(path);
if (errc) return errc;
if (path && chdir(path) == -1) {
progerr("could not change directory '%s': %s", path, strerror(errno));
return PROGRAM_EFILEIO;
}
return PROGRAM_ENONE;
}
int write_file(const char *path, void *data, size_t size) {
assert(data);
FILE *f = NULL;
int errc = open_file(path, "wb", &f);
if (errc) return errc;
if (!f) return PROGRAM_EGENERAL;
if (fwrite(data, 1, size, f) != size) {
progerr("partial write failure for file '%s': %s", path, strerror(errno));
return PROGRAM_EFILEIO;
}
fclose(f);
return PROGRAM_ENONE;
}