From a6dac2e2dce95eecd5a32eaf1f74c7089f2b6e33 Mon Sep 17 00:00:00 2001 From: zongor Date: Sat, 3 Sep 2022 23:49:10 -0400 Subject: [PATCH] first commit --- Makefile | 9 + README.md | 3 + ctar.c | 549 ++++++++++++++++++++++++++++++++++++++++++++ dumparchiveheader.c | 80 +++++++ tar.h | 17 ++ utar.c | 122 ++++++++++ 6 files changed, 780 insertions(+) create mode 100755 Makefile create mode 100755 README.md create mode 100755 ctar.c create mode 100755 dumparchiveheader.c create mode 100755 tar.h create mode 100755 utar.c diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..0fa9ef1 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +all: ctar utar dump + +ctar: ctar.c; gcc -o ctar ctar.c + +utar: utar.c; gcc -o utar utar.c + +dump: dumparchiveheader.c; gcc -o dump dumparchiveheader.c + +clean:; rm -f ctar ; rm -f utar ; rm -f dump diff --git a/README.md b/README.md new file mode 100755 index 0000000..b2f00ed --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +A simple `tar` and `untar` program + +Also includes a `dump` program to check if the archive header is valid diff --git a/ctar.c b/ctar.c new file mode 100755 index 0000000..cf90da4 --- /dev/null +++ b/ctar.c @@ -0,0 +1,549 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tar.h" + +int archiveexists(char *fname); + +int last_header_pointer; + +hdr head = {0x63746172, // head header for rewriting eop pointer + sizeof(head), + 0, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + -1}; + +hdr empty = {0x63746172, // empty header for copying + sizeof(empty), + 0, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0}, + -1}; + +int main(int argc, char *argv[]) +{ + + if (argc < 2) + { // check to see if inputs exist + fprintf(stderr, "%s [No Input]:\n Usage: ctar (-a | -d) \n", strerror(5)); + exit(EXIT_FAILURE); + } + + char *f = argv[1]; // read the flag + char *archivename = argv[2]; // name of archive + int numberoffiles = argc - 3; // number of files to process + char buffer[300]; // character buffer for sprintf + int i, j, k, x; // loop counters + int r; // read pointer + int w; // write pointer + int fp; // file pointer + char *current_file; + int Current_EOP; + + if (argc < 3 && strcmp(argv[1], "-a") == 0) + { // check to see if arguments are correct for flag -a + fprintf(stderr, "%s:\n Usage: ctar -a file1, file2, ... filen\n", strerror(5)); + exit(EXIT_FAILURE); + } + else if (argc != 4 && strcmp(argv[1], "-d") == 0) + { // check to see if arguments are correct for flag -d + fprintf(stderr, "%s:\n Usage: ctar -d \n", strerror(5)); + exit(EXIT_FAILURE); + } + else if (strcmp(argv[1], "-a") != 0 && strcmp(argv[1], "-d") != 0) + { // check to see if the user has a valid flag + fprintf(stderr, "%s [Unknown Flag]:\n Usage: ctar (-a | -d) \n", strerror(5)); + exit(EXIT_FAILURE); + } +#ifdef DEBUG + printf("numberoffiles = %d\n", numberoffiles); +#endif + if (archiveexists(archivename) == 0) + { // if file does not exist + fp = open(archivename, O_RDWR | O_CREAT, 0644); // opens file; creates it if it does not exist; + + if (strcmp(argv[1], "-a") == 0) + { +#ifdef DEBUG + sprintf(buffer, "case -a (file doesn't exist)\n"); + write(1, buffer, strlen(buffer)); +#endif + if (numberoffiles == 0) + { // create an empty archive file + w = write(fp, (char *)&head, sizeof(head)); + if (w < 0) + { + fprintf(stderr, "%s\n", strerror(5)); + exit(EXIT_FAILURE); + } + close(fp); + return EXIT_SUCCESS; + } + else + { // create an archive file with content +#ifdef DEBUG + sprintf(buffer, "create an archive with content\n"); + write(1, buffer, strlen(buffer)); +#endif + int numberofheaders = (numberoffiles / 8) + 1; // calculate the number of headers + hdr temp; + int temp_sizeof_file; + int temp_file_pointer; + int temp_file_read; + int temp_filename_pointer; + int argv_pointer; + int temp_header_pointer = 0; + char byte; + short int char_len_buf; + + // First write empty header to archive + lseek(fp, 0, SEEK_SET); + w = write(fp, (char *)&head, sizeof(head)); + Current_EOP = sizeof(empty); + + for (i = 0; i < numberofheaders; i++) + { // iterate through all headers +#ifdef DEBUG + printf("ITERATION:%i\n", i); +#endif + temp = empty; // sets the temp header to an empty hdr + head.eop = Current_EOP; // write the eop to the head node + for (j = 1; j <= 8; j++) + { // reads 8 files at a time + argv_pointer = (j + (i * 8)) + 2; + if (argv_pointer - 2 > numberoffiles) + { +#ifdef DEBUG + sprintf(buffer, "makes sure that the parser ends when the last file is read [file:%d]\n", argv_pointer - 2); + write(1, buffer, strlen(buffer)); +#endif + close(fp); + return EXIT_SUCCESS; // makes sure that the parser ends when the last file is read + } + + if (i > 0) + { +#ifdef DEBUG + printf("write new header : [header %i]\n", temp_header_pointer); +#endif + lseek(fp, temp_header_pointer, SEEK_SET); + w = write(fp, (char *)&temp, sizeof(temp)); + } + + current_file = argv[argv_pointer]; + + temp_file_pointer = open(current_file, O_RDWR, 0644); // opens file; + + if (temp_file_pointer < 0) + { + fprintf(stderr, "%s\n", strerror(5)); + exit(EXIT_FAILURE); + } + + temp_sizeof_file = 0; // reset file size counter + + // Create Filename, Write to archive + Current_EOP = lseek(fp, 0, SEEK_END); + temp_filename_pointer = Current_EOP; + char_len_buf = strlen(argv[argv_pointer]); + write(fp, (char *)&char_len_buf, sizeof(char_len_buf)); // write size + Current_EOP = lseek(fp, 0, SEEK_END); +#ifdef DEBUG + sprintf(buffer, "file_name_size written to archive [file:%d]\n", argv_pointer - 2); + write(1, buffer, strlen(buffer)); +#endif + write(fp, argv[argv_pointer], char_len_buf * sizeof(char)); // write title + Current_EOP = lseek(fp, 0, SEEK_END); + + // Write file to archive + temp_file_read = read(temp_file_pointer, &byte, sizeof(byte)); // read first byte + Current_EOP = lseek(fp, 0, SEEK_END); + temp_sizeof_file += sizeof(byte); // increment the size of file + write(fp, &byte, sizeof(byte)); // write first byte +#ifdef DEBUG + sprintf(buffer, "Read first byte [file:%d]\n", argv_pointer - 2); + write(1, buffer, strlen(buffer)); +#endif + int k = 1; + + while (temp_file_read > 0) + { // iterate until it reaches end of file + temp_file_read = read(temp_file_pointer, &byte, sizeof(byte)); // read all next bytes + if (temp_file_read < 1) + { + break; // breaks to make sure the last byte isnt written twice + } + + Current_EOP = lseek(fp, 0, SEEK_END); + temp_sizeof_file += sizeof(byte); // increment the size of file +#ifdef DEBUG + sprintf(buffer, "Read %d-th byte [file:%d]\n", k, argv_pointer - 2); + write(1, buffer, strlen(buffer)); +#endif + write(fp, &byte, sizeof(byte)); // write following byte(s) +#ifdef DEBUG + sprintf(buffer, "wrote %d-th byte [file:%d]\n", k, argv_pointer - 2); + write(1, buffer, strlen(buffer)); +#endif + k++; + } +#ifdef DEBUG + sprintf(buffer, "file written to archive [file:%d]\n", argv_pointer - 2); + write(1, buffer, strlen(buffer)); +#endif + Current_EOP = lseek(fp, 0, SEEK_END); + head.eop = Current_EOP; + + lseek(fp, 0, SEEK_SET); + w = write(fp, (char *)&head, sizeof(head)); +#ifdef DEBUG + sprintf(buffer, "first header rewritten [file:%d]\n", argv_pointer - 2); + write(1, buffer, strlen(buffer)); + + sprintf(buffer, "filename is: %s, written to archive [file:%d]\n", argv[argv_pointer], argv_pointer - 2); + write(1, buffer, strlen(buffer)); +#endif + if (i < 1) + { + head.block_count = (head.block_count + 1); + head.file_size[j - 1] = temp_sizeof_file; + head.file_name[j - 1] = temp_filename_pointer; + } + else + { + temp.block_count = (temp.block_count + 1); + temp.file_size[j - 1] = temp_sizeof_file; + temp.file_name[j - 1] = temp_filename_pointer; + } +#ifdef DEBUG + sprintf(buffer, "starting writing file to archive [file:%d]\n", argv_pointer - 2); + write(1, buffer, strlen(buffer)); +#endif + if (w < 0) + { + fprintf(stderr, "%s\n", strerror(5)); + exit(EXIT_FAILURE); + } + + if (i > 0) + { +#ifdef DEBUG + printf("write header %i data\n", i); +#endif + lseek(fp, temp_header_pointer, SEEK_SET); + w = write(fp, (char *)&temp, sizeof(temp)); + + if (w < 0) + { + fprintf(stderr, "%s\n", strerror(5)); + exit(EXIT_FAILURE); + } + } + else + { +#ifdef DEBUG + printf("write header %i data\n", i); +#endif + lseek(fp, 0, SEEK_SET); + w = write(fp, (char *)&head, sizeof(head)); + + if (w < 0) + { + fprintf(stderr, "%s\n", strerror(5)); + exit(EXIT_FAILURE); + } + } + } + if (i < 1) + { + head.next = head.eop; + temp_header_pointer = head.eop; + } + else + { + temp.next = head.eop; + temp_header_pointer = head.eop; + } + } + + close(fp); + return EXIT_SUCCESS; + } + } + close(fp); + } + else + { // file already exist + fp = open(archivename, O_RDWR, 0644); // opens file; creates it if it does not exist; + + if (strcmp(argv[1], "-a") == 0) + { // add file(s) to an archive that already exists +#ifdef DEBUG + printf("case -a (file exists)\n"); +#endif + hdr header; + int temp_sizeof_file; + int temp_file_pointer; + int temp_file_read; + int temp_filename_pointer; + char f_name[sizeof(short int)]; + short int l; + int p = 0; + int poi; + + lseek(fp, 0, SEEK_SET); + r = read(fp, &header, sizeof(hdr)); // load first header + if (r != sizeof(hdr)) + { + fprintf(stderr, "%s: file is not the size of a header object", strerror(5)); + exit(EXIT_FAILURE); + } + else if (header.magic != 0x63746172) + { + fprintf(stderr, "%s: header does not include the magic number", strerror(5)); + exit(EXIT_FAILURE); + } + + char byte; + int char_len_buf; + int not_finished_reading; + int temp_header_pointer = 0; + int number_of_headers; + k = 0; + + while (k < argc - 3) + { + not_finished_reading = true; + number_of_headers = 1; + while (not_finished_reading) + { + if (header.block_count < 8) + { // if it has 8 elements then the header is full and we must move to the next one + for (j = 0; j < header.block_count; j++) + { // search through all blocks in the header + lseek(fp, header.file_name[j], SEEK_SET); + read(fp, (char *)&l, sizeof(short int)); + read(fp, f_name, l); + + if (header.deleted[j] == 1) + { + // do nothing because the file is already deleted + } + else + { + if (strcmp(argv[k + 3], f_name) == 0) + { // check if the filename is the same as the input + fprintf(stderr, "%s: file already exists\n", strerror(5)); + exit(EXIT_FAILURE); + } + } + } + } + + if (header.next > 0) + { + number_of_headers++; + p = header.next; + temp_header_pointer = lseek(fp, header.next, SEEK_SET); + r = read(fp, (char *)&header, sizeof(hdr)); + } + else + { + not_finished_reading = false; // first file has been iterated through + } + } +#ifdef DEBUG + sprintf(buffer, "file \"%s\" is not in archive: writing file\n", argv[k + 3]); + write(1, buffer, strlen(buffer)); +#endif + current_file = argv[k + 3]; + + temp_sizeof_file = 0; // reset file size counter + temp_file_pointer = open(current_file, O_RDWR, 0644); // opens file; + + // Create Filename, Write to archive + Current_EOP = lseek(fp, 0, SEEK_END); + temp_filename_pointer = Current_EOP; + char_len_buf = strlen(argv[header.block_count]); +#ifdef DEBUG + sprintf(buffer, "char_len_buf=%i\n", char_len_buf); + write(1, buffer, strlen(buffer)); +#endif + write(fp, &char_len_buf, sizeof(char_len_buf)); // write size + Current_EOP = lseek(fp, 0, SEEK_END); +#ifdef DEBUG + sprintf(buffer, "file \"%s\" : writing filename\n", argv[header.block_count]); + write(1, buffer, strlen(buffer)); +#endif + write(fp, argv[header.block_count], char_len_buf * sizeof(char)); // write title + Current_EOP = lseek(fp, 0, SEEK_END); +#ifdef DEBUG + sprintf(buffer, "file \"%s\" : Write file to archive\n", argv[header.block_count]); + write(1, buffer, strlen(buffer)); +#endif + // Write file to archive + temp_file_read = read(temp_file_pointer, &byte, sizeof(byte)); // read first byte + Current_EOP = lseek(fp, 0, SEEK_END); + temp_sizeof_file += sizeof(byte); // increment the size of file + write(fp, &byte, sizeof(byte)); // write first byte + + int x = 1; + + while (temp_file_read > 0) + { // iterate until it reaches end of file + temp_file_read = read(temp_file_pointer, &byte, sizeof(byte)); // read all next bytes + if (temp_file_read < 1) + { + break; // breaks to make sure the last byte isnt written twice + } +#ifdef DEBUG + sprintf(buffer, "Read %d-th byte [file:%d]\n", x, header.block_count - 2); + write(1, buffer, strlen(buffer)); +#endif + write(fp, &byte, sizeof(byte)); // write following byte(s) + Current_EOP = lseek(fp, 0, SEEK_END); + temp_sizeof_file += sizeof(byte); // increment the size of file +#ifdef DEBUG + sprintf(buffer, "wrote %d-th byte [file:%d]\n", x, header.block_count - 2); + write(1, buffer, strlen(buffer)); +#endif + x++; + } + + header.file_size[header.block_count] = temp_sizeof_file; + header.file_name[header.block_count] = temp_filename_pointer; + header.block_count = (header.block_count + 1); +#ifdef DEBUG + printf("write header %i data\n", i); +#endif + lseek(fp, temp_header_pointer, SEEK_SET); + w = write(fp, (char *)&header, sizeof(header)); + + if (w < 0) + { + fprintf(stderr, "%s\n", strerror(5)); + exit(EXIT_FAILURE); + } + + if (header.block_count == 8) + { + Current_EOP = lseek(fp, 0, SEEK_END); + header = empty; +#ifdef DEBUG + printf("write header %i data\n", i); +#endif + lseek(fp, Current_EOP, SEEK_SET); + w = write(fp, (char *)&header, sizeof(header)); + + if (w < 0) + { + fprintf(stderr, "%s\n", strerror(5)); + exit(EXIT_FAILURE); + } + } + + k++; // get the next input + } + } + else + { // Delete the file +#ifdef DEBUG + printf("case -d\n"); +#endif + hdr header; + char f_name[sizeof(short int)]; + short int l; + int p = 0; + int poi; + lseek(fp, 0, SEEK_SET); + + r = read(fp, (char *)&header, sizeof(hdr)); // load first header + + if (r != sizeof(hdr)) + { + fprintf(stderr, "%s: file is not the size of a header object", strerror(5)); + exit(EXIT_FAILURE); + } + else if (header.magic != 0x63746172) + { + fprintf(stderr, "%s: header does not include the magic number", strerror(5)); + exit(EXIT_FAILURE); + } + + if (header.block_count == 0) + { + fprintf(stderr, "%s: Archive is empty\n", strerror(2)); + exit(EXIT_FAILURE); + } + + while (true) + { + for (i = 0; i < header.block_count; i++) + { + lseek(fp, header.file_name[i], SEEK_SET); + read(fp, (char *)&l, sizeof(short int)); + read(fp, f_name, l); + + if (strcmp(argv[3], f_name) == 0) + { + + if (header.deleted[i] == 1) + { + // do nothing because the file is already deleted + } + else + { + header.deleted[i] = (char)1; // set found file to deleted + poi = lseek(fp, p, SEEK_SET); + + w = write(fp, (char *)&header, sizeof(header)); + + if (w < 0) + { + fprintf(stderr, "%s\n", strerror(5)); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); + } + } + } + if (header.next < 0) + { + fprintf(stderr, "%s\n", strerror(2)); + exit(EXIT_FAILURE); + } + else + { + p = header.next; + lseek(fp, header.next, SEEK_SET); + r = read(fp, (char *)&header, sizeof(hdr)); + } + } + } + + close(r); + close(fp); + } + return EXIT_SUCCESS; +} + +int archiveexists(char *fname) +{ + if (access(fname, F_OK) != -1) + { + return true; // file exists + } + else + { + return false; // file doesn't exist + } +} diff --git a/dumparchiveheader.c b/dumparchiveheader.c new file mode 100755 index 0000000..9792a27 --- /dev/null +++ b/dumparchiveheader.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "tar.h" + +int main(int argc, char *argv[]) +{ + char *name = argv[1]; // name of archive + int numberoffiles = argc - 3; + char buffer[300]; // character buffer for write + int fp, r, i, p; + + if (argc != 2) + { + fprintf(stderr, "%s: Usage: dah filename \n", strerror(5)); + exit(EXIT_FAILURE); + } + + fp = open(name, O_RDONLY, 0644); // opens file; creates it if it does not exist; + if (fp < 0) + { + fprintf(stderr, "cannot open %s because of %s\n", name, strerror(5)); + exit(EXIT_FAILURE); + } + + write(1, "\n", 1); + + hdr header; + while (true) + { + r = read(fp, &header, sizeof(hdr)); + if (r != sizeof(hdr)) + { + fprintf(stderr, "%s: file is not the size of a header object\n", strerror(5)); + exit(EXIT_FAILURE); + } + else if (header.magic != 0x63746172) + { + fprintf(stderr, "%s: header does not include the magic number [magic number is: %x]\n", strerror(5), header.magic); + exit(EXIT_FAILURE); + } + printf("magic number is: %x\n", header.magic); + printf("The end of file pointer is at: %i\n", header.eop); + printf("number of used blocks are: %i\n", header.block_count); + for (i = 0; i < 8; i++) + { + printf("The filesize of block [%i] is %i\n", i, header.file_size[i]); + } + for (i = 0; i < 8; i++) + { + printf("Is block [%i] deleted? (1=true, 0=false): %i\n", i, header.deleted[i]); + } + for (i = 0; i < 8; i++) + { + printf("The filename in block [%i] is %i\n", i, header.file_name[i]); + } + printf("The next header is at: %i\n", header.next); + + if (header.next < 0) + { + printf("End of headers\n"); + exit(EXIT_SUCCESS); + } + else + { + p = header.next; + lseek(fp, header.next, SEEK_SET); + } + } + + close(r); + close(fp); + + return EXIT_SUCCESS; +} diff --git a/tar.h b/tar.h new file mode 100755 index 0000000..3cb8dbe --- /dev/null +++ b/tar.h @@ -0,0 +1,17 @@ +#ifndef TAR_ +#define TAR_ + +#define true 1 +#define false 0 + +typedef struct { + int magic; /* This value must be 0x63746172 */ + int eop; /* End of file pointer */ + int block_count; /* Number of entries in the block which are in use */ + int file_size[8]; /* File size in bytes for files 1..8 */ + char deleted[8]; /* Contains binary one at position i if i-th entry was deleted */ + int file_name[8]; /* pointer to the name of the file. */ + int next; /* pointer to the next header block */ +} hdr; + +#endif diff --git a/utar.c b/utar.c new file mode 100755 index 0000000..4675ac4 --- /dev/null +++ b/utar.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "tar.h" + +int fileexists(char *fname); + +int main(int argc, char *argv[]) +{ + char *name = argv[1]; // name of archive + char buffer[300]; // character buffer for sprintf + int fp, r, i, j, p, w; // counters and pointers + + if (argc != 2) + { + fprintf(stderr, "%s:\n Usage: utar filename \n", strerror(5)); + exit(EXIT_FAILURE); + } + + if (fileexists(name) == 0) + { + fprintf(stderr, "archive doesnt exist%s\n", strerror(2)); + exit(EXIT_FAILURE); + } + + fp = open(name, O_RDONLY, 0644); // opens file; creates it if it does not exist; + if (fp < 0) + { + fprintf(stderr, "cannot open %s because of %s\n", argv[2], strerror(5)); + exit(EXIT_FAILURE); + } + + hdr header; + int tempfp; + char byte; + char f_name[sizeof(short int)]; + short int l; + + while (true) + { + + r = read(fp, &header, sizeof(hdr)); + if (r != sizeof(hdr)) + { + fprintf(stderr, "%s: file is not the size of a header object\n", strerror(5)); + exit(EXIT_FAILURE); + } + else if (header.magic != 0x63746172) + { + fprintf(stderr, "%s: header does not include the magic number [magic number is: %x]\n", strerror(5), header.magic); + exit(EXIT_FAILURE); + } + + for (i = 0; i < header.block_count; i++) + { + if (header.deleted[i] == 1) + { + // skip it + } + else + { + lseek(fp, header.file_name[i], SEEK_SET); + read(fp, (char *)&l, sizeof(short int)); + read(fp, f_name, l); + + if (fileexists(f_name)) + { + fprintf(stderr, "%s\n", strerror(17)); + exit(EXIT_FAILURE); + } + + tempfp = open(f_name, O_RDWR | O_CREAT, 0644); // creates the new file; + for (j = 0; j < header.file_size[i]; j++) + { + r = read(fp, &byte, sizeof(byte)); + if (r < 0) + { + fprintf(stderr, "%s: file %s could not be read from archive\n", f_name, strerror(5)); + exit(EXIT_FAILURE); + } + + w = write(tempfp, &byte, sizeof(byte)); + if (w < 0) + { + fprintf(stderr, "%s: file %s could not be written to file\n", f_name, strerror(5)); + exit(EXIT_FAILURE); + } + } + } + } + + if (header.next < 0) + { + printf("Untared Successfully\n"); + exit(EXIT_SUCCESS); + } + else + { + p = header.next; + lseek(fp, header.next, SEEK_SET); + } + } + + return EXIT_SUCCESS; +} + +int fileexists(char *fname) +{ + if (open(fname, O_RDONLY, 0644) < 0) + { + return false; // file doesn't exist + } + else + { + return true; // file exists + } +}