ctar/ctar.c

550 lines
15 KiB
C
Executable File

#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
}
}