aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles <sircharlesaze@gmail.com>2020-06-20 17:17:36 +0200
committerCharles <sircharlesaze@gmail.com>2020-06-20 17:17:36 +0200
commit0fa3308034c7776b6c078e493f3b758f0a0bf7e6 (patch)
treee4f2ea5954009bfa3fcd3caf6196a4b4a9f4dc87
parent95e1552a898078b4dec1eae3fcf975b392cfad6d (diff)
downloadtar-0fa3308034c7776b6c078e493f3b758f0a0bf7e6.tar.gz
tar-0fa3308034c7776b6c078e493f3b758f0a0bf7e6.tar.bz2
tar-0fa3308034c7776b6c078e493f3b758f0a0bf7e6.zip
Added recursion for directory, not complete ustar format
-rw-r--r--README.md3
-rw-r--r--inc/tar.h26
-rw-r--r--src/fs.c85
-rw-r--r--src/header.c79
-rw-r--r--src/main.c64
5 files changed, 195 insertions, 62 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7153804
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# tar
+
+Shitty clone of the `tar` program made for educational purposes.
diff --git a/inc/tar.h b/inc/tar.h
index 8663926..1dc382f 100644
--- a/inc/tar.h
+++ b/inc/tar.h
@@ -4,22 +4,36 @@
# include <sys/types.h>
# include <sys/stat.h>
+# ifndef S_IFMT
+# define S_IFMT __S_IFMT
+# endif
# ifndef S_IFDIR
# define S_IFDIR __S_IFDIR
# endif
-# ifndef S_IFMT
-# define S_IFMT __S_IFMT
+# ifndef S_IFREG
+# define S_IFREG __S_IFREG
# endif
# include <unistd.h>
# include <stdbool.h>
+# include <stdint.h>
# include <getopt.h>
# include <fcntl.h>
+# include <dirent.h>
# include <stdio.h>
# include <stdlib.h>
# include <strings.h>
# include <string.h>
+# include <grp.h>
+# include <pwd.h>
+
+# include <limits.h>
+# ifdef __linux__
+# include <linux/limits.h>
+# endif
+
+# define RECORD_SIZE 512
// # define FILE_NAME_MAX 100
@@ -44,5 +58,13 @@ typedef struct
char file_name_prefix[155];
} t_header;
+// header.c
+int record_write(int fd, char *s, size_t size);
+int header_write(int fd, char *file_name, struct stat *statbuf);
+
+// fs.c
+int file_content_write(int fd, int file_fd, struct stat *statbuf);
+int file_write(int fd, char file_name[PATH_MAX]);
+int directory_write(int fd, char dir_name[PATH_MAX]);
#endif // TAR_H
diff --git a/src/fs.c b/src/fs.c
new file mode 100644
index 0000000..78ef25a
--- /dev/null
+++ b/src/fs.c
@@ -0,0 +1,85 @@
+#include "tar.h"
+
+int file_content_write(int fd, int file_fd, struct stat *statbuf)
+{
+ char *content;
+
+ if ((content = malloc(statbuf->st_size)) == NULL)
+ {
+ perror("file_content_write");
+ close(file_fd);
+ return -1;
+ }
+ if (read(file_fd, content, statbuf->st_size) == -1)
+ {
+ perror("file_content_write");
+ close(file_fd);
+ free(content);
+ return -1;
+ }
+ int ret = record_write(fd, content, statbuf->st_size);
+ close(file_fd);
+ free(content);
+ return (ret);
+}
+
+int file_write(int fd, char file_name[PATH_MAX])
+{
+ int file_fd;
+ struct stat statbuf;
+
+ fprintf(stderr, "|%s|\n", file_name);
+ if (stat(file_name, &statbuf) == -1)
+ {
+ perror("file_write stat");
+ return -1;
+ }
+ if (header_write(fd, file_name, &statbuf) == -1)
+ return -1;
+
+ switch (statbuf.st_mode & S_IFMT)
+ {
+ case S_IFDIR:
+ return directory_write(fd, file_name);
+ default:
+ if ((file_fd = open(file_name, O_RDONLY)) == -1)
+ {
+ perror("file_write open");
+ return -1;
+ }
+ return file_content_write(fd, file_fd, &statbuf);
+ }
+ return (0);
+}
+
+int directory_write(int fd, char dir_name[PATH_MAX])
+{
+ DIR *dir;
+ struct dirent *entry;
+ size_t len;
+
+ if ((dir = opendir(dir_name)) == NULL)
+ {
+ perror("directory_write");
+ return -1;
+ }
+ len = strlen(dir_name);
+ strcat(dir_name, "/");
+ len++;
+ while ((entry = readdir(dir)) != NULL)
+ {
+ if (strcmp(entry->d_name, ".") == 0 ||
+ strcmp(entry->d_name, "..") == 0)
+ continue;
+ strcat(dir_name, entry->d_name);
+ if (file_write(fd, dir_name) == -1)
+ {
+ closedir(dir);
+ return -1;
+ }
+ dir_name[len] = '\0';
+ }
+ dir_name[len - 1] = '\0';
+ closedir(dir);
+ return 0;
+}
diff --git a/src/header.c b/src/header.c
index a0cf2fb..133a895 100644
--- a/src/header.c
+++ b/src/header.c
@@ -1,3 +1,80 @@
#include "tar.h"
-/* int header_write(int fd, */
+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 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);
+ 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));
+
+ /* getpwuid(); */
+
+ 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));
+}
diff --git a/src/main.c b/src/main.c
index 1161278..1c0f12f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3,63 +3,6 @@
// only first hard link
// checksum positive and negative bytes
-int write_file(int fd, char *file_name)
-{
- struct stat statbuf;
- t_header header;
-
- stat(file_name, &statbuf);
- bzero(&header, sizeof(t_header));
- strncpy(header.file_name, file_name, sizeof(header.file_name));
- 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);
- sprintf(header.file_size, "%011lo", statbuf.st_size);
- sprintf(header.last_time, "%011lo", statbuf.st_mtime);
- memset(header.checksum, ' ', sizeof(header.checksum));
- header.file_type[0] = '0';
-
- /* strncpy(header.ustar, "ustar", sizeof(header.ustar)); */
- char *header_ptr = (char*)&header;
- unsigned int sum = 0;
- for (size_t i = 0; i < sizeof(t_header); i++)
- sum += header_ptr[i];
- sprintf(header.checksum, "%06o", sum);
-
- char buf[512] = {0};
- memcpy(buf, &header, sizeof(t_header));
- write(fd, buf, 512);
-
-
- int from;
- char *content;
- switch (statbuf.st_mode & S_IFMT)
- {
- case S_IFDIR: break;
- default:
- from = open(file_name, O_RDONLY);
- content = calloc(statbuf.st_size + 1, sizeof(char));
- read(from, content, statbuf.st_size);
- write(fd, content, statbuf.st_size);
- free(content);
- close(from);
- memset(buf, '\0', 512);
- write(fd, buf, 512 - statbuf.st_size % 512);
- }
-
- // if dir
- // write_dir
- // else
- // write content
- return (0);
-}
-
-int write_directory(int fd, char *dirname)
-{
- // for f in files
- // write_file
-}
-
int main(int argc, char **argv)
{
int opt;
@@ -90,17 +33,20 @@ int main(int argc, char **argv)
fd = open(output_file_name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1)
{
- perror(NULL);
+ perror("main");
return 1;
}
}
/* printf("out: %s\n", output_file_name); */
+ char file_name[PATH_MAX];
char **files = argv + optind;
for (; *files != NULL; files++)
{
/* printf("%s\n", *files); */
- write_file(fd, *files);
+ bzero(file_name, PATH_MAX);
+ strcpy(file_name, *files);
+ file_write(fd, file_name);
}
char buf[512] = {'\0'};
write(fd, buf, 512);