/*
Trash restore
Here's a program to restore files which were put in the trash by yesterday's program. Today, I gave up on sbrk
and I'm just gonna assume the length of the path is less than 16384.
Today's procedure is strlen
.
*/
#include "procs-2019-10-04.c"
#include
#include
int main(int argc, char **argv) {
extern char *getenv(const char *name);
extern int rename(const char *oldpath, const char *newpath);
const char *err;
char *home = getenv("HOME");
char *pwd = getenv("PWD");
int a;
if (!home || !pwd) {
err = "Could not get $HOME or $PWD.\n";
write(stderr, err, (size_t)strlen(err));
return exitfailure;
}
if (argc < 2) {
err = "Please specify a file.\n";
write(stderr, err, (size_t)strlen(err));
return exitfailure;
}
for (a = 1; a < argc; a++) {
long i;
char *p, *lastslash = NULL;
char *basename;
static char trashname[16384];
for (p = argv[a]; *p; p++)
if (*p == '/')
lastslash = p;
if (lastslash) {
if (lastslash[1] == 0) {
/* e.g. foo/bar/ => bar */
if (argv[a] == lastslash) {
err = "Cannot restore /.\n";
write(stderr, err, (size_t)strlen(err));
return exitfailure;
}
*lastslash = 0; /* get rid of trailing / */
do lastslash--;
while (lastslash > argv[a] && *lastslash != '/');
if (*lastslash == '/') {
/* e.g. /foo/bar/ */
basename = lastslash + 1;
} else {
/* e.g. foo/ */
basename = lastslash;
}
} else {
/* e.g. foo/bar */
basename = lastslash + 1;
}
} else {
/* e.g. foo */
basename = argv[a];
}
p = trashname;
for (i = 0; home[i]; i++)
*p++ = home[i];
for (i = 0; i < strlen("/.trash/"); i++)
*p++ = "/.trash/"[i];
for (i = 0; i < strlen(basename); i++)
*p++ = basename[i];
*p = 0;
{
/* find correct trashed file */
long id = 0;
static char whencename[16384];
char *trashend = trashname + strlen(trashname);
int filewithnameintrash = false;
while (1) {
struct stat st;
if (stat(trashname, &st) == 0) {
/* check whence */
int whenced;
static char whence[16384]; /* should be long enough for a path... */
static char hence[16384];
int henceiswhence;
ssize_t bytesread;
p = whencename;
for (i = 0; trashname[i]; i++) {
*p++ = trashname[i];
}
*p++ = '-';
*p++ = 'w';
*p++ = 'h';
*p++ = 'e';
*p++ = 'n';
*p++ = 'c';
*p++ = 'e';
*p = 0;
whenced = open(whencename, O_RDONLY);
bytesread = read(whenced, whence, sizeof whence);
if (bytesread < 0) {
err = "An error occured while reading the whence file for ";
close(whenced);
write(stderr, err, (size_t)strlen(err));
write(stderr, argv[a], (size_t)strlen(argv[a]));
write(stderr, "\n", 1);
return exitfailure;
}
if (bytesread == sizeof whence) {
err = "The path is too long for ";
close(whenced);
write(stderr, err, (size_t)strlen(err));
write(stderr, argv[a], (size_t)strlen(argv[a]));
write(stderr, "\n", 1);
return exitfailure;
}
close(whenced);
whence[bytesread] = 0;
p = hence;
if (argv[a][0] != '/') {
/* pwd/ */
for (i = 0; pwd[i]; i++)
*p++ = pwd[i];
*p++ = '/';
}
for (i = 0; argv[a][i]; i++)
*p++ = argv[a][i];
henceiswhence = 1;
if (whence[0]) filewithnameintrash = true;
for (i = 0; i == 0 || hence[i-1]; i++) {
if (hence[i] != whence[i]) {
henceiswhence = 0;
break;
}
}
if (henceiswhence) {
break;
} else {
id++;
ltoa(id, trashend);
}
} else {
err = "Could not find trashed file: ";
write(stderr, err, (size_t)strlen(err));
write(stderr, argv[a], (size_t)strlen(argv[a]));
write(stderr, "\n", 1);
if (filewithnameintrash) {
err = "There are files by that name in the trash, but not from here.\n";
write(stderr, err, (size_t)strlen(err));
}
return exitfailure;
}
}
rename(trashname, argv[a]);
{
int blank;
if ((blank = creat(trashname, 0666)) == -1) {
err = "Could not create blank file.\n";
write(stderr, err, (size_t)strlen(err));
return exitfailure;
}
close(blank);
if ((blank = creat(whencename, 0666)) == -1) {
err = "Could not create blank file.\n";
write(stderr, err, (size_t)strlen(err));
return exitfailure;
}
close(blank);
}
}
}
return 0;
}