header.c

 avatar
unknown
plain_text
a year ago
8.7 kB
8
Indexable
#include "header.h"

header *create_header(struct stat sb, char *path){
    struct header *curr_header;
    struct passwd *file_pwd;
    struct group *file_group;
    char *size8_buff, *size12_buff, *name_buff;;
    int chksum_val, error, linkname_len;

    /* Initialize header */
    curr_header = malloc(sizeof(header));
    if(curr_header == NULL){
        perror("malloc");
        exit(EXIT_FAILURE);
    }

    /* Initialize string buffers */
    size8_buff = malloc(sizeof(char) * (MODE_SIZE + 1));
    if(size8_buff == NULL){
        perror("malloc");
        exit(EXIT_FAILURE);
    }

    size12_buff = malloc(sizeof(char) * (FILESIZE_SIZE + 1));
    if(size12_buff == NULL){
        perror("malloc");
        exit(EXIT_FAILURE);
    }

    /* Call function that packs name and prefix fields */
    if((error = pack_name_and_prefix(path, curr_header)) == -1){
        free(curr_header);
        free(size8_buff);
        free(size12_buff);
        return NULL;
    }

    /* Write mode as an octal num and store in header */
    if(snprintf(size8_buff, MODE_SIZE, "%07o", (unsigned int) sb.st_mode) < 0){
        perror("word overflow");
    }
    curr_header->mode = strdup(size8_buff);

    /* Write uid as an octal num and store in header */
    if(snprintf(size8_buff, UID_SIZE, "%07o", (unsigned int) sb.st_uid) < 0){
        perror("word overflow");
    }
    curr_header->uid = strdup(size8_buff);

    /* Write gid as an octal num and store in header */
    if(snprintf(size8_buff, GID_SIZE, "%07o", (unsigned int) sb.st_gid) < 0){
        perror("word overflow");
    }
    curr_header->gid = strdup(size8_buff);

    /* Write size as an octal num and store in header */
    if(snprintf(size12_buff, FILESIZE_SIZE, "%011o",
        (unsigned int) sb.st_size) < 0){
        perror("word overflow");
    }
    curr_header->size = strdup(size12_buff);

    /* Write mtime as an octal num and store in header */
    if(snprintf(size12_buff, MTIME_SIZE, "%011o", (unsigned int) sb.st_mtime)
        < 0){
        perror("word overflow");
    }
    curr_header->mtime = strdup(size12_buff);

    if(S_ISREG(sb.st_mode)){
        curr_header->typeflag = '0';
    }
    else if(S_ISDIR(sb.st_mode)){
        curr_header->typeflag = '5';
    }
    else if (S_ISLNK(sb.st_mode)){
        curr_header->typeflag = '2';
    }
    else{
        curr_header->typeflag = '\0';
    }

    /* Adding linkname field */
    if(S_ISLNK(sb.st_mode)){
        /* Malloc space for name buff */
        name_buff = malloc(sizeof(char) * (LINKNAME_SIZE + 1));
        if(name_buff == NULL){
            perror("malloc");
            exit(EXIT_FAILURE);
        }

        /* Get the file name, on error return NULL */
        if((linkname_len = readlink(path, name_buff, LINKNAME_SIZE)) == -1){
            perror("readlink");
            free(curr_header);
            free(size8_buff);
            free(size12_buff);
            return NULL;
        }

        /* Set name buff to header field */
        name_buff[linkname_len] = '\0';
        curr_header->linkname = strdup(name_buff);
        free(name_buff);
    }
    else{
        curr_header->linkname = NULL;
    }

    /* Adding constant header fields */
    curr_header->magic = strdup("ustar");
    curr_header->version = strdup("00");
    curr_header->devmajor = NULL;
    curr_header->devminor = NULL;

    /* Get user password for user name */
    file_pwd = getpwuid(sb.st_uid);
    if(file_pwd == NULL){
        perror("getpwuid");
        exit(EXIT_FAILURE);
    }

    /* Get group for group name */
    file_group = getgrgid(sb.st_gid);
    if(file_group == NULL){
        perror("getgrgid");
        exit(EXIT_FAILURE);
    }

    /* Assign user name and group name */
    curr_header->uname = strdup(file_pwd->pw_name);
    curr_header->gname = strdup(file_group->gr_name);

    /* Write chksum as an octal num and store in header */
    chksum_val = get_chksum_val(curr_header);
    if(snprintf(size8_buff, CHKSUM_SIZE, "%07o", chksum_val) < 0){
        perror("word overflow");
    }
    curr_header->chksum = strdup(size8_buff);

    free(size8_buff);
    free(size12_buff);

    return curr_header;
}

int pack_name_and_prefix(char *path, header *curr_header){
    char *name_buff, *prefix_buff;
    size_t path_len;
    int i;

    prefix_buff = malloc(sizeof(char) * PREFIX_SIZE);
    if(prefix_buff == NULL){
        perror("malloc");
        exit(EXIT_FAILURE);
    }

    name_buff = malloc(sizeof(char) * NAME_SIZE);
    if(name_buff == NULL){
        perror("malloc");
        exit(EXIT_FAILURE);
    }

    path_len = strlen(path);

    /* Pack name and prefix fields */
    if(path_len >= MAX_NAME_LEN){
        perror("file name too long");
        return -1;
    }
    else if(path_len < NAME_SIZE){
        /* If name fits in name block */
        if((curr_header->name = strdup(path)) == NULL){
            perror("strdup");
            exit(EXIT_FAILURE);
        }

        curr_header->prefix = NULL;
    }
    else if(path_len == NAME_SIZE){
        /* If name is exactly 100 chars decide if it goes in prefix or name */
        for(i = 0; i < NAME_SIZE; i++){
            if(path[i] == '\0'){
                curr_header->name = NULL;

                if((curr_header->prefix = strdup(path)) == NULL){
                    perror("strdup");
                    exit(EXIT_FAILURE);
                }
            }
            else if(path[i] == '/'){
                if((curr_header->name = strdup(path)) == NULL){
                    perror("strdup");
                    exit(EXIT_FAILURE);
                }

                curr_header->prefix = NULL;
                break;
            }
        }
    }
    else{
        /* Split name at first slash, return -1 if name is too long */
        for(i = path_len - NAME_SIZE; i < path_len; i++){
            if(path[i] == '/'){
                /* Split the path and copy each part to its respective field */
                strncpy(prefix_buff, path, i);
                strncpy(name_buff, &path[i + 1], path_len - i);

                /* Add null char to prefix */
                prefix_buff[i] = '\0';

                /* Realloc prefix to exact length */
                if((prefix_buff = realloc(prefix_buff, i + 1)) == NULL){
                    perror("realloc");
                    exit(EXIT_FAILURE);
                }

                /* Realloc name to exact length */
                if((name_buff = realloc(name_buff, path_len - i)) == NULL){
                    perror("realloc");
                    exit(EXIT_FAILURE);
                }

                /* Set name and prefix fields */
                curr_header->name = name_buff;
                curr_header->prefix = prefix_buff;

                return 0;
            }
        }

        /* Name to long, return -1 */
        perror("unable to construct header.");
        free(prefix_buff);
        free(name_buff);
        return -1;
    }

    free(prefix_buff);
    free(name_buff);

    return 0;
}

unsigned int get_chksum_val(struct header *file_header){
    unsigned int chksum_val = 0;
    int i;

    chksum_val += (unsigned int) file_header->typeflag;

    for(i = 0; i < strlen(file_header->uid); i++){
        chksum_val += (unsigned int) file_header->uid[i];
    }

    for(i = 0; i < strlen(file_header->gid); i++){
        chksum_val += (unsigned int) file_header->gid[i];
    }

    for(i = 0; i < strlen(file_header->mtime); i++){
        chksum_val += (unsigned int) file_header->mtime[i];
    }

    for(i = 0; i < strlen(file_header->mode); i++){
        chksum_val += (unsigned int) file_header->mode[i];
    }

    for(i = 0; i < strlen(file_header->magic); i++){
        chksum_val += (unsigned int) file_header->magic[i];
    }

    for(i = 0; i < strlen(file_header->size); i++){
        chksum_val += (unsigned int) file_header->size[i];
    }

    if(file_header->prefix != NULL){
        for(i = 0; i < strlen(file_header->prefix); i++){
            chksum_val += (unsigned int) file_header->prefix[i];
        }
    }

    if(file_header->name != NULL){
        for(i = 0; i < strlen(file_header->name); i++){
            chksum_val += (unsigned int) file_header->name[i];
        }
    }

    if(file_header->linkname != NULL){
        for(i = 0; i < strlen(file_header->linkname); i++){
            chksum_val += (unsigned int) file_header->linkname[i];
        }
    }

    for(i = 0; i < strlen(file_header->uname); i++){
        chksum_val += (unsigned int) file_header->uname[i];
    }

    for(i = 0; i < strlen(file_header->gname); i++){
        chksum_val += (unsigned int) file_header->gname[i];
    }

    return chksum_val;
}
Editor is loading...
Leave a Comment