| /* $Id$ */ |
| /* |
| * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) |
| * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| #include <pj/file_io.h> |
| #include <pj/unicode.h> |
| #include <pj/errno.h> |
| #include <pj/assert.h> |
| |
| #include <windows.h> |
| |
| #ifndef INVALID_SET_FILE_POINTER |
| # define INVALID_SET_FILE_POINTER ((DWORD)-1) |
| #endif |
| |
| /** |
| * Check for end-of-file condition on the specified descriptor. |
| * |
| * @param fd The file descriptor. |
| * @param access The desired access. |
| * |
| * @return Non-zero if file is EOF. |
| */ |
| PJ_DECL(pj_bool_t) pj_file_eof(pj_oshandle_t fd, |
| enum pj_file_access access); |
| |
| |
| PJ_DEF(pj_status_t) pj_file_open( pj_pool_t *pool, |
| const char *pathname, |
| unsigned flags, |
| pj_oshandle_t *fd) |
| { |
| PJ_DECL_UNICODE_TEMP_BUF(wpathname,256) |
| HANDLE hFile; |
| DWORD dwDesiredAccess = 0; |
| DWORD dwShareMode = 0; |
| DWORD dwCreationDisposition = 0; |
| DWORD dwFlagsAndAttributes = 0; |
| |
| PJ_UNUSED_ARG(pool); |
| |
| PJ_ASSERT_RETURN(pathname!=NULL, PJ_EINVAL); |
| |
| if ((flags & PJ_O_WRONLY) == PJ_O_WRONLY) { |
| dwDesiredAccess |= GENERIC_WRITE; |
| if ((flags & PJ_O_APPEND) == PJ_O_APPEND) { |
| #if !defined(PJ_WIN32_WINCE) || !PJ_WIN32_WINCE |
| /* FILE_APPEND_DATA is invalid on WM2003 and WM5, but it seems |
| * to be working on WM6. All are tested on emulator though. |
| * Removing this also seem to work (i.e. data is appended), so |
| * I guess this flag is "optional". |
| * See http://trac.pjsip.org/repos/ticket/825 |
| */ |
| dwDesiredAccess |= FILE_APPEND_DATA; |
| #endif |
| dwCreationDisposition |= OPEN_ALWAYS; |
| } else { |
| dwDesiredAccess &= ~(FILE_APPEND_DATA); |
| dwCreationDisposition |= CREATE_ALWAYS; |
| } |
| } |
| if ((flags & PJ_O_RDONLY) == PJ_O_RDONLY) { |
| dwDesiredAccess |= GENERIC_READ; |
| if (flags == PJ_O_RDONLY) |
| dwCreationDisposition |= OPEN_EXISTING; |
| } |
| |
| if (dwDesiredAccess == 0) { |
| pj_assert(!"Invalid file open flags"); |
| return PJ_EINVAL; |
| } |
| |
| dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; |
| dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; |
| |
| hFile = CreateFile(PJ_STRING_TO_NATIVE(pathname,wpathname,sizeof(wpathname)), |
| dwDesiredAccess, dwShareMode, NULL, |
| dwCreationDisposition, dwFlagsAndAttributes, NULL); |
| if (hFile == INVALID_HANDLE_VALUE) { |
| *fd = 0; |
| return PJ_RETURN_OS_ERROR(GetLastError()); |
| } |
| |
| if ((flags & PJ_O_APPEND) == PJ_O_APPEND) { |
| pj_status_t status; |
| |
| status = pj_file_setpos(hFile, 0, PJ_SEEK_END); |
| if (status != PJ_SUCCESS) { |
| pj_file_close(hFile); |
| return status; |
| } |
| } |
| |
| *fd = hFile; |
| return PJ_SUCCESS; |
| } |
| |
| PJ_DEF(pj_status_t) pj_file_close(pj_oshandle_t fd) |
| { |
| if (CloseHandle(fd)==0) |
| return PJ_RETURN_OS_ERROR(GetLastError()); |
| return PJ_SUCCESS; |
| } |
| |
| PJ_DEF(pj_status_t) pj_file_write( pj_oshandle_t fd, |
| const void *data, |
| pj_ssize_t *size) |
| { |
| BOOL rc; |
| DWORD bytesWritten; |
| |
| rc = WriteFile(fd, data, (DWORD)*size, &bytesWritten, NULL); |
| if (!rc) { |
| *size = -1; |
| return PJ_RETURN_OS_ERROR(GetLastError()); |
| } |
| |
| *size = bytesWritten; |
| return PJ_SUCCESS; |
| } |
| |
| PJ_DEF(pj_status_t) pj_file_read( pj_oshandle_t fd, |
| void *data, |
| pj_ssize_t *size) |
| { |
| BOOL rc; |
| DWORD bytesRead; |
| |
| rc = ReadFile(fd, data, (DWORD)*size, &bytesRead, NULL); |
| if (!rc) { |
| *size = -1; |
| return PJ_RETURN_OS_ERROR(GetLastError()); |
| } |
| |
| *size = bytesRead; |
| return PJ_SUCCESS; |
| } |
| |
| /* |
| PJ_DEF(pj_bool_t) pj_file_eof(pj_oshandle_t fd, enum pj_file_access access) |
| { |
| BOOL rc; |
| DWORD dummy = 0, bytes; |
| DWORD dwStatus; |
| |
| if ((access & PJ_O_RDONLY) == PJ_O_RDONLY) { |
| rc = ReadFile(fd, &dummy, 0, &bytes, NULL); |
| } else if ((access & PJ_O_WRONLY) == PJ_O_WRONLY) { |
| rc = WriteFile(fd, &dummy, 0, &bytes, NULL); |
| } else { |
| pj_assert(!"Invalid access"); |
| return PJ_TRUE; |
| } |
| |
| dwStatus = GetLastError(); |
| if (dwStatus==ERROR_HANDLE_EOF) |
| return PJ_TRUE; |
| |
| return 0; |
| } |
| */ |
| |
| PJ_DEF(pj_status_t) pj_file_setpos( pj_oshandle_t fd, |
| pj_off_t offset, |
| enum pj_file_seek_type whence) |
| { |
| DWORD dwMoveMethod; |
| DWORD dwNewPos; |
| LONG hi32; |
| |
| if (whence == PJ_SEEK_SET) |
| dwMoveMethod = FILE_BEGIN; |
| else if (whence == PJ_SEEK_CUR) |
| dwMoveMethod = FILE_CURRENT; |
| else if (whence == PJ_SEEK_END) |
| dwMoveMethod = FILE_END; |
| else { |
| pj_assert(!"Invalid whence in file_setpos"); |
| return PJ_EINVAL; |
| } |
| |
| hi32 = (LONG)(offset >> 32); |
| dwNewPos = SetFilePointer(fd, (long)offset, &hi32, dwMoveMethod); |
| if (dwNewPos == (DWORD)INVALID_SET_FILE_POINTER) { |
| DWORD dwStatus = GetLastError(); |
| if (dwStatus != 0) |
| return PJ_RETURN_OS_ERROR(dwStatus); |
| /* dwNewPos actually is not an error. */ |
| } |
| |
| return PJ_SUCCESS; |
| } |
| |
| PJ_DEF(pj_status_t) pj_file_getpos( pj_oshandle_t fd, |
| pj_off_t *pos) |
| { |
| LONG hi32 = 0; |
| DWORD lo32; |
| |
| lo32 = SetFilePointer(fd, 0, &hi32, FILE_CURRENT); |
| if (lo32 == (DWORD)INVALID_SET_FILE_POINTER) { |
| DWORD dwStatus = GetLastError(); |
| if (dwStatus != 0) |
| return PJ_RETURN_OS_ERROR(dwStatus); |
| } |
| |
| *pos = hi32; |
| *pos = (*pos << 32) + lo32; |
| return PJ_SUCCESS; |
| } |
| |
| PJ_DEF(pj_status_t) pj_file_flush(pj_oshandle_t fd) |
| { |
| BOOL rc; |
| |
| rc = FlushFileBuffers(fd); |
| |
| if (!rc) { |
| DWORD dwStatus = GetLastError(); |
| if (dwStatus != 0) |
| return PJ_RETURN_OS_ERROR(dwStatus); |
| } |
| |
| return PJ_SUCCESS; |
| } |