Home | History | Annotate | Download | only in applypatch
      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