1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* 2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2013 Google Inc. 3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * 4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be 5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file. 6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */ 7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOSFile.h" 9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkString.h" 10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTFitsIn.h" 11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTemplates.h" 12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTypes.h" 13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <dirent.h> 15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <stdio.h> 16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <string.h> 17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <sys/mman.h> 18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <sys/stat.h> 19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <sys/types.h> 20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include <unistd.h> 21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_BUILD_FOR_IOS 23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkOSFile_ios.h" 24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif 25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool sk_exists(const char *path, SkFILE_Flags flags) { 27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int mode = F_OK; 28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (flags & kRead_SkFILE_Flag) { 29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot mode |= R_OK; 30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (flags & kWrite_SkFILE_Flag) { 32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot mode |= W_OK; 33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_BUILD_FOR_IOS 35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // if the default path fails, check the bundle (but only if read-only) 36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (0 == access(path, mode)) { 37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return true; 38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { 39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return (kRead_SkFILE_Flag == flags && ios_get_path_in_bundle(path, nullptr)); 40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#else 42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return (0 == access(path, mode)); 43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif 44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottypedef struct { 47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot dev_t dev; 48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ino_t ino; 49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} SkFILEID; 50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic bool sk_ino(FILE* a, SkFILEID* id) { 52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int fd = fileno(a); 53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (fd < 0) { 54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return 0; 55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot struct stat status; 57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (0 != fstat(fd, &status)) { 58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return 0; 59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot id->dev = status.st_dev; 61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot id->ino = status.st_ino; 62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return true; 63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool sk_fidentical(FILE* a, FILE* b) { 66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkFILEID aID, bID; 67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return sk_ino(a, &aID) && sk_ino(b, &bID) 68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot && aID.ino == bID.ino 69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot && aID.dev == bID.dev; 70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid sk_fmunmap(const void* addr, size_t length) { 73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot munmap(const_cast<void*>(addr), length); 74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid* sk_fdmmap(int fd, size_t* size) { 77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot struct stat status; 78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (0 != fstat(fd, &status)) { 79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return nullptr; 80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!S_ISREG(status.st_mode)) { 82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return nullptr; 83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!SkTFitsIn<size_t>(status.st_size)) { 85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return nullptr; 86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t fileSize = static_cast<size_t>(status.st_size); 88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot void* addr = mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fd, 0); 90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (MAP_FAILED == addr) { 91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return nullptr; 92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *size = fileSize; 95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return addr; 96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotint sk_fileno(FILE* f) { 99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return fileno(f); 100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid* sk_fmmap(FILE* f, size_t* size) { 103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int fd = sk_fileno(f); 104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (fd < 0) { 105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return nullptr; 106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return sk_fdmmap(fd, size); 109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotsize_t sk_qread(FILE* file, void* buffer, size_t count, size_t offset) { 112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int fd = sk_fileno(file); 113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (fd < 0) { 114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return SIZE_MAX; 115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ssize_t bytesRead = pread(fd, buffer, count, offset); 117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (bytesRead < 0) { 118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return SIZE_MAX; 119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return bytesRead; 121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//////////////////////////////////////////////////////////////////////////// 124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstruct SkOSFileIterData { 126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkOSFileIterData() : fDIR(nullptr) { } 127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot DIR* fDIR; 128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkString fPath, fSuffix; 129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}; 130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic_assert(sizeof(SkOSFileIterData) <= SkOSFile::Iter::kStorageSize, "not_enough_space"); 131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkOSFile::Iter::Iter() { new (fSelf.get()) SkOSFileIterData; } 133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkOSFile::Iter::Iter(const char path[], const char suffix[]) { 135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot new (fSelf.get()) SkOSFileIterData; 136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot this->reset(path, suffix); 137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkOSFile::Iter::~Iter() { 140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get()); 141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (self.fDIR) { 142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ::closedir(self.fDIR); 143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot self.~SkOSFileIterData(); 145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkOSFile::Iter::reset(const char path[], const char suffix[]) { 148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get()); 149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (self.fDIR) { 150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ::closedir(self.fDIR); 151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot self.fDIR = nullptr; 152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot self.fPath.set(path); 154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (path) { 156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot self.fDIR = ::opendir(path); 157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_BUILD_FOR_IOS 158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot // check bundle for directory 159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!self.fDIR && ios_get_path_in_bundle(path, &self.fPath)) { 160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot self.fDIR = ::opendir(self.fPath.c_str()); 161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif 163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot self.fSuffix.set(suffix); 164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { 165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot self.fSuffix.reset(); 166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// returns true if suffix is empty, or if str ends with suffix 170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic bool issuffixfor(const SkString& suffix, const char str[]) { 171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t suffixLen = suffix.size(); 172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t strLen = strlen(str); 173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return strLen >= suffixLen && 175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot memcmp(suffix.c_str(), str + strLen - suffixLen, suffixLen) == 0; 176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotbool SkOSFile::Iter::next(SkString* name, bool getDir) { 179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkOSFileIterData& self = *static_cast<SkOSFileIterData*>(fSelf.get()); 180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (self.fDIR) { 181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot dirent* entry; 182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot while ((entry = ::readdir(self.fDIR)) != nullptr) { 184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot struct stat s; 185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkString str(self.fPath); 186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!str.endsWith("/") && !str.endsWith("\\")) { 188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot str.append("/"); 189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot str.append(entry->d_name); 191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (0 == stat(str.c_str(), &s)) { 193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (getDir) { 194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (s.st_mode & S_IFDIR) { 195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot break; 196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { 198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!(s.st_mode & S_IFDIR) && issuffixfor(self.fSuffix, entry->d_name)) { 199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot break; 200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (entry) { // we broke out with a file 205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (name) { 206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot name->set(entry->d_name); 207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return true; 209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return false; 212fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 213