1 /*-------------------------------------------------------------------------
2 * drawElements Utility Library
3 * ----------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief File abstraction.
22 *//*--------------------------------------------------------------------*/
23
24 #include "deFile.h"
25 #include "deMemory.h"
26
27 #if (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_OSX) || (DE_OS == DE_OS_IOS) || (DE_OS == DE_OS_ANDROID) || \
28 (DE_OS == DE_OS_SYMBIAN) || (DE_OS == DE_OS_QNX) || (DE_OS == DE_OS_FUCHSIA)
29
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <errno.h>
35
36 struct deFile_s
37 {
38 int fd;
39 };
40
deFileExists(const char * filename)41 bool deFileExists(const char *filename)
42 {
43 struct stat st;
44 int result = stat(filename, &st);
45 return result == 0;
46 }
47
deDeleteFile(const char * filename)48 bool deDeleteFile(const char *filename)
49 {
50 return unlink(filename) == 0;
51 }
52
deFile_createFromHandle(uintptr_t handle)53 deFile *deFile_createFromHandle(uintptr_t handle)
54 {
55 int fd = (int)handle;
56 deFile *file = (deFile *)deCalloc(sizeof(deFile));
57 if (!file)
58 {
59 close(fd);
60 return file;
61 }
62
63 file->fd = fd;
64 return file;
65 }
66
mapOpenMode(deFileMode mode)67 static int mapOpenMode(deFileMode mode)
68 {
69 int flag = 0;
70
71 /* Read, write or read and write access is required. */
72 DE_ASSERT((mode & DE_FILEMODE_READ) != 0 || ((mode & DE_FILEMODE_WRITE) != 0));
73
74 /* Create, open or create and open mode is required. */
75 DE_ASSERT((mode & DE_FILEMODE_OPEN) != 0 || ((mode & DE_FILEMODE_CREATE) != 0));
76
77 /* Require write when using create. */
78 DE_ASSERT(!(mode & DE_FILEMODE_CREATE) || (mode & DE_FILEMODE_WRITE));
79
80 /* Require write and open when using truncate */
81 DE_ASSERT(!(mode & DE_FILEMODE_TRUNCATE) || ((mode & DE_FILEMODE_WRITE) && (mode & DE_FILEMODE_OPEN)));
82
83 if (mode & DE_FILEMODE_READ)
84 flag |= O_RDONLY;
85
86 if (mode & DE_FILEMODE_WRITE)
87 flag |= O_WRONLY;
88
89 if (mode & DE_FILEMODE_TRUNCATE)
90 flag |= O_TRUNC;
91
92 if (mode & DE_FILEMODE_CREATE)
93 flag |= O_CREAT;
94
95 if (!(mode & DE_FILEMODE_OPEN))
96 flag |= O_EXCL;
97
98 return flag;
99 }
100
deFile_create(const char * filename,uint32_t mode)101 deFile *deFile_create(const char *filename, uint32_t mode)
102 {
103 int fd = open(filename, mapOpenMode(mode), 0777);
104 if (fd >= 0)
105 return deFile_createFromHandle((uintptr_t)fd);
106 else
107 return DE_NULL;
108 }
109
deFile_destroy(deFile * file)110 void deFile_destroy(deFile *file)
111 {
112 close(file->fd);
113 deFree(file);
114 }
115
deFile_setFlags(deFile * file,uint32_t flags)116 bool deFile_setFlags(deFile *file, uint32_t flags)
117 {
118 /* Non-blocking. */
119 {
120 int oldFlags = fcntl(file->fd, F_GETFL, 0);
121 int newFlags = (flags & DE_FILE_NONBLOCKING) ? (oldFlags | O_NONBLOCK) : (oldFlags & ~O_NONBLOCK);
122 if (fcntl(file->fd, F_SETFL, newFlags) != 0)
123 return false;
124 }
125
126 /* Close on exec. */
127 {
128 int oldFlags = fcntl(file->fd, F_GETFD, 0);
129 int newFlags = (flags & DE_FILE_CLOSE_ON_EXEC) ? (oldFlags | FD_CLOEXEC) : (oldFlags & ~FD_CLOEXEC);
130 if (fcntl(file->fd, F_SETFD, newFlags) != 0)
131 return false;
132 }
133
134 return true;
135 }
136
mapSeekPosition(deFilePosition position)137 static int mapSeekPosition(deFilePosition position)
138 {
139 switch (position)
140 {
141 case DE_FILEPOSITION_BEGIN:
142 return SEEK_SET;
143 case DE_FILEPOSITION_END:
144 return SEEK_END;
145 case DE_FILEPOSITION_CURRENT:
146 return SEEK_CUR;
147 default:
148 DE_ASSERT(false);
149 return 0;
150 }
151 }
152
deFile_seek(deFile * file,deFilePosition base,int64_t offset)153 bool deFile_seek(deFile *file, deFilePosition base, int64_t offset)
154 {
155 return lseek(file->fd, (off_t)offset, mapSeekPosition(base)) >= 0;
156 }
157
deFile_getPosition(const deFile * file)158 int64_t deFile_getPosition(const deFile *file)
159 {
160 return lseek(file->fd, 0, SEEK_CUR);
161 }
162
deFile_getSize(const deFile * file)163 int64_t deFile_getSize(const deFile *file)
164 {
165 int64_t size = 0;
166 int64_t curPos = lseek(file->fd, 0, SEEK_CUR);
167
168 if (curPos < 0)
169 return -1;
170
171 size = lseek(file->fd, 0, SEEK_END);
172
173 if (size < 0)
174 return -1;
175
176 lseek(file->fd, (off_t)curPos, SEEK_SET);
177
178 return size;
179 }
180
mapReadWriteResult(int64_t numBytes)181 static deFileResult mapReadWriteResult(int64_t numBytes)
182 {
183 if (numBytes > 0)
184 return DE_FILERESULT_SUCCESS;
185 else if (numBytes == 0)
186 return DE_FILERESULT_END_OF_FILE;
187 else
188 return errno == EAGAIN ? DE_FILERESULT_WOULD_BLOCK : DE_FILERESULT_ERROR;
189 }
190
deFile_read(deFile * file,void * buf,int64_t bufSize,int64_t * numReadPtr)191 deFileResult deFile_read(deFile *file, void *buf, int64_t bufSize, int64_t *numReadPtr)
192 {
193 int64_t numRead = read(file->fd, buf, (size_t)bufSize);
194
195 if (numReadPtr)
196 *numReadPtr = numRead;
197
198 return mapReadWriteResult(numRead);
199 }
200
deFile_write(deFile * file,const void * buf,int64_t bufSize,int64_t * numWrittenPtr)201 deFileResult deFile_write(deFile *file, const void *buf, int64_t bufSize, int64_t *numWrittenPtr)
202 {
203 int64_t numWritten = write(file->fd, buf, (size_t)bufSize);
204
205 if (numWrittenPtr)
206 *numWrittenPtr = numWritten;
207
208 return mapReadWriteResult(numWritten);
209 }
210
211 #elif (DE_OS == DE_OS_WIN32)
212
213 #define VC_EXTRALEAN
214 #define WIN32_LEAN_AND_MEAN
215 #include <windows.h>
216
217 struct deFile_s
218 {
219 HANDLE handle;
220 };
221
deFileExists(const char * filename)222 bool deFileExists(const char *filename)
223 {
224 return GetFileAttributes(filename) != INVALID_FILE_ATTRIBUTES;
225 }
226
deDeleteFile(const char * filename)227 bool deDeleteFile(const char *filename)
228 {
229 return DeleteFile(filename) == TRUE;
230 }
231
deFile_createFromHandle(uintptr_t handle)232 deFile *deFile_createFromHandle(uintptr_t handle)
233 {
234 deFile *file = (deFile *)deCalloc(sizeof(deFile));
235 if (!file)
236 {
237 CloseHandle((HANDLE)handle);
238 return file;
239 }
240
241 file->handle = (HANDLE)handle;
242 return file;
243 }
244
deFile_create(const char * filename,uint32_t mode)245 deFile *deFile_create(const char *filename, uint32_t mode)
246 {
247 DWORD access = 0;
248 DWORD create = OPEN_EXISTING;
249 HANDLE handle = DE_NULL;
250
251 /* Read, write or read and write access is required. */
252 DE_ASSERT((mode & DE_FILEMODE_READ) != 0 || ((mode & DE_FILEMODE_WRITE) != 0));
253
254 /* Create, open or create and open mode is required. */
255 DE_ASSERT((mode & DE_FILEMODE_OPEN) != 0 || ((mode & DE_FILEMODE_CREATE) != 0));
256
257 /* Require write when using create. */
258 DE_ASSERT(!(mode & DE_FILEMODE_CREATE) || (mode & DE_FILEMODE_WRITE));
259
260 /* Require write and open when using truncate */
261 DE_ASSERT(!(mode & DE_FILEMODE_TRUNCATE) || ((mode & DE_FILEMODE_WRITE) && (mode & DE_FILEMODE_OPEN)));
262
263 if (mode & DE_FILEMODE_READ)
264 access |= GENERIC_READ;
265
266 if (mode & DE_FILEMODE_WRITE)
267 access |= GENERIC_WRITE;
268
269 if ((mode & DE_FILEMODE_TRUNCATE))
270 {
271 if ((mode & DE_FILEMODE_CREATE) && (mode & DE_FILEMODE_OPEN))
272 create = CREATE_ALWAYS;
273 else if (mode & DE_FILEMODE_OPEN)
274 create = TRUNCATE_EXISTING;
275 else
276 DE_ASSERT(false);
277 }
278 else
279 {
280 if ((mode & DE_FILEMODE_CREATE) && (mode & DE_FILEMODE_OPEN))
281 create = OPEN_ALWAYS;
282 else if (mode & DE_FILEMODE_CREATE)
283 create = CREATE_NEW;
284 else if (mode & DE_FILEMODE_OPEN)
285 create = OPEN_EXISTING;
286 else
287 DE_ASSERT(false);
288 }
289
290 handle = CreateFile(filename, access, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, DE_NULL, create,
291 FILE_ATTRIBUTE_NORMAL, DE_NULL);
292 if (handle == INVALID_HANDLE_VALUE)
293 return DE_NULL;
294
295 return deFile_createFromHandle((uintptr_t)handle);
296 }
297
deFile_destroy(deFile * file)298 void deFile_destroy(deFile *file)
299 {
300 CloseHandle(file->handle);
301 deFree(file);
302 }
303
deFile_setFlags(deFile * file,uint32_t flags)304 bool deFile_setFlags(deFile *file, uint32_t flags)
305 {
306 /* Non-blocking. */
307 if (flags & DE_FILE_NONBLOCKING)
308 return false; /* Not supported. */
309
310 /* Close on exec. */
311 if (!SetHandleInformation(file->handle, HANDLE_FLAG_INHERIT,
312 (flags & DE_FILE_CLOSE_ON_EXEC) ? HANDLE_FLAG_INHERIT : 0))
313 return false;
314
315 return true;
316 }
317
deFile_seek(deFile * file,deFilePosition base,int64_t offset)318 bool deFile_seek(deFile *file, deFilePosition base, int64_t offset)
319 {
320 DWORD method = 0;
321 LONG lowBits = (LONG)(offset & 0xFFFFFFFFll);
322 LONG highBits = (LONG)((offset >> 32) & 0xFFFFFFFFll);
323
324 switch (base)
325 {
326 case DE_FILEPOSITION_BEGIN:
327 method = FILE_BEGIN;
328 break;
329 case DE_FILEPOSITION_END:
330 method = FILE_END;
331 break;
332 case DE_FILEPOSITION_CURRENT:
333 method = FILE_CURRENT;
334 break;
335 default:
336 DE_ASSERT(false);
337 return false;
338 }
339
340 return SetFilePointer(file->handle, lowBits, &highBits, method) != INVALID_SET_FILE_POINTER;
341 }
342
deFile_getPosition(const deFile * file)343 int64_t deFile_getPosition(const deFile *file)
344 {
345 LONG highBits = 0;
346 LONG lowBits = SetFilePointer(file->handle, 0, &highBits, FILE_CURRENT);
347
348 return (int64_t)(((uint64_t)highBits << 32) | (uint64_t)lowBits);
349 }
350
deFile_getSize(const deFile * file)351 int64_t deFile_getSize(const deFile *file)
352 {
353 DWORD highBits = 0;
354 DWORD lowBits = GetFileSize(file->handle, &highBits);
355
356 return (int64_t)(((uint64_t)highBits << 32) | (uint64_t)lowBits);
357 }
358
mapReadWriteResult(BOOL retVal,DWORD numBytes)359 static deFileResult mapReadWriteResult(BOOL retVal, DWORD numBytes)
360 {
361 if (retVal && numBytes > 0)
362 return DE_FILERESULT_SUCCESS;
363 else if (retVal && numBytes == 0)
364 return DE_FILERESULT_END_OF_FILE;
365 else
366 {
367 DWORD error = GetLastError();
368
369 if (error == ERROR_HANDLE_EOF)
370 return DE_FILERESULT_END_OF_FILE;
371 else
372 return DE_FILERESULT_ERROR;
373 }
374 }
375
deFile_read(deFile * file,void * buf,int64_t bufSize,int64_t * numReadPtr)376 deFileResult deFile_read(deFile *file, void *buf, int64_t bufSize, int64_t *numReadPtr)
377 {
378 DWORD bufSize32 = (DWORD)bufSize;
379 DWORD numRead32 = 0;
380 BOOL result;
381
382 /* \todo [2011-10-03 pyry] 64-bit IO. */
383 DE_ASSERT((int64_t)bufSize32 == bufSize);
384
385 result = ReadFile(file->handle, buf, bufSize32, &numRead32, DE_NULL);
386
387 if (numReadPtr)
388 *numReadPtr = (int64_t)numRead32;
389
390 return mapReadWriteResult(result, numRead32);
391 }
392
deFile_write(deFile * file,const void * buf,int64_t bufSize,int64_t * numWrittenPtr)393 deFileResult deFile_write(deFile *file, const void *buf, int64_t bufSize, int64_t *numWrittenPtr)
394 {
395 DWORD bufSize32 = (DWORD)bufSize;
396 DWORD numWritten32 = 0;
397 BOOL result;
398
399 /* \todo [2011-10-03 pyry] 64-bit IO. */
400 DE_ASSERT((int64_t)bufSize32 == bufSize);
401
402 result = WriteFile(file->handle, buf, bufSize32, &numWritten32, DE_NULL);
403
404 if (numWrittenPtr)
405 *numWrittenPtr = (int64_t)numWritten32;
406
407 return mapReadWriteResult(result, numWritten32);
408 }
409
410 #else
411 #error Implement deFile for your OS.
412 #endif
413