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