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 402