Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ca78c9f0 authored by Yabin Cui's avatar Yabin Cui
Browse files

resolve merge conflicts of 715d8a20 to master.

Change-Id: Ic868ee9b27ef7251aa49ac814de7355ecd9c7d37
parents e284cd58 715d8a20
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -55,7 +55,9 @@ LOCAL_CLANG := true
LOCAL_SRC_FILES := main.cpp
LOCAL_MODULE := applypatch
LOCAL_C_INCLUDES += bootable/recovery
LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libmtdutils libcrypto_static libbz
LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libmtdutils libcrypto_static libbz \
                          libedify \

LOCAL_SHARED_LIBRARIES += libz libcutils libc

include $(BUILD_EXECUTABLE)
+83 −96
Original line number Diff line number Diff line
@@ -25,6 +25,9 @@
#include <sys/types.h>
#include <unistd.h>

#include <memory>
#include <string>

#include <android-base/strings.h>

#include "openssl/sha.h"
@@ -68,25 +71,29 @@ int LoadFileContents(const char* filename, FileContents* file) {
    }

    file->size = file->st.st_size;
    file->data = reinterpret_cast<unsigned char*>(malloc(file->size));
    file->data = nullptr;

    std::unique_ptr<unsigned char, decltype(&free)> data(
            static_cast<unsigned char*>(malloc(file->size)), free);
    if (data == nullptr) {
        printf("failed to allocate memory: %s\n", strerror(errno));
        return -1;
    }

    FILE* f = ota_fopen(filename, "rb");
    if (f == NULL) {
        printf("failed to open \"%s\": %s\n", filename, strerror(errno));
        free(file->data);
        file->data = NULL;
        return -1;
    }

    size_t bytes_read = ota_fread(file->data, 1, file->size, f);
    size_t bytes_read = ota_fread(data.get(), 1, file->size, f);
    if (bytes_read != static_cast<size_t>(file->size)) {
        printf("short read of \"%s\" (%zu bytes of %zd)\n", filename, bytes_read, file->size);
        free(file->data);
        file->data = NULL;
        fclose(f);
        return -1;
    }
    ota_fclose(f);

    file->data = data.release();
    SHA1(file->data, file->size, file->sha1);
    return 0;
}
@@ -186,7 +193,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
    uint8_t parsed_sha[SHA_DIGEST_LENGTH];

    // Allocate enough memory to hold the largest size.
    file->data = reinterpret_cast<unsigned char*>(malloc(size[index[pairs-1]]));
    file->data = static_cast<unsigned char*>(malloc(size[index[pairs-1]]));
    char* p = (char*)file->data;
    file->size = 0;                // # bytes read so far
    bool found = false;
@@ -314,7 +321,7 @@ int SaveFileContents(const char* filename, const FileContents* file) {
// "MTD:<partition>[:...]" or "EMMC:<partition_device>[:...]". The target name
// might contain multiple colons, but WriteToPartition() only uses the first
// two and ignores the rest. Return 0 on success.
int WriteToPartition(unsigned char* data, size_t len, const char* target) {
int WriteToPartition(const unsigned char* data, size_t len, const char* target) {
    std::string copy(target);
    std::vector<std::string> pieces = android::base::Split(copy, ":");

@@ -353,7 +360,7 @@ int WriteToPartition(unsigned char* data, size_t len, const char* target) {
                return -1;
            }

            size_t written = mtd_write_data(ctx, reinterpret_cast<char*>(data), len);
            size_t written = mtd_write_data(ctx, reinterpret_cast<const char*>(data), len);
            if (written != len) {
                printf("only wrote %zu of %zu bytes to MTD %s\n", written, len, partition);
                mtd_write_close(ctx);
@@ -579,7 +586,7 @@ int ShowLicenses() {
}

ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) {
    int fd = *reinterpret_cast<int *>(token);
    int fd = *static_cast<int*>(token);
    ssize_t done = 0;
    ssize_t wrote;
    while (done < len) {
@@ -593,19 +600,9 @@ ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) {
    return done;
}

typedef struct {
    unsigned char* buffer;
    ssize_t size;
    ssize_t pos;
} MemorySinkInfo;

ssize_t MemorySink(const unsigned char* data, ssize_t len, void* token) {
    MemorySinkInfo* msi = reinterpret_cast<MemorySinkInfo*>(token);
    if (msi->size - msi->pos < len) {
        return -1;
    }
    memcpy(msi->buffer + msi->pos, data, len);
    msi->pos += len;
    std::string* s = static_cast<std::string*>(token);
    s->append(reinterpret_cast<const char*>(data), len);
    return len;
}

@@ -816,31 +813,52 @@ static int GenerateTarget(FileContents* source_file,
                          const Value* bonus_data) {
    int retry = 1;
    SHA_CTX ctx;
    int output;
    MemorySinkInfo msi;
    std::string memory_sink_str;
    FileContents* source_to_use;
    char* outname;
    int made_copy = 0;

    bool target_is_partition = (strncmp(target_filename, "MTD:", 4) == 0 ||
                                strncmp(target_filename, "EMMC:", 5) == 0);
    const std::string tmp_target_filename = std::string(target_filename) + ".patch";

    // assume that target_filename (eg "/system/app/Foo.apk") is located
    // on the same filesystem as its top-level directory ("/system").
    // We need something that exists for calling statfs().
    char target_fs[strlen(target_filename)+1];
    char* slash = strchr(target_filename+1, '/');
    if (slash != NULL) {
        int count = slash - target_filename;
        strncpy(target_fs, target_filename, count);
        target_fs[count] = '\0';
    std::string target_fs = target_filename;
    auto slash_pos = target_fs.find('/', 1);
    if (slash_pos != std::string::npos) {
        target_fs.resize(slash_pos);
    }

    const Value* patch;
    if (source_patch_value != NULL) {
        source_to_use = source_file;
        patch = source_patch_value;
    } else {
        strcpy(target_fs, target_filename);
        source_to_use = copy_file;
        patch = copy_patch_value;
    }
    if (patch->type != VAL_BLOB) {
        printf("patch is not a blob\n");
        return 1;
    }
    char* header = patch->data;
    ssize_t header_bytes_read = patch->size;
    bool use_bsdiff = false;
    if (header_bytes_read >= 8 && memcmp(header, "BSDIFF40", 8) == 0) {
        use_bsdiff = true;
    } else if (header_bytes_read >= 8 && memcmp(header, "IMGDIFF2", 8) == 0) {
        use_bsdiff = false;
    } else {
        printf("Unknown patch file format\n");
        return 1;
    }

    do {
        // Is there enough room in the target filesystem to hold the patched
        // file?

        if (strncmp(target_filename, "MTD:", 4) == 0 ||
            strncmp(target_filename, "EMMC:", 5) == 0) {
        if (target_is_partition) {
            // If the target is a partition, we're actually going to
            // write the output to /tmp and then copy it to the
            // partition.  statfs() always returns 0 blocks free for
@@ -862,7 +880,7 @@ static int GenerateTarget(FileContents* source_file,
        } else {
            int enough_space = 0;
            if (retry > 0) {
                size_t free_space = FreeSpaceForFile(target_fs);
                size_t free_space = FreeSpaceForFile(target_fs.c_str());
                enough_space =
                    (free_space > (256 << 10)) &&          // 256k (two-block) minimum
                    (free_space > (target_size * 3 / 2));  // 50% margin of error
@@ -902,84 +920,53 @@ static int GenerateTarget(FileContents* source_file,
                made_copy = 1;
                unlink(source_filename);

                size_t free_space = FreeSpaceForFile(target_fs);
                size_t free_space = FreeSpaceForFile(target_fs.c_str());
                printf("(now %zu bytes free for target) ", free_space);
            }
        }

        const Value* patch;
        if (source_patch_value != NULL) {
            source_to_use = source_file;
            patch = source_patch_value;
        } else {
            source_to_use = copy_file;
            patch = copy_patch_value;
        }

        if (patch->type != VAL_BLOB) {
            printf("patch is not a blob\n");
            return 1;
        }

        SinkFn sink = NULL;
        void* token = NULL;
        output = -1;
        outname = NULL;
        if (strncmp(target_filename, "MTD:", 4) == 0 ||
            strncmp(target_filename, "EMMC:", 5) == 0) {
        int output_fd = -1;
        if (target_is_partition) {
            // We store the decoded output in memory.
            msi.buffer = reinterpret_cast<unsigned char*>(malloc(target_size));
            if (msi.buffer == NULL) {
                printf("failed to alloc %zu bytes for output\n", target_size);
                return 1;
            }
            msi.pos = 0;
            msi.size = target_size;
            sink = MemorySink;
            token = &msi;
            token = &memory_sink_str;
        } else {
            // We write the decoded output to "<tgt-file>.patch".
            outname = reinterpret_cast<char*>(malloc(strlen(target_filename) + 10));
            strcpy(outname, target_filename);
            strcat(outname, ".patch");

            output = ota_open(outname, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR | S_IWUSR);
            if (output < 0) {
                printf("failed to open output file %s: %s\n",
                       outname, strerror(errno));
            output_fd = ota_open(tmp_target_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_SYNC,
                          S_IRUSR | S_IWUSR);
            if (output_fd < 0) {
                printf("failed to open output file %s: %s\n", tmp_target_filename.c_str(),
                       strerror(errno));
                return 1;
            }
            sink = FileSink;
            token = &output;
            token = &output_fd;
        }

        char* header = patch->data;
        ssize_t header_bytes_read = patch->size;

        SHA1_Init(&ctx);

        int result;

        if (header_bytes_read >= 8 &&
            memcmp(header, "BSDIFF40", 8) == 0) {
        if (use_bsdiff) {
            result = ApplyBSDiffPatch(source_to_use->data, source_to_use->size,
                                      patch, 0, sink, token, &ctx);
        } else if (header_bytes_read >= 8 &&
                   memcmp(header, "IMGDIFF2", 8) == 0) {
        } else {
            result = ApplyImagePatch(source_to_use->data, source_to_use->size,
                                     patch, sink, token, &ctx, bonus_data);
        } else {
            printf("Unknown patch file format\n");
            return 1;
        }

        if (output >= 0) {
            if (ota_fsync(output) != 0) {
                printf("failed to fsync file \"%s\" (%s)\n", outname, strerror(errno));
        if (!target_is_partition) {
            if (ota_fsync(output_fd) != 0) {
                printf("failed to fsync file \"%s\" (%s)\n", tmp_target_filename.c_str(),
                       strerror(errno));
                result = 1;
            }
            if (ota_close(output) != 0) {
                printf("failed to close file \"%s\" (%s)\n", outname, strerror(errno));
            if (ota_close(output_fd) != 0) {
                printf("failed to close file \"%s\" (%s)\n", tmp_target_filename.c_str(),
                       strerror(errno));
                result = 1;
            }
        }
@@ -991,8 +978,8 @@ static int GenerateTarget(FileContents* source_file,
            } else {
                printf("applying patch failed; retrying\n");
            }
            if (outname != NULL) {
                unlink(outname);
            if (!target_is_partition) {
                unlink(tmp_target_filename.c_str());
            }
        } else {
            // succeeded; no need to retry
@@ -1009,27 +996,27 @@ static int GenerateTarget(FileContents* source_file,
        printf("now %s\n", short_sha1(target_sha1).c_str());
    }

    if (output < 0) {
    if (target_is_partition) {
        // Copy the temp file to the partition.
        if (WriteToPartition(msi.buffer, msi.pos, target_filename) != 0) {
        if (WriteToPartition(reinterpret_cast<const unsigned char*>(memory_sink_str.c_str()),
                             memory_sink_str.size(), target_filename) != 0) {
            printf("write of patched data to %s failed\n", target_filename);
            return 1;
        }
        free(msi.buffer);
    } else {
        // Give the .patch file the same owner, group, and mode of the
        // original source file.
        if (chmod(outname, source_to_use->st.st_mode) != 0) {
            printf("chmod of \"%s\" failed: %s\n", outname, strerror(errno));
        if (chmod(tmp_target_filename.c_str(), source_to_use->st.st_mode) != 0) {
            printf("chmod of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno));
            return 1;
        }
        if (chown(outname, source_to_use->st.st_uid, source_to_use->st.st_gid) != 0) {
            printf("chown of \"%s\" failed: %s\n", outname, strerror(errno));
        if (chown(tmp_target_filename.c_str(), source_to_use->st.st_uid, source_to_use->st.st_gid) != 0) {
            printf("chown of \"%s\" failed: %s\n", tmp_target_filename.c_str(), strerror(errno));
            return 1;
        }

        // Finally, rename the .patch file to replace the target file.
        if (rename(outname, target_filename) != 0) {
        if (rename(tmp_target_filename.c_str(), target_filename) != 0) {
            printf("rename of .patch to \"%s\" failed: %s\n", target_filename, strerror(errno));
            return 1;
        }
+7 −4
Original line number Diff line number Diff line
@@ -18,6 +18,9 @@
#define _APPLYPATCH_H

#include <sys/stat.h>

#include <vector>

#include "openssl/sha.h"
#include "edify/expr.h"

@@ -68,22 +71,22 @@ void FreeFileContents(FileContents* file);
int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str,
                      int num_patches);

// bsdiff.c
// bsdiff.cpp
void ShowBSDiffLicense();
int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
                     const Value* patch, ssize_t patch_offset,
                     SinkFn sink, void* token, SHA_CTX* ctx);
int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
                        const Value* patch, ssize_t patch_offset,
                        unsigned char** new_data, ssize_t* new_size);
                        std::vector<unsigned char>* new_data);

// imgpatch.c
// imgpatch.cpp
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
                    const Value* patch,
                    SinkFn sink, void* token, SHA_CTX* ctx,
                    const Value* bonus_data);

// freecache.c
// freecache.cpp
int MakeFreeSpaceOnCache(size_t bytes_needed);

#endif
+14 −23
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <malloc.h>
#include <unistd.h>
#include <string.h>

@@ -103,26 +102,22 @@ int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
                     const Value* patch, ssize_t patch_offset,
                     SinkFn sink, void* token, SHA_CTX* ctx) {

    unsigned char* new_data;
    ssize_t new_size;
    if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset,
                            &new_data, &new_size) != 0) {
    std::vector<unsigned char> new_data;
    if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset, &new_data) != 0) {
        return -1;
    }

    if (sink(new_data, new_size, token) < new_size) {
    if (sink(new_data.data(), new_data.size(), token) < static_cast<ssize_t>(new_data.size())) {
        printf("short write of output: %d (%s)\n", errno, strerror(errno));
        return 1;
    }
    if (ctx) SHA1_Update(ctx, new_data, new_size);
    free(new_data);

    if (ctx) SHA1_Update(ctx, new_data.data(), new_data.size());
    return 0;
}

int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
                        const Value* patch, ssize_t patch_offset,
                        unsigned char** new_data, ssize_t* new_size) {
                        std::vector<unsigned char>* new_data) {
    // Patch data format:
    //   0       8       "BSDIFF40"
    //   8       8       X
@@ -141,12 +136,12 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
        return 1;
    }

    ssize_t ctrl_len, data_len;
    ssize_t ctrl_len, data_len, new_size;
    ctrl_len = offtin(header+8);
    data_len = offtin(header+16);
    *new_size = offtin(header+24);
    new_size = offtin(header+24);

    if (ctrl_len < 0 || data_len < 0 || *new_size < 0) {
    if (ctrl_len < 0 || data_len < 0 || new_size < 0) {
        printf("corrupt patch file header (data lengths)\n");
        return 1;
    }
@@ -183,18 +178,14 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
        printf("failed to bzinit extra stream (%d)\n", bzerr);
    }

    *new_data = reinterpret_cast<unsigned char*>(malloc(*new_size));
    if (*new_data == NULL) {
        printf("failed to allocate %zd bytes of memory for output file\n", *new_size);
        return 1;
    }
    new_data->resize(new_size);

    off_t oldpos = 0, newpos = 0;
    off_t ctrl[3];
    off_t len_read;
    int i;
    unsigned char buf[24];
    while (newpos < *new_size) {
    while (newpos < new_size) {
        // Read control data
        if (FillBuffer(buf, 24, &cstream) != 0) {
            printf("error while reading control stream\n");
@@ -210,13 +201,13 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
        }

        // Sanity check
        if (newpos + ctrl[0] > *new_size) {
        if (newpos + ctrl[0] > new_size) {
            printf("corrupt patch (new file overrun)\n");
            return 1;
        }

        // Read diff string
        if (FillBuffer(*new_data + newpos, ctrl[0], &dstream) != 0) {
        if (FillBuffer(new_data->data() + newpos, ctrl[0], &dstream) != 0) {
            printf("error while reading diff stream\n");
            return 1;
        }
@@ -233,13 +224,13 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
        oldpos += ctrl[0];

        // Sanity check
        if (newpos + ctrl[1] > *new_size) {
        if (newpos + ctrl[1] > new_size) {
            printf("corrupt patch (new file overrun)\n");
            return 1;
        }

        // Read extra string
        if (FillBuffer(*new_data + newpos, ctrl[1], &estream) != 0) {
        if (FillBuffer(new_data->data() + newpos, ctrl[1], &estream) != 0) {
            printf("error while reading extra stream\n");
            return 1;
        }
+49 −92
Original line number Diff line number Diff line
@@ -25,119 +25,90 @@
#include <dirent.h>
#include <ctype.h>

#include <memory>
#include <set>
#include <string>

#include <android-base/parseint.h>
#include <android-base/stringprintf.h>

#include "applypatch.h"

static int EliminateOpenFiles(char** files, int file_count) {
  DIR* d;
  struct dirent* de;
  d = opendir("/proc");
  if (d == NULL) {
static int EliminateOpenFiles(std::set<std::string>* files) {
  std::unique_ptr<DIR, decltype(&closedir)> d(opendir("/proc"), closedir);
  if (!d) {
    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/");
  struct dirent* de;
  while ((de = readdir(d.get())) != 0) {
    unsigned int pid;
    if (!android::base::ParseUint(de->d_name, &pid)) {
        continue;
    }
    std::string path = android::base::StringPrintf("/proc/%s/fd/", de->d_name);

    DIR* fdd;
    struct dirent* fdde;
    fdd = opendir(path);
    if (fdd == NULL) {
      printf("error opening %s: %s\n", path, strerror(errno));
    std::unique_ptr<DIR, decltype(&closedir)> fdd(opendir(path.c_str()), closedir);
    if (!fdd) {
      printf("error opening %s: %s\n", path.c_str(), strerror(errno));
      continue;
    }
    while ((fdde = readdir(fdd)) != 0) {
      char fd_path[FILENAME_MAX];
    while ((fdde = readdir(fdd.get())) != 0) {
      std::string fd_path = path + fdde->d_name;
      char link[FILENAME_MAX];
      strcpy(fd_path, path);
      strcat(fd_path, fdde->d_name);

      int count;
      count = readlink(fd_path, link, sizeof(link)-1);
      int count = readlink(fd_path.c_str(), 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) {
          if (files->erase(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 = reinterpret_cast<char**>(malloc(size * sizeof(char*)));

  char path[FILENAME_MAX];

static std::set<std::string> FindExpendableFiles() {
  std::set<std::string> files;
  // We're allowed to delete unopened regular files in any of these
  // directories.
  const char* dirs[2] = {"/cache", "/cache/recovery/otatest"};

  for (size_t i = 0; i < sizeof(dirs)/sizeof(dirs[0]); ++i) {
    d = opendir(dirs[i]);
    if (d == NULL) {
    std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dirs[i]), closedir);
    if (!d) {
      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);
    struct dirent* de;
    while ((de = readdir(d.get())) != 0) {
      std::string path = std::string(dirs[i]) + "/" + 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;
      if (path == CACHE_TEMP_SOURCE) {
        continue;
      }

      struct stat st;
      if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
        if (*entries >= size) {
          size *= 2;
          *names = reinterpret_cast<char**>(realloc(*names, size * sizeof(char*)));
        }
        (*names)[(*entries)++] = strdup(path);
      if (stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
        files.insert(path);
      }
    }

    closedir(d);
  }

  printf("%d regular files in deletable directories\n", *entries);

  if (EliminateOpenFiles(*names, *entries) < 0) {
    return -1;
  printf("%zu regular files in deletable directories\n", files.size());
  if (EliminateOpenFiles(&files) < 0) {
    return std::set<std::string>();
  }

  return 0;
  return files;
}

int MakeFreeSpaceOnCache(size_t bytes_needed) {
@@ -147,15 +118,8 @@ int MakeFreeSpaceOnCache(size_t bytes_needed) {
  if (free_now >= bytes_needed) {
    return 0;
  }

  char** names;
  int entries;

  if (FindExpendableFiles(&names, &entries) < 0) {
    return -1;
  }

  if (entries == 0) {
  std::set<std::string> files = FindExpendableFiles();
  if (files.empty()) {
    // nothing we can delete to free up space!
    printf("no files can be deleted to free space on /cache\n");
    return -1;
@@ -167,20 +131,13 @@ int MakeFreeSpaceOnCache(size_t bytes_needed) {
  //
  // Instead, we'll be dumb.

  int i;
  for (i = 0; i < entries && free_now < bytes_needed; ++i) {
    if (names[i]) {
      unlink(names[i]);
  for (const auto& file : files) {
    unlink(file.c_str());
    free_now = FreeSpaceForFile("/cache");
      printf("deleted %s; now %zu bytes free\n", names[i], free_now);
      free(names[i]);
    printf("deleted %s; now %zu bytes free\n", file.c_str(), free_now);
    if (free_now < bytes_needed) {
        break;
    }
  }

  for (; i < entries; ++i) {
    free(names[i]);
  }
  free(names);

  return (free_now >= bytes_needed) ? 0 : -1;
}
Loading