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