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