1#include <ctype.h> 2#include <dirent.h> 3#include <errno.h> 4#include <stdlib.h> 5#include <stdio.h> 6#include <string.h> 7#include <sys/stat.h> 8#include <unistd.h> 9 10#include "srm.h" 11#include "config.h" 12 13int empty_directory(const char *path) { 14 DIR *dp; 15 struct dirent *de; 16 17 dp = opendir(path); 18 if (dp == NULL) { 19 return -1; 20 } 21 while ((de = readdir(dp)) != NULL) { 22 if (de->d_namlen < 3 && (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))) { 23 continue; 24 } 25 (void)closedir(dp); 26 return -1; 27 } 28 (void)closedir(dp); 29 return 0; 30} 31 32int rename_unlink(const char *path) { 33 char *new_name, *p, c; 34 struct stat statbuf; 35 size_t new_name_size = strlen(path) + 15; 36 int i = 0; 37 38 if ( (new_name = (char *)alloca(new_name_size)) == NULL ) { 39 errno = ENOMEM; 40 return -1; 41 } 42 43 strncpy(new_name, path, new_name_size); 44 45 if ( (p = strrchr(new_name, '/')) != NULL ) { 46 p++; 47 *p = '\0'; 48 } else { 49 p = new_name; 50 } 51 52 do { 53 i = 0; 54 55 while (i < 14) { 56 c = random_char(); 57 if (isalnum((int) c)) { 58 p[i] = c; 59 i++; 60 } 61 } 62 p[i] = '\0'; 63 } while (lstat(new_name, &statbuf) == 0); 64 65 if (lstat(path, &statbuf) == -1) 66 return -1; 67 68 if (S_ISDIR(statbuf.st_mode) && (empty_directory(path) == -1)) { 69 /* Directory isn't empty (e.g. because it contains an immutable file). 70 Attempting to remove it will fail, so avoid renaming it. */ 71 errno = ENOTEMPTY; 72 return -1; 73 } 74 75 if (rename(path, new_name) == -1) 76 return -1; 77 78 sync(); 79 80 if (lstat(new_name, &statbuf) == -1) { 81 /* Bad mojo, we just renamed to new_name and now the path is invalid. 82 Die ungracefully and exit before anything worse happens. */ 83 perror("Fatal error in rename_unlink()"); 84 exit(EXIT_FAILURE); 85 } 86 87 if (S_ISDIR(statbuf.st_mode)) 88 return rmdir(new_name); 89 90 return unlink(new_name); 91} 92