core: Add file counting + state management
Signed-off-by: Ian Moffett <ian@mirocom.org>
This commit is contained in:
163
src/main.c
163
src/main.c
@@ -1,9 +1,32 @@
|
||||
#define _DEFAULT_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#define CAV_VERSION "0.0.1"
|
||||
|
||||
static const char *input_name = NULL;
|
||||
static const char *output_name = "out.cav";
|
||||
|
||||
/*
|
||||
* Represents the consume and vomit state machine
|
||||
*
|
||||
* @dir_fd: Input directory file descriptor
|
||||
* @dir: Opened directory
|
||||
* @pass_count: Number of passes made in file
|
||||
* @file_count: Number of files encountered including subdirectories
|
||||
*/
|
||||
struct cav_state {
|
||||
int dir_fd;
|
||||
DIR *dir;
|
||||
uint8_t pass_count;
|
||||
size_t file_count;
|
||||
};
|
||||
|
||||
static void
|
||||
help(void)
|
||||
{
|
||||
@@ -12,6 +35,8 @@ help(void)
|
||||
"--------------------------\n"
|
||||
"[-h] Display this help menu\n"
|
||||
"[-v] Display the version\n"
|
||||
"[-i] Input directory\n"
|
||||
"[-o] Output filename\n"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -27,12 +52,119 @@ version(void)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the cav state machine
|
||||
*
|
||||
* @state: State to initialize
|
||||
*
|
||||
* Returns zero on success
|
||||
*/
|
||||
static int
|
||||
state_init(struct cav_state *state)
|
||||
{
|
||||
if (state == NULL) {
|
||||
errno = -EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
state->dir_fd = open(input_name, O_RDONLY);
|
||||
if (state->dir_fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
state->dir = fdopendir(state->dir_fd);
|
||||
if (state->dir == NULL) {
|
||||
close(state->dir_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
state->pass_count = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the consume and vomit state
|
||||
*
|
||||
* @state: State to destroy
|
||||
*/
|
||||
static void
|
||||
state_destroy(struct cav_state *state)
|
||||
{
|
||||
if (state == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
closedir(state->dir);
|
||||
close(state->dir_fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Begin recursively scanning a directory to obtain information
|
||||
* needed to structure the offsets at the beginning of the file.
|
||||
*/
|
||||
static void
|
||||
consume_scan(const char *dir_path, struct cav_state *state, DIR *subdir)
|
||||
{
|
||||
struct dirent *dirent;
|
||||
char buf[256];
|
||||
DIR *dir;
|
||||
|
||||
if (dir_path == NULL || state == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
dir = (subdir == NULL) ? state->dir : subdir;
|
||||
while ((dirent = readdir(dir)) != NULL) {
|
||||
if (dirent->d_name[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (dirent->d_type) {
|
||||
case DT_DIR:
|
||||
snprintf(buf, sizeof(buf), "%s/%s", dir_path, dirent->d_name);
|
||||
if ((subdir = opendir(buf)) == NULL) {
|
||||
printf("failed to open subdir %s\n", buf);
|
||||
perror("opendir");
|
||||
continue;
|
||||
}
|
||||
|
||||
consume_scan(buf, state, subdir);
|
||||
break;
|
||||
default:
|
||||
++state->file_count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Consume a single pass in our yummy yummy consumption
|
||||
* process only to be thrown up again along with stomach
|
||||
* acids of your extraterrestrial friends.
|
||||
*/
|
||||
static void
|
||||
consume_pass(struct cav_state *state)
|
||||
{
|
||||
if (state == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (state->pass_count++) {
|
||||
case 0:
|
||||
/* Scan pass */
|
||||
consume_scan(input_name, state, NULL);
|
||||
printf("[pass 0] scanned %zu files\n", state->file_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct cav_state state;
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "hv")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "hvi:o:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
help();
|
||||
@@ -40,8 +172,37 @@ main(int argc, char **argv)
|
||||
case 'v':
|
||||
version();
|
||||
return -1;
|
||||
case 'i':
|
||||
input_name = strdup(optarg);
|
||||
break;
|
||||
case 'o':
|
||||
output_name = strdup(optarg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (input_name == NULL) {
|
||||
printf("fatal: expected input path\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize the state machine */
|
||||
if (state_init(&state) < 0) {
|
||||
perror("state_init");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are three passes required in the consumption operation
|
||||
*
|
||||
* pass 0): Obtain number of files for offset table creation
|
||||
* pass 1): Construct an offset table using what we know
|
||||
* pass 2): Construct the archive segments
|
||||
*/
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
consume_pass(&state);
|
||||
}
|
||||
|
||||
state_destroy(&state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user