6
\$\begingroup\$

I recently implemented a subset of the ustar archiving utility as my first year programming one project. I would like to get it reviewed and if anyone has anything to point out.

dir.c

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "star.h"
void dir_untar(struct header_ustar *h)
{
    mode_t mode;
    char modeoct[9] = {0};
    strncpy(modeoct,h->mode,8);
    sscanf(modeoct,"%o",&mode);
    char filename[260]={0};
        if(h->prefix[0]){
        strncat(filename,h->prefix,155);
        strcat(filename,"/");
    }
    strncat(filename,h->name,100);
    mkdir(filename,mode);
}
void dir_tar(FILE *tarf, char *dirname, struct stat *s)
{
    struct header_ustar h;
    bzero(&h,sizeof(struct header_ustar));
    int len = (int)strlen(dirname);
    if(len>255)
        return;
    if(len>100){
        int j=154;
        while(dirname[j]!='/')
            j--;
        if(len-j>100)
            return;
        strncpy(h.prefix,dirname,(size_t)j);
        strncpy(h.name,dirname+j+1,(size_t)(len-j-1));
    }else
        strcpy(h.name,dirname);
    char *buf=malloc(sizeof(char)*512);
    sprintf(buf,"%08o",s->st_uid);
    strncpy(h.uid,buf,8);
    sprintf(buf,"%08o",s->st_gid);
    strncpy(h.gid,buf,8);
    sprintf(buf,"%012o",0);
    strncpy(h.size,buf,12);
    sprintf(buf,"%012o",(int)s->st_mtime);
    strncpy(h.mtime,buf,12);
    h.typeflag = '5';
    sprintf(buf,"%08o",s->st_mode);
    strncpy(h.mode,buf,8);
    strcpy(h.magic,MAGIC);
    strncpy(h.version,"00",2);
    unsigned int chksum = checksum(&h);
    sprintf(h.checksum,"%06o",chksum);
    h.checksum[7] = ' ';
    fwrite(&h,sizeof(struct header_ustar),1,tarf);

    DIR *dp;
    dp = opendir(dirname);

    struct dirent * content;
    while((content= readdir(dp)) != NULL)
    {
        if(strcmp(content->d_name,"..")==0 || strcmp(content->d_name,".")==0)
            continue;
        struct stat s2;
        char filename[255]={0};
        strcat(filename,dirname);
        int l2 = (int)strlen(filename);
        if(filename[l2-1]!='/'){
            filename[l2] = '/';
            filename[l2+1]= 0;
        }
        strcat(filename,content->d_name);
        stat(filename,&s2);
        if (S_ISREG(s2.st_mode))
            regular_tar(tarf,filename,&s2);
        else if(S_ISDIR(s2.st_mode))
            dir_tar(tarf,filename,&s2);
    }
    closedir(dp);
}

Doxyfile (almost automatically generated and I just wanted to know if their is any option I missed out there)

DOXYFILE_ENCODING      = UTF-8
PROJECT_NAME           = "star"
PROJECT_NUMBER         =0.1
PROJECT_BRIEF          ="subset of Unix standard tar"
OUTPUT_DIRECTORY       =docs
CREATE_SUBDIRS         = NO
OUTPUT_LANGUAGE        = English
BRIEF_MEMBER_DESC      = YES
REPEAT_BRIEF           = YES
ABBREVIATE_BRIEF       =
ALWAYS_DETAILED_SEC    = NO
INLINE_INHERITED_MEMB  = NO
FULL_PATH_NAMES        = YES
STRIP_FROM_PATH        =
STRIP_FROM_INC_PATH    =
SHORT_NAMES            = NO
JAVADOC_AUTOBRIEF      = NO
QT_AUTOBRIEF           = NO
MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS           = YES
SEPARATE_MEMBER_PAGES  = NO
TAB_SIZE               = 4
ALIASES                =
TCL_SUBST              =
OPTIMIZE_OUTPUT_FOR_C  = YES
OPTIMIZE_OUTPUT_JAVA   = NO
OPTIMIZE_FOR_FORTRAN   = NO
OPTIMIZE_OUTPUT_VHDL   = NO
EXTENSION_MAPPING      =
MARKDOWN_SUPPORT       = YES
AUTOLINK_SUPPORT       = YES
BUILTIN_STL_SUPPORT    = NO
CPP_CLI_SUPPORT        = NO
SIP_SUPPORT            = NO
IDL_PROPERTY_SUPPORT   = YES
DISTRIBUTE_GROUP_DOC   = NO
SUBGROUPING            = YES
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS  = NO
TYPEDEF_HIDES_STRUCT   = NO
LOOKUP_CACHE_SIZE      = 0
EXTRACT_ALL            = YES
EXTRACT_PRIVATE        = NO
EXTRACT_PACKAGE        = NO
EXTRACT_STATIC         = NO
EXTRACT_LOCAL_CLASSES  = YES
EXTRACT_LOCAL_METHODS  = NO
EXTRACT_ANON_NSPACES   = NO
HIDE_UNDOC_MEMBERS     = NO
HIDE_UNDOC_CLASSES     = NO
HIDE_FRIEND_COMPOUNDS  = NO
HIDE_IN_BODY_DOCS      = NO
INTERNAL_DOCS          = NO
CASE_SENSE_NAMES       = YES
HIDE_SCOPE_NAMES       = NO
SHOW_INCLUDE_FILES     = YES
SHOW_GROUPED_MEMB_INC  = NO
FORCE_LOCAL_INCLUDES   = NO
INLINE_INFO            = YES
SORT_MEMBER_DOCS       = YES
SORT_BRIEF_DOCS        = NO
SORT_MEMBERS_CTORS_1ST = NO
SORT_GROUP_NAMES       = NO
SORT_BY_SCOPE_NAME     = NO
STRICT_PROTO_MATCHING  = NO
GENERATE_TODOLIST      = YES
GENERATE_TESTLIST      = YES
GENERATE_BUGLIST       = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS       =
MAX_INITIALIZER_LINES  = 30
SHOW_USED_FILES        = YES
SHOW_FILES             = YES
SHOW_NAMESPACES        = YES
FILE_VERSION_FILTER    =
LAYOUT_FILE            =
CITE_BIB_FILES         =
QUIET                  = NO
WARNINGS               = YES
WARN_IF_UNDOCUMENTED   = YES
WARN_IF_DOC_ERROR      = YES
WARN_NO_PARAMDOC       = NO
WARN_FORMAT            = "$file:$line: $text"
WARN_LOGFILE           =
INPUT                  = dir.c general.c help.c main.c regular.c tar.c untar.c star.h
INPUT_ENCODING         = UTF-8
FILE_PATTERNS          =
RECURSIVE              = NO
EXCLUDE                =
EXCLUDE_SYMLINKS       = NO
EXCLUDE_PATTERNS       =
EXCLUDE_SYMBOLS        =
EXAMPLE_PATH           =
EXAMPLE_PATTERNS       =
EXAMPLE_RECURSIVE      = NO
IMAGE_PATH             =
INPUT_FILTER           =
FILTER_PATTERNS        =
FILTER_SOURCE_FILES    = NO
FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE =
SOURCE_BROWSER         = NO
INLINE_SOURCES         = NO
STRIP_CODE_COMMENTS    = YES
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION    = NO
REFERENCES_LINK_SOURCE = YES
SOURCE_TOOLTIPS        = YES
USE_HTAGS              = NO
VERBATIM_HEADERS       = YES
ALPHABETICAL_INDEX     = YES
COLS_IN_ALPHA_INDEX    = 5
IGNORE_PREFIX          =
GENERATE_HTML          = YES
HTML_OUTPUT            = html
HTML_FILE_EXTENSION    = .html
HTML_HEADER            =
HTML_FOOTER            =
HTML_STYLESHEET        =
HTML_EXTRA_STYLESHEET  =
HTML_EXTRA_FILES       =
HTML_COLORSTYLE_HUE    = 220
HTML_COLORSTYLE_SAT    = 100
HTML_COLORSTYLE_GAMMA  = 80
HTML_TIMESTAMP         = YES
HTML_DYNAMIC_SECTIONS  = NO
HTML_INDEX_NUM_ENTRIES = 100
GENERATE_DOCSET        = NO
DOCSET_FEEDNAME        = "Doxygen generated docs"
DOCSET_BUNDLE_ID       = org.doxygen.Project
DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
DOCSET_PUBLISHER_NAME  = Publisher
GENERATE_HTMLHELP      = NO
CHM_FILE               =
HHC_LOCATION           =
GENERATE_CHI           = NO
CHM_INDEX_ENCODING     =
BINARY_TOC             = NO
TOC_EXPAND             = NO
GENERATE_QHP           = NO
QCH_FILE               =
QHP_NAMESPACE          = org.doxygen.Project
QHP_VIRTUAL_FOLDER     = doc
QHP_CUST_FILTER_NAME   =
QHP_CUST_FILTER_ATTRS  =
QHP_SECT_FILTER_ATTRS  =
QHG_LOCATION           =
GENERATE_ECLIPSEHELP   = NO
ECLIPSE_DOC_ID         = org.doxygen.Project
DISABLE_INDEX          = NO
GENERATE_TREEVIEW      = NO
ENUM_VALUES_PER_LINE   = 4
TREEVIEW_WIDTH         = 250
EXT_LINKS_IN_WINDOW    = NO
FORMULA_FONTSIZE       = 10
FORMULA_TRANSPARENT    = YES
USE_MATHJAX            = NO
MATHJAX_FORMAT         = HTML-CSS
MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
MATHJAX_EXTENSIONS     =
MATHJAX_CODEFILE       =
SEARCHENGINE           = NO
SERVER_BASED_SEARCH    = NO
EXTERNAL_SEARCH        = NO
SEARCHENGINE_URL       =
SEARCHDATA_FILE        = searchdata.xml
GENERATE_LATEX         = NO
LATEX_CMD_NAME         = latex
MAKEINDEX_CMD_NAME     = makeindex
COMPACT_LATEX          = NO
PAPER_TYPE             = a4
PDF_HYPERLINKS         = YES
USE_PDFLATEX           = YES
LATEX_BATCHMODE        = NO
LATEX_HIDE_INDICES     = NO
LATEX_SOURCE_CODE      = NO
LATEX_BIB_STYLE        = plain
GENERATE_RTF           = NO
RTF_OUTPUT             = rtf
COMPACT_RTF            = NO
RTF_HYPERLINKS         = NO
GENERATE_MAN           = NO
MAN_OUTPUT             = man
MAN_EXTENSION          = .3
MAN_LINKS              = NO
GENERATE_XML           = NO
XML_OUTPUT             = xml
XML_PROGRAMLISTING     = YES
GENERATE_DOCBOOK       = NO
DOCBOOK_OUTPUT         = docbook
GENERATE_AUTOGEN_DEF   = NO
GENERATE_PERLMOD       = NO
PERLMOD_LATEX          = NO
PERLMOD_PRETTY         = YES
ENABLE_PREPROCESSING   = YES
MACRO_EXPANSION        = NO
EXPAND_ONLY_PREDEF     = NO
SEARCH_INCLUDES        = NO
SKIP_FUNCTION_MACROS   = YES
ALLEXTERNALS           = NO
EXTERNAL_GROUPS        = YES
EXTERNAL_PAGES         = YES
PERL_PATH              = /usr/bin/perl
CLASS_DIAGRAMS         = YES
HIDE_UNDOC_RELATIONS   = YES
HAVE_DOT               = NO
DOT_NUM_THREADS        = 0
DOT_FONTNAME           = Helvetica
DOT_FONTSIZE           = 10
CLASS_GRAPH            = YES
COLLABORATION_GRAPH    = YES
GROUP_GRAPHS           = YES
UML_LOOK               = NO
UML_LIMIT_NUM_FIELDS   = 10
TEMPLATE_RELATIONS     = NO
INCLUDE_GRAPH          = YES
INCLUDED_BY_GRAPH      = YES
CALL_GRAPH             = NO
CALLER_GRAPH           = NO
GRAPHICAL_HIERARCHY    = YES
DIRECTORY_GRAPH        = YES
DOT_IMAGE_FORMAT       = png
INTERACTIVE_SVG        = NO
DOT_GRAPH_MAX_NODES    = 50
MAX_DOT_GRAPH_DEPTH    = 0
DOT_TRANSPARENT        = NO
DOT_MULTI_TARGETS      = YES
GENERATE_LEGEND        = YES
DOT_CLEANUP            = YES

general.c

#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include "star.h"
int file_exist(char *path)
{
    FILE *fp;
    fp = fopen(path,"r");
    if (fp){
        fclose(fp);
        return TRUE;
    }
    return FALSE;
}
int isvalid_tar (const struct header_ustar *h)
{
    unsigned int n;
    sscanf(h->checksum,"%o",&n);
    return n==checksum(h)   &&
        (strcmp(h->magic,MAGIC)+1)%2;
}
unsigned int checksum (const struct header_ustar *h)
{
    unsigned int chksum=' '*8;
    unsigned int i;
    const unsigned char *hp = (unsigned char*)h;
    for(i=0;i<offsetof(struct header_ustar,checksum);i++)
        chksum+=hp[i];
    for(i+=(unsigned int)sizeof(char)*8;i<sizeof(struct header_ustar);i++)
        chksum +=hp[i];
    return chksum;
}

help.c

#include <stdio.h>
#include "star.h"
void show_help(void)
{
    char help[HELP_MAX+1];
    FILE *helpf;
    helpf = fopen("help.doc","r");
    if(!helpf){
        puts("Can't open help.doc");
        return;
    }
    int len= (int)(fread(help,sizeof(char),HELP_MAX,helpf)/sizeof(char));
    help[len]='\0';
    printf("%s",help);
    fclose(helpf);
}

help.doc

Usage:
    star
        print help
    star output.tar input1 input2 input3...
        creates archive
    star input.tar
        extract archive

main.c

#include <stdio.h>
#include "star.h"
int main(int argc, char**argv)
{
    switch(argc){
    case 1:
        show_help();
        break;
    case 2:
        untar(argv[1]);
        break;
    default:
        tar(argc-1,&argv[1]);
    }
    argv++;
    return 0;
}

Makefile

CC=gcc
CFLAGS= -Wall -Wextra -Wfloat-equal -Wundef -Werror -std=gnu99 -fverbose-asm  -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes -Wstrict-overflow=5 -Wwrite-strings -Wconversion
GDBFLAGS= -g -ggdb -ggdb3
.PHONY: all clean docs help
help:
    @echo "make [target]";
    @echo "list of possible targets";
    @echo "install : intall the binaries to /opt";
    @echo "remove  : remove the installed files";
    @echo "all     : release build";
    @echo "docs    : build  the documentation";
    @echo "debug   : debug build";
    @echo "clean   : clean directory from all builds"
remove:
    \rm -rf /opt/star /bin/star
install: all
    mkdir /opt/star/
    cp star /opt/star
    cp help.doc /opt/star
    ln /opt/star/star /bin/star
all:star
docs:
    doxygen
star: main.o help.o tar.o untar.o general.o regular.o dir.o
    $(CC) $(CFLAGS) *.o -o star
    strip star
main.o: main.c star.h 
    $(CC) -c $(CFLAGS) main.c -o main.o
help.o: help.c star.h
    $(CC) -c $(CFLAGS) help.c -o help.o
tar.o: tar.c star.h
    $(CC) -c $(CFLAGS) tar.c -o tar.o
untar.o: untar.c star.h
    $(CC) -c $(CFLAGS) untar.c -o untar.o
general.o: general.c star.h
    $(CC) -c $(CFLAGS) general.c -o general.o
regular.o: regular.c star.h
    $(CC) -c $(CFLAGS) regular.c -o regular.o
dir.o: star.h
    $(CC) -c $(CFLAGS) dir.c -o dir.o
clean:
    \rm -rf *.o star docs
debug: CFLAGS += $(GDBFLAGS)
debug: all

regular.c

#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include "star.h"
void regular_untar(FILE *tarf, struct header_ustar *h)
{
    /*getting the file name from prefix/name*/
    char filename[260]={0};
    if(h->prefix[0]){
        strncat(filename,h->prefix,155);
        strcat(filename,"/");
    }
    strncat(filename,h->name,100);
    FILE *fp; //output file
    fp = fopen(filename,"w");
    if(fp ==NULL)
            return;
    /*write file data*/
    unsigned int filesize;
    sscanf(h->size,"%12o",&filesize);
    char *buffer = malloc(sizeof(unsigned char)*filesize);
    fread(buffer,sizeof(unsigned char),(size_t)(filesize),tarf);
    fwrite(buffer,sizeof(unsigned char),(size_t)filesize,fp);
    long int  toseek = 512-ftell(tarf)%512;
    if(toseek <512)
        fseek(tarf,toseek,SEEK_CUR);
    fclose(fp);
}
void regular_tar(FILE *tarf, char *filename,struct stat * filestat)
{
    struct header_ustar h;
    bzero(&h,sizeof(struct header_ustar) );
    int len = (int) strlen(filename);
    /*filling in the name,prefix members of the structure*/
    if(len>255)
        return;
    if(len>100){
        int j=154;
        while(filename[j]!='/')
            j--;
        if(len-j>100)
            return;
        strncpy(h.prefix,filename,(size_t)j);
        strncpy(h.name,filename+j+1,(size_t)(len-j-1));
    }
    else
        strcpy(h.name,filename);

    /*getting the uid,gid & rest of the struct members*/
    char *buf=malloc(sizeof(unsigned char)*512);
    sprintf(buf,"%08o",filestat->st_uid);
    strncpy(h.uid,buf,8);
    sprintf(buf,"%08o",filestat->st_gid);
    strncpy(h.gid,buf,8);
    sprintf(buf,"%012o",(unsigned int)filestat->st_size);
    strncpy(h.size,buf,12);
    sprintf(buf,"%012o",(unsigned int)filestat->st_mtime);
    strncpy(h.mtime,buf,12);
    h.typeflag='0';
    sprintf(buf,"%08o",filestat->st_mode);
    strncpy(h.mode,buf,8);
    strcpy(h.magic,MAGIC);
    strncpy(h.version,"00",2);
    unsigned int chksum = checksum(&h);
    sprintf(h.checksum,"%06o",chksum);
    h.checksum[7] = ' ';
    fwrite(&h,sizeof(struct header_ustar),1,tarf);
    FILE *fp;
    fp=fopen(filename,"rb");

    bzero(buf,512);
    while((int) fread(buf,sizeof(unsigned char),(size_t)512,fp)!=0){
        fwrite(buf,(size_t)512,sizeof(unsigned char),tarf);
        bzero(buf,512);
    }
    fclose(fp);
}

star.h

#ifndef __TAR_H__
#define __TAR_H__
#include <sys/stat.h>
#define HELP_MAX 100000
#define TRUE 1
#define FALSE 0
#define MAGIC "ustar"
#define SUCCESS 0
#define ERR -1

/**
 * header_ustar structure
 */
struct header_ustar
{
/**
 * Pathname, stored as a null-terminated string except when all characters in
 * the array contain non-NUL characters including the last character.One common
 * early convention used a trailing "/"character to indicate a directory name,
 */
    char name[100];
//! File mode, stored as an octal number in ASCII.
    char mode[8];
//! User id of owner, as octal numbers in ASCII.
    char uid[8];
//! Group id of owner, as octal numbers in ASCII.
    char gid[8]; 
/**
 * Size of file, as octal number in ASCII. For regular files only,
 * this indicates the amount of data that follows the header. In
 * particular,zero is stored for anything other than regular files.
 */
    char size[12];
/**
 * Modification time of file, as an octal number in ASCII. This
 * indicates the number of seconds since the start of the epoch,
 * 00:00:00 UTC January 1, 1970.
 */
    char mtime[12];
/**
 * Header checksum, stored as an octal number in ASCII. To compute the checksum,
 * set the checksum field to all spaces, then sum all bytes in the header using
 * unsigned arithmetic. This field should be stored as six octal digits followed
 * by a null and a space character.
 */
    char checksum[8];
/**
 * Type of entry. POSIX extended the earlier linkflag field with several new
 * type values:
 *     * '0'   Regular file.
 *     * '1'   Hard link.
 *     * '2'   Symbolic link.
 *     * '3'   Character device node.
 *     * '4'   Block device node.
 *     * '5'   Directory.
 *     * '6'   FIFO node.
 *     *  Other treated as a regular file.
 * Note that in this tar implementation only Regular files and Directories are implemented.
 */
    char typeflag;
/**
 *Not used in my implementation
 */
    char linkname[100];
/**
 * Contains the magic value "ustar" followed by a NUL byte to
 * indicate that this is a POSIX standard archive. Full compliance
 * requires the uname and gname fields be properly set.
 */
    char magic[6];
/**
 * Version. This should be "00" (two copies of the ASCII digit zero) for 
 * POSIX standard archives without the NUL byte.
 */
    char version[2];
/**
 * Not used in my implementation. The uid is used instead.
 */
    char uname[32];
/**
 * Not used in my implementation. The gid is used instead.
 */
    char gname[32];
/**
 * Not used in my implementation.
 */
    char devmajor[8];
/**
 * Not used in my implementation.
 */
    char devminor[8];
/**
 * If the pathname is too long to fit in the 100 bytes provided by name , it can
 * be split at any / character with the first portion going into the prefix
 * field. If the prefix field is not empty, the path name will be in form 
 * of `prefix/name`
 */
    char prefix[155];
/**
 * ustar tape archive is used to store data on 9-track industry-standard 12.7 mm (0.5 in).
 * Data is read and written in form of consecutive logical record each of size 512 bytes.
 * padding is used to make the header logical record fit on 512 byte border.
 */
    char padding[12];
} __attribute__((packed));

/**
 * \breif reads the file from tar archive and write it  
 */
void regular_untar (FILE* tarf, struct header_ustar* h);
/*!
 * \brief writes the tar header to the file content to the tar file
 * \param tarf pointer to the tar file
 * \param filename pathname of the file
 * \param filestat pointer to the structure stat that contains file state info
 * the function regular_tar creates struct header_ustar and fill it with info
 * from the filestat then write this data to the file pointer to by tarf
 * next the content of the file is written all in binary..
 * after the content of file is written the stream tarf is filled with zeros
 * till it is alligned on boundry of 512 bytes
 */
void regular_tar (FILE* tarf, char* filename,struct stat * filestat);
/*!
 * \brief creates directory with the name carried by the header_ustar *h
 * \param h pointer to the ustar_header that contains directory info
 * the dir dir_untar function creates directory with name found in prefix/name
 * members of the struct header_ustar. No persmissions are set on created
 * folder
 */

void dir_untar(struct header_ustar* h);
/*!
 * \brief add directory and its content to the tar archive
 * \param tarf pointer to the tar file structure
 * \param dirname null terminated directory name
 * \param s pointer to the directory state structure
 * the function dir_tar will create struct header_ustar for the directory
 * then write it to the tarf steam then iterate over all the direcotry content
 * and tar them either with dir_tar or with regular_tar accordint to the
 * directory type.
 */
void dir_tar(FILE* tarf, char* dirname, struct stat* s);
/*!
 * read HELP_MAX character from file called help.doc
 * and print write them to stdout
 */

void show_help(void);
/*!
 * \brief calculates the checksum
 *
 * \param h pointer to tar header that will have checksum calculated for
 *
 * for extra information on how checksum is calculated read struct 
 * header_ustar member checksum
 */

unsigned int checksum (const struct header_ustar* h);

/*!
 * \brief create pack list of files into one tar archive
 * \param c number of elementes in the array of strings names
 * \param names the first element in names represent the name of the tar
 * and the rest (c-1) names represent the files/folders to be tarred
 * 
 * tar creates file with Pathnam = names[0] and it decides the type of the
 * given names and call either regular_tar or dir_tar to do both regular file
 * tarring and directory tarring
 */
void tar(int c, char** names);

/*!
 * \brief unpack the tar archive into its original contents
 *
 * \param name the Pathname of the tar archive
 *
 * untar reads header_ustar logical block from the file and use it to determine the type
 * of the file. and then passes this block to either regular_untar or dir_untar based on
 * the member type_flag 
 */
void untar(char* name);

/*!
 * \brief Function thar returns TRUE if the given file path is correct
 * and FALSE otherwise.
 *
 * \param path Pathname of the file.
 *
 * file_exist tries opening file with fopen and returns TRUE if fopen succeeded
 * and FALSE if fopen failed
 */
int file_exist(char* path);

/*!
 * \brief Function that returns 1 if the given struct is
 * valid header_ustar and zero otherwise
 * 
 * \param h pointer to the struct that will be checked
 * 
 * this function makesure that the h->magic is identical to the MAGIC
 * number and that the h->checksum of the struct is the right
 * checksum
 */
int isvalid_tar (const struct header_ustar* h);
#endif

tar.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "star.h"
void tar(int c, char**names){
    int i;
    FILE *tar_file;
    tar_file = fopen(names[0],"wb");
    for(i=1;i<c;i++)
    {
        struct stat s;
        stat(names[i],&s);
        if( S_ISREG(s.st_mode))
            regular_tar(tar_file,names[i],&s);
        else if (S_ISDIR(s.st_mode))
            dir_tar(tar_file,names[i],&s);
    }
    for(i=0;i<256;i++){
        int z=0;
        fwrite(&z,sizeof(int),1,tar_file);
    }
    fclose(tar_file);
}

untar.c

#include <stdio.h>
#include "star.h"
void untar(char *name)
{
    FILE *tarptr;
    tarptr = fopen(name,"rb");
    struct header_ustar h;
    fread(&h,sizeof(struct header_ustar),1,tarptr);
    while(isvalid_tar(&h)){
        switch(h.typeflag){
            case '0':
                regular_untar(tarptr,&h);
                break;
            case '5':
                dir_untar(&h);
        }
        fread(&h,sizeof(struct header_ustar),1,tarptr);
    }

}
\$\endgroup\$
2
\$\begingroup\$

This line: * \breif reads the file from tar archive and write it

contains a misspelling of the key word brief

For readability/understandability, separate code blocks: (for, if, else, while, do...while, switch, case, default) by a blank line

when calling system functions: fopen() and fread() always check the returned value to assure the operation was successful

the switch() statements should include a default: case so unexpected input, etc is caught and handled

in the file: untar.c the controlling variable for the while() loop should be the call to fread(), and have isvalid() be in an if statement inside the loop, Then the loop will be properly exited when the fread() fails.

The code contains several 'magic' numbers. 'magic' numbers make the code difficult to understand, debug, maintain. Suggest using #defines or an enum to give those magic numbers meaningful names then use those meaningful names throughout the code. Some of the 'magic' numbers are 100, 256, 154.

The stat() function needs a path for the first parameter, not just the file name.

regarding the header file: star.h leading underscores, especially double leading underscores are 'effectively' reserved for the compiler. Strongly suggest removing the double leading underscores and use the complete file name in the #ifndef, etc statements. I.E:

#ifndef STAR_H
#define STAR_H
...
#endif

when calling malloc(), always check (!=NULL) the returned value to assure the operation was successful.

regarding this line: long int toseek = 512-ftell(tarf)%512;

the % operator has a lower precedence than the - operator so the result of the line will be drastically different that what is expected.

Also, if the file is less than 512 bytes long, then the % operator will threat the resulting negative value as a very large positive value, again resulting a drastically different value than what is expected.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.