• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
EliminateOpenFiles(char ** files,int file_count)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 
FindExpendableFiles(char *** names,int * entries)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 
MakeFreeSpaceOnCache(size_t bytes_needed)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