Merge vk-gl-cts/vulkan-cts-1.0.2 into vk-gl-cts/master
[platform/upstream/VK-GL-CTS.git] / framework / delibs / deutil / deFile.c
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) || (DE_OS == DE_OS_QNX)
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
40 deBool deFileExists (const char* filename)
41 {
42         struct stat st;
43         int result = stat(filename, &st);
44         return result == 0;
45 }
46
47 deBool deDeleteFile (const char* filename)
48 {
49         return unlink(filename) == 0;
50 }
51
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
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
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
109 void deFile_destroy (deFile* file)
110 {
111         close(file->fd);
112         deFree(file);
113 }
114
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
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
149 deBool deFile_seek (deFile* file, deFilePosition base, deInt64 offset)
150 {
151         return lseek(file->fd, (off_t)offset, mapSeekPosition(base)) >= 0;
152 }
153
154 deInt64 deFile_getPosition (const deFile* file)
155 {
156         return lseek(file->fd, 0, SEEK_CUR);
157 }
158
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         size = lseek(file->fd, 0, SEEK_END);
168
169         if (size < 0)
170                 return -1;
171
172         lseek(file->fd, (off_t)curPos, SEEK_SET);
173
174         return size;
175 }
176
177 static deFileResult mapReadWriteResult (deInt64 numBytes)
178 {
179         if (numBytes > 0)
180                 return DE_FILERESULT_SUCCESS;
181         else if (numBytes == 0)
182                 return DE_FILERESULT_END_OF_FILE;
183         else
184                 return errno == EAGAIN ? DE_FILERESULT_WOULD_BLOCK : DE_FILERESULT_ERROR;
185 }
186
187 deFileResult deFile_read (deFile* file, void* buf, deInt64 bufSize, deInt64* numReadPtr)
188 {
189         deInt64 numRead = read(file->fd, buf, (size_t)bufSize);
190
191         if (numReadPtr)
192                 *numReadPtr = numRead;
193
194         return mapReadWriteResult(numRead);
195 }
196
197 deFileResult deFile_write (deFile* file, const void* buf, deInt64 bufSize, deInt64* numWrittenPtr)
198 {
199         deInt64 numWritten = write(file->fd, buf, (size_t)bufSize);
200
201         if (numWrittenPtr)
202                 *numWrittenPtr = numWritten;
203
204         return mapReadWriteResult(numWritten);
205 }
206
207 #elif (DE_OS == DE_OS_WIN32)
208
209 #define VC_EXTRALEAN
210 #define WIN32_LEAN_AND_MEAN
211 #include <windows.h>
212
213 struct deFile_s
214 {
215         HANDLE handle;
216 };
217
218 deBool deFileExists (const char* filename)
219 {
220         return GetFileAttributes(filename) != INVALID_FILE_ATTRIBUTES;
221 }
222
223 deBool deDeleteFile (const char* filename)
224 {
225         return DeleteFile(filename) == TRUE;
226 }
227
228 deFile* deFile_createFromHandle (deUintptr handle)
229 {
230         deFile* file = (deFile*)deCalloc(sizeof(deFile));
231         if (!file)
232         {
233                 CloseHandle((HANDLE)handle);
234                 return file;
235         }
236
237         file->handle = (HANDLE)handle;
238         return file;
239 }
240
241 deFile* deFile_create (const char* filename, deUint32 mode)
242 {
243         DWORD   access          = 0;
244         DWORD   create          = OPEN_EXISTING;
245         HANDLE  handle          = DE_NULL;
246
247         /* Read, write or read and write access is required. */
248         DE_ASSERT((mode & DE_FILEMODE_READ) != 0 || ((mode & DE_FILEMODE_WRITE) != 0));
249
250         /* Create, open or create and open mode is required. */
251         DE_ASSERT((mode & DE_FILEMODE_OPEN) != 0 || ((mode & DE_FILEMODE_CREATE) != 0));
252
253         /* Require write when using create. */
254         DE_ASSERT(!(mode & DE_FILEMODE_CREATE) || (mode & DE_FILEMODE_WRITE));
255
256         /* Require write and open when using truncate */
257         DE_ASSERT(!(mode & DE_FILEMODE_TRUNCATE) || ((mode & DE_FILEMODE_WRITE) && (mode & DE_FILEMODE_OPEN)));
258
259
260         if (mode & DE_FILEMODE_READ)
261                 access |= GENERIC_READ;
262
263         if (mode & DE_FILEMODE_WRITE)
264                 access |= GENERIC_WRITE;
265
266         if ((mode & DE_FILEMODE_TRUNCATE))
267         {
268                 if ((mode & DE_FILEMODE_CREATE) && (mode & DE_FILEMODE_OPEN))
269                         create = CREATE_ALWAYS;
270                 else if (mode & DE_FILEMODE_OPEN)
271                         create = TRUNCATE_EXISTING;
272                 else
273                         DE_ASSERT(DE_FALSE);
274         }
275         else
276         {
277                 if ((mode & DE_FILEMODE_CREATE) && (mode & DE_FILEMODE_OPEN))
278                         create = OPEN_ALWAYS;
279                 else if (mode & DE_FILEMODE_CREATE)
280                         create = CREATE_NEW;
281                 else if (mode & DE_FILEMODE_OPEN)
282                         create = OPEN_EXISTING;
283                 else
284                         DE_ASSERT(DE_FALSE);
285         }
286
287         handle = CreateFile(filename, access, FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE, DE_NULL, create, FILE_ATTRIBUTE_NORMAL, DE_NULL);
288         if (handle == INVALID_HANDLE_VALUE)
289                 return DE_NULL;
290
291         return deFile_createFromHandle((deUintptr)handle);
292 }
293
294 void deFile_destroy (deFile* file)
295 {
296         CloseHandle(file->handle);
297         deFree(file);
298 }
299
300 deBool deFile_setFlags (deFile* file, deUint32 flags)
301 {
302         /* Non-blocking. */
303         if (flags & DE_FILE_NONBLOCKING)
304                 return DE_FALSE; /* Not supported. */
305
306         /* Close on exec. */
307         if (!SetHandleInformation(file->handle, HANDLE_FLAG_INHERIT, (flags & DE_FILE_CLOSE_ON_EXEC) ? HANDLE_FLAG_INHERIT : 0))
308                 return DE_FALSE;
309
310         return DE_TRUE;
311 }
312
313 deBool deFile_seek (deFile* file, deFilePosition base, deInt64 offset)
314 {
315         DWORD   method          = 0;
316         LONG    lowBits         = (LONG)(offset & 0xFFFFFFFFll);
317         LONG    highBits        = (LONG)((offset >> 32) & 0xFFFFFFFFll);
318
319         switch (base)
320         {
321                 case DE_FILEPOSITION_BEGIN:             method = FILE_BEGIN;    break;
322                 case DE_FILEPOSITION_END:               method = FILE_END;              break;
323                 case DE_FILEPOSITION_CURRENT:   method = FILE_CURRENT;  break;
324                 default:
325                         DE_ASSERT(DE_FALSE);
326                         return DE_FALSE;
327         }
328
329         return SetFilePointer(file->handle, lowBits, &highBits, method) != INVALID_SET_FILE_POINTER;
330 }
331
332 deInt64 deFile_getPosition (const deFile* file)
333 {
334         LONG    highBits        = 0;
335         LONG    lowBits         = SetFilePointer(file->handle, 0, &highBits, FILE_CURRENT);
336
337         return (deInt64)(((deUint64)highBits << 32) | (deUint64)lowBits);
338 }
339
340 deInt64 deFile_getSize (const deFile* file)
341 {
342         DWORD   highBits        = 0;
343         DWORD   lowBits         = GetFileSize(file->handle, &highBits);
344
345         return (deInt64)(((deUint64)highBits << 32) | (deUint64)lowBits);
346 }
347
348 static deFileResult mapReadWriteResult (BOOL retVal, DWORD numBytes)
349 {
350         if (retVal && numBytes > 0)
351                 return DE_FILERESULT_SUCCESS;
352         else if (retVal && numBytes == 0)
353                 return DE_FILERESULT_END_OF_FILE;
354         else
355         {
356                 DWORD error = GetLastError();
357
358                 if (error == ERROR_HANDLE_EOF)
359                         return DE_FILERESULT_END_OF_FILE;
360                 else
361                         return DE_FILERESULT_ERROR;
362         }
363 }
364
365 deFileResult deFile_read (deFile* file, void* buf, deInt64 bufSize, deInt64* numReadPtr)
366 {
367         DWORD   bufSize32       = (DWORD)bufSize;
368         DWORD   numRead32       = 0;
369         BOOL    result;
370
371         /* \todo [2011-10-03 pyry] 64-bit IO. */
372         DE_ASSERT((deInt64)bufSize32 == bufSize);
373
374         result = ReadFile(file->handle, buf, bufSize32, &numRead32, DE_NULL);
375
376         if (numReadPtr)
377                 *numReadPtr = (deInt64)numRead32;
378
379         return mapReadWriteResult(result, numRead32);
380 }
381
382 deFileResult deFile_write (deFile* file, const void* buf, deInt64 bufSize, deInt64* numWrittenPtr)
383 {
384         DWORD   bufSize32               = (DWORD)bufSize;
385         DWORD   numWritten32    = 0;
386         BOOL    result;
387
388         /* \todo [2011-10-03 pyry] 64-bit IO. */
389         DE_ASSERT((deInt64)bufSize32 == bufSize);
390
391         result = WriteFile(file->handle, buf, bufSize32, &numWritten32, DE_NULL);
392
393         if (numWrittenPtr)
394                 *numWrittenPtr = (deInt64)numWritten32;
395
396         return mapReadWriteResult(result, numWritten32);
397 }
398
399 #else
400 #       error Implement deFile for your OS.
401 #endif