Skip to content

Instantly share code, notes, and snippets.

@cat-in-136
Last active August 18, 2022 11:47
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save cat-in-136/5509961 to your computer and use it in GitHub Desktop.
Save cat-in-136/5509961 to your computer and use it in GitHub Desktop.
Study for reading/writing a tar file using libtar
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <libtar.h>
int main(int argc, char *argv[]) {
TAR *tar = NULL;
int ret = 0;
int exitcode = 0;
if (argc != 2) {
fprintf(stderr, "Usage: %s tarfile.tar\n", argv[0]);
return 1;
}
ret = tar_open(&tar, argv[1], NULL, O_RDONLY, 0, 0);
if (ret != 0) {
fprintf(stderr, "Fail to open file: %s\n", argv[1]);
return 1;
}
while (th_read(tar) == 0) {
char *filename = th_get_pathname(tar);
printf("%s\n", filename);
free(filename);
if (TH_ISREG(tar) && (tar_skip_regfile(tar) != 0)) {
fprintf(stderr, "tar_skip_regfile()\n");
exitcode = 2;
break;
}
}
ret = tar_close(tar);
tar = NULL;
return exitcode;
}
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <libtar.h>
int main(int argc, char *argv[]) {
TAR *tar = NULL;
int ret = 0;
int th_found = 0;
int exitcode = 0;
if (argc != 3) {
fprintf(stderr, "Usage: %s tarfile.tar entry\n", argv[0]);
return 1;
}
ret = tar_open(&tar, argv[1], NULL, O_RDONLY, 0, 0);
if (ret != 0) {
fprintf(stderr, "Fail to open file: %s\n", argv[1]);
return 1;
}
while (th_read(tar) == 0) {
char *filename = th_get_pathname(tar);
if (strcmp(filename, argv[2]) == 0) {
th_found = 1;
free(filename);
break;
}
free(filename);
if (TH_ISREG(tar) && (tar_skip_regfile(tar) != 0)) {
fprintf(stderr, "tar_skip_regfile()\n");
exitcode = 2;
break;
}
}
if (th_found == 1) {
char buf[T_BLOCKSIZE];
const off_t size = th_get_size(tar);
int i;
for (i = size; i > 0; i -= T_BLOCKSIZE) {
int n_buf = tar_block_read(tar, buf);
if (n_buf == EOF) {
break;
}
fwrite(buf, sizeof(char), (n_buf > T_BLOCKSIZE)? T_BLOCKSIZE : n_buf, stdout);
}
} else if (exitcode == 0) {
fprintf(stderr, "entry \"%s\" could not found.\n", argv[2]);
exitcode = 1;
}
ret = tar_close(tar);
tar = NULL;
return 0;
}
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <libtar.h>
int main(int argc, char *argv[]) {
TAR *tar = NULL;
int ret = 0;
int th_found = 0;
int exitcode = 0;
char tmp_filepath[] = P_tmpdir "/tartest-tmpfile-XXXXXX";
int tmp_fd = -1;
if (argc != 3) {
fprintf(stderr, "Usage: %s tarfile.tar entry\n", argv[0]);
fprintf(stderr, " (entry body is captured from STDIN.)\n");
return 1;
}
ret = tar_open(&tar, argv[1], NULL, O_RDONLY, 0, 0);
if (ret != 0) {
fprintf(stderr, "Fail to open file: %s\n", argv[1]);
return 1;
}
while (th_read(tar) == 0) {
char *filename = th_get_pathname(tar);
if (strcmp(filename, argv[2]) == 0) {
th_found = 1;
free(filename);
break;
}
free(filename);
if (TH_ISREG(tar) && (tar_skip_regfile(tar) != 0)) {
fprintf(stderr, "tar_skip_regfile()\n");
exitcode = 2;
break;
}
}
tmp_fd = mkstemp(tmp_filepath);
if (tmp_fd == -1) {
fprintf(stderr, "Failed to build temp file.\n");
exitcode = 2;
}
if (exitcode == 0) {
if (th_found == 1) {
if (tar_extract_regfile(tar, tmp_filepath) != 0) {
char *filename = th_get_pathname(tar);
fprintf(stderr, "Failed to extract \"%s\" to \"%s\"\n", filename, tmp_filepath);
free(filename);
exitcode = 2;
}
}
}
ret = tar_close(tar);
if (ret != 0) {
perror("Failed to close tar file.");
exitcode = 2;
}
tar = NULL;
if (exitcode == 0) {
char buf[BUFSIZ];
ssize_t n_buf = 0;
FILE *tmpfile = NULL;
tmpfile = fdopen(tmp_fd, "w");
if (tmpfile != NULL) {
while ((n_buf = fread(buf, sizeof(char), BUFSIZ, stdin)) != 0) {
fwrite(buf, sizeof(char), (n_buf > BUFSIZ)? BUFSIZ : n_buf, tmpfile);
}
fclose(tmpfile);
tmpfile = NULL;
} else {
perror("Failed to open temp file.");
exitcode = 2;
}
}
if (exitcode == 0) {
// Note: libtar is NOT able to replace a given file from an archive.
// So, we use GNU tar(1) command!
const char TAR_PROG_NAME[] = "gtar"; // GNU tar. (may be tar).
char cmdl[BUFSIZ];
// TODO multiple file is appended when the file is already exists in the tar file.
sprintf(cmdl, "%s -uf '%s' --xform='s|%s|%s|' -- '%s' > /dev/null 2> /dev/null",
TAR_PROG_NAME,
argv[1], // tar file
tmp_filepath+1, // --xform
argv[2], // --xform (replacement)
tmp_filepath);
// printf("%s\n", cmdl);
// TODO do not use system() and use fork() and execve(). (Secure Coding - ENV04-C)
system(cmdl);
}
if (tmp_fd != -1) {
if (remove(tmp_filepath) == -1) {
fprintf(stderr, "Failed to remove a temp file \"%s\".\n", tmp_filepath);
exitcode = 2;
}
tmp_fd = -1;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment