aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles <sircharlesaze@gmail.com>2020-06-22 15:09:59 +0200
committerCharles <sircharlesaze@gmail.com>2020-06-22 15:09:59 +0200
commit86e8aeb5bb66ae5625002533b529752a7814e6c0 (patch)
treebb30c103a5059c8dda817310dc57256d5b812ede
parent3f37f1c9bf64866de90ec418adcfe31b634231c2 (diff)
downloadtar-86e8aeb5bb66ae5625002533b529752a7814e6c0.tar.gz
tar-86e8aeb5bb66ae5625002533b529752a7814e6c0.tar.bz2
tar-86e8aeb5bb66ae5625002533b529752a7814e6c0.zip
Added archive extracting
-rw-r--r--README.md4
-rw-r--r--inc/tar.h11
-rw-r--r--src/archive.c78
-rw-r--r--src/fs.c2
-rw-r--r--src/header.c (renamed from src/utils.c)71
-rw-r--r--src/record.c60
6 files changed, 149 insertions, 77 deletions
diff --git a/README.md b/README.md
index 95120ca..4c93688 100644
--- a/README.md
+++ b/README.md
@@ -4,10 +4,12 @@ Shitty clone of the `tar` program made for educational purposes.
## TODO
-- [ ] `x` Extracting archive
+- [x] `x` Extracting archive
- [ ] `d` Difference between file system and archive
- [ ] `t` List archive
- [ ] `v` Verbose mode
- [ ] `A` Concatenate 2 archives together
- [ ] `r` Add files to archive
- [ ] `u` Update file in archive
+- [ ] Remove `..` from member name
+- [ ] Complete ustar format
diff --git a/inc/tar.h b/inc/tar.h
index dbeca6d..66e3c64 100644
--- a/inc/tar.h
+++ b/inc/tar.h
@@ -65,10 +65,9 @@ typedef enum
FLAG_LIST = 1 << 0,
} t_flags;
-// utils.c
-int record_write(int fd, char *s, size_t size);
-int record_write_blank(int fd, size_t count);
+// header.c
int header_write(int fd, char *file_name, struct stat *statbuf);
+int header_parse(char record[RECORD_SIZE], struct stat *statbuf, t_header *header);
// fs.c
int file_content_write(int fd, int file_fd, struct stat *statbuf);
@@ -79,4 +78,10 @@ int directory_write(int fd, char dir_name[PATH_MAX]);
int archive_write(char *archive_file_name, char **files);
int archive_read(char *archive_file_name);
+// record.c
+int record_write(int fd, char *s, size_t size);
+int record_write_blank(int fd, size_t count);
+int record_read(int fd, char record[RECORD_SIZE]);
+bool record_is_blank(char record[RECORD_SIZE]);
+
#endif // TAR_H
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/utils.c b/src/header.c
index ce56307..d881275 100644
--- a/src/utils.c
+++ b/src/header.c
@@ -1,44 +1,5 @@
#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;
@@ -97,22 +58,26 @@ int header_write(int fd, char *file_name, struct stat *statbuf)
return record_write(fd, (char*)&header, sizeof(t_header));
}
-int header_parse(char record[RECORD_SIZE])
+int header_parse(char record[RECORD_SIZE], struct stat *statbuf, t_header *header)
{
- t_header header;
- mode_t mode;
- gid_t gid;
- uid_t uid;
+ unsigned int actual_checksum;
+ unsigned int expected_checksum;
+
+ memcpy(header, record, sizeof(t_header));
- memcpy(&header, record, sizeof(t_header));
- /* sscanf(header.file_mode, "% */
+ 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", statbuf->st_size); */
- /* */
- /* sscanf(header.last_time, "%011lo", statbuf->st_mtime); */
+ 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;
+}