Home | History | Annotate | Download | only in deutil
      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