qse/qse/lib/cmn/fio.c

1613 lines
34 KiB
C
Raw Normal View History

2008-11-27 03:05:00 +00:00
/*
2012-08-16 03:47:55 +00:00
* $Id$
*
Copyright 2006-2012 Chung, Hyung-Hwan.
2009-09-16 04:01:02 +00:00
This file is part of QSE.
2009-09-16 04:01:02 +00:00
QSE is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
2009-09-16 04:01:02 +00:00
QSE 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 Lesser General Public License for more details.
2009-09-16 04:01:02 +00:00
You should have received a copy of the GNU Lesser General Public
License along with QSE. If not, see <http://www.gnu.org/licenses/>.
2008-11-27 03:05:00 +00:00
*/
2008-12-21 21:35:07 +00:00
#include <qse/cmn/fio.h>
2009-01-18 01:48:21 +00:00
#include <qse/cmn/str.h>
#include <qse/cmn/fmt.h>
#include <qse/cmn/alg.h>
#include <qse/cmn/time.h>
2012-02-12 13:20:39 +00:00
#include <qse/cmn/mbwc.h>
2008-11-27 03:05:00 +00:00
#include "mem.h"
2011-03-15 09:40:35 +00:00
#if defined(_WIN32)
2009-01-27 09:26:15 +00:00
# include <windows.h>
/*# include <psapi.h>*/ /* for GetMappedFileName(). but dynamically loaded */
2011-03-17 02:37:06 +00:00
# include <tchar.h>
#elif defined(__OS2__)
# define INCL_DOSFILEMGR
# define INCL_DOSERRORS
2011-03-15 09:40:35 +00:00
# include <os2.h>
2011-05-05 09:11:23 +00:00
#elif defined(__DOS__)
# include <io.h>
# include <fcntl.h>
2012-02-20 14:45:49 +00:00
# include <errno.h>
2012-05-28 07:11:13 +00:00
#elif defined(vms) || defined(__vms)
# define __NEW_STARLET 1
2012-05-28 07:11:13 +00:00
# include <starlet.h>
# include <rms.h>
2008-11-27 03:05:00 +00:00
#else
2009-01-27 09:26:15 +00:00
# include "syscall.h"
2008-11-27 03:05:00 +00:00
#endif
/* internal status codes */
enum
{
STATUS_APPEND = (1 << 0),
STATUS_NOCLOSE = (1 << 1)
};
2012-02-12 13:20:39 +00:00
#if defined(_WIN32)
static qse_fio_errnum_t syserr_to_errnum (DWORD e)
{
switch (e)
{
2012-02-21 09:23:51 +00:00
case ERROR_NOT_ENOUGH_MEMORY:
case ERROR_OUTOFMEMORY:
return QSE_FIO_ENOMEM;
2012-02-12 13:20:39 +00:00
case ERROR_INVALID_PARAMETER:
case ERROR_INVALID_HANDLE:
case ERROR_INVALID_NAME:
return QSE_FIO_EINVAL;
case ERROR_ACCESS_DENIED:
return QSE_FIO_EACCES;
2012-02-21 09:23:51 +00:00
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
return QSE_FIO_ENOENT;
2012-02-12 13:20:39 +00:00
case ERROR_ALREADY_EXISTS:
case ERROR_FILE_EXISTS:
return QSE_FIO_EEXIST;
default:
2012-02-21 09:23:51 +00:00
return QSE_FIO_ESYSERR;
2012-02-12 13:20:39 +00:00
}
}
#elif defined(__OS2__)
static qse_fio_errnum_t syserr_to_errnum (APIRET e)
{
switch (e)
{
2012-02-21 09:23:51 +00:00
case ERROR_NOT_ENOUGH_MEMORY:
return QSE_FIO_ENOMEM;
2012-02-12 13:20:39 +00:00
case ERROR_INVALID_PARAMETER:
case ERROR_INVALID_HANDLE:
case ERROR_INVALID_NAME:
return QSE_FIO_EINVAL;
case ERROR_ACCESS_DENIED:
return QSE_FIO_EACCES;
2012-02-21 09:23:51 +00:00
case ERROR_FILE_NOT_FOUND:
case ERROR_PATH_NOT_FOUND:
return QSE_FIO_ENOENT;
2012-02-12 13:20:39 +00:00
case ERROR_ALREADY_EXISTS:
return QSE_FIO_EEXIST;
default:
2012-02-21 09:23:51 +00:00
return QSE_FIO_ESYSERR;
2012-02-12 13:20:39 +00:00
}
}
#elif defined(__DOS__)
static qse_fio_errnum_t syserr_to_errnum (int e)
{
switch (e)
{
case ENOMEM:
return QSE_FIO_ENOMEM;
case EINVAL:
return QSE_FIO_EINVAL;
case EACCES:
return QSE_FIO_EACCES;
2012-02-21 09:23:51 +00:00
case ENOENT:
return QSE_FIO_ENOENT;
2012-02-12 13:20:39 +00:00
case EEXIST:
return QSE_FIO_EEXIST;
default:
2012-02-21 09:23:51 +00:00
return QSE_FIO_ESYSERR;
2012-02-12 13:20:39 +00:00
}
}
#elif defined(vms) || defined(__vms)
static qse_fio_errnum_t syserr_to_errnum (unsigned long e)
{
switch (e)
{
case RMS$_NORMAL:
return QSE_FIO_ENOERR;
/* TODO: add more */
default:
return QSE_FIO_ESYSERR;
}
}
2012-02-12 13:20:39 +00:00
#else
static qse_fio_errnum_t syserr_to_errnum (int e)
{
switch (e)
{
case ENOMEM:
return QSE_FIO_ENOMEM;
case EINVAL:
return QSE_FIO_EINVAL;
case ENOENT:
return QSE_FIO_ENOENT;
case EACCES:
return QSE_FIO_EACCES;
case EEXIST:
return QSE_FIO_EEXIST;
case EINTR:
return QSE_FIO_EINTR;
default:
2012-02-21 09:23:51 +00:00
return QSE_FIO_ESYSERR;
2012-02-12 13:20:39 +00:00
}
}
#endif
2009-01-27 09:26:15 +00:00
2008-12-21 21:35:07 +00:00
qse_fio_t* qse_fio_open (
qse_mmgr_t* mmgr, qse_size_t ext,
2008-12-21 21:35:07 +00:00
const qse_char_t* path, int flags, int mode)
2008-11-27 03:05:00 +00:00
{
2008-12-21 21:35:07 +00:00
qse_fio_t* fio;
2008-11-27 03:05:00 +00:00
2008-12-21 21:35:07 +00:00
fio = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_fio_t) + ext);
if (fio == QSE_NULL) return QSE_NULL;
2008-11-27 03:05:00 +00:00
2011-09-01 09:43:46 +00:00
if (qse_fio_init (fio, mmgr, path, flags, mode) <= -1)
2008-11-27 03:05:00 +00:00
{
2008-12-21 21:35:07 +00:00
QSE_MMGR_FREE (mmgr, fio);
return QSE_NULL;
2008-11-27 03:05:00 +00:00
}
return fio;
}
2008-12-21 21:35:07 +00:00
void qse_fio_close (qse_fio_t* fio)
2008-11-27 03:05:00 +00:00
{
2008-12-21 21:35:07 +00:00
qse_fio_fini (fio);
QSE_MMGR_FREE (fio->mmgr, fio);
2008-11-27 03:05:00 +00:00
}
2011-09-01 09:43:46 +00:00
int qse_fio_init (
2008-12-21 21:35:07 +00:00
qse_fio_t* fio, qse_mmgr_t* mmgr,
const qse_char_t* path, int flags, int mode)
2008-11-27 03:05:00 +00:00
{
2008-12-21 21:35:07 +00:00
qse_fio_hnd_t handle;
2008-11-27 03:05:00 +00:00
qse_uint32_t temp_no;
qse_char_t* temp_ptr;
qse_size_t temp_tries;
#if defined(_WIN32)
int fellback = 0;
#endif
2008-12-21 21:35:07 +00:00
QSE_MEMSET (fio, 0, QSE_SIZEOF(*fio));
2008-11-27 03:05:00 +00:00
fio->mmgr = mmgr;
if (!(flags & (QSE_FIO_READ | QSE_FIO_WRITE | QSE_FIO_APPEND | QSE_FIO_HANDLE)))
{
/* one of QSE_FIO_READ, QSE_FIO_WRITE, QSE_FIO_APPEND,
* and QSE_FIO_HANDLE must be specified */
fio->errnum = QSE_FIO_EINVAL;
return -1;
}
/* Store some flags for later use */
if (flags & QSE_FIO_NOCLOSE)
fio->status |= STATUS_NOCLOSE;
if (flags & QSE_FIO_TEMPORARY)
{
qse_ntime_t now;
2012-12-04 16:44:59 +00:00
if (flags & (QSE_FIO_HANDLE | QSE_FIO_MBSPATH))
{
2012-12-04 16:44:59 +00:00
/* QSE_FIO_TEMPORARY and QSE_FIO_HANDLE/QSE_FIO_MBSPATH
* are mutually exclusive */
fio->errnum = QSE_FIO_EINVAL;
return -1;
}
temp_no = 0;
2011-12-31 15:24:48 +00:00
/* if QSE_FIO_TEMPORARY is used, the path name must
* be writable. */
for (temp_ptr = (qse_char_t*)path; *temp_ptr; temp_ptr++)
temp_no += *temp_ptr;
/* The path name template must be at least 4 characters long
* excluding the terminating null. this function fails if not */
2012-02-12 13:20:39 +00:00
if (temp_ptr - path < 4)
{
fio->errnum = QSE_FIO_EINVAL;
return -1;
}
qse_gettime (&now);
temp_no += (now.sec & 0xFFFFFFFFlu);
temp_tries = 0;
temp_ptr -= 4;
retry_temporary:
temp_tries++;
/* Fails after 5000 tries. 5000 randomly chosen */
2012-02-12 13:20:39 +00:00
if (temp_tries > 5000)
{
fio->errnum = QSE_FIO_EINVAL;
return -1;
}
/* Generate the next random number to use to make a
* new path name */
temp_no = qse_rand31 (temp_no);
/*
* You must not pass a constant string for a path name
* when QSE_FIO_TEMPORARY is set, because it changes
* the path name with a random number generated
*/
qse_fmtuintmax (
temp_ptr,
4,
temp_no % 0x10000,
16 | QSE_FMTUINTMAX_NOTRUNC | QSE_FMTUINTMAX_NONULL,
4,
QSE_T('\0'),
QSE_NULL
);
}
2011-03-15 09:40:35 +00:00
#if defined(_WIN32)
2008-12-21 21:35:07 +00:00
if (flags & QSE_FIO_HANDLE)
2008-11-27 03:05:00 +00:00
{
2008-12-21 21:35:07 +00:00
handle = *(qse_fio_hnd_t*)path;
QSE_ASSERTX (
handle != INVALID_HANDLE_VALUE,
"Do not specify an invalid handle value"
);
2008-11-27 03:05:00 +00:00
}
else
{
2008-11-27 03:56:27 +00:00
DWORD desired_access = 0;
DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2008-11-27 03:56:27 +00:00
DWORD creation_disposition = 0;
DWORD flag_and_attr = FILE_ATTRIBUTE_NORMAL;
2008-11-27 03:56:27 +00:00
if (fellback) share_mode &= ~FILE_SHARE_DELETE;
if (flags & QSE_FIO_APPEND)
2008-11-27 03:05:00 +00:00
{
if (fellback)
{
desired_access |= GENERIC_WRITE;
}
else
{
/* this is not officially documented for CreateFile.
* ZwCreateFile (kernel) seems to document it */
fio->status &= ~STATUS_APPEND;
desired_access |= FILE_APPEND_DATA;
}
2008-11-27 03:05:00 +00:00
}
2008-12-21 21:35:07 +00:00
else if (flags & QSE_FIO_WRITE)
{
/* In WIN32, FILE_APPEND_DATA and GENERIC_WRITE can't
* be used together */
desired_access |= GENERIC_WRITE;
}
2008-12-21 21:35:07 +00:00
if (flags & QSE_FIO_READ) desired_access |= GENERIC_READ;
if (flags & QSE_FIO_CREATE)
2008-11-27 03:05:00 +00:00
{
creation_disposition =
2008-12-21 21:35:07 +00:00
(flags & QSE_FIO_EXCLUSIVE)? CREATE_NEW:
(flags & QSE_FIO_TRUNCATE)? CREATE_ALWAYS: OPEN_ALWAYS;
2008-11-27 03:05:00 +00:00
}
else if (flags & QSE_FIO_TRUNCATE)
2008-11-27 03:05:00 +00:00
{
creation_disposition = TRUNCATE_EXISTING;
}
else creation_disposition = OPEN_EXISTING;
if (flags & QSE_FIO_NOSHREAD)
share_mode &= ~FILE_SHARE_READ;
if (flags & QSE_FIO_NOSHWRITE)
share_mode &= ~FILE_SHARE_WRITE;
if (flags & QSE_FIO_NOSHDELETE)
share_mode &= ~FILE_SHARE_DELETE;
if (!(mode & QSE_FIO_WUSR))
flag_and_attr = FILE_ATTRIBUTE_READONLY;
if (flags & QSE_FIO_SYNC)
flag_and_attr |= FILE_FLAG_WRITE_THROUGH;
2011-10-19 22:29:28 +00:00
if (flags & QSE_FIO_NOFOLLOW)
flag_and_attr |= FILE_FLAG_OPEN_REPARSE_POINT;
/* these two are just hints to OS */
if (flags & QSE_FIO_RANDOM)
flag_and_attr |= FILE_FLAG_RANDOM_ACCESS;
if (flags & QSE_FIO_SEQUENTIAL)
flag_and_attr |= FILE_FLAG_SEQUENTIAL_SCAN;
2012-12-04 16:44:59 +00:00
if (flags & QSE_FIO_MBSPATH)
{
handle = CreateFileA (
(const qse_mchar_t*)path, desired_access, share_mode,
QSE_NULL, /* set noinherit by setting no secattr */
creation_disposition, flag_and_attr, 0
);
}
else
{
handle = CreateFile (
path, desired_access, share_mode,
QSE_NULL, /* set noinherit by setting no secattr */
creation_disposition, flag_and_attr, 0
);
}
if (handle == INVALID_HANDLE_VALUE)
{
DWORD e = GetLastError();
if (!fellback && e == ERROR_INVALID_PARAMETER &&
((share_mode & FILE_SHARE_DELETE) || (flags & QSE_FIO_APPEND)))
{
/* old windows fails with ERROR_INVALID_PARAMETER
* when some advanced flags are used. so try again
* with fallback flags */
fellback = 1;
share_mode &= ~FILE_SHARE_DELETE;
if (flags & QSE_FIO_APPEND)
{
fio->status |= STATUS_APPEND;
desired_access &= ~FILE_APPEND_DATA;
desired_access |= GENERIC_WRITE;
}
2012-12-04 16:44:59 +00:00
if (flags & QSE_FIO_MBSPATH)
{
handle = CreateFileA (
path, desired_access, share_mode,
QSE_NULL, /* set noinherit by setting no secattr */
creation_disposition, flag_and_attr, 0
);
}
else
{
handle = CreateFile (
path, desired_access, share_mode,
QSE_NULL, /* set noinherit by setting no secattr */
creation_disposition, flag_and_attr, 0
);
}
if (handle == INVALID_HANDLE_VALUE)
{
if (flags & QSE_FIO_TEMPORARY) goto retry_temporary;
fio->errnum = syserr_to_errnum(GetLastError());
return -1;
}
}
else
{
if (flags & QSE_FIO_TEMPORARY) goto retry_temporary;
fio->errnum = syserr_to_errnum(e);
return -1;
}
}
}
2008-11-27 03:05:00 +00:00
/* some special check */
#if 0
if (GetFileType(handle) == FILE_TYPE_UNKNOWN)
2008-11-27 03:05:00 +00:00
{
2012-02-12 13:20:39 +00:00
fio->errnum = syserr_to_errnum(GetLastError());
CloseHandle (handle);
2011-09-01 09:43:46 +00:00
return -1;
2008-11-27 03:05:00 +00:00
}
#endif
2008-11-27 03:05:00 +00:00
2011-03-17 02:37:06 +00:00
/* TODO: support more features on WIN32 - TEMPORARY, DELETE_ON_CLOSE */
#elif defined(__OS2__)
if (flags & QSE_FIO_HANDLE)
{
handle = *(qse_fio_hnd_t*)path;
}
else
{
APIRET ret;
ULONG action_taken = 0;
ULONG open_action, open_mode, open_attr;
2011-03-17 02:37:06 +00:00
LONGLONG zero;
#if defined(QSE_CHAR_IS_MCHAR)
const qse_mchar_t* path_mb = path;
#else
qse_mchar_t path_mb_buf[CCHMAXPATH];
qse_mchar_t* path_mb;
qse_size_t wl, ml;
int px;
2012-12-04 16:44:59 +00:00
if (flags & QSE_FIO_MBSPATH)
{
2012-12-04 16:44:59 +00:00
path_mb = (qse_mchar_t*)path;
}
else
{
path_mb = path_mb_buf;
ml = QSE_COUNTOF(path_mb_buf);
px = qse_wcstombs (path, &wl, path_mb, &ml);
if (px == -2)
2012-02-12 13:20:39 +00:00
{
2012-12-04 16:44:59 +00:00
/* the static buffer is too small.
* dynamically allocate a buffer */
path_mb = qse_wcstombsdup (path, QSE_NULL, mmgr);
if (path_mb == QSE_NULL)
{
fio->errnum = QSE_FIO_ENOMEM;
return -1;
}
}
else if (px <= -1)
{
fio->errnum = QSE_FIO_EINVAL;
2012-02-12 13:20:39 +00:00
return -1;
}
}
#endif
2011-03-17 02:37:06 +00:00
zero.ulLo = 0;
zero.ulHi = 0;
if (flags & QSE_FIO_APPEND)
2012-02-20 14:45:49 +00:00
fio->status |= STATUS_APPEND;
2011-03-17 02:37:06 +00:00
if (flags & QSE_FIO_CREATE)
{
if (flags & QSE_FIO_EXCLUSIVE)
2011-03-17 02:37:06 +00:00
{
open_action = OPEN_ACTION_FAIL_IF_EXISTS |
OPEN_ACTION_CREATE_IF_NEW;
}
2011-03-17 02:37:06 +00:00
else if (flags & QSE_FIO_TRUNCATE)
{
open_action = OPEN_ACTION_REPLACE_IF_EXISTS |
OPEN_ACTION_CREATE_IF_NEW;
}
2011-03-17 02:37:06 +00:00
else
{
open_action = OPEN_ACTION_CREATE_IF_NEW |
OPEN_ACTION_OPEN_IF_EXISTS;
}
2011-03-17 02:37:06 +00:00
}
else if (flags & QSE_FIO_TRUNCATE)
{
open_action = OPEN_ACTION_REPLACE_IF_EXISTS |
OPEN_ACTION_FAIL_IF_NEW;
2011-03-17 02:37:06 +00:00
}
else
{
open_action = OPEN_ACTION_OPEN_IF_EXISTS |
OPEN_ACTION_FAIL_IF_NEW;
2011-03-17 02:37:06 +00:00
}
open_mode = OPEN_FLAGS_NOINHERIT;
if (flags & QSE_FIO_SYNC)
open_mode |= OPEN_FLAGS_WRITE_THROUGH;
if ((flags & QSE_FIO_NOSHREAD) && (flags & QSE_FIO_NOSHWRITE))
open_mode |= OPEN_SHARE_DENYREADWRITE;
else if (flags & QSE_FIO_NOSHREAD)
open_mode |= OPEN_SHARE_DENYREAD;
else if (flags & QSE_FIO_NOSHWRITE)
open_mode |= OPEN_SHARE_DENYWRITE;
else
open_mode |= OPEN_SHARE_DENYNONE;
2011-03-17 02:37:06 +00:00
if ((flags & QSE_FIO_READ) &&
(flags & QSE_FIO_WRITE)) open_mode |= OPEN_ACCESS_READWRITE;
else if (flags & QSE_FIO_READ) open_mode |= OPEN_ACCESS_READONLY;
else if (flags & QSE_FIO_WRITE) open_mode |= OPEN_ACCESS_WRITEONLY;
open_attr = (mode & QSE_FIO_WUSR)? FILE_NORMAL: FILE_READONLY;
2011-03-17 02:37:06 +00:00
ret = DosOpenL (
path_mb, /* file name */
2011-03-17 02:37:06 +00:00
&handle, /* file handle */
&action_taken, /* store action taken */
zero, /* size */
open_attr, /* attribute */
2011-03-17 02:37:06 +00:00
open_action, /* action if it exists */
open_mode, /* open mode */
0L
);
#if defined(QSE_CHAR_IS_MCHAR)
/* nothing to do */
#else
if (path_mb != path_mb_buf) QSE_MMGR_FREE (mmgr, path_mb);
#endif
if (ret != NO_ERROR)
{
if (flags & QSE_FIO_TEMPORARY) goto retry_temporary;
2012-02-12 13:20:39 +00:00
fio->errnum = syserr_to_errnum(ret);
return -1;
}
2011-03-15 09:40:35 +00:00
}
2011-05-05 09:11:23 +00:00
2011-05-04 08:00:38 +00:00
#elif defined(__DOS__)
2011-05-05 09:11:23 +00:00
if (flags & QSE_FIO_HANDLE)
{
handle = *(qse_fio_hnd_t*)path;
QSE_ASSERTX (
handle >= 0,
"Do not specify an invalid handle value"
);
2011-05-05 09:11:23 +00:00
}
else
{
int oflags = 0;
int permission = 0;
#if defined(QSE_CHAR_IS_MCHAR)
2011-05-05 09:11:23 +00:00
const qse_mchar_t* path_mb = path;
#else
qse_mchar_t path_mb_buf[_MAX_PATH];
qse_mchar_t* path_mb;
qse_size_t wl, ml;
int px;
path_mb = path_mb_buf;
ml = QSE_COUNTOF(path_mb_buf);
px = qse_wcstombs (path, &wl, path_mb, &ml);
if (px == -2)
{
path_mb = qse_wcstombsdup (path, QSE_NULL, mmgr);
2012-02-12 13:20:39 +00:00
if (path_mb == QSE_NULL)
{
fio->errnum = QSE_FIO_ENOMEM;
return -1;
}
}
else if (px <= -1)
{
fio->errnum = QSE_FIO_EINVAL;
return -1;
}
2011-05-05 09:11:23 +00:00
#endif
if (flags & QSE_FIO_APPEND)
{
if ((flags & QSE_FIO_READ)) oflags |= O_RDWR;
else oflags |= O_WRONLY;
oflags |= O_APPEND;
}
else
{
if ((flags & QSE_FIO_READ) &&
(flags & QSE_FIO_WRITE)) oflags |= O_RDWR;
else if (flags & QSE_FIO_READ) oflags |= O_RDONLY;
else if (flags & QSE_FIO_WRITE) oflags |= O_WRONLY;
}
if (flags & QSE_FIO_CREATE) oflags |= O_CREAT;
if (flags & QSE_FIO_TRUNCATE) oflags |= O_TRUNC;
if (flags & QSE_FIO_EXCLUSIVE) oflags |= O_EXCL;
oflags |= O_BINARY | O_NOINHERIT;
if (mode & QSE_FIO_RUSR) permission |= S_IREAD;
if (mode & QSE_FIO_WUSR) permission |= S_IWRITE;
handle = open (
path_mb,
oflags,
permission
);
#if defined(QSE_CHAR_IS_MCHAR)
/* nothing to do */
#else
if (path_mb != path_mb_buf) QSE_MMGR_FREE (mmgr, path_mb);
#endif
if (handle <= -1)
{
if (flags & QSE_FIO_TEMPORARY) goto retry_temporary;
2012-02-12 13:20:39 +00:00
fio->errnum = syserr_to_errnum (errno);
return -1;
}
2011-05-05 09:11:23 +00:00
}
#elif defined(vms) || defined(__vms)
if (flags & QSE_FIO_HANDLE)
{
/* TODO: implement this */
fio->errnum = QSE_FIO_ENOIMPL;
return -1;
}
else
{
struct FAB* fab;
struct RAB* rab;
unsigned long r0;
#if defined(QSE_CHAR_IS_MCHAR)
const qse_mchar_t* path_mb = path;
#else
qse_mchar_t path_mb_buf[1024];
qse_mchar_t* path_mb;
qse_size_t wl, ml;
int px;
2012-12-04 16:44:59 +00:00
if (flags & QSE_FIO_MBSPATH)
{
2012-12-04 16:44:59 +00:00
path_mb = (qse_mchar_t*)path;
}
else
{
path_mb = path_mb_buf;
ml = QSE_COUNTOF(path_mb_buf);
px = qse_wcstombs (path, &wl, path_mb, &ml);
if (px == -2)
{
2012-12-04 16:44:59 +00:00
/* the static buffer is too small.
* allocate a buffer */
path_mb = qse_wcstombsdup (path, mmgr);
if (path_mb == QSE_NULL)
{
fio->errnum = QSE_FIO_ENOMEM;
return -1;
}
}
else if (px <= -1)
{
fio->errnum = QSE_FIO_EINVAL;
return -1;
}
}
#endif
rab = (struct RAB*)QSE_MMGR_ALLOC (
mmgr, QSE_SIZEOF(*rab) + QSE_SIZEOF(*fab));
if (rab == QSE_NULL)
{
#if defined(QSE_CHAR_IS_MCHAR)
/* nothing to do */
#else
if (path_mb != path_mb_buf) QSE_MMGR_FREE (mmgr, path_mb);
#endif
fio->errnum = QSE_FIO_ENOMEM;
return -1;
}
fab = (struct FAB*)(rab + 1);
*rab = cc$rms_rab;
rab->rab$l_fab = fab;
*fab = cc$rms_fab;
fab->fab$l_fna = path_mb;
fab->fab$b_fns = strlen(path_mb);
fab->fab$b_org = FAB$C_SEQ;
fab->fab$b_rfm = FAB$C_VAR; /* FAB$C_STM, FAB$C_STMLF, FAB$C_VAR, etc... */
fab->fab$b_fac = FAB$M_GET | FAB$M_PUT;
fab->fab$b_fac = FAB$M_NIL;
if (flags & QSE_FIO_READ) fab->fab$b_fac |= FAB$M_GET;
if (flags & (QSE_FIO_WRITE | QSE_FIO_APPEND)) fab->fab$b_fac |= FAB$M_PUT | FAB$M_TRN; /* put, truncate */
fab->fab$b_shr |= FAB$M_SHRPUT | FAB$M_SHRGET; /* FAB$M_NIL */
if (flags & QSE_FIO_NOSHREAD) fab->fab$b_shr &= ~FAB$M_SHRGET;
if (flags & QSE_FIO_NOSHWRITE) fab->fab$b_shr &= ~FAB$M_SHRPUT;
if (flags & QSE_FIO_APPEND) rab->rab$l_rop |= RAB$M_EOF;
if (flags & QSE_FIO_CREATE)
{
if (flags & QSE_FIO_EXCLUSIVE)
fab->fab$l_fop &= ~FAB$M_CIF;
else
fab->fab$l_fop |= FAB$M_CIF;
r0 = sys$create (&fab, 0, 0);
}
else
{
r0 = sys$open (&fab, 0, 0);
}
if (r0 != RMS$_NORMAL && r0 != RMS$_CREATED)
{
#if defined(QSE_CHAR_IS_MCHAR)
/* nothing to do */
#else
if (path_mb != path_mb_buf) QSE_MMGR_FREE (mmgr, path_mb);
#endif
fio->errnum = syserr_to_errnum (r0);
return -1;
}
r0 = sys$connect (&rab, 0, 0);
if (r0 != RMS$_NORMAL)
{
#if defined(QSE_CHAR_IS_MCHAR)
/* nothing to do */
#else
if (path_mb != path_mb_buf) QSE_MMGR_FREE (mmgr, path_mb);
#endif
fio->errnum = syserr_to_errnum (r0);
return -1;
}
#if defined(QSE_CHAR_IS_MCHAR)
/* nothing to do */
#else
if (path_mb != path_mb_buf) QSE_MMGR_FREE (mmgr, path_mb);
#endif
handle = rab;
}
2008-11-27 03:05:00 +00:00
#else
2008-12-21 21:35:07 +00:00
if (flags & QSE_FIO_HANDLE)
2008-11-27 03:05:00 +00:00
{
2008-12-21 21:35:07 +00:00
handle = *(qse_fio_hnd_t*)path;
QSE_ASSERTX (
handle >= 0,
"Do not specify an invalid handle value"
);
2008-11-27 03:05:00 +00:00
}
else
{
2008-11-27 03:56:27 +00:00
int desired_access = 0;
2009-01-19 08:32:51 +00:00
#if defined(QSE_CHAR_IS_MCHAR)
2008-12-21 21:35:07 +00:00
const qse_mchar_t* path_mb = path;
2008-11-27 03:56:27 +00:00
#else
qse_mchar_t path_mb_buf[1024]; /* PATH_MAX instead? */
qse_mchar_t* path_mb;
qse_size_t wl, ml;
int px;
2012-12-04 16:44:59 +00:00
if (flags & QSE_FIO_MBSPATH)
{
2012-12-04 16:44:59 +00:00
path_mb = (qse_mchar_t*)path;
}
else
{
path_mb = path_mb_buf;
ml = QSE_COUNTOF(path_mb_buf);
px = qse_wcstombs (path, &wl, path_mb, &ml);
if (px == -2)
2012-02-12 13:20:39 +00:00
{
2012-12-04 16:44:59 +00:00
/* the static buffer is too small.
* allocate a buffer */
path_mb = qse_wcstombsdup (path, QSE_NULL, mmgr);
if (path_mb == QSE_NULL)
{
fio->errnum = QSE_FIO_ENOMEM;
return -1;
}
}
else if (px <= -1)
{
fio->errnum = QSE_FIO_EINVAL;
2012-02-12 13:20:39 +00:00
return -1;
}
}
2008-11-27 03:56:27 +00:00
#endif
/*
* rwa -> RDWR | APPEND
2008-12-12 23:47:07 +00:00
* ra -> RDWR | APPEND
* wa -> WRONLY | APPEND
* a -> WRONLY | APPEND
*/
if (flags & QSE_FIO_APPEND)
{
2008-12-21 21:35:07 +00:00
if ((flags & QSE_FIO_READ)) desired_access |= O_RDWR;
2008-12-12 23:47:07 +00:00
else desired_access |= O_WRONLY;
desired_access |= O_APPEND;
}
2008-12-12 23:47:07 +00:00
else
{
if ((flags & QSE_FIO_READ) &&
2008-12-21 21:35:07 +00:00
(flags & QSE_FIO_WRITE)) desired_access |= O_RDWR;
else if (flags & QSE_FIO_READ) desired_access |= O_RDONLY;
else if (flags & QSE_FIO_WRITE) desired_access |= O_WRONLY;
2008-12-12 23:47:07 +00:00
}
2008-11-27 03:05:00 +00:00
2008-12-21 21:35:07 +00:00
if (flags & QSE_FIO_CREATE) desired_access |= O_CREAT;
if (flags & QSE_FIO_TRUNCATE) desired_access |= O_TRUNC;
if (flags & QSE_FIO_EXCLUSIVE) desired_access |= O_EXCL;
if (flags & QSE_FIO_SYNC) desired_access |= O_SYNC;
2008-11-27 03:05:00 +00:00
2011-10-19 22:29:28 +00:00
#if defined(O_NOFOLLOW)
if (flags & QSE_FIO_NOFOLLOW) desired_access |= O_NOFOLLOW;
#endif
2008-11-27 03:05:00 +00:00
#if defined(O_LARGEFILE)
desired_access |= O_LARGEFILE;
#endif
#if defined(O_CLOEXEC)
desired_access |= O_CLOEXEC; /* no inherit */
#endif
2008-11-27 03:05:00 +00:00
2008-12-31 00:08:03 +00:00
handle = QSE_OPEN (path_mb, desired_access, mode);
#if defined(QSE_CHAR_IS_MCHAR)
/* nothing to do */
#else
if (path_mb != path_mb_buf) QSE_MMGR_FREE (mmgr, path_mb);
#endif
if (handle == -1)
{
if (flags & QSE_FIO_TEMPORARY) goto retry_temporary;
fio->errnum = syserr_to_errnum (errno);
return -1;
}
2008-11-27 03:05:00 +00:00
/* set some file access hints */
#if defined(POSIX_FADV_RANDOM)
if (flags & QSE_FIO_RANDOM)
posix_fadvise (handle, 0, 0, POSIX_FADV_RANDOM);
#endif
#if defined(POSIX_FADV_SEQUENTIAL)
if (flags & QSE_FIO_SEQUENTIAL)
posix_fadvise (handle, 0, 0, POSIX_FADV_SEQUENTIAL);
#endif
}
2008-11-27 03:05:00 +00:00
#endif
fio->handle = handle;
2011-09-01 09:43:46 +00:00
return 0;
2008-11-27 03:05:00 +00:00
}
2008-12-21 21:35:07 +00:00
void qse_fio_fini (qse_fio_t* fio)
2008-11-27 03:05:00 +00:00
{
if (!(fio->status & STATUS_NOCLOSE))
{
2011-03-15 09:40:35 +00:00
#if defined(_WIN32)
CloseHandle (fio->handle);
2011-03-17 02:37:06 +00:00
#elif defined(__OS2__)
DosClose (fio->handle);
2011-05-04 08:00:38 +00:00
#elif defined(__DOS__)
close (fio->handle);
#elif defined(vms) || defined(__vms)
struct RAB* rab = (struct RAB*)fio->handle;
sys$disconnect (rab, 0, 0);
sys$close ((struct FAB*)(rab + 1), 0, 0);
QSE_MMGR_FREE (fio->mmgr, fio->handle);
2008-11-27 03:05:00 +00:00
#else
QSE_CLOSE (fio->handle);
2008-11-27 03:05:00 +00:00
#endif
}
2008-11-27 03:05:00 +00:00
}
qse_mmgr_t* qse_fio_getmmgr (qse_fio_t* fio)
{
return fio->mmgr;
}
void* qse_fio_getxtn (qse_fio_t* fio)
{
return QSE_XTN (fio);
}
qse_fio_errnum_t qse_fio_geterrnum (const qse_fio_t* fio)
{
return fio->errnum;
}
qse_fio_hnd_t qse_fio_gethandle (const qse_fio_t* fio)
2008-11-27 03:05:00 +00:00
{
return fio->handle;
}
qse_ubi_t qse_fio_gethandleasubi (const qse_fio_t* fio)
{
2012-02-12 13:20:39 +00:00
qse_ubi_t handle;
#if defined(_WIN32)
handle.ptr = fio->handle;
#elif defined(__OS2__)
handle.ul = fio->handle;
#elif defined(__DOS__)
handle.i = fio->handle;
#elif defined(vms) || defined(__vms)
handle.ptr = fio->handle;
2012-02-12 13:20:39 +00:00
#else
handle.i = fio->handle;
#endif
return handle;
}
2008-12-21 21:35:07 +00:00
qse_fio_off_t qse_fio_seek (
qse_fio_t* fio, qse_fio_off_t offset, qse_fio_ori_t origin)
2008-11-27 03:05:00 +00:00
{
2011-03-15 09:40:35 +00:00
#if defined(_WIN32)
static int seek_map[] =
2008-11-27 03:05:00 +00:00
{
FILE_BEGIN,
FILE_CURRENT,
FILE_END
2008-11-27 03:05:00 +00:00
};
LARGE_INTEGER x;
#if 0
LARGE_INTEGER y;
#endif
2008-11-27 03:05:00 +00:00
2009-06-09 07:09:01 +00:00
QSE_ASSERT (QSE_SIZEOF(offset) <= QSE_SIZEOF(x.QuadPart));
2008-11-27 03:05:00 +00:00
2011-09-01 09:43:46 +00:00
/* SetFilePointerEx is not available on Windows NT 4.
* So let's use SetFilePointer */
2011-09-01 09:43:46 +00:00
#if 0
2008-11-27 03:05:00 +00:00
x.QuadPart = offset;
if (SetFilePointerEx (fio->handle, x, &y, seek_map[origin]) == FALSE)
{
2008-12-21 21:35:07 +00:00
return (qse_fio_off_t)-1;
}
2008-12-21 21:35:07 +00:00
return (qse_fio_off_t)y.QuadPart;
2011-09-01 09:43:46 +00:00
#endif
x.QuadPart = offset;
x.LowPart = SetFilePointer (
fio->handle, x.LowPart, &x.HighPart, seek_map[origin]);
if (x.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
{
2012-02-12 13:20:39 +00:00
fio->errnum = syserr_to_errnum (GetLastError());
2008-12-21 21:35:07 +00:00
return (qse_fio_off_t)-1;
}
2008-12-21 21:35:07 +00:00
return (qse_fio_off_t)x.QuadPart;
2011-09-01 09:43:46 +00:00
2011-03-17 02:37:06 +00:00
#elif defined(__OS2__)
static int seek_map[] =
{
FILE_BEGIN,
FILE_CURRENT,
FILE_END
};
LONGLONG pos, newpos;
APIRET ret;
QSE_ASSERT (QSE_SIZEOF(offset) >= QSE_SIZEOF(pos));
pos.ulLo = (ULONG)(offset&0xFFFFFFFFlu);
pos.ulHi = (ULONG)(offset>>32);
ret = DosSetFilePtrL (fio->handle, pos, seek_map[origin], &newpos);
2012-02-12 13:20:39 +00:00
if (ret != NO_ERROR)
{
fio->errnum = syserr_to_errnum (ret);
return (qse_fio_off_t)-1;
}
2011-03-17 02:37:06 +00:00
return ((qse_fio_off_t)pos.ulHi << 32) | pos.ulLo;
2011-05-04 08:00:38 +00:00
#elif defined(__DOS__)
2011-05-05 09:11:23 +00:00
static int seek_map[] =
{
SEEK_SET,
SEEK_CUR,
SEEK_END
};
2011-05-04 08:00:38 +00:00
2011-05-05 09:11:23 +00:00
return lseek (fio->handle, offset, seek_map[origin]);
#elif defined(vms) || defined(__vms)
/* TODO: */
fio->errnum = QSE_FIO_ENOIMPL;
return (qse_fio_off_t)-1;
2008-11-27 03:05:00 +00:00
#else
static int seek_map[] =
2008-11-27 03:05:00 +00:00
{
2011-03-15 09:40:35 +00:00
SEEK_SET,
2008-11-27 03:05:00 +00:00
SEEK_CUR,
SEEK_END
};
2009-01-05 07:38:55 +00:00
#if defined(QSE_LLSEEK)
2008-11-27 03:05:00 +00:00
loff_t tmp;
2009-01-05 07:38:55 +00:00
if (QSE_LLSEEK (fio->handle,
2008-11-27 03:05:00 +00:00
(unsigned long)(offset>>32),
(unsigned long)(offset&0xFFFFFFFFlu),
2008-11-27 03:05:00 +00:00
&tmp,
seek_map[origin]) == -1)
{
2012-02-12 13:20:39 +00:00
fio->errnum = syserr_to_errnum (errno);
2008-12-21 21:35:07 +00:00
return (qse_fio_off_t)-1;
}
2008-11-27 03:05:00 +00:00
2008-12-21 21:35:07 +00:00
return (qse_fio_off_t)tmp;
2008-11-27 03:05:00 +00:00
#else
2009-01-05 07:38:55 +00:00
return QSE_LSEEK (fio->handle, offset, seek_map[origin]);
2008-11-27 03:05:00 +00:00
#endif
#endif
}
2008-12-21 21:35:07 +00:00
int qse_fio_truncate (qse_fio_t* fio, qse_fio_off_t size)
2008-11-29 00:43:44 +00:00
{
#if defined(_WIN32)
2011-09-01 09:43:46 +00:00
#if 0
2008-11-29 00:43:44 +00:00
LARGE_INTEGER x;
x.QuadPart = size;
if (SetFilePointerEx(fio->handle,x,NULL,FILE_BEGIN) == FALSE ||
SetEndOfFile(fio->handle) == FALSE) return -1;
2011-09-01 09:43:46 +00:00
#endif
if (qse_fio_seek (fio, size, QSE_FIO_BEGIN) == (qse_fio_off_t)-1) return -1;
2012-02-12 13:20:39 +00:00
if (SetEndOfFile(fio->handle) == FALSE)
{
fio->errnum = syserr_to_errnum (GetLastError());
return -1;
}
2008-11-29 00:43:44 +00:00
2011-03-17 02:37:06 +00:00
return 0;
#elif defined(__OS2__)
APIRET ret;
LONGLONG sz;
/* the file must have the write access for it to succeed */
sz.ulLo = (ULONG)(size&0xFFFFFFFFlu);
sz.ulHi = (ULONG)(size>>32);
ret = DosSetFileSizeL (fio->handle, sz);
2012-02-12 13:20:39 +00:00
if (ret != NO_ERROR)
{
fio->errnum = syserr_to_errnum (ret);
return -1;
}
return 0;
2011-05-04 08:00:38 +00:00
#elif defined(__DOS__)
2011-05-05 09:11:23 +00:00
2012-02-12 13:20:39 +00:00
int n;
n = chsize (fio->handle, size);
if (n <= -1) fio->errnum = syserr_to_errnum (errno);
return n;
2011-05-04 08:00:38 +00:00
#elif defined(vms) || defined(__vms)
unsigned long r0;
struct RAB* rab = (struct RAB*)fio->handle;
if ((r0 = sys$rewind (rab, 0, 0)) != RMS$_NORMAL ||
(r0 = sys$truncate (rab, 0, 0)) != RMS$_NORMAL)
{
fio->errnum = syserr_to_errnum (r0);
return -1;
}
return 0;
2008-11-29 00:43:44 +00:00
#else
2012-02-12 13:20:39 +00:00
int n;
n = QSE_FTRUNCATE (fio->handle, size);
if (n <= -1) fio->errnum = syserr_to_errnum (errno);
return n;
2008-11-29 00:43:44 +00:00
#endif
}
2012-02-12 13:20:39 +00:00
qse_ssize_t qse_fio_read (qse_fio_t* fio, void* buf, qse_size_t size)
2008-11-27 03:05:00 +00:00
{
2011-03-15 09:40:35 +00:00
#if defined(_WIN32)
2011-05-05 09:11:23 +00:00
2008-11-27 03:05:00 +00:00
DWORD count;
2012-12-04 16:44:59 +00:00
if (size > (QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(DWORD)))
size = QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(DWORD);
2012-12-04 16:44:59 +00:00
if (ReadFile (fio->handle, buf, (DWORD)size, &count, QSE_NULL) == FALSE)
2012-02-12 13:20:39 +00:00
{
fio->errnum = syserr_to_errnum (GetLastError());
return -1;
}
2011-03-17 02:37:06 +00:00
return (qse_ssize_t)count;
2011-05-05 09:11:23 +00:00
2011-03-17 02:37:06 +00:00
#elif defined(__OS2__)
2011-05-05 09:11:23 +00:00
2012-02-12 13:20:39 +00:00
APIRET ret;
2011-03-17 02:37:06 +00:00
ULONG count;
if (size > (QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(ULONG)))
size = QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(ULONG);
2012-02-12 13:20:39 +00:00
ret = DosRead (fio->handle, buf, (ULONG)size, &count);
if (ret != NO_ERROR)
{
fio->errnum = syserr_to_errnum (ret);
return -1;
}
return (qse_ssize_t)count;
2011-05-04 08:00:38 +00:00
#elif defined(__DOS__)
2011-05-05 09:11:23 +00:00
2012-02-12 13:20:39 +00:00
int n;
if (size > (QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(unsigned int)))
size = QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(unsigned int);
n = read (fio->handle, buf, size);
if (n <= -1) fio->errnum = syserr_to_errnum (errno);
return n;
2011-05-05 09:11:23 +00:00
#elif defined(vms) || defined(__vms)
unsigned long r0;
struct RAB* rab = (struct RAB*)fio->handle;
if (size > 32767) size = 32767;
rab->rab$l_ubf = buf;
rab->rab$w_usz = size;
r0 = sys$get (rab, 0, 0);
if (r0 != RMS$_NORMAL)
{
fio->errnum = syserr_to_errnum (r0);
return -1;
}
return rab->rab$w_rsz;
2008-11-27 03:05:00 +00:00
#else
2012-02-12 13:20:39 +00:00
ssize_t n;
if (size > (QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(size_t)))
size = QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(size_t);
2012-02-12 13:20:39 +00:00
n = QSE_READ (fio->handle, buf, size);
if (n <= -1) fio->errnum = syserr_to_errnum (errno);
return n;
2008-11-27 03:05:00 +00:00
#endif
}
2012-02-12 13:20:39 +00:00
qse_ssize_t qse_fio_write (qse_fio_t* fio, const void* data, qse_size_t size)
2008-11-27 03:05:00 +00:00
{
2011-03-15 09:40:35 +00:00
#if defined(_WIN32)
2008-11-27 03:05:00 +00:00
DWORD count;
if (fio->status & STATUS_APPEND)
{
/* TODO: only when FILE_APPEND_DATA failed??? how do i know this??? */
/* i do this on a best-effort basis */
SetFilePointer (fio->handle, 0, QSE_NULL, FILE_END);
}
if (size > (QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(DWORD)))
size = QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(DWORD);
2011-05-05 09:11:23 +00:00
if (WriteFile (fio->handle,
2012-02-12 13:20:39 +00:00
data, (DWORD)size, &count, QSE_NULL) == FALSE)
{
fio->errnum = syserr_to_errnum (GetLastError());
return -1;
}
2011-03-17 02:37:06 +00:00
return (qse_ssize_t)count;
2011-05-05 09:11:23 +00:00
2011-03-17 02:37:06 +00:00
#elif defined(__OS2__)
2011-05-05 09:11:23 +00:00
2012-02-12 13:20:39 +00:00
APIRET ret;
2011-03-17 02:37:06 +00:00
ULONG count;
if (fio->status & STATUS_APPEND)
2012-02-12 13:20:39 +00:00
{
/* i do this on a best-effort basis */
LONGLONG pos, newpos;
pos.ulLo = (ULONG)0;
pos.ulHi = (ULONG)0;
DosSetFilePtrL (fio->handle, pos, FILE_END, &newpos);
}
if (size > (QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(ULONG)))
size = QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(ULONG);
2012-02-12 13:20:39 +00:00
ret = DosWrite(fio->handle,
(PVOID)data, (ULONG)size, &count);
if (ret != NO_ERROR)
{
fio->errnum = syserr_to_errnum (ret);
return -1;
}
return (qse_ssize_t)count;
2011-05-04 08:00:38 +00:00
#elif defined(__DOS__)
2011-05-05 09:11:23 +00:00
2012-02-12 13:20:39 +00:00
int n;
if (size > (QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(unsigned int)))
size = QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(unsigned int);
n = write (fio->handle, data, size);
if (n <= -1) fio->errnum = syserr_to_errnum (errno);
return n;
2011-05-05 09:11:23 +00:00
#elif defined(vms) || defined(__vms)
unsigned long r0;
struct RAB* rab = (struct RAB*)fio->handle;
if (size > 32767) size = 32767;
rab->rab$l_rbf = (char*)data;
rab->rab$w_rsz = size;
r0 = sys$put (rab, 0, 0);
if (r0 != RMS$_NORMAL)
{
fio->errnum = syserr_to_errnum (r0);
return -1;
}
return rab->rab$w_rsz;
2008-11-27 03:05:00 +00:00
#else
2011-05-05 09:11:23 +00:00
2012-02-12 13:20:39 +00:00
ssize_t n;
if (size > (QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(size_t)))
size = QSE_TYPE_MAX(qse_ssize_t) & QSE_TYPE_MAX(size_t);
2012-02-12 13:20:39 +00:00
n = QSE_WRITE (fio->handle, data, size);
if (n <= -1) fio->errnum = syserr_to_errnum (errno);
return n;
#endif
2009-01-27 09:26:15 +00:00
}
#if defined(_WIN32)
static int get_devname_from_handle (
2012-02-12 13:20:39 +00:00
qse_fio_t* fio, qse_char_t* buf, qse_size_t len)
{
HANDLE map = NULL;
void* mem = NULL;
DWORD olen;
HINSTANCE psapi;
typedef DWORD (WINAPI*getmappedfilename_t) (
HANDLE hProcess,
LPVOID lpv,
LPTSTR lpFilename,
DWORD nSize
);
getmappedfilename_t getmappedfilename;
/* try to load psapi.dll dynamially for
* systems without it. direct linking to the library
* may end up with dependency failure on such systems.
* this way, the worst case is that this function simply
* fails. */
psapi = LoadLibrary (QSE_T("PSAPI.DLL"));
if (!psapi)
{
fio->errnum = syserr_to_errnum (GetLastError());
return -1;
}
getmappedfilename = (getmappedfilename_t)
GetProcAddress (psapi, QSE_T("GetMappedFileName"));
if (!getmappedfilename)
{
fio->errnum = syserr_to_errnum (GetLastError());
FreeLibrary (psapi);
return -1;
}
/* create a file mapping object */
map = CreateFileMapping (
2012-02-12 13:20:39 +00:00
fio->handle,
NULL,
PAGE_READONLY,
0,
1,
NULL
);
2012-02-12 13:20:39 +00:00
if (map == NULL)
{
fio->errnum = syserr_to_errnum (GetLastError());
FreeLibrary (psapi);
2012-02-12 13:20:39 +00:00
return -1;
}
/* create a file mapping to get the file name. */
mem = MapViewOfFile (map, FILE_MAP_READ, 0, 0, 1);
if (mem == NULL)
{
2012-02-12 13:20:39 +00:00
fio->errnum = syserr_to_errnum (GetLastError());
CloseHandle (map);
FreeLibrary (psapi);
return -1;
}
olen = getmappedfilename (GetCurrentProcess(), mem, buf, len);
if (olen == 0)
{
2012-02-12 13:20:39 +00:00
fio->errnum = syserr_to_errnum (GetLastError());
UnmapViewOfFile (mem);
CloseHandle (map);
FreeLibrary (psapi);
return -1;
}
UnmapViewOfFile (mem);
CloseHandle (map);
FreeLibrary (psapi);
return 0;
}
static int get_volname_from_handle (
2012-02-12 13:20:39 +00:00
qse_fio_t* fio, qse_char_t* buf, qse_size_t len)
{
2012-02-12 13:20:39 +00:00
if (get_devname_from_handle (fio, buf, len) == -1) return -1;
if (qse_strcasebeg (buf, QSE_T("\\Device\\LanmanRedirector\\")))
{
/*buf[0] = QSE_T('\\');*/
qse_strcpy (&buf[1], &buf[24]);
}
else
{
DWORD n;
qse_char_t drives[128];
n = GetLogicalDriveStrings (QSE_COUNTOF(drives), drives);
if (n == 0 /* error */ ||
n > QSE_COUNTOF(drives) /* buffer small */)
{
2012-02-12 13:20:39 +00:00
fio->errnum = syserr_to_errnum (GetLastError());
return -1;
}
while (n > 0)
{
qse_char_t drv[3];
qse_char_t path[MAX_PATH];
drv[0] = drives[--n];
drv[1] = QSE_T(':');
drv[2] = QSE_T('\0');
if (QueryDosDevice (drv, path, QSE_COUNTOF(path)))
{
qse_size_t pl = qse_strlen(path);
qse_size_t bl = qse_strlen(buf);
if (bl > pl && buf[pl] == QSE_T('\\') &&
qse_strxncasecmp(buf, pl, path, pl) == 0)
{
buf[0] = drv[0];
buf[1] = QSE_T(':');
qse_strcpy (&buf[2], &buf[pl]);
break;
}
}
}
}
/* if the match is not found, the device name is returned
* without translation */
return 0;
}
#endif
int qse_fio_chmod (qse_fio_t* fio, int mode)
{
2011-03-15 09:40:35 +00:00
#if defined(_WIN32)
2011-05-05 09:11:23 +00:00
int flags = FILE_ATTRIBUTE_NORMAL;
qse_char_t name[MAX_PATH];
/* it is a best effort implementation. if the file size is 0,
2011-03-17 02:37:06 +00:00
* it can't even get the file name from the handle and thus fails.
* if GENERIC_READ is not set in CreateFile, CreateFileMapping fails.
* so if this fio is opened without QSE_FIO_READ, this function fails.
2011-03-15 09:40:35 +00:00
*/
2012-02-12 13:20:39 +00:00
if (get_volname_from_handle (fio, name, QSE_COUNTOF(name)) == -1) return -1;
if (!(mode & QSE_FIO_WUSR)) flags = FILE_ATTRIBUTE_READONLY;
2012-02-12 13:20:39 +00:00
if (SetFileAttributes (name, flags) == FALSE)
{
fio->errnum = syserr_to_errnum (GetLastError());
return -1;
}
return 0;
2011-05-05 09:11:23 +00:00
2011-03-17 02:37:06 +00:00
#elif defined(__OS2__)
2011-05-05 09:11:23 +00:00
2012-02-12 13:20:39 +00:00
APIRET n;
2011-03-17 02:37:06 +00:00
int flags = FILE_NORMAL;
FILESTATUS3L stat;
ULONG size = QSE_SIZEOF(stat);
2012-02-12 13:20:39 +00:00
n = DosQueryFileInfo (fio->handle, FIL_STANDARDL, &stat, size);
if (n != NO_ERROR)
{
fio->errnum = syserr_to_errnum (n);
return -1;
}
2011-03-17 02:37:06 +00:00
if (!(mode & QSE_FIO_WUSR)) flags = FILE_READONLY;
stat.attrFile = flags;
2012-02-12 13:20:39 +00:00
n = DosSetFileInfo (fio->handle, FIL_STANDARDL, &stat, size);
if (n != NO_ERROR)
{
fio->errnum = syserr_to_errnum (n);
return -1;
}
return 0;
2011-05-04 08:00:38 +00:00
#elif defined(__DOS__)
2011-05-05 09:11:23 +00:00
int permission = 0;
if (mode & QSE_FIO_RUSR) permission |= S_IREAD;
if (mode & QSE_FIO_WUSR) permission |= S_IWRITE;
/* TODO: fchmod not available. find a way to do this
return fchmod (fio->handle, permission); */
2012-02-12 13:20:39 +00:00
fio->errnum = QSE_FIO_ENOIMPL;
2011-05-04 08:00:38 +00:00
return -1;
2011-05-05 09:11:23 +00:00
#elif defined(vms) || defined(__vms)
/* TODO: */
fio->errnum = QSE_FIO_ENOIMPL;
return (qse_fio_off_t)-1;
#else
2012-02-12 13:20:39 +00:00
int n;
n = QSE_FCHMOD (fio->handle, mode);
if (n <= -1) fio->errnum = syserr_to_errnum (errno);
return n;
#endif
}
2009-01-19 08:32:51 +00:00
int qse_fio_sync (qse_fio_t* fio)
{
2011-03-15 09:40:35 +00:00
#if defined(_WIN32)
2011-05-05 09:11:23 +00:00
2012-02-12 13:20:39 +00:00
if (FlushFileBuffers (fio->handle) == FALSE)
{
fio->errnum = syserr_to_errnum (GetLastError());
return -1;
}
return 0;
2011-05-05 09:11:23 +00:00
2011-03-17 02:37:06 +00:00
#elif defined(__OS2__)
2011-05-05 09:11:23 +00:00
2012-02-12 13:20:39 +00:00
APIRET n;
n = DosResetBuffer (fio->handle);
if (n != NO_ERROR)
{
fio->errnum = syserr_to_errnum (n);
return -1;
}
return 0;
2011-05-04 08:00:38 +00:00
#elif defined(__DOS__)
2011-05-05 09:11:23 +00:00
2012-02-12 13:20:39 +00:00
int n;
n = fsync (fio->handle);
if (n <= -1) fio->errnum = syserr_to_errnum (errno);
return n;
2011-05-05 09:11:23 +00:00
#elif defined(vms) || defined(__vms)
/* TODO: */
fio->errnum = QSE_FIO_ENOIMPL;
return (qse_fio_off_t)-1;
2009-01-19 08:32:51 +00:00
#else
2011-05-05 09:11:23 +00:00
2012-02-12 13:20:39 +00:00
int n;
n = QSE_FSYNC (fio->handle);
if (n <= -1) fio->errnum = syserr_to_errnum (errno);
return n;
2009-01-19 08:32:51 +00:00
#endif
}
int qse_fio_lock (qse_fio_t* fio, qse_fio_lck_t* lck, int flags)
{
/* TODO: qse_fio_lock
* struct flock fl;
* fl.l_type = F_RDLCK, F_WRLCK;
* QSE_FCNTL (fio->handle, F_SETLK, &fl);
*/
2012-02-12 13:20:39 +00:00
fio->errnum = QSE_FIO_ENOIMPL;
2009-01-19 08:32:51 +00:00
return -1;
}
int qse_fio_unlock (qse_fio_t* fio, qse_fio_lck_t* lck, int flags)
{
/* TODO: qse_fio_unlock
* struct flock fl;
* fl.l_type = F_UNLCK;
* QSE_FCNTL (fio->handle, F_SETLK, &fl);
*/
2012-02-12 13:20:39 +00:00
fio->errnum = QSE_FIO_ENOIMPL;
2009-01-19 08:32:51 +00:00
return -1;
}
2009-01-27 09:26:15 +00:00
int qse_getstdfiohandle (qse_fio_std_t std, qse_fio_hnd_t* hnd)
{
#if defined(_WIN32)
DWORD tab[] =
{
STD_INPUT_HANDLE,
STD_OUTPUT_HANDLE,
STD_ERROR_HANDLE
};
#elif defined(vms) || defined(__vms)
/* TODO */
int tab[] = { 0, 1, 2 };
#else
qse_fio_hnd_t tab[] =
{
#if defined(__OS2__)
(HFILE)0, (HFILE)1, (HFILE)2
#elif defined(__DOS__)
0, 1, 2
#else
0, 1, 2
#endif
};
#endif
if (std < 0 || std >= QSE_COUNTOF(tab)) return -1;
#if defined(_WIN32)
{
HANDLE tmp = GetStdHandle (tab[std]);
if (tmp == INVALID_HANDLE_VALUE) return -1;
*hnd = tmp;
}
#elif defined(vms) || defined(__vms)
/* TODO: */
return -1;
#else
*hnd = tab[std];
#endif
return 0;
}