Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

create a program capable of archiving the contents of a directory into a single

ID: 3818498 • Letter: C

Question

create a program capable of archiving the contents of a directory into a single file, much like tar does. You will write a makefile that compiles your program into an executable named arch, which has usage arch action -c to create a new archive file -e to expand an existing archive file source Specifies the path-name of a directory that contains the files to be archived (-c) or of the archive file (-e) being expanded. target Specifies the path-name of the archive file that is to be created (-e) or of the directory to be created to hold the contents of the archive file. Please answer it with Program

Explanation / Answer

arch.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>

#define BSIZE 2048


struct mdata
{
char name[255];
FILE *fp;
int size;
int nsize;
int ssize;
struct mdata *next;
};

struct mdata *mhead = NULL, *current = NULL;

int min(int x, int y)
{
if(x < y) return x;
else return y;
}
int getsize(FILE *fp)
{
int size = 0;
fseek(fp, 0L, SEEK_END);
size = ftell(fp);
fseek(fp, 0L, SEEK_SET);   
return size;
}

int addsize(char *name, int size)
{
char ntemp[255];
struct mdata *newm;
newm = (struct mdata *)malloc(sizeof(struct mdata));
strcpy(newm->name, name);
newm->size = size;
newm->nsize = strlen(name);
sprintf(ntemp, "%d", newm->size);
newm->ssize = strlen(ntemp);
newm->next = NULL;
printf("File %s is being processed... ", name);
if(mhead == NULL)
{
mhead = newm;
current = newm;
}
else
{
current->next = newm;
current = newm;
}
}

int readh(FILE *fp1)
{
int i = 0, j= 1 ;
int hsize = 0, size = 0;
int byte;
char shsize[50];
char name[255];
char ssize[50];
while((byte = fgetc(fp1))!='|')
{
shsize[i] = (char)byte;
i++;
}
shsize[i] = '';
hsize = atoi(shsize);
hsize += strlen(shsize);
printf("The total size of header is %d. ", hsize);
printf("Contents starts at %dth byte. ", hsize);
//COLLECT NAMES AND SIZES
j = strlen(shsize)+1;
while(j <= hsize-1)
{
i = 0;
while((byte = fgetc(fp1))!='|')
{
name[i++] = byte;
j++;
}
j++;
name[i] = '';
i = 0;
while((byte = fgetc(fp1))!='|')
{
ssize[i++] = byte;
j++;
}   
j++;
ssize[i] = '';
size = atoi(ssize);
printf("File '%s' with size %d added to list. ", name, size);
addsize(name, size);
printf("File '%s' processing completed. ", name);
}
printf("File meta data collection successfully completed. ");
}

void getFilePath(const char* filepath,char *path)
{
size_t i;
strcpy (path,filepath);
for(i = strlen(filepath) - 1; i >= 0; i--)
{
if (path[i] == '/')
{
path[i]='';
return;
}
}
}

int extract(char* unarcfile)
{
char block[BSIZE];
char stsize[5];
char shsize[100];
int rsize = 0;
int tnsize = 0, tssize = 0, hsize = 0, scount = 0;
int totsize = 0;
int unreadcount = 0;
struct mdata *ptr;
FILE *fpar, *fp;
char path[255];

//COLLECTING HEADER
printf("Opening file %s... ", unarcfile);
fpar = fopen(unarcfile, "r+");
if(fpar == NULL)
{
printf("Error opening file %s. ", unarcfile);
}
readh(fpar);
ptr = mhead;
lseek(fpar, hsize+1, SEEK_SET);
while(ptr != NULL)
{
totsize = 0;
printf("Creating file %s... ", ptr->name);
getFilePath(ptr->name,path);
mkdir(path,0775);
fp = fopen(ptr->name, "w+");
printf("Writing %d bytes of %s... ", ptr->size, ptr->name);
unreadcount = ptr->size;
while(unreadcount > 0)
{
if(sizeof(block)>= unreadcount)
{
rsize = fread(block, 1, unreadcount, fpar);
}
else
{
rsize = fread(block, 1, sizeof(block), fpar);
}
unreadcount -= rsize;
totsize += rsize;
fwrite(block, 1, rsize, fp);
}
printf("Written %d bytes to file %s. ", totsize, ptr->name);
ptr = ptr->next;
}
printf("Extraction completed. ");
fclose(fpar);
return 0;
}

int add(char *name)
{
FILE *fp;
char ntemp[255];
struct mdata *newm;
newm = (struct mdata *)malloc(sizeof(struct mdata));
strcpy(newm->name, name);
fp = fopen(name, "r+");
newm->fp = fp;
newm->size = getsize(fp);
newm->nsize = strlen(name);
sprintf(ntemp, "%d", newm->size);
newm->ssize = strlen(ntemp);
newm->next = NULL;
printf("File %s is being processed... ", name);
if(mhead == NULL)
{
mhead = newm;
current = newm;
}
else
{
current->next = newm;
current = newm;
}
}

int preproc(int argc, char** argv)
{
int i;

for(i = 2; i <= argc-2; i++)
{   
add(argv[i]);
}
}

void show_dir_content(char *path)
{
DIR * d = opendir(path); // open the path
if(d==NULL) return; // if was not able return
struct dirent * dir; // for the directory entries
while ((dir = readdir(d)) != NULL) // if we were able to read somehting from the directory
{
if(dir-> d_type != DT_DIR) { // if the type is not directory just print it with blue
char d_path[255]; // here I am using sprintf which is safer than strcat
sprintf(d_path, "%s/%s", path, dir->d_name);
add(d_path);
}
else
if(dir -> d_type == DT_DIR && strcmp(dir->d_name,".")!=0 && strcmp(dir->d_name,"..")!=0 ) // if it is a directory
{
char d_path[255]; // here I am using sprintf which is safer than strcat
sprintf(d_path, "%s/%s", path, dir->d_name);
add(d_path);
show_dir_content(d_path); // recall with the new path
}
}
closedir(d); // finally close the directory
}

int archive(int argc, char** argv)
{
char block[BSIZE];
char stsize[5];
char shsize[100];
int rsize = 0;
int tnsize = 0, tssize = 0, hsize = 0, scount = 0;
struct mdata *ptr;
FILE *fpar, *fp;

//CREATE HEADER
printf("Pre-processing the files to collect meta data... ");
//preproc(argc, argv);
show_dir_content(argv[2]); //directory path 3rd argument.
printf("Pre-processing completed. ");
printf("Compiling header information. ");
fpar = fopen(argv[argc-1], "w+");
ptr = mhead;
while(ptr != NULL)
{
tnsize += ptr->nsize;
tssize += ptr->ssize;
ptr = ptr->next;
scount +=2;
}
hsize = tnsize+tssize+scount+1;
printf("Total length of file names is %d ", tnsize);
printf("Total length of file sizes is %d ", tssize);
printf("Total size of header except file size is %d. ", hsize);
sprintf(shsize, "%d|", hsize); //10 bytes of header size
fwrite(shsize, 1, strlen(shsize), fpar);
ptr = mhead;
while(ptr != NULL)
{
fwrite(ptr->name, 1, ptr->nsize, fpar);   
fwrite("|", 1, 1, fpar);
sprintf(stsize, "%d", ptr->size);
fwrite(stsize, 1, ptr->ssize, fpar);
fwrite("|", 1, 1, fpar);
ptr = ptr->next;
}
printf("The header created and written to archieve file. ");
//CREATE BODY
ptr = mhead;
while(ptr != NULL)
{
fp = ptr->fp;
while(rsize = fread(block, 1, sizeof(block), fp))
{
fwrite(block, 1, rsize, fpar);
}
ptr = ptr->next;
}   
printf("Contents of all files written to archieve file. ");
fclose(fpar);
return 0;
}

int main(int argc,char **argv){
if (argc<=2) {
printf("Usage : %s -[c|e] <filelist> <archive> ",argv[0]);
return 1;
}
if (strcmp(argv[1],"-c")==0) {
return archive (argc,argv);
}
if (strcmp(argv[1],"-e")==0) {
return extract (argv[2]);
}
return 1;
}

Usage:

arch -c <directoryname> <archivename>

arch -e <archivename>