1 #include <errno.h> 2 #include <libgen.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <sys/stat.h> 7 #include <sys/statfs.h> 8 #include <unistd.h> 9 #include <dirent.h> 10 #include <ctype.h> 11 12 #include "applypatch.h" 13 14 static int EliminateOpenFiles(char** files, int file_count) { 15 DIR* d; 16 struct dirent* de; 17 d = opendir("/proc"); 18 if (d == NULL) { 19 printf("error opening /proc: %s\n", strerror(errno)); 20 return -1; 21 } 22 while ((de = readdir(d)) != 0) { 23 int i; 24 for (i = 0; de->d_name[i] != '\0' && isdigit(de->d_name[i]); ++i); 25 if (de->d_name[i]) continue; 26 27 // de->d_name[i] is numeric 28 29 char path[FILENAME_MAX]; 30 strcpy(path, "/proc/"); 31 strcat(path, de->d_name); 32 strcat(path, "/fd/"); 33 34 DIR* fdd; 35 struct dirent* fdde; 36 fdd = opendir(path); 37 if (fdd == NULL) { 38 printf("error opening %s: %s\n", path, strerror(errno)); 39 continue; 40 } 41 while ((fdde = readdir(fdd)) != 0) { 42 char fd_path[FILENAME_MAX]; 43 char link[FILENAME_MAX]; 44 strcpy(fd_path, path); 45 strcat(fd_path, fdde->d_name); 46 47 int count; 48 count = readlink(fd_path, link, sizeof(link)-1); 49 if (count >= 0) { 50 link[count] = '\0'; 51 52 // This is inefficient, but it should only matter if there are 53 // lots of files in /cache, and lots of them are open (neither 54 // of which should be true, especially in recovery). 55 if (strncmp(link, "/cache/", 7) == 0) { 56 int j; 57 for (j = 0; j < file_count; ++j) { 58 if (files[j] && strcmp(files[j], link) == 0) { 59 printf("%s is open by %s\n", link, de->d_name); 60 free(files[j]); 61 files[j] = NULL; 62 } 63 } 64 } 65 } 66 } 67 closedir(fdd); 68 } 69 closedir(d); 70 71 return 0; 72 } 73 74 int FindExpendableFiles(char*** names, int* entries) { 75 DIR* d; 76 struct dirent* de; 77 int size = 32; 78 *entries = 0; 79 *names = malloc(size * sizeof(char*)); 80 81 char path[FILENAME_MAX]; 82 83 // We're allowed to delete unopened regular files in any of these 84 // directories. 85 const char* dirs[2] = {"/cache", "/cache/recovery/otatest"}; 86 87 unsigned int i; 88 for (i = 0; i < sizeof(dirs)/sizeof(dirs[0]); ++i) { 89 d = opendir(dirs[i]); 90 if (d == NULL) { 91 printf("error opening %s: %s\n", dirs[i], strerror(errno)); 92 continue; 93 } 94 95 // Look for regular files in the directory (not in any subdirectories). 96 while ((de = readdir(d)) != 0) { 97 strcpy(path, dirs[i]); 98 strcat(path, "/"); 99 strcat(path, de->d_name); 100 101 // We can't delete CACHE_TEMP_SOURCE; if it's there we might have 102 // restarted during installation and could be depending on it to 103 // be there. 104 if (strcmp(path, CACHE_TEMP_SOURCE) == 0) continue; 105 106 struct stat st; 107 if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) { 108 if (*entries >= size) { 109 size *= 2; 110 *names = realloc(*names, size * sizeof(char*)); 111 } 112 (*names)[(*entries)++] = strdup(path); 113 } 114 } 115 116 closedir(d); 117 } 118 119 printf("%d regular files in deletable directories\n", *entries); 120 121 if (EliminateOpenFiles(*names, *entries) < 0) { 122 return -1; 123 } 124 125 return 0; 126 } 127 128 int MakeFreeSpaceOnCache(size_t bytes_needed) { 129 size_t free_now = FreeSpaceForFile("/cache"); 130 printf("%ld bytes free on /cache (%ld needed)\n", 131 (long)free_now, (long)bytes_needed); 132 133 if (free_now >= bytes_needed) { 134 return 0; 135 } 136 137 char** names; 138 int entries; 139 140 if (FindExpendableFiles(&names, &entries) < 0) { 141 return -1; 142 } 143 144 if (entries == 0) { 145 // nothing we can delete to free up space! 146 printf("no files can be deleted to free space on /cache\n"); 147 return -1; 148 } 149 150 // We could try to be smarter about which files to delete: the 151 // biggest ones? the smallest ones that will free up enough space? 152 // the oldest? the newest? 153 // 154 // Instead, we'll be dumb. 155 156 int i; 157 for (i = 0; i < entries && free_now < bytes_needed; ++i) { 158 if (names[i]) { 159 unlink(names[i]); 160 free_now = FreeSpaceForFile("/cache"); 161 printf("deleted %s; now %ld bytes free\n", names[i], (long)free_now); 162 free(names[i]); 163 } 164 } 165 166 for (; i < entries; ++i) { 167 free(names[i]); 168 } 169 free(names); 170 171 return (free_now >= bytes_needed) ? 0 : -1; 172 } 173