- Move applypatch to this package (from build).
- Add a rudimentary type system to edify:  instead of just returning a
  char*, functions now return a Value*, which is a struct that can
  carry different types of value (currently just STRING and BLOB).
  Convert all functions to this new scheme.
- Change the one-argument form of package_extract_file to return a
  Value of the new BLOB type.
- Add read_file() to load a local file and return a blob, and
  sha1_check() to test a blob (or string) against a set of possible
  sha1s.  read_file() uses the file-loading code from applypatch so it
  can read MTD partitions as well.
This is the start of better integration between applypatch and the
rest of edify.
b/2361316 - VZW Issue PP628: Continuous reset to Droid logo:
            framework-res.apk update failed (CR LIBtt59130)
Change-Id: Ibd038074749a4d515de1f115c498c6c589ee91e5
		
	
		
			
				
	
	
		
			173 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include <errno.h>
 | 
						|
#include <libgen.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <sys/statfs.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <dirent.h>
 | 
						|
#include <ctype.h>
 | 
						|
 | 
						|
#include "applypatch.h"
 | 
						|
 | 
						|
static int EliminateOpenFiles(char** files, int file_count) {
 | 
						|
  DIR* d;
 | 
						|
  struct dirent* de;
 | 
						|
  d = opendir("/proc");
 | 
						|
  if (d == NULL) {
 | 
						|
    printf("error opening /proc: %s\n", strerror(errno));
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
  while ((de = readdir(d)) != 0) {
 | 
						|
    int i;
 | 
						|
    for (i = 0; de->d_name[i] != '\0' && isdigit(de->d_name[i]); ++i);
 | 
						|
    if (de->d_name[i]) continue;
 | 
						|
 | 
						|
    // de->d_name[i] is numeric
 | 
						|
 | 
						|
    char path[FILENAME_MAX];
 | 
						|
    strcpy(path, "/proc/");
 | 
						|
    strcat(path, de->d_name);
 | 
						|
    strcat(path, "/fd/");
 | 
						|
 | 
						|
    DIR* fdd;
 | 
						|
    struct dirent* fdde;
 | 
						|
    fdd = opendir(path);
 | 
						|
    if (fdd == NULL) {
 | 
						|
      printf("error opening %s: %s\n", path, strerror(errno));
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    while ((fdde = readdir(fdd)) != 0) {
 | 
						|
      char fd_path[FILENAME_MAX];
 | 
						|
      char link[FILENAME_MAX];
 | 
						|
      strcpy(fd_path, path);
 | 
						|
      strcat(fd_path, fdde->d_name);
 | 
						|
 | 
						|
      int count;
 | 
						|
      count = readlink(fd_path, link, sizeof(link)-1);
 | 
						|
      if (count >= 0) {
 | 
						|
        link[count] = '\0';
 | 
						|
 | 
						|
        // This is inefficient, but it should only matter if there are
 | 
						|
        // lots of files in /cache, and lots of them are open (neither
 | 
						|
        // of which should be true, especially in recovery).
 | 
						|
        if (strncmp(link, "/cache/", 7) == 0) {
 | 
						|
          int j;
 | 
						|
          for (j = 0; j < file_count; ++j) {
 | 
						|
            if (files[j] && strcmp(files[j], link) == 0) {
 | 
						|
              printf("%s is open by %s\n", link, de->d_name);
 | 
						|
              free(files[j]);
 | 
						|
              files[j] = NULL;
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    closedir(fdd);
 | 
						|
  }
 | 
						|
  closedir(d);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int FindExpendableFiles(char*** names, int* entries) {
 | 
						|
  DIR* d;
 | 
						|
  struct dirent* de;
 | 
						|
  int size = 32;
 | 
						|
  *entries = 0;
 | 
						|
  *names = malloc(size * sizeof(char*));
 | 
						|
 | 
						|
  char path[FILENAME_MAX];
 | 
						|
 | 
						|
  // We're allowed to delete unopened regular files in any of these
 | 
						|
  // directories.
 | 
						|
  const char* dirs[2] = {"/cache", "/cache/recovery/otatest"};
 | 
						|
 | 
						|
  unsigned int i;
 | 
						|
  for (i = 0; i < sizeof(dirs)/sizeof(dirs[0]); ++i) {
 | 
						|
    d = opendir(dirs[i]);
 | 
						|
    if (d == NULL) {
 | 
						|
      printf("error opening %s: %s\n", dirs[i], strerror(errno));
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    // Look for regular files in the directory (not in any subdirectories).
 | 
						|
    while ((de = readdir(d)) != 0) {
 | 
						|
      strcpy(path, dirs[i]);
 | 
						|
      strcat(path, "/");
 | 
						|
      strcat(path, de->d_name);
 | 
						|
 | 
						|
      // We can't delete CACHE_TEMP_SOURCE; if it's there we might have
 | 
						|
      // restarted during installation and could be depending on it to
 | 
						|
      // be there.
 | 
						|
      if (strcmp(path, CACHE_TEMP_SOURCE) == 0) continue;
 | 
						|
 | 
						|
      struct stat st;
 | 
						|
      if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
 | 
						|
        if (*entries >= size) {
 | 
						|
          size *= 2;
 | 
						|
          *names = realloc(*names, size * sizeof(char*));
 | 
						|
        }
 | 
						|
        (*names)[(*entries)++] = strdup(path);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    closedir(d);
 | 
						|
  }
 | 
						|
 | 
						|
  printf("%d regular files in deletable directories\n", *entries);
 | 
						|
 | 
						|
  if (EliminateOpenFiles(*names, *entries) < 0) {
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int MakeFreeSpaceOnCache(size_t bytes_needed) {
 | 
						|
  size_t free_now = FreeSpaceForFile("/cache");
 | 
						|
  printf("%ld bytes free on /cache (%ld needed)\n",
 | 
						|
         (long)free_now, (long)bytes_needed);
 | 
						|
 | 
						|
  if (free_now >= bytes_needed) {
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  char** names;
 | 
						|
  int entries;
 | 
						|
 | 
						|
  if (FindExpendableFiles(&names, &entries) < 0) {
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  if (entries == 0) {
 | 
						|
    // nothing we can delete to free up space!
 | 
						|
    printf("no files can be deleted to free space on /cache\n");
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  // We could try to be smarter about which files to delete:  the
 | 
						|
  // biggest ones?  the smallest ones that will free up enough space?
 | 
						|
  // the oldest?  the newest?
 | 
						|
  //
 | 
						|
  // Instead, we'll be dumb.
 | 
						|
 | 
						|
  int i;
 | 
						|
  for (i = 0; i < entries && free_now < bytes_needed; ++i) {
 | 
						|
    if (names[i]) {
 | 
						|
      unlink(names[i]);
 | 
						|
      free_now = FreeSpaceForFile("/cache");
 | 
						|
      printf("deleted %s; now %ld bytes free\n", names[i], (long)free_now);
 | 
						|
      free(names[i]);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  for (; i < entries; ++i) {
 | 
						|
    free(names[i]);
 | 
						|
  }
 | 
						|
  free(names);
 | 
						|
 | 
						|
  return (free_now >= bytes_needed) ? 0 : -1;
 | 
						|
}
 |