first commit

This commit is contained in:
zongor 2022-09-03 23:49:10 -04:00
commit a6dac2e2dc
6 changed files with 780 additions and 0 deletions

9
Makefile Executable file
View File

@ -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

3
README.md Executable file
View File

@ -0,0 +1,3 @@
A simple `tar` and `untar` program
Also includes a `dump` program to check if the archive header is valid

549
ctar.c Executable file
View File

@ -0,0 +1,549 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#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) <archive file name> <file name> \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 <archive file name> 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 <archive file name> <file name>\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) <archive file name> <file name>\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
}
}

80
dumparchiveheader.c Executable file
View File

@ -0,0 +1,80 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#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;
}

17
tar.h Executable file
View File

@ -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

122
utar.c Executable file
View File

@ -0,0 +1,122 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#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
}
}