Last active
August 19, 2022 13:47
-
-
Save supechicken/030a621da06e97272befdc7090bf68f5 to your computer and use it in GitHub Desktop.
A simple C program that adds remove-on-copy support to "tar c | tar x" command
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
remove_on_copy.c: Remove each file listed in tar archive once they sent to stdout | |
Usage: | |
stdin: Tar archive (only ustar format is supported) created by tar -c | |
stdout: Tar extract command (tar -x) | |
Option: | |
-v Enable verbose output | |
Example usage: | |
tar -c . | ./remove_on_copy | tar -xp -C / | |
# equivalent to: | |
# rsync --remove-source-files . / | |
This file can be built with: | |
gcc remove_on_copy.c -lm -o remove_on_copy | |
*/ | |
#include <stdbool.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <math.h> | |
bool verbose = false; | |
int main (int argc, char * argv[]) { | |
int exitstatus = 0; | |
if ( argc > 1 && strcmp(argv[1], "-v") == 0 ) verbose = true; | |
// process each file in archive | |
while (true) { | |
char name[100], octal_size[12], type[1]; | |
// filename (first 100 byte) | |
{ | |
read(STDIN_FILENO, name, 100); | |
if (name[0] == '\0') { | |
// exit if filename is empty (extra empty blocks created by tar) | |
break; | |
} else { | |
// write it back to stdout | |
write(STDOUT_FILENO, name, 100); | |
} | |
} | |
// metadata between filename and file size (24 bytes) | |
{ | |
// read it from stdin and pass it to stdout | |
char buf[24]; | |
read(STDIN_FILENO, buf, 24); | |
write(STDOUT_FILENO, buf, 24); | |
} | |
// file size in octal (12 bytes) | |
{ | |
read(STDIN_FILENO, octal_size, 12); | |
write(STDOUT_FILENO, octal_size, 12); | |
} | |
// metadata between file size and type flag (20 bytes) | |
{ | |
char buf[20]; | |
read(STDIN_FILENO, buf, 20); | |
write(STDOUT_FILENO, buf, 20); | |
} | |
// type flag (1 byte) | |
{ | |
read(STDIN_FILENO, type, 1); | |
write(STDOUT_FILENO, type, 1); | |
} | |
// remaining metadata (355 bytes) | |
{ | |
char buf[355]; | |
read(STDIN_FILENO, buf, 355); | |
write(STDOUT_FILENO, buf, 355); | |
} | |
// 100 + 24 + 12 + 20 + 1 + 355 = 512, end of file meta | |
// calculate number of blocks taken by the file, write all blocks | |
// to stdout (contain contents of the file) | |
int size = strtol(octal_size, NULL, 8), | |
block = ceil(size / 512.0); | |
//if (verbose == true) fprintf(stderr, "[tar_remove_on_copy]: \e[0;33mname: %s, type: %c, size: %dB\e[0m\n", name, type[0], size); | |
for (int i=0; i < block; i++) { | |
// each block takes 512 bytes | |
char buf[512]; | |
read(STDIN_FILENO, buf, 512); | |
write(STDOUT_FILENO, buf, 512); | |
} | |
// ignore directory, remove file only | |
if (type[0] != '5') { | |
// remove the file | |
if ( remove(name) == 0 ) { | |
if (verbose == true) fprintf(stderr, "[tar_remove_on_copy]: \e[1;32mFile removed: %s\e[0m\n", name); | |
} else { | |
fprintf(stderr, "[tar_remove_on_copy]: \e[1;31m%s%s\e[0m\n", "Failed to remove file: ", name); | |
exitstatus = 1; | |
} | |
} | |
fflush(stderr); | |
} | |
return exitstatus; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment