aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErik Liodden <eriklio@stud.ntnu.no>2017-07-13 01:10:45 +0200
committerErik Liodden <eriklio@stud.ntnu.no>2017-07-13 01:10:45 +0200
commit19fec861fd75e133088ba2709dfdbc1fce3adbe0 (patch)
tree4da1607eb3acbd9e13214f6cf9dd24d04eefa64a
parenta5236438bdeb79ba422580436b8a42448a0a95e3 (diff)
downloadbinary-chopper-19fec861fd75e133088ba2709dfdbc1fce3adbe0.tar.gz
add first working version of the program
See README for details on usage. This commit add the first working version of the BinaryChopper program. Build by executing `make` or `make prog` from the top directory.
-rw-r--r--Makefile30
-rw-r--r--include/cut.h7
-rw-r--r--include/file.h10
-rw-r--r--include/merge.h6
-rw-r--r--include/options.h12
-rw-r--r--src/Makefile31
-rw-r--r--src/file/cut.c80
-rw-r--r--src/file/file.c34
-rw-r--r--src/file/merge.c59
-rw-r--r--src/file/module.mk3
-rw-r--r--src/main.c25
-rw-r--r--src/options/module.mk1
-rw-r--r--src/options/options.c70
13 files changed, 368 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..8e8b1f5
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,30 @@
+all: prog
+
+prog:
+ @mkdir -p bin
+ make -C src
+ @cp src/prog ./bin
+
+debug:
+ @mkdir -p bin
+ make -C src debug
+ @cp src/prog ./bin/prog-debug
+
+# valgrind:
+# @mkdir -p bin
+# make -C src debug
+# @cp src/prog ./bin/prog-debug
+# valgrind --leak-check=full --track-origins=yes ./bin/prog-debug
+#
+# test:
+# make -C test/
+# @mkdir -p bin
+# @cp test/test ./bin
+# @./bin/test
+
+.PHONY : clean test
+
+clean :
+ make clean -C test
+ make clean -C src
+ rm -rf bin
diff --git a/include/cut.h b/include/cut.h
new file mode 100644
index 0000000..420e0e7
--- /dev/null
+++ b/include/cut.h
@@ -0,0 +1,7 @@
+#ifndef _CUT_H
+#define _CUT_H
+
+uint64_t *bytes_per_chunk(char *file_name, int parts);
+int write_chunks(char *file_name, int parts);
+
+#endif
diff --git a/include/file.h b/include/file.h
new file mode 100644
index 0000000..ddf9172
--- /dev/null
+++ b/include/file.h
@@ -0,0 +1,10 @@
+#ifndef _FILE_H
+#define _FILE_H
+
+#define HEADER_SIZE 256
+#define BUF_SIZE 8388608
+
+uint64_t get_file_size(char *name);
+FILE *open_file(char *name, char *mode);
+
+#endif
diff --git a/include/merge.h b/include/merge.h
new file mode 100644
index 0000000..2ccc7c9
--- /dev/null
+++ b/include/merge.h
@@ -0,0 +1,6 @@
+#ifndef _MERGE_H
+#define _MERGE_H
+
+int merge_chunks(char *file_name);
+
+#endif
diff --git a/include/options.h b/include/options.h
new file mode 100644
index 0000000..0947851
--- /dev/null
+++ b/include/options.h
@@ -0,0 +1,12 @@
+#ifndef _OPTIONS_H
+#define _OPTIONS_H
+
+struct opts {
+ int cut_flag;
+ int merge_flag;
+ int parts;
+ char *file_name;
+};
+struct opts *get_options(int argc, char **argv);
+
+#endif
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..fa64d3a
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,31 @@
+CC=gcc-6
+OUTPUT_OPTION=-MMD -MP -o $@
+
+CFLAGS += -Wall -Ofast --std=c99 -Wvla -I../include
+MODULES := options file
+CFLAGS += $(patsubst %,-I%,$(MODULES))
+
+LIBS :=
+SRC := main.c
+include $(patsubst %,%/module.mk,$(MODULES))
+OBJ := $(patsubst %.c,%.o,$(filter %.c,$(SRC)))
+DEP := $(patsubst %.c,%.d,$(filter %.c,$(SRC)))
+
+all : prog
+
+prog : $(OBJ)
+ $(CC) -o $@ $(OBJ) $(LIBS)
+
+debug : CFLAGS += -O0 -g
+debug : clean prog
+
+valgrind: debug
+ valgrind ./prog
+
+-include $(DEP)
+
+.PHONY: clean
+
+clean:
+ rm -f $(OBJ) $(DEP) prog
+ rm -rf *.dSYM
diff --git a/src/file/cut.c b/src/file/cut.c
new file mode 100644
index 0000000..7219b31
--- /dev/null
+++ b/src/file/cut.c
@@ -0,0 +1,80 @@
+/*
+ * file/cut.c
+ * Cut a file in smaller pieces.
+ *
+ * Erik Liodden
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <string.h>
+#include "file.h"
+#include "cut.h"
+
+/* bytes_per_chunk: return an array of number of bytes per chunk
+ * TODO: This one could/should be written better.
+ */
+uint64_t *bytes_per_chunk(char *file_name, int parts)
+{
+ uint64_t fsize, base;
+ int rest, i;
+ uint64_t *bytes_per_chunk = malloc(parts * sizeof(uint64_t));
+
+ fsize = get_file_size(file_name);
+ rest = fsize % parts;
+ fsize -= rest;
+ base = fsize / parts;
+
+ for (i = 0; i < parts; i++) {
+ bytes_per_chunk[i] = base;
+ }
+ bytes_per_chunk[parts-1] += rest;
+
+ return bytes_per_chunk;
+}
+
+/* write_chunks: write bytes to .bin files of size given in bpc */
+int write_chunks(char *file_name, int parts)
+{
+ int i, bytes;
+ FILE *fp_out, *fp_in;
+ char *buffer = malloc(BUF_SIZE);
+ uint64_t *bpc;
+
+ fp_in = open_file(file_name, "rb");
+ bpc = bytes_per_chunk(file_name, parts);
+ bytes = 0;
+
+ for (i = 0; i < parts; i++) {
+ snprintf(buffer, BUF_SIZE, "data%d.bin", i);
+ fp_out = open_file(buffer, "wb"); /* open file to write to */
+
+ /* clear buffer and write header to file.
+ * Possibly overkill header size.
+ */
+ memset(buffer, 0, BUF_SIZE);
+ snprintf(buffer, HEADER_SIZE, "%d %llu %s", (i+1) % parts,
+ bpc[i], file_name);
+ fwrite(buffer, 1, HEADER_SIZE, fp_out);
+
+ /* Read to buffer and write to chunk.
+ * Read and write one full buffer at a time.
+ */
+ while (bpc[i] > BUF_SIZE) {
+ bytes += fread(buffer, 1, BUF_SIZE, fp_in);
+ bytes -= fwrite(buffer, 1, BUF_SIZE, fp_out);
+ bpc[i] -= BUF_SIZE;
+ }
+ /* read and write the rest that did not fill buffer */
+ bytes += fread(buffer, 1, bpc[i], fp_in);
+ bytes -= fwrite(buffer, 1, bpc[i], fp_out);
+ fclose(fp_out);
+ }
+ fclose(fp_in);
+ free(buffer);
+ free(bpc);
+
+ return bytes;
+}
diff --git a/src/file/file.c b/src/file/file.c
new file mode 100644
index 0000000..862c1ea
--- /dev/null
+++ b/src/file/file.c
@@ -0,0 +1,34 @@
+/*
+ * file/file.c
+ * File related operations
+ *
+ * Erik Liodden
+ */
+
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "file.h"
+
+/* get_file_size: return size of file with filename 'name' */
+uint64_t get_file_size(char *name)
+{
+ uint64_t size;
+ struct stat st;
+ stat(name, &st);
+ size = st.st_size;
+ return size;
+}
+
+/* open_file: open file and return pointer to the file if it exists. */
+FILE *open_file(char *name, char *mode)
+{
+ FILE *fp;
+ fp = fopen(name, mode);
+ if (fp == NULL) {
+ perror("cant open file");
+ exit(1);
+ }
+ return fp;
+}
diff --git a/src/file/merge.c b/src/file/merge.c
new file mode 100644
index 0000000..e88cd0b
--- /dev/null
+++ b/src/file/merge.c
@@ -0,0 +1,59 @@
+/*
+ * file/merge.c
+ * Merge multiple files to one big file
+ *
+ * Erik Liodden
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <string.h>
+#include "merge.h"
+#include "file.h"
+
+
+int merge_chunks(char *file_name)
+{
+ int id_next, bytes=0;
+ FILE *fp_out = NULL;
+ FILE *fp_chunk;
+ uint64_t size;
+ char out_file[HEADER_SIZE];
+ char *buffer = malloc(BUF_SIZE);
+ snprintf(buffer, BUF_SIZE, "data0.bin");
+
+ do {
+ fp_chunk = open_file(buffer, "rb");
+ fread(buffer, 1, HEADER_SIZE, fp_chunk);
+ sscanf(buffer, "%d %llu %s", &id_next, &size, out_file);
+ if (file_name != NULL && strcmp(out_file, file_name) != 0)
+ strcpy(out_file, file_name);
+ if (!fp_out)
+ fp_out = open_file(out_file, "wb");
+
+ /* Read to buffer and write to file.
+ * Read and write one full buffer at a time.
+ */
+ while (size > BUF_SIZE) {
+ bytes += fread(buffer, 1, BUF_SIZE, fp_chunk);
+ bytes -= fwrite(buffer, 1, BUF_SIZE, fp_out);
+ size -= BUF_SIZE;
+ }
+ /* read and write the rest that did not fill buffer */
+ bytes += fread(buffer, 1, size, fp_chunk);
+ bytes -= fwrite(buffer, 1, size, fp_out);
+ if (bytes != 0) {
+ fprintf(stderr, "bytes in != bytes out. Hmm\n");
+ exit(1);
+ }
+ fclose(fp_chunk);
+ snprintf(buffer, BUF_SIZE, "data%d.bin", id_next);
+ } while (id_next);
+
+ fclose(fp_out);
+ free(buffer);
+
+ return bytes;
+}
diff --git a/src/file/module.mk b/src/file/module.mk
new file mode 100644
index 0000000..0094169
--- /dev/null
+++ b/src/file/module.mk
@@ -0,0 +1,3 @@
+SRC += file/cut.c \
+ file/file.c \
+ file/merge.c
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..d71bf23
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <inttypes.h>
+#include "file.h"
+#include "cut.h"
+#include "merge.h"
+#include "options.h"
+
+
+int main(int argc, char *argv[])
+{
+ struct opts *options;
+ options = get_options(argc, argv);
+
+ if (options->cut_flag)
+ write_chunks(options->file_name, options->parts);
+ else if (options->merge_flag)
+ merge_chunks(options->file_name);
+ else
+ return 1;
+
+ free(options);
+ return 0;
+}
diff --git a/src/options/module.mk b/src/options/module.mk
new file mode 100644
index 0000000..1dc06eb
--- /dev/null
+++ b/src/options/module.mk
@@ -0,0 +1 @@
+SRC += options/options.c
diff --git a/src/options/options.c b/src/options/options.c
new file mode 100644
index 0000000..7f86c86
--- /dev/null
+++ b/src/options/options.c
@@ -0,0 +1,70 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "options.h"
+#include <getopt.h>
+
+struct opts *get_options(int argc, char **argv)
+{
+ int option_index = 0;
+ int c;
+ opterr = 0;
+
+ struct opts *options = calloc(1, sizeof(struct opts));
+ struct option long_options[] = {
+ /* These options set a flag.
+ * {"verbose", no_argument, &verbose_flag, 1},
+ * {"brief", no_argument, &verbose_flag, 0},
+ */
+ /* These options don’t set a flag.
+ We distinguish them by their indices. */
+ {"merge", no_argument, 0, 'm'},
+ {"file", required_argument, 0, 'f'},
+ {"cut", required_argument, 0, 'c'},
+ {0, 0, 0, 0}
+ };
+
+
+ while((c = getopt_long(argc, argv, "mf:c:",
+ long_options, &option_index)) != -1)
+ switch (c) {
+ case 'c':
+ options->cut_flag = 1;
+ options->parts = atoi(optarg);
+ break;
+ case 'm':
+ options->merge_flag = 1;
+ break;
+ case 'f':
+ options->file_name = optarg;
+ break;
+ case '?':
+ if (optopt == 'c' || optopt == 'f')
+ fprintf (stderr, "Option -%c" \
+ "requires an argument.\n", optopt);
+ else if (isprint(optopt))
+ fprintf(stderr, "Unknown option `-%c'.\n", optopt);
+ else
+ fprintf(stderr,
+ "Unknown option character `\\x%x'.\n", optopt);
+ exit(EXIT_FAILURE);
+ default:
+ abort();
+ }
+
+ if (options->cut_flag && options->merge_flag) {
+ fprintf(stderr, "Error: cannot merge and cut at the same time\n");
+ exit(EXIT_FAILURE);
+ }
+ /*
+ printf("cut_flag = %d, merge_flag = %d, parts = %d, file = %s\n",
+ options->cut_flag,
+ options->merge_flag,
+ options->parts,
+ options->file_name);
+
+ for (option_index = optind; option_index < argc; option_index++)
+ printf("Non-option argument %s\n", argv[option_index]);
+ */
+ return options;
+}