diff --git a/mercury25/gitUpdate.bat b/mercury25/gitUpdate.bat new file mode 100644 index 00000000..e040eab0 --- /dev/null +++ b/mercury25/gitUpdate.bat @@ -0,0 +1,8 @@ +git status . + +echo "press enter to continue" +@pause + +git add . +git commit -m"update mercury25," +start git push diff --git a/mercury25/task1/COMP1521 24T2 Assignment 2_ a file synchroniser.pdf b/mercury25/task1/COMP1521 24T2 Assignment 2_ a file synchroniser.pdf new file mode 100644 index 00000000..bf86295d Binary files /dev/null and b/mercury25/task1/COMP1521 24T2 Assignment 2_ a file synchroniser.pdf differ diff --git a/mercury25/task1/notes.md b/mercury25/task1/notes.md new file mode 100644 index 00000000..4535c275 --- /dev/null +++ b/mercury25/task1/notes.md @@ -0,0 +1,3 @@ +https://github.com/errorterror6/COMP1521-24T2 + +TEL: 9 7 6 6 2 6 2 2 diff --git a/mercury25/task1/provided/Makefile b/mercury25/task1/provided/Makefile new file mode 100644 index 00000000..cdbe0404 --- /dev/null +++ b/mercury25/task1/provided/Makefile @@ -0,0 +1,22 @@ +# COMP1521 22T2 ... a general makefile for multiple exercises + +ifneq (, $(shell which dcc)) +CC = dcc +else ifneq (, $(shell which clang) ) +CC = clang +else +CC = gcc +endif + +EXERCISES ?= +CLEAN_FILES ?= + +.DEFAULT_GOAL = all +.PHONY: all clean + +-include *.mk + +all: ${EXERCISES} + +clean: + -rm -f ${CLEAN_FILES} diff --git a/mercury25/task1/provided/rbuoy.c b/mercury25/task1/provided/rbuoy.c new file mode 100644 index 00000000..af2a36ca --- /dev/null +++ b/mercury25/task1/provided/rbuoy.c @@ -0,0 +1,73 @@ +//////////////////////////////////////////////////////////////////////// +// COMP1521 24T2 --- Assignment 2: `rbuoy', a simple file synchroniser +// +// +// Written by YOUR-NAME-HERE (z5555555) on INSERT-DATE-HERE. +// INSERT-DESCRIPTION-OF-PROGAM-HERE +// +// 2023-07-12 v1.0 Team COMP1521 + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rbuoy.h" + + +/// @brief Create a TABI file from an array of pathnames. +/// @param out_pathname A path to where the new TABI file should be created. +/// @param in_pathnames An array of strings containing, in order, the files +// that should be placed in the new TABI file. +/// @param num_in_pathnames The length of the `in_pathnames` array. In +/// subset 5, when this is zero, you should include +/// everything in the current directory. +void stage_1(char *out_pathname, char *in_pathnames[], size_t num_in_pathnames) { + // TODO: implement this. + + // Hint: you will need to: + // * Open `out_pathname` using fopen, which will be the output TABI file. + // * For each pathname in `in_pathnames`: + // * Write the length of the pathname as a 2 byte little endian integer + // * Write the pathname + // * Check the size of the input file, e.g. using stat + // * Compute the number of blocks using number_of_blocks_in_file + // * Write the number of blocks as a 3 byte little endian integer + // * Open the input file, and read in blocks of size BLOCK_SIZE, and + // * For each block call hash_black to compute the hash + // * Write out that hash as an 8 byte little endian integer + // Each time you need to write out a little endian integer you should + // compute each byte using bitwise operations like <<, &, or | +} + + +/// @brief Create a TBBI file from a TABI file. +/// @param out_pathname A path to where the new TBBI file should be created. +/// @param in_pathname A path to where the existing TABI file is located. +void stage_2(char *out_pathname, char *in_pathname) { + // TODO: implement this. +} + + +/// @brief Create a TCBI file from a TBBI file. +/// @param out_pathname A path to where the new TCBI file should be created. +/// @param in_pathname A path to where the existing TBBI file is located. +void stage_3(char *out_pathname, char *in_pathname) { + // TODO: implement this. +} + + +/// @brief Apply a TCBI file to the filesystem. +/// @param in_pathname A path to where the existing TCBI file is located. +void stage_4(char *in_pathname) { + // TODO: implement this. +} diff --git a/mercury25/task1/provided/rbuoy.h b/mercury25/task1/provided/rbuoy.h new file mode 100644 index 00000000..78bf56a7 --- /dev/null +++ b/mercury25/task1/provided/rbuoy.h @@ -0,0 +1,42 @@ +#ifndef RSYNC_H +#define RSYNC_H + +#include +#include + + +// Sizes (in bytes) of various fields. +#define MAGIC_SIZE 4 +#define NUM_RECORDS_SIZE 1 +#define PATHNAME_LEN_SIZE 2 +#define NUM_BLOCKS_SIZE 3 +#define HASH_SIZE 8 +#define MODE_SIZE 10 +#define FILE_SIZE_SIZE 4 +#define BLOCK_INDEX_SIZE 3 +#define UPDATE_LEN_SIZE 2 + +#define MATCH_BYTE_BITS 8 + +// Note that the rbuoy index magic numbers are exactly 4 bytes, and so +// don't include the nul-terminator implicit at the end of these strings. +#define TYPE_A_MAGIC "TABI" +#define TYPE_B_MAGIC "TBBI" +#define TYPE_C_MAGIC "TCBI" + +// The maximum size of a block (the trailing block of a file might be smaller). +#define BLOCK_SIZE 256 + +// rbuoy.c +void stage_1(char *out_pathname, char *in_pathnames[], size_t num_in_pathnames); +void stage_2(char *out_pathname, char *in_pathname); +void stage_3(char *out_pathname, char *in_pathname); +void stage_4(char *in_pathname); + +// rbuoy_provided.c +uint64_t hash_block(char block[], size_t block_size); +size_t number_of_blocks_in_file(size_t num_bytes); +size_t num_tbbi_match_bytes(size_t num_blocks); + + +#endif /* RSYNC_H */ diff --git a/mercury25/task1/provided/rbuoy.mk b/mercury25/task1/provided/rbuoy.mk new file mode 100644 index 00000000..6d967e1d --- /dev/null +++ b/mercury25/task1/provided/rbuoy.mk @@ -0,0 +1,23 @@ +CFLAGS = + +ifneq (, $(shell which dcc)) +CC ?= dcc +else +CC ?= clang +CFLAGS += -Wall +endif + +EXERCISES += rbuoy + +SRC = rbuoy.c rbuoy_main.c rbuoy_provided.c +INCLUDES = rbuoy.h + +# if you add extra .c files, add them here +SRC += + +# if you add extra .h files, add them here +INCLUDES += + + +rbuoy: $(SRC) $(INCLUDES) + $(CC) $(CFLAGS) $(SRC) -o $@ diff --git a/mercury25/task1/provided/rbuoy_hash_block.c b/mercury25/task1/provided/rbuoy_hash_block.c new file mode 100644 index 00000000..5a956a12 --- /dev/null +++ b/mercury25/task1/provided/rbuoy_hash_block.c @@ -0,0 +1,23 @@ +// Given up to BLOCK_SIZE (256) bytes, produce the +// hash of that block. You should not modify this file, +// and should not attempt to compile it as part of your +// solution. + +// You can run this program yourself using +// 1521 rbuoy-hash-block - for example, +// 1521 rbuoy-hash-block < examples/aaa/emojis.txt + +#include "rbuoy.h" +#include + +int main(void) { + char buf[BLOCK_SIZE]; + // Read in up to BLOCK_SIZE bytes from stdin + size_t bytes_read = fread(buf, 1, BLOCK_SIZE, stdin); + // It's important that we pass in the number of bytes read + // to hash_block - not BLOCK_SIZE - since it's possible that + // we reach the end of file/user input before filling up + // the buffer. + printf("%016lx\n", hash_block(buf, bytes_read)); + return 0; +} diff --git a/mercury25/task1/provided/rbuoy_main.c b/mercury25/task1/provided/rbuoy_main.c new file mode 100644 index 00000000..4246c349 --- /dev/null +++ b/mercury25/task1/provided/rbuoy_main.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include + +#include "rbuoy.h" + +int main(int argc, char **argv) { + int stage = 0; + for (;;) { + int option_index; + int opt = getopt_long( + argc, argv, + ":1234", + (struct option[]) { + {"stage-1", no_argument, NULL, 1}, + {"stage-2", no_argument, NULL, 2}, + {"stage-3", no_argument, NULL, 3}, + {"stage-4", no_argument, NULL, 4}, + {0, 0, 0, '?'}, + }, + &option_index + ); + + if (opt == -1) { + break; + } + + switch (opt) { + case 1: + case 2: + case 3: + case 4: { + stage = opt; + break; + } + case ':': + case '?': + default: { + fprintf(stderr, "Usage: %s [--stage-1|--stage-2|--stage-3|--stage-4]\n", argv[0]); + return EXIT_FAILURE; + } + } + } + + switch (stage) { + case 1: { + if (argc - optind < 1) { + fprintf(stderr, "Usage: %s --stage-1 [ ...]\n", argv[0]); + return EXIT_FAILURE; + } + char *outfile = argv[optind]; + char **files = argv + optind + 1; + size_t num_files = argc - optind - 1; + stage_1(outfile, files, num_files); + break; + } + case 2: { + if (argc - optind != 2) { + fprintf(stderr, "Usage: %s --stage-2 \n", argv[0]); + return EXIT_FAILURE; + } + char *outfile = argv[optind]; + char *infile = argv[optind + 1]; + stage_2(outfile, infile); + break; + } + case 3: { + if (argc - optind != 2) { + fprintf(stderr, "Usage: %s --stage-3 \n", argv[0]); + return EXIT_FAILURE; + } + char *outfile = argv[optind]; + char *infile = argv[optind + 1]; + stage_3(outfile, infile); + break; + } + case 4: { + if (argc - optind != 1) { + fprintf(stderr, "Usage: %s --stage-4 \n", argv[0]); + return EXIT_FAILURE; + } + char *infile = argv[optind]; + stage_4(infile); + break; + } + case 0: { + fprintf(stderr, "Usage: %s [--stage-1|--stage-2|--stage-3|--stage-4]\n", argv[0]); + return EXIT_FAILURE; + } + } + + return EXIT_SUCCESS; +} diff --git a/mercury25/task1/provided/rbuoy_provided.c b/mercury25/task1/provided/rbuoy_provided.c new file mode 100644 index 00000000..5589a3e1 --- /dev/null +++ b/mercury25/task1/provided/rbuoy_provided.c @@ -0,0 +1,47 @@ +#include +#include +#include + +#include "rbuoy.h" + + +/// @brief Compute the hash of a block of bytes, using the 64 bit NFV-1a hash. +/// +/// If you wish to represent your bytes differently (say as an array of uint8_t) +/// you may want to make a wrapper around this function. +/// +/// @param block The array of bytes to be hashed. +/// @param block_size The length of that array. Must be at most 256. +/// +/// @return The hash of the block. +uint64_t hash_block(char block[], size_t block_size) { + assert(block_size <= BLOCK_SIZE); + + uint64_t hash = 0xcbf29ce484222325ull; + for (size_t i = 0; i < block_size; ++i) { + hash ^= (unsigned char) block[i]; + hash *= 0x100000001b3; + } + + return hash; +} + + +/// @brief Compute the number of blocks in a file, given its size. +/// @param num_bytes The number of bytes in a file. +/// @return The nunber of blocks that are needed for that file. +size_t number_of_blocks_in_file(size_t num_bytes) { + // This is equal to + // ceil(num_bytes / BLOCK_SIZE) + return (num_bytes + BLOCK_SIZE - 1) / BLOCK_SIZE; +} + + +/// @brief Compute the nunber of 'match' bytes that are needed for a TBBI record. +/// @param num_blocks The number of blocks. +/// @return The number of 'match' bytes needed. +size_t num_tbbi_match_bytes(size_t num_blocks) { + // This is equal to + // ceil(num_blocks / 8) + return (num_blocks + MATCH_BYTE_BITS - 1) / MATCH_BYTE_BITS; +}