From 86e8aeb5bb66ae5625002533b529752a7814e6c0 Mon Sep 17 00:00:00 2001 From: Charles Date: Mon, 22 Jun 2020 15:09:59 +0200 Subject: Added archive extracting --- src/archive.c | 78 ++++++++++++++++++++++++++++---------- src/fs.c | 2 + src/header.c | 83 +++++++++++++++++++++++++++++++++++++++++ src/record.c | 60 +++++++++++++++++++++++++++++ src/utils.c | 118 ---------------------------------------------------------- 5 files changed, 203 insertions(+), 138 deletions(-) create mode 100644 src/header.c create mode 100644 src/record.c delete mode 100644 src/utils.c (limited to 'src') diff --git a/src/archive.c b/src/archive.c index 11457d6..a3addd3 100644 --- a/src/archive.c +++ b/src/archive.c @@ -41,33 +41,71 @@ int archive_write(char *archive_file_name, char **files) int archive_read(char *archive_file_name) { - int fd; + int archive_fd; - if ((fd = open(archive_file_name, O_RDONLY)) == -1) + if (archive_file_name == NULL) + archive_fd = STDIN_FILENO; + else { - perror("achive_write"); - return -1; + if ((archive_fd = open(archive_file_name, O_RDONLY)) == -1) + { + perror("achive_write"); + return -1; + } } - int ret; - char buf[RECORD_SIZE]; + char record[RECORD_SIZE]; t_header header; - int current_fd; + int fd; + struct stat statbuf; - while ((ret = read(fd, buf, RECORD_SIZE)) == RECORD_SIZE) - { - /* header_parse(&header, buf); */ - /* current_fd = open(header.file_name, O_WRONLY | O_CREAT | O_TRUNC, header. */ - // read content - // TODO - } - if (ret == -1) + while (true) { - perror(NULL); - return -1; + if (record_read(archive_fd, record) == -1) + return -1; + if (record_is_blank(record)) + { + if (record_read(archive_fd, record) == -1) + return -1; + if (record_is_blank(record)) + break; + else + return -1; + } + if (header_parse(record, &statbuf, &header) == -1) + return -1; + + switch (header.file_type[0]) + { + case '5': + if (mkdir(header.file_name, statbuf.st_mode) == -1) + { + close(archive_fd); + perror(NULL); + return -1; + } + break; + case '0': + fd = open(header.file_name, O_WRONLY | O_CREAT | O_TRUNC, statbuf.st_mode); + if (fd == -1) + { + perror(NULL); + return -1; + } + char *content = malloc(statbuf.st_size); + if (content == NULL || + read(archive_fd, content, statbuf.st_size) == -1 || + lseek(archive_fd, RECORD_SIZE - statbuf.st_size % RECORD_SIZE, SEEK_CUR) == -1 || + write(fd, content, statbuf.st_size) == -1) + { + perror(NULL); + return -1; + } + break; + default: + return -1; + } } - if (ret < RECORD_SIZE) - return -1; - close(fd); + close(archive_fd); return 0; } diff --git a/src/fs.c b/src/fs.c index 78ef25a..c285259 100644 --- a/src/fs.c +++ b/src/fs.c @@ -83,3 +83,5 @@ int directory_write(int fd, char dir_name[PATH_MAX]) closedir(dir); return 0; } + +/* int file_content_read(int archive_fd, */ diff --git a/src/header.c b/src/header.c new file mode 100644 index 0000000..d881275 --- /dev/null +++ b/src/header.c @@ -0,0 +1,83 @@ +#include "tar.h" + +int header_write(int fd, char *file_name, struct stat *statbuf) +{ + t_header header; + struct group *group; + struct passwd *passwd; + unsigned int sum; + + bzero(&header, sizeof(t_header)); + strncpy(header.file_name, file_name, sizeof(header.file_name)); + if (S_ISDIR(statbuf->st_mode)) + strncat(header.file_name, "/", sizeof(header.file_name) - 1); + sprintf(header.file_mode, "%07o", statbuf->st_mode & 0777); + sprintf(header.user_id, "%07o", statbuf->st_uid); + sprintf(header.group_id, "%07o", statbuf->st_gid); + + if (S_ISDIR(statbuf->st_mode)) + sprintf(header.file_size, "%011lo", 0lu); + else + sprintf(header.file_size, "%011lo", statbuf->st_size); + + sprintf(header.last_time, "%011lo", statbuf->st_mtime); + memset(header.checksum, ' ', sizeof(header.checksum)); + + switch (statbuf->st_mode & S_IFMT) + { + case S_IFREG: header.file_type[0] = '0'; break; + /* case S_IFLNK: header.file_type[0] = '0' break; */ + /* case S_IFBLK: header.file_type[0] = '0' break; */ + /* case S_IFCHR: header.file_type[0] = '0' break; */ + case S_IFDIR: header.file_type[0] = '5'; break; + /* case S_IFIFO: header.file_type[0] = '0' break; */ + /* case S_IFSOCK: header.file_type[0] = '0' break; */ + } + + memcpy(header.ustar, "ustar ", sizeof(header.ustar)); + memcpy(header.ustar_version, " ", sizeof(header.ustar_version)); + + if ((passwd = getpwuid(statbuf->st_gid)) == NULL) + { + perror("header_write getpwduid"); + return -1; + } + strncpy(header.user_name, passwd->pw_name, sizeof(header.user_name)); + if ((group = getgrgid(statbuf->st_gid)) == NULL) + { + perror("header_write getgrgid"); + return -1; + } + strncpy(header.group_name, group->gr_name, sizeof(header.group_name)); + + sum = 0; + for (size_t i = 0; i < sizeof(t_header); i++) + sum += ((uint8_t*)&header)[i]; + sprintf(header.checksum, "%06o", sum); + + return record_write(fd, (char*)&header, sizeof(t_header)); +} + +int header_parse(char record[RECORD_SIZE], struct stat *statbuf, t_header *header) +{ + unsigned int actual_checksum; + unsigned int expected_checksum; + + memcpy(header, record, sizeof(t_header)); + + actual_checksum = -1; + sscanf(header->checksum, "%06o", &actual_checksum); + memset(header->checksum, ' ', 8); + expected_checksum = 0; + for (size_t i = 0; i < sizeof(t_header); i++) + expected_checksum += ((uint8_t*)header)[i]; + if (actual_checksum != expected_checksum) + return -1; + + sscanf(header->file_mode, "%07o", &statbuf->st_mode); + sscanf(header->user_id, "%07o", &statbuf->st_uid); + sscanf(header->group_id, "%07o", &statbuf->st_gid); + sscanf(header->file_size, "%011lo", (long unsigned int*)&statbuf->st_size); + sscanf(header->last_time, "%011lo", (long unsigned int*)&statbuf->st_mtime); + return 0; +} diff --git a/src/record.c b/src/record.c new file mode 100644 index 0000000..be78978 --- /dev/null +++ b/src/record.c @@ -0,0 +1,60 @@ +#include "tar.h" + +int record_write(int fd, char *s, size_t size) +{ + char buf[RECORD_SIZE]; + + while (size > RECORD_SIZE) + { + memcpy(buf, s, RECORD_SIZE); + s += RECORD_SIZE; + size -= RECORD_SIZE; + if (write(fd, buf, RECORD_SIZE) == -1) + { + perror(NULL); + return -1; + } + } + bzero(buf, RECORD_SIZE); + memcpy(buf, s, size); + if (write(fd, buf, RECORD_SIZE) == -1) + { + perror(NULL); + return -1; + } + return (0); +} + +int record_write_blank(int fd, size_t count) +{ + char buf[RECORD_SIZE] = {0}; + while (count-- > 0) + { + if (write(fd, buf, RECORD_SIZE) == -1) + { + perror(NULL); + return -1; + } + } + return 0; +} + +int record_read(int fd, char record[RECORD_SIZE]) +{ + int ret = read(fd, record, RECORD_SIZE); + if (ret == -1) + { + perror(NULL); + return -1; + } + if (ret != RECORD_SIZE) + return -1; + return 0; +} + +static char g_record_blank[RECORD_SIZE] = {0}; + +bool record_is_blank(char record[RECORD_SIZE]) +{ + return memcmp(record, g_record_blank, RECORD_SIZE) == 0; +} diff --git a/src/utils.c b/src/utils.c deleted file mode 100644 index ce56307..0000000 --- a/src/utils.c +++ /dev/null @@ -1,118 +0,0 @@ -#include "tar.h" - -int record_write(int fd, char *s, size_t size) -{ - char buf[RECORD_SIZE]; - - while (size > RECORD_SIZE) - { - memcpy(buf, s, RECORD_SIZE); - s += RECORD_SIZE; - size -= RECORD_SIZE; - if (write(fd, buf, RECORD_SIZE) == -1) - { - perror(NULL); - return -1; - } - } - bzero(buf, RECORD_SIZE); - memcpy(buf, s, size); - if (write(fd, buf, RECORD_SIZE) == -1) - { - perror(NULL); - return -1; - } - return (0); -} - -int record_write_blank(int fd, size_t count) -{ - char buf[RECORD_SIZE] = {0}; - while (count-- > 0) - { - if (write(fd, buf, RECORD_SIZE) == -1) - { - perror(NULL); - return -1; - } - } - return 0; -} - -int header_write(int fd, char *file_name, struct stat *statbuf) -{ - t_header header; - struct group *group; - struct passwd *passwd; - unsigned int sum; - - bzero(&header, sizeof(t_header)); - strncpy(header.file_name, file_name, sizeof(header.file_name)); - if (S_ISDIR(statbuf->st_mode)) - strncat(header.file_name, "/", sizeof(header.file_name) - 1); - sprintf(header.file_mode, "%07o", statbuf->st_mode & 0777); - sprintf(header.user_id, "%07o", statbuf->st_uid); - sprintf(header.group_id, "%07o", statbuf->st_gid); - - if (S_ISDIR(statbuf->st_mode)) - sprintf(header.file_size, "%011lo", 0lu); - else - sprintf(header.file_size, "%011lo", statbuf->st_size); - - sprintf(header.last_time, "%011lo", statbuf->st_mtime); - memset(header.checksum, ' ', sizeof(header.checksum)); - - switch (statbuf->st_mode & S_IFMT) - { - case S_IFREG: header.file_type[0] = '0'; break; - /* case S_IFLNK: header.file_type[0] = '0' break; */ - /* case S_IFBLK: header.file_type[0] = '0' break; */ - /* case S_IFCHR: header.file_type[0] = '0' break; */ - case S_IFDIR: header.file_type[0] = '5'; break; - /* case S_IFIFO: header.file_type[0] = '0' break; */ - /* case S_IFSOCK: header.file_type[0] = '0' break; */ - } - - memcpy(header.ustar, "ustar ", sizeof(header.ustar)); - memcpy(header.ustar_version, " ", sizeof(header.ustar_version)); - - if ((passwd = getpwuid(statbuf->st_gid)) == NULL) - { - perror("header_write getpwduid"); - return -1; - } - strncpy(header.user_name, passwd->pw_name, sizeof(header.user_name)); - if ((group = getgrgid(statbuf->st_gid)) == NULL) - { - perror("header_write getgrgid"); - return -1; - } - strncpy(header.group_name, group->gr_name, sizeof(header.group_name)); - - sum = 0; - for (size_t i = 0; i < sizeof(t_header); i++) - sum += ((uint8_t*)&header)[i]; - sprintf(header.checksum, "%06o", sum); - - return record_write(fd, (char*)&header, sizeof(t_header)); -} - -int header_parse(char record[RECORD_SIZE]) -{ - t_header header; - mode_t mode; - gid_t gid; - uid_t uid; - - memcpy(&header, record, sizeof(t_header)); - /* sscanf(header.file_mode, "% */ - - /* sscanf(header.file_mode, "%07o", statbuf->st_mode); */ - /* sscanf(header.user_id, "%07o", statbuf->st_uid); */ - /* sscanf(header.group_id, "%07o", statbuf->st_gid); */ - /* */ - /* sscanf(header.file_size, "%011lo", statbuf->st_size); */ - /* */ - /* sscanf(header.last_time, "%011lo", statbuf->st_mtime); */ - return 0; -} -- cgit