* source/rtl/net.c
* contrib/hbziparc/hbziparc.prg
* contrib/hbct/files.c
* Minor formatting.
* source/rtl/gtxwc/gtxwc.c
! Fix to recent fix. An '!' was missing, Przemek pls check me.
* source/rtl/philes.c
+ HB_PROGNAME() now returns absolute path in *NIX systems, too.
(please test and refine)
* source/lang/msgca.c
! Fixes from xhb.
* contrib/hbziparc/hbziparc.prg
* Minor correction ( = -> := )
* source/rtl/gtwin/gtwin.c
+ Added HB_GTI_CODEPAGE support.
As per MS docs, this works only when non-raster font is used
in the console window. Notice that the accepted CP values are
different from the GTWVT ones (GTWIN being the more "logical"
one, since it's a newer API). Currently, Harbour doesn't try
to hide these interface details.
; TODO: UNICODE and BOX char support for GTWIN mode.
* source/rtl/tbrowse.prg
* Using HB_DISPOUTATBOX() to draw column/header/footer separators.
; NOTE: This may cause problems if someone wants to use native
CP (accented or other special CP specific) chars to draw
these screen elements. Maybe an option should be added,
or some sort of markings in the separator strings to
control that.
Pls REVIEW.
* include/hbextern.ch
* source/rtl/console.c
+ Added HB_DISPOUTATBOX() which is similar to HB_DISPOUTAT(),
but marks the text drawn as HB_GT_ATTR_BOX, so these chars
can be properly displayed as drawing chars, regardless of
the selected codepage. Another difference is that this
function only supports strings to be printed. Other types
don't print anything.
; NOTE: Maybe this function could use a better name, pls
review and decide.
* source/rtl/gtwvt/gtwvt.c
* source/rtl/gtwvt/gtwvt.h
! Fixed not accepting zero as a HB_GTI_CODEPAGE value.
! Fixed HB_GTI_CODEPAGE to change the codepage.
+ Added box char support in Unicode mode.
For chars marked as HB_GT_ATTR_BOX, chars will be
mapped to Unicode according to CP437.
+ Added box char support in non-Unicode mode.
For chars marked as HB_GT_ATTR_BOX, OEM_CHARSET will
always be used.
; NOTE: This way it's possible to use ISO/WIN codepages with
GTWVT, while still being able to use various drawing
chars (lines, blocks, arrows).
; NOTE: The available set of drawing chars depends on the
OS OEM_CHARSET mapping _for non-Unicode Harbour_.
For Unicode Harbour, full CP437 codepage is
always available.
; NOTE: This solution doesn't go as far as (GTWXC) to
graphically draw / emulate these chars.
; TODO: Add HB_GTI_BOXCP support to change hard-wired "EN" CP.
* include/hbapigt.h
* include/hbgtcore.h
! Moved HB_GT_ATTR_* macros to public headers, because they
are needed for public API functions.
* contrib/hbwin/win_reg.prg
+ w32_regRead(): Added second parameter to specify the default
value returned in case the reg entry doesn't exist.
If not specified, NIL will be returned, just like before.
+ GetRegistry(): Added 4th parameter with same purpose as above.
* source/rtl/hbregex.c
* Minor opt.
* contrib/hbwin/win_misc.c
* Added command line option parameter to WIN_RUNDETACHED().
* include/hbapi.h
+ HB_ERRCODE (to replace ERRCODE)
+ HB_SUCCESS (to replace SUCCESS)
+ HB_FAILURE (to replace FAILURE)
+ contrib/hbwin/win_misc.c
* contrib/hbwin/common.mak
* contrib/hbwin/Makefile
+ WIN_SHELLEXECUTE()
WIN_RUNDETACHED()
WIN_LOADRESOURCE()
Added some new Windows API wrappers.
; TODO: Add hb_osEncode() to them.
* source/rtl/diskspac.c
* source/rtl/disksphb.c
! Fixed DISKSPACE() and HB_DISKSPACE() for Darwin.
Previously they had returned erroneous values.
; TOFIX: Probably HB_DISKSPACE() should be implemented for Watcom and CEGCC,
just like DISKSPACE() is.
* source/rtl/filesys.c
! hb_fsGetAttr() to set the returned attribute to zero
in case of error.
* include/hbextern.ch
* source/rtl/philes.c
+ HB_FSETATTR( <cFileName>, @<nAttr> ) -> <lSuccess>
+ HB_FGETATTR( <cFileName>, <nAttr> ) -> <lSuccess>
+ HB_FSETDATETIME( <cFileName>, [<dDate>], [<cTime HH:MM:SS>] ) -> <lSuccess>
* source/rtl/direct.c
! Fixed DIRECTORY() when called with "V" (label) parameter.
Tested under Windows. Please test/correct for other platforms.
On Windows, the dirspec should not contain a filemask in order
to work.
* contrib/hbtip/base64x.c
% HB_BASE64(): Optimized, cleaned.
! HB_BASE64(): Removed second parameter allowing to pass the length of
the string. This could cause GPF if passed incorrectly. Now length
is simply determined using hb_parclen().
; TOFIX: Input string size limit checking.
* include/hbdefs.h
+ HB_SIZEOFARRAY() macro, which does: ( sizeof( var ) / sizeof( *var ) )
To be really precise, f.e. all hb_strncpy() calls should use
'hb_strncpy( d, s, HB_SIZEOFARRAY( d ) );' instead of:
'hb_strncpy( d, s, sizeof( d ) );' (given that 'd' is allocated at compile time).
So that the code adapts to changing character sizes (like UTF-16/32).
It's useful in some other places, too.
* contrib/hbct/dattime2.c
* 0 -> FALSE for BOOL types.
* include/hbextern.ch
* source/rtl/strmatch.c
+ HB_WILDMATCHI(). Case-instenstive, exact match. First
two parameters and return value are the same as for
HB_WILDMATCH().
* include/hbextern.ch
* source/rtl/cdpapi.c
+ HB_CDPSELECT() which does the same as HB_SETCODEPAGE(), but
aligns well with function naming rules and namespace.
HB_SETCODEPAGE() still works, but usage is not recommended.
+ Added HB_CDPUNIID( <cHarbourCP> ) -> <cCPName>
This will return the std CP ID of a Harbour CP, or empty
if the Harbour CP isn't linked.
* include/hbapi.h
* source/rtl/is.c
! Fixed compile error when HB_CDP_SUPPORT_OFF is defined.
+ Added following functions:
hb_charIsDigit()
hb_charIsAlpha()
hb_charIsLower()
hb_charIsUpper()
* include/hbapi.h
- hb_strUpperCopy() removed. Implementation was missing.
* source/rtl/strcase.c
* Minor formatting.
* source/rtl/filesys.c
! hb_fsCurDirBuff() fixed potential buffer overrun by one byte.
* source/rtl/hbrunfun.c
* source/rtl/run.c
! Fixed missing header hbapiitm.h (after previous local change).
* include/hbapi.h
* include/hbset.h
* include/hbapifs.h
* include/set.ch
* source/rtl/hbffind.c
* source/rtl/gete.c
* source/rtl/filesys.c
* source/rtl/hbrunfun.c
* source/rtl/run.c
* source/rtl/philes.c
* source/vm/set.c
* source/vm/cmdarg.c
+ Added file system CP translation.
Set( _SET_FNAMECP[, <cCPID> ] ) -> <cOldCPID>
All operations passing filenames to/from the
OS will convert them to/from the host CP from/to
the FS CP specified using _SET_FNAMECP.
* hb_fsNameConv() extended to deal with CP
conversion, if requested by the app.
+ hb_fsNameConvFrom() (exported) added to deal
with CP conversions for filenames received from OS.
+ hb_fsNameConvTo() (exported) added to deal
with CP conversions for filenames/string sent to the OS.
+ Added hb_setGetFNAMECP() (exported) function.
+ Added hb_setGetFileCPTransTo(), hb_setGetFileCPTransFrom()
(non-exported) functions.
+ hb_fsCurDirBuff() and hb_fsFindNextLow() extended
to use hb_fsNameConvFrom().
+ Added hb_fsBaseDirBuff() to return the base
directory on the C level (based on argv[0]).
+ Added HB_PROGNAME() to return the executable
program name (based on argv[0]).
+ Added HB_DIRBASE() to return the executable
base directory (based on argv[0]).
* Renames done regarding OS/FS CP conversion:
hb_fsNameConvFrom() -> hb_osDecode()
hb_fsNameConvTo() -> hb_osEncode()
hb_setGetFileCPTransTo() -> -
hb_setGetFileCPTransFrom() -> -
hb_setGetFNAMECP() -> hb_setGetOSCODEPAGE()
_SET_FNAMECP -> _SET_OSCODEPAGE
* hb_osDecode()/hb_osEncode() extended to have a second
parameter BOOL * fFree.
Changed all calls to handle the case when fFree is set
to TRUE by hb_osDecode()/hb_osEncode().
+ HB_GETENV(): Added 3rd logical parameter to control wether
to convert the returned value from OS CP to Harbour CP.
The default is TRUE to be in sync with GETE[NV]() and the
rest of core.
* hb_fsNameConv() is now doing OS CP conversion using std APIs,
rather than duplicating such logic. I've traded some speed
for modularity.
* hb_osDecode/hb_osEncode() function declarations moved to hbapi.h
* hb_osDecode/hb_osEncode() function definitions moved to set.c
; NOTE: None of these were extensively tested, and I tend
to make mistakes when dealing with pointers.
It compiles cleanly with BCC, and some basic tests
worked, but bFree = TRUE codepaths are not yet
working so this needs more review.
* source/rtl/teditor.prg
* source/rtl/tpersist.prg
* utils/hbmake/hbmake.prg
* MemoRead() -> hb_MemoRead()
* contrib/hbct/files.c
; TOFIX: Many functions here are possibly not thread safe.
; TOFIX: Calling hb_fsFindClose() at app exit (and thus keeping
the FF handles open for the whole app lifetime) doesn't
play well with server side apps (as the app may run for
months or even longer), and even worse, they
will lock the passed directory so that they cannot be
removed (maybe even renamed), until the app exists.
At least on Windows.
* source/rtl/dirdrive.c
! Fixed to use F_ERROR instead of -1.
* include/hbextern.ch
! Added missing HB_GCSTEP().
* source/vm/extrap.c
+ Added CPU dump code for Windows x64.
+ Enabled module listing for Windows 64-bit platforms.
% Minor cleanup in Windows x86 CPU dump code.
+ Added TODO for Windows IA64 CPU dump.
+ Added TODO for Windows x64 stack walk, with pointers.
+ Added TOFIX regarding displaying module names in Windows x64 mode.
* source/rtl/fstemp.c
! Minor formatting.
* source/rtl/gete.c
* source/rtl/run.c
* source/rtl/hbrunfun.c
* source/vm/cmdarg.c
+ Added CP conversion to:
GETE[NV](), HB_GETENV(), __RUN(), HB_RUN(),
HB_ARGSTRING(), HB_CMDLINE().
; TODO: dbCreateTemp( <cAlias>, <aStruct>, <cRDD>, <cDelimArg>, <nConnection> ) -> <lSuccess>
Generates and opens a new dbf with a temporary filename
in exclusive mode, deletes it automatically when closed.
All indexes created for this table, should ideally have
the temporary flag on, so those get deleted too, when closed.
; TOFIX: hb_regex*() functions will not honor Harbour CP setting,
when case insensitivity is selected.
; TOFIX: hbct / SetFDaTi() to move any local logic into Harbour core
functions and use a simple Harbour API call only.
I'm not sure what is the reason with keeping the logic
duplicated here; if this isn't by intent, this function
could be much simplified.
; TOFIX: Avoid using C level toupper()/tolower()/islower()/isupper()
; TOFIX: hb_regexMatch()'s 3rd parameter has a double meaning.
It controls case-sensitivity (in sync with the documentation),
but it also controls if hb_regexMatch() behaves like
hb_regexLike() (.T.), or hb_regexHas() (.F.). This means
that hb_regexMatch(,, .T.) == hb_regexLike(,, .T.) (case-sensitive) and
hb_regexMatch(,, .F.) == hb_regexHas(,, .F.) (case-insensitive)
Maybe this was the intent of the original developers, but
to me it looks a rather strange behaviour which was added by
accidentally forgetting about the 3rd parameter already being
utilized. This either needs to be fixed, or properly documented.
; NOTE: Noteworthy links:
http://docs.python.org/3.0/whatsnew/3.0.html
- Unicode/text section
- Removed <> (use != instead)
http://sphinx.pocoo.org/
- Documentation format
http://fredeaker.blogspot.com/2007/01/character-encoding-detection.html
- Character encoding detection
3277 lines
84 KiB
C
3277 lines
84 KiB
C
/*
|
|
* $Id$
|
|
*/
|
|
|
|
/*
|
|
* Harbour Project source code:
|
|
* The FileSys API (C level)
|
|
*
|
|
* Copyright 1999 {list of individual authors and e-mail addresses}
|
|
* www - http://www.harbour-project.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, 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 software; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
* Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/).
|
|
*
|
|
* As a special exception, the Harbour Project gives permission for
|
|
* additional uses of the text contained in its release of Harbour.
|
|
*
|
|
* The exception is that, if you link the Harbour libraries with other
|
|
* files to produce an executable, this does not by itself cause the
|
|
* resulting executable to be covered by the GNU General Public License.
|
|
* Your use of that executable is in no way restricted on account of
|
|
* linking the Harbour library code into it.
|
|
*
|
|
* This exception does not however invalidate any other reasons why
|
|
* the executable file might be covered by the GNU General Public License.
|
|
*
|
|
* This exception applies only to the code released by the Harbour
|
|
* Project under the name Harbour. If you copy code from other
|
|
* Harbour Project or Free Software Foundation releases into a copy of
|
|
* Harbour, as the General Public License permits, the exception does
|
|
* not apply to the code that you add in this way. To avoid misleading
|
|
* anyone as to the status of such modified files, you must delete
|
|
* this exception notice from them.
|
|
*
|
|
* If you write modifications of your own for Harbour, it is your choice
|
|
* whether to permit this exception to apply to your modifications.
|
|
* If you do not wish that, delete this exception notice.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* The following parts are Copyright of the individual authors.
|
|
* www - http://www.harbour-project.org
|
|
*
|
|
* Copyright 1999-2001 Viktor Szakats <viktor.szakats@syenar.hu>
|
|
* hb_fsSetError()
|
|
* hb_fsSetDevMode()
|
|
* hb_fsReadLarge()
|
|
* hb_fsWriteLarge()
|
|
* hb_fsCurDirBuff()
|
|
* hb_fsBaseDirBuff()
|
|
*
|
|
* Copyright 1999 Jose Lalin <dezac@corevia.com>
|
|
* hb_fsChDrv()
|
|
* hb_fsCurDrv()
|
|
* hb_fsIsDrv()
|
|
* hb_fsIsDevice()
|
|
*
|
|
* Copyright 2000 Luiz Rafael Culik <culik@sl.conex.net>
|
|
* and David G. Holm <dholm@jsd-llc.com>
|
|
* hb_fsEof()
|
|
*
|
|
* Copyright 2001 Jose Gimenez (JFG) <jfgimenez@wanadoo.es>
|
|
* <tecnico.sireinsa@ctv.es>
|
|
* Added __WIN32__ check for any compiler to use the Win32
|
|
* API calls to allow openning an unlimited number of files
|
|
* simultaneously.
|
|
*
|
|
* See doc/license.txt for licensing terms.
|
|
*
|
|
*/
|
|
|
|
/* NOTE: In DOS/DJGPP under WinNT4 hb_fsSeek( fhnd, offset < 0, FS_SET ) will
|
|
set the file pointer to the passed negative value and the subsequent
|
|
hb_fsWrite() call will fail. In CA-Cl*pper, _fsSeek() will fail,
|
|
the pointer will not be moved and thus the _fsWrite() call will
|
|
successfully write the buffer to the current file position. [vszakats]
|
|
|
|
This has been corrected by ptucker
|
|
*/
|
|
|
|
/* *nixes */
|
|
#if !defined( _LARGEFILE64_SOURCE )
|
|
# define _LARGEFILE64_SOURCE
|
|
#endif
|
|
#if !defined( _XOPEN_SOURCE )
|
|
# define _XOPEN_SOURCE 500
|
|
#endif
|
|
|
|
/* OS2 */
|
|
#define INCL_DOSFILEMGR /* File Manager values */
|
|
#define INCL_DOSERRORS /* DOS error values */
|
|
#define INCL_DOSDATETIME /* DATETIME functions */
|
|
|
|
/* W32 */
|
|
#define HB_OS_WIN_32_USED
|
|
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
#include "hbapi.h"
|
|
#include "hbvm.h"
|
|
#include "hbstack.h"
|
|
#include "hbapifs.h"
|
|
#include "hbapierr.h"
|
|
#include "hbdate.h"
|
|
#include "hb_io.h"
|
|
#include "hbset.h"
|
|
|
|
#if defined(HB_OS_UNIX_COMPATIBLE)
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
#include <utime.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#endif
|
|
|
|
#if ( defined(__DMC__) || defined(__BORLANDC__) || \
|
|
defined(__IBMCPP__) || defined(_MSC_VER) || \
|
|
defined(__MINGW32__) || defined(__WATCOMC__) ) && \
|
|
!defined( HB_OS_UNIX ) && !defined( HB_WINCE )
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <process.h>
|
|
#if !defined( __POCC__ ) && !defined( __XCC__ )
|
|
#include <share.h>
|
|
#endif
|
|
#include <direct.h>
|
|
#if defined(__BORLANDC__)
|
|
#include <dir.h>
|
|
#include <dos.h>
|
|
#elif defined(__WATCOMC__)
|
|
#include <dos.h>
|
|
#endif
|
|
|
|
#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__DMC__)
|
|
#include <sys/locking.h>
|
|
#define ftruncate _chsize
|
|
#if defined(__MINGW32__) && !defined(_LK_UNLCK)
|
|
#define _LK_UNLCK _LK_UNLOCK
|
|
#endif
|
|
#else
|
|
#define ftruncate chsize
|
|
#endif
|
|
#if !defined(HAVE_POSIX_IO)
|
|
#define HAVE_POSIX_IO
|
|
#endif
|
|
#elif defined(__GNUC__) || defined(HB_OS_UNIX)
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#if defined(__CYGWIN__)
|
|
#include <io.h>
|
|
#elif defined(__DJGPP__)
|
|
#include <dir.h>
|
|
#include <utime.h>
|
|
#include <time.h>
|
|
#endif
|
|
#if !defined(HAVE_POSIX_IO)
|
|
#define HAVE_POSIX_IO
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(__MPW__)
|
|
#include <fcntl.h>
|
|
#endif
|
|
|
|
#if defined(HB_OS_DOS)
|
|
#include <dos.h>
|
|
#include <time.h>
|
|
#include <utime.h>
|
|
#elif defined(HB_OS_OS2)
|
|
#include <time.h>
|
|
#include <share.h>
|
|
#ifndef SH_COMPAT
|
|
#define SH_COMPAT 0x0000
|
|
#endif
|
|
#elif defined( HB_IO_WIN )
|
|
#include <windows.h>
|
|
|
|
#if !defined( INVALID_SET_FILE_POINTER ) && \
|
|
( defined(__DMC__) || defined( _MSC_VER ) || defined( __LCC__ ) )
|
|
#define INVALID_SET_FILE_POINTER ((DWORD)-1)
|
|
#endif
|
|
#if !defined( INVALID_FILE_ATTRIBUTES )
|
|
#define INVALID_FILE_ATTRIBUTES ( ( DWORD ) -1 )
|
|
#endif
|
|
#endif
|
|
#if defined( HB_USE_SHARELOCKS ) && defined( HB_USE_BSDLOCKS )
|
|
#include <sys/file.h>
|
|
#endif
|
|
|
|
#if !defined( HB_USE_LARGEFILE64 ) && defined( HB_OS_UNIX_COMPATIBLE )
|
|
#if defined( __USE_LARGEFILE64 )
|
|
/*
|
|
* The macro: __USE_LARGEFILE64 is set when _LARGEFILE64_SOURCE is
|
|
* define and efectively enables lseek64/flock64/ftruncate64 functions
|
|
* on 32bit machines.
|
|
*/
|
|
#define HB_USE_LARGEFILE64
|
|
#elif defined( HB_OS_HPUX ) && defined( O_LARGEFILE )
|
|
#define HB_USE_LARGEFILE64
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(HB_OS_HAS_DRIVE_LETTER)
|
|
/* 27/08/2004 - <maurilio.longo@libero.it>
|
|
HB_FS_GETDRIVE() should return a number in the range 0..25 ('A'..'Z')
|
|
HB_FS_SETDRIVE() should accept a number inside same range.
|
|
|
|
If a particular platform/compiler returns/accepts different ranges of
|
|
values, simply define a branch for that platform.
|
|
|
|
NOTE: There is not an implicit "current disk", ALWAYS use
|
|
|
|
my_func( hb_fsCurDrv(), ...)
|
|
|
|
to refer to current disk
|
|
*/
|
|
|
|
#if defined( __DJGPP__ )
|
|
#define HB_FS_GETDRIVE(n) do { n = getdisk(); } while( 0 )
|
|
#define HB_FS_SETDRIVE(n) setdisk( n )
|
|
|
|
#elif defined( __WATCOMC__ )
|
|
#define HB_FS_GETDRIVE(n) do { _dos_getdrive( &( n ) ); --( n ); } while( 0 )
|
|
#define HB_FS_SETDRIVE(n) do { \
|
|
UINT uiDummy; \
|
|
_dos_setdrive( ( n ) + 1, &uiDummy ); \
|
|
} while( 0 )
|
|
|
|
#elif defined(HB_OS_OS2)
|
|
#define HB_FS_GETDRIVE(n) do { n = _getdrive() - 'A'; } while( 0 )
|
|
#define HB_FS_SETDRIVE(n) _chdrive( ( n ) + 'A' )
|
|
|
|
#else
|
|
#define HB_FS_GETDRIVE(n) do { \
|
|
n = _getdrive(); \
|
|
n -= ( ( n ) < 'A' ) ? 1 : 'A'; \
|
|
} while( 0 )
|
|
#define HB_FS_SETDRIVE(n) _chdrive( ( n ) + 1 )
|
|
|
|
#endif
|
|
#endif /* HB_OS_HAS_DRIVE_LETTER */
|
|
|
|
#ifndef O_BINARY
|
|
#define O_BINARY 0 /* O_BINARY not defined on Linux */
|
|
#endif
|
|
|
|
#ifndef O_LARGEFILE
|
|
#define O_LARGEFILE 0 /* O_LARGEFILE is used for LFS in 32-bit Linux */
|
|
#endif
|
|
|
|
#if !defined( HB_OS_UNIX )
|
|
#if !defined( S_IREAD ) && defined( S_IRUSR )
|
|
#define S_IREAD S_IRUSR
|
|
#endif
|
|
#if !defined( S_IWRITE ) && defined( S_IWUSR )
|
|
#define S_IWRITE S_IWUSR
|
|
#endif
|
|
#if !defined( S_IEXEC ) && defined( S_IXUSR )
|
|
#define S_IEXEC S_IXUSR
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#if defined(HAVE_POSIX_IO) || defined( HB_IO_WIN ) || defined(_MSC_VER) || defined(__MINGW32__) || defined(__LCC__) || defined(__DMC__)
|
|
/* Only compilers with Posix or Posix-like I/O support are supported */
|
|
#define HB_FS_FILE_IO
|
|
#endif
|
|
|
|
#if defined(__DMC__) || defined(_MSC_VER) || defined(__MINGW32__) || defined(__IBMCPP__) || defined(__WATCOMC__) || defined(HB_OS_OS2)
|
|
/* These compilers use sopen() rather than open(), because their
|
|
versions of open() do not support combined O_ and SH_ flags */
|
|
#define HB_FS_SOPEN
|
|
#endif
|
|
|
|
#if UINT_MAX == USHRT_MAX
|
|
#define LARGE_MAX ( UINT_MAX - 1L )
|
|
#else
|
|
#define HB_FS_LARGE_OPTIMIZED
|
|
#endif
|
|
|
|
static BOOL s_fUseWaitLocks = TRUE;
|
|
|
|
#if defined(HB_FS_FILE_IO)
|
|
|
|
#if defined(HB_IO_WIN)
|
|
|
|
static HANDLE DosToWinHandle( HB_FHANDLE fHandle )
|
|
{
|
|
if( fHandle == ( HB_FHANDLE ) HB_STDIN_HANDLE )
|
|
return GetStdHandle( STD_INPUT_HANDLE );
|
|
|
|
else if( fHandle == ( HB_FHANDLE ) HB_STDOUT_HANDLE )
|
|
return GetStdHandle( STD_OUTPUT_HANDLE );
|
|
|
|
else if( fHandle == ( HB_FHANDLE ) HB_STDERR_HANDLE )
|
|
return GetStdHandle( STD_ERROR_HANDLE );
|
|
|
|
else
|
|
return ( HANDLE ) fHandle;
|
|
}
|
|
|
|
static void convert_open_flags( BOOL fCreate, ULONG ulAttr, USHORT uiFlags,
|
|
DWORD *dwMode, DWORD *dwShare,
|
|
DWORD *dwCreat, DWORD *dwAttr )
|
|
{
|
|
if( fCreate )
|
|
{
|
|
*dwCreat = CREATE_ALWAYS;
|
|
*dwMode = GENERIC_READ | GENERIC_WRITE;
|
|
}
|
|
else
|
|
{
|
|
if( uiFlags & FO_CREAT )
|
|
{
|
|
if( uiFlags & FO_EXCL )
|
|
*dwCreat = CREATE_NEW;
|
|
else if( uiFlags & FO_TRUNC )
|
|
*dwCreat = CREATE_ALWAYS;
|
|
else
|
|
*dwCreat = OPEN_ALWAYS;
|
|
}
|
|
else if( uiFlags & FO_TRUNC )
|
|
{
|
|
*dwCreat = TRUNCATE_EXISTING;
|
|
}
|
|
else
|
|
{
|
|
*dwCreat = OPEN_EXISTING;
|
|
}
|
|
|
|
*dwMode = 0;
|
|
switch( uiFlags & ( FO_READ | FO_WRITE | FO_READWRITE ) )
|
|
{
|
|
case FO_READWRITE:
|
|
*dwMode |= GENERIC_READ | GENERIC_WRITE;
|
|
break;
|
|
case FO_WRITE:
|
|
*dwMode |= GENERIC_WRITE;
|
|
break;
|
|
case FO_READ:
|
|
*dwMode |= GENERIC_READ;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* shared flags */
|
|
switch( uiFlags & ( FO_DENYREAD | FO_DENYWRITE | FO_EXCLUSIVE | FO_DENYNONE ) )
|
|
{
|
|
case FO_DENYREAD:
|
|
*dwShare = FILE_SHARE_WRITE;
|
|
break;
|
|
case FO_DENYWRITE:
|
|
*dwShare = FILE_SHARE_READ;
|
|
break;
|
|
case FO_EXCLUSIVE:
|
|
*dwShare = 0;
|
|
break;
|
|
default:
|
|
*dwShare = FILE_SHARE_WRITE | FILE_SHARE_READ;
|
|
break;
|
|
}
|
|
|
|
/* file attributes flags */
|
|
if( ulAttr == FC_NORMAL )
|
|
{
|
|
*dwAttr = FILE_ATTRIBUTE_NORMAL;
|
|
}
|
|
else
|
|
{
|
|
*dwAttr = FILE_ATTRIBUTE_ARCHIVE;
|
|
if( ulAttr & FC_READONLY )
|
|
*dwAttr |= FILE_ATTRIBUTE_READONLY;
|
|
if( ulAttr & FC_HIDDEN )
|
|
*dwAttr |= FILE_ATTRIBUTE_HIDDEN;
|
|
if( ulAttr & FC_SYSTEM )
|
|
*dwAttr |= FILE_ATTRIBUTE_SYSTEM;
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
static void convert_open_flags( BOOL fCreate, ULONG ulAttr, USHORT uiFlags,
|
|
int *flags, unsigned *mode,
|
|
int *share, int *attr )
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("convert_open_flags(%d, %lu, %hu, %p, %p, %p, %p)", fCreate, ulAttr, uiFlags, flags, mode, share, attr));
|
|
|
|
/* file access mode */
|
|
#if defined( HB_OS_UNIX )
|
|
*mode = HB_FA_POSIX_ATTR( ulAttr );
|
|
if( *mode == 0 )
|
|
{
|
|
*mode = ( ulAttr & FC_HIDDEN ) ? S_IRUSR : ( S_IRUSR | S_IRGRP | S_IROTH );
|
|
if( !( ulAttr & FC_READONLY ) )
|
|
{
|
|
if( *mode & S_IRUSR ) *mode |= S_IWUSR;
|
|
if( *mode & S_IRGRP ) *mode |= S_IWGRP;
|
|
if( *mode & S_IROTH ) *mode |= S_IWOTH;
|
|
}
|
|
if( ulAttr & FC_SYSTEM )
|
|
{
|
|
if( *mode & S_IRUSR ) *mode |= S_IXUSR;
|
|
if( *mode & S_IRGRP ) *mode |= S_IXGRP;
|
|
if( *mode & S_IROTH ) *mode |= S_IXOTH;
|
|
}
|
|
}
|
|
#else
|
|
*mode = S_IREAD |
|
|
( ( ulAttr & FC_READONLY ) ? 0 : S_IWRITE ) |
|
|
( ( ulAttr & FC_SYSTEM ) ? S_IEXEC : 0 );
|
|
#endif
|
|
|
|
/* dos file attributes */
|
|
#if defined( HB_FS_DOSATTR )
|
|
if( ulAttr == FC_NORMAL )
|
|
{
|
|
*attr = _A_NORMAL;
|
|
}
|
|
else
|
|
{
|
|
*attr = _A_ARCH;
|
|
if( ulAttr & FC_READONLY )
|
|
*attr |= _A_READONLY;
|
|
if( ulAttr & FC_HIDDEN )
|
|
*attr |= _A_HIDDEN;
|
|
if( ulAttr & FC_SYSTEM )
|
|
*attr |= _A_SYSTEM;
|
|
}
|
|
#else
|
|
*attr = 0;
|
|
#endif
|
|
|
|
if( fCreate )
|
|
{
|
|
*flags = O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE |
|
|
( ( uiFlags & FO_EXCL ) ? O_EXCL : 0 );
|
|
}
|
|
else
|
|
{
|
|
*attr = 0;
|
|
*flags = O_BINARY | O_LARGEFILE;
|
|
switch( uiFlags & ( FO_READ | FO_WRITE | FO_READWRITE ) )
|
|
{
|
|
case FO_READ:
|
|
*flags |= O_RDONLY;
|
|
break;
|
|
case FO_WRITE:
|
|
*flags |= O_WRONLY;
|
|
break;
|
|
case FO_READWRITE:
|
|
*flags |= O_RDWR;
|
|
break;
|
|
default:
|
|
/* this should not happen and it's here to force default OS behavior */
|
|
*flags |= ( O_RDONLY | O_WRONLY | O_RDWR );
|
|
break;
|
|
}
|
|
|
|
if( uiFlags & FO_CREAT ) *flags |= O_CREAT;
|
|
if( uiFlags & FO_TRUNC ) *flags |= O_TRUNC;
|
|
if( uiFlags & FO_EXCL ) *flags |= O_EXCL;
|
|
}
|
|
|
|
/* shared flags (HB_FS_SOPEN) */
|
|
#if defined( _MSC_VER ) || defined( __DMC__ )
|
|
if( ( uiFlags & FO_DENYREAD ) == FO_DENYREAD )
|
|
*share = _SH_DENYRD;
|
|
else if( uiFlags & FO_EXCLUSIVE )
|
|
*share = _SH_DENYRW;
|
|
else if( uiFlags & FO_DENYWRITE )
|
|
*share = _SH_DENYWR;
|
|
else if( uiFlags & FO_DENYNONE )
|
|
*share = _SH_DENYNO;
|
|
else
|
|
*share = _SH_COMPAT;
|
|
#elif !defined( HB_OS_UNIX )
|
|
if( ( uiFlags & FO_DENYREAD ) == FO_DENYREAD )
|
|
*share = SH_DENYRD;
|
|
else if( uiFlags & FO_EXCLUSIVE )
|
|
*share = SH_DENYRW;
|
|
else if( uiFlags & FO_DENYWRITE )
|
|
*share = SH_DENYWR;
|
|
else if( uiFlags & FO_DENYNONE )
|
|
*share = SH_DENYNO;
|
|
else
|
|
*share = SH_COMPAT;
|
|
#else
|
|
*share = 0;
|
|
#endif
|
|
|
|
HB_TRACE(HB_TR_INFO, ("convert_open_flags: flags=0x%04x, mode=0x%04x, share=0x%04x, attr=0x%04x", *flags, *mode, *share, *attr));
|
|
|
|
}
|
|
#endif
|
|
|
|
static USHORT convert_seek_flags( USHORT uiFlags )
|
|
{
|
|
/* by default FS_SET is set */
|
|
USHORT result_flags = SEEK_SET;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("convert_seek_flags(%hu)", uiFlags));
|
|
|
|
if( uiFlags & FS_RELATIVE )
|
|
result_flags = SEEK_CUR;
|
|
|
|
if( uiFlags & FS_END )
|
|
result_flags = SEEK_END;
|
|
|
|
return result_flags;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
* filesys.api functions:
|
|
*/
|
|
|
|
HB_FHANDLE hb_fsGetOsHandle( HB_FHANDLE hFileHandle )
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsGetOsHandle(%p)", ( void * ) ( HB_PTRDIFF ) hFileHandle));
|
|
|
|
#if defined(HB_IO_WIN)
|
|
return ( HB_FHANDLE ) DosToWinHandle( hFileHandle );
|
|
#else
|
|
return hFileHandle;
|
|
#endif
|
|
}
|
|
|
|
HB_FHANDLE hb_fsPOpen( BYTE * pFilename, BYTE * pMode )
|
|
{
|
|
HB_FHANDLE hFileHandle = FS_ERROR;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsPOpen(%p, %s)", pFilename, pMode));
|
|
|
|
#if defined(HB_OS_UNIX_COMPATIBLE) && !defined(__CYGWIN__)
|
|
{
|
|
HB_FHANDLE hPipeHandle[2], hNullHandle;
|
|
pid_t pid;
|
|
BYTE * pbyTmp;
|
|
BOOL bRead;
|
|
ULONG ulLen;
|
|
int iMaxFD;
|
|
|
|
ulLen = strlen( ( char * ) pFilename );
|
|
if( pMode && ( *pMode == 'r' || *pMode == 'w' ) )
|
|
bRead = ( *pMode == 'r' );
|
|
else
|
|
{
|
|
if( pFilename[0] == '|' )
|
|
bRead = FALSE;
|
|
else if( pFilename[ ulLen - 1 ] == '|' )
|
|
bRead = TRUE;
|
|
else
|
|
bRead = FALSE;
|
|
}
|
|
|
|
if( pFilename[0] == '|' )
|
|
{
|
|
++pFilename;
|
|
--ulLen;
|
|
}
|
|
if( pFilename[ ulLen - 1 ] == '|' )
|
|
{
|
|
pbyTmp = ( BYTE * ) hb_strdup( ( char * ) pFilename );
|
|
pbyTmp[--ulLen] = 0;
|
|
pFilename = pbyTmp;
|
|
} else
|
|
pbyTmp = NULL;
|
|
|
|
hb_vmUnlock();
|
|
if( pipe( hPipeHandle ) == 0 ) {
|
|
if( ( pid = fork() ) != -1 ) {
|
|
if( pid != 0 ) {
|
|
if( bRead ) {
|
|
close( hPipeHandle[ 1 ] );
|
|
hFileHandle = hPipeHandle[ 0 ];
|
|
} else {
|
|
close( hPipeHandle[ 0 ] );
|
|
hFileHandle = hPipeHandle[ 1 ];
|
|
}
|
|
} else {
|
|
char * argv[4];
|
|
argv[0] = ( char * ) "sh";
|
|
argv[1] = ( char * ) "-c";
|
|
argv[2] = ( char * ) pFilename;
|
|
argv[3] = ( char * ) 0;
|
|
hNullHandle = open( "/dev/null", O_RDWR );
|
|
if( bRead ) {
|
|
close( hPipeHandle[ 0 ] );
|
|
dup2( hPipeHandle[ 1 ], 1 );
|
|
dup2( hNullHandle, 0 );
|
|
dup2( hNullHandle, 2 );
|
|
} else {
|
|
close( hPipeHandle[ 1 ] );
|
|
dup2( hPipeHandle[ 0 ], 0 );
|
|
dup2( hNullHandle, 1 );
|
|
dup2( hNullHandle, 2 );
|
|
}
|
|
iMaxFD = sysconf( _SC_OPEN_MAX );
|
|
if( iMaxFD < 3 )
|
|
iMaxFD = 1024;
|
|
for( hNullHandle = 3; hNullHandle < iMaxFD; ++hNullHandle )
|
|
close( hNullHandle );
|
|
setuid( getuid() );
|
|
setgid( getgid() );
|
|
execv( "/bin/sh", argv );
|
|
exit(1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
close( hPipeHandle[0] );
|
|
close( hPipeHandle[1] );
|
|
}
|
|
}
|
|
hb_fsSetIOError( hFileHandle != FS_ERROR, 0 );
|
|
hb_vmLock();
|
|
|
|
if( pbyTmp )
|
|
hb_xfree( pbyTmp );
|
|
}
|
|
#else
|
|
|
|
HB_SYMBOL_UNUSED( pFilename );
|
|
HB_SYMBOL_UNUSED( pMode );
|
|
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
return hFileHandle;
|
|
}
|
|
|
|
HB_FHANDLE hb_fsOpen( BYTE * pFilename, USHORT uiFlags )
|
|
{
|
|
HB_FHANDLE hFileHandle;
|
|
BOOL fFree;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsOpen(%s, %hu)", pFilename, uiFlags));
|
|
|
|
pFilename = hb_fsNameConv( pFilename, &fFree );
|
|
|
|
#if defined(HB_IO_WIN)
|
|
{
|
|
DWORD dwMode, dwShare, dwCreat, dwAttr;
|
|
HANDLE hFile;
|
|
|
|
convert_open_flags( FALSE, FC_NORMAL, uiFlags, &dwMode, &dwShare, &dwCreat, &dwAttr );
|
|
|
|
hb_vmUnlock();
|
|
hFile = ( HANDLE ) CreateFileA( ( char * ) pFilename, dwMode, dwShare,
|
|
NULL, dwCreat, dwAttr, NULL );
|
|
hb_fsSetIOError( hFile != ( HANDLE ) INVALID_HANDLE_VALUE, 0 );
|
|
hb_vmLock();
|
|
|
|
hFileHandle = ( HB_FHANDLE ) hFile;
|
|
}
|
|
#elif defined(HB_FS_FILE_IO)
|
|
{
|
|
int flags, share, attr;
|
|
unsigned mode;
|
|
|
|
convert_open_flags( FALSE, FC_NORMAL, uiFlags, &flags, &mode, &share, &attr );
|
|
hb_vmUnlock();
|
|
#if defined(_MSC_VER) || defined(__DMC__)
|
|
if( share )
|
|
hFileHandle = _sopen( ( char * ) pFilename, flags, share, mode );
|
|
else
|
|
hFileHandle = _open( ( char * ) pFilename, flags, mode );
|
|
#elif defined(HB_FS_SOPEN)
|
|
if( share )
|
|
hFileHandle = sopen( ( char * ) pFilename, flags, share, mode );
|
|
else
|
|
hFileHandle = open( ( char * ) pFilename, flags, mode );
|
|
#else
|
|
hFileHandle = open( ( char * ) pFilename, flags | share, mode );
|
|
#endif
|
|
hb_fsSetIOError( hFileHandle != FS_ERROR, 0 );
|
|
hb_vmLock();
|
|
}
|
|
#else
|
|
|
|
hFileHandle = FS_ERROR;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
if( fFree )
|
|
hb_xfree( pFilename );
|
|
|
|
return hFileHandle;
|
|
}
|
|
|
|
HB_FHANDLE hb_fsCreate( BYTE * pFilename, ULONG ulAttr )
|
|
{
|
|
HB_FHANDLE hFileHandle;
|
|
BOOL fFree;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsCreate(%s, %lu)", pFilename, ulAttr));
|
|
|
|
pFilename = hb_fsNameConv( pFilename, &fFree );
|
|
|
|
#if defined(HB_IO_WIN)
|
|
{
|
|
DWORD dwMode, dwShare, dwCreat, dwAttr;
|
|
HANDLE hFile;
|
|
|
|
convert_open_flags( TRUE, ulAttr, FO_EXCLUSIVE, &dwMode, &dwShare, &dwCreat, &dwAttr );
|
|
|
|
hb_vmUnlock();
|
|
hFile = ( HANDLE ) CreateFileA( ( char * ) pFilename, dwMode, dwShare,
|
|
NULL, dwCreat, dwAttr, NULL );
|
|
hb_fsSetIOError( hFile != ( HANDLE ) INVALID_HANDLE_VALUE, 0 );
|
|
hb_vmLock();
|
|
|
|
hFileHandle = ( HB_FHANDLE ) hFile;
|
|
}
|
|
#elif defined(HB_FS_FILE_IO)
|
|
{
|
|
int flags, share, attr;
|
|
unsigned mode;
|
|
convert_open_flags( TRUE, ulAttr, FO_EXCLUSIVE, &flags, &mode, &share, &attr );
|
|
|
|
hb_vmUnlock();
|
|
#if defined(HB_FS_DOSCREAT)
|
|
hFileHandle = _creat( ( char * ) pFilename, attr );
|
|
#elif defined(HB_FS_SOPEN)
|
|
hFileHandle = open( ( char * ) pFilename, flags, mode );
|
|
#else
|
|
hFileHandle = open( ( char * ) pFilename, flags | share, mode );
|
|
#endif
|
|
hb_fsSetIOError( hFileHandle != FS_ERROR, 0 );
|
|
hb_vmLock();
|
|
}
|
|
#else
|
|
|
|
hFileHandle = FS_ERROR;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
if( fFree )
|
|
hb_xfree( pFilename );
|
|
|
|
return hFileHandle;
|
|
}
|
|
|
|
/* Derived from hb_fsCreate()
|
|
|
|
NOTE: The default opening mode differs from the one used in hb_fsCreate()
|
|
[vszakats]
|
|
*/
|
|
|
|
HB_FHANDLE hb_fsCreateEx( BYTE * pFilename, ULONG ulAttr, USHORT uiFlags )
|
|
{
|
|
HB_FHANDLE hFileHandle;
|
|
BOOL fFree;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsCreateEx(%s, %lu, %hu)", pFilename, ulAttr, uiFlags));
|
|
|
|
pFilename = hb_fsNameConv( pFilename, &fFree );
|
|
|
|
#if defined( HB_IO_WIN )
|
|
{
|
|
DWORD dwMode, dwShare, dwCreat, dwAttr;
|
|
HANDLE hFile;
|
|
|
|
convert_open_flags( TRUE, ulAttr, uiFlags, &dwMode, &dwShare, &dwCreat, &dwAttr );
|
|
|
|
hb_vmUnlock();
|
|
hFile = ( HANDLE ) CreateFileA( ( char * ) pFilename, dwMode, dwShare,
|
|
NULL, dwCreat, dwAttr, NULL );
|
|
hb_fsSetIOError( hFile != ( HANDLE ) INVALID_HANDLE_VALUE, 0 );
|
|
hb_vmLock();
|
|
|
|
hFileHandle = ( HB_FHANDLE ) hFile;
|
|
}
|
|
#elif defined(HB_FS_FILE_IO)
|
|
{
|
|
int flags, share, attr;
|
|
unsigned mode;
|
|
convert_open_flags( TRUE, ulAttr, uiFlags, &flags, &mode, &share, &attr );
|
|
|
|
hb_vmUnlock();
|
|
#if defined(HB_FS_SOPEN)
|
|
hFileHandle = open( ( char * ) pFilename, flags, mode );
|
|
#else
|
|
hFileHandle = open( ( char * ) pFilename, flags | share, mode );
|
|
#endif
|
|
hb_fsSetIOError( hFileHandle != FS_ERROR, 0 );
|
|
hb_vmLock();
|
|
}
|
|
#else
|
|
|
|
hFileHandle = FS_ERROR;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
if( fFree )
|
|
hb_xfree( pFilename );
|
|
|
|
return hFileHandle;
|
|
}
|
|
|
|
void hb_fsClose( HB_FHANDLE hFileHandle )
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsClose(%p)", ( void * ) ( HB_PTRDIFF ) hFileHandle));
|
|
|
|
#if defined(HB_FS_FILE_IO)
|
|
|
|
hb_vmUnlock();
|
|
#if defined(HB_IO_WIN)
|
|
hb_fsSetIOError( CloseHandle( DosToWinHandle( hFileHandle ) ), 0 );
|
|
#else
|
|
hb_fsSetIOError( close( hFileHandle ) == 0, 0 );
|
|
#endif
|
|
hb_vmLock();
|
|
|
|
#else
|
|
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
}
|
|
|
|
BOOL hb_fsSetDevMode( HB_FHANDLE hFileHandle, USHORT uiDevMode )
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsSetDevMode(%p, %hu)", ( void * ) ( HB_PTRDIFF ) hFileHandle, uiDevMode));
|
|
|
|
/* TODO: HB_IO_WIN support */
|
|
|
|
#if defined(__BORLANDC__) || defined(__IBMCPP__) || defined(__DJGPP__) || \
|
|
defined(__CYGWIN__) || defined(__WATCOMC__) || defined(HB_OS_OS2)
|
|
{
|
|
int iRet = 0;
|
|
|
|
#if defined(HB_IO_WIN)
|
|
if( hFileHandle != ( HB_FHANDLE ) 0 &&
|
|
hFileHandle != ( HB_FHANDLE ) 1 &&
|
|
hFileHandle != ( HB_FHANDLE ) 2 )
|
|
iRet = -1;
|
|
else
|
|
#endif
|
|
switch( uiDevMode )
|
|
{
|
|
case FD_BINARY:
|
|
iRet = setmode( ( HB_NHANDLE ) hFileHandle, O_BINARY );
|
|
break;
|
|
|
|
case FD_TEXT:
|
|
iRet = setmode( ( HB_NHANDLE ) hFileHandle, O_TEXT );
|
|
break;
|
|
}
|
|
|
|
hb_fsSetIOError( iRet != -1, 0 );
|
|
|
|
return iRet != -1;
|
|
}
|
|
#elif ( defined(_MSC_VER) || defined(__MINGW32__) || defined(__DMC__) ) && \
|
|
!defined(HB_WINCE)
|
|
{
|
|
int iRet = 0;
|
|
|
|
#if defined(HB_IO_WIN)
|
|
if( hFileHandle != ( HB_FHANDLE ) 0 &&
|
|
hFileHandle != ( HB_FHANDLE ) 1 &&
|
|
hFileHandle != ( HB_FHANDLE ) 2 )
|
|
iRet = -1;
|
|
else
|
|
#endif
|
|
switch( uiDevMode )
|
|
{
|
|
case FD_BINARY:
|
|
iRet = _setmode( ( HB_NHANDLE ) hFileHandle, _O_BINARY );
|
|
break;
|
|
|
|
case FD_TEXT:
|
|
iRet = _setmode( ( HB_NHANDLE ) hFileHandle, _O_TEXT );
|
|
break;
|
|
}
|
|
|
|
hb_fsSetIOError( iRet != -1, 0 );
|
|
|
|
return iRet != -1;
|
|
}
|
|
#elif defined( HB_OS_UNIX ) || defined( HB_WINCE )
|
|
|
|
HB_SYMBOL_UNUSED( hFileHandle );
|
|
|
|
if( uiDevMode == FD_TEXT )
|
|
{
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
return FALSE;
|
|
}
|
|
|
|
hb_fsSetError( 0 );
|
|
return TRUE;
|
|
|
|
#else
|
|
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
return FALSE;
|
|
|
|
#endif
|
|
}
|
|
|
|
BOOL hb_fsGetFileTime( BYTE * pszFileName, LONG * plJulian, LONG * plMillisec )
|
|
{
|
|
BOOL fResult;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsGetFileTime(%s, %p, %p)", pszFileName, plJulian, plMillisec));
|
|
|
|
fResult = FALSE;
|
|
|
|
#if defined( HB_IO_WIN )
|
|
{
|
|
HB_FHANDLE hFile = hb_fsOpen( pszFileName, FO_READ | FO_SHARED );
|
|
|
|
if( hFile != FS_ERROR )
|
|
{
|
|
FILETIME ft, local_ft;
|
|
SYSTEMTIME st;
|
|
|
|
hb_vmUnlock();
|
|
if( GetFileTime( DosToWinHandle( hFile ), NULL, NULL, &ft ) &&
|
|
FileTimeToLocalFileTime( &ft, &local_ft ) &&
|
|
FileTimeToSystemTime( &local_ft, &st ) )
|
|
{
|
|
*plJulian = hb_dateEncode( st.wYear, st.wMonth, st.wDay );
|
|
*plMillisec = hb_timeStampEncode( st.wHour, st.wMinute, st.wSecond, st.wMilliseconds );
|
|
|
|
fResult = TRUE;
|
|
}
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
hb_fsClose( hFile );
|
|
}
|
|
}
|
|
#elif defined( HB_OS_UNIX ) || defined( HB_OS_OS2 ) || defined( HB_OS_DOS ) || defined( __GNUC__ )
|
|
{
|
|
struct stat sStat;
|
|
BOOL fFree;
|
|
|
|
pszFileName = hb_fsNameConv( pszFileName, &fFree );
|
|
|
|
hb_vmUnlock();
|
|
if( stat( ( char * ) pszFileName, &sStat ) == 0 )
|
|
{
|
|
time_t ftime;
|
|
struct tm ft;
|
|
|
|
ftime = sStat.st_mtime;
|
|
# if _POSIX_C_SOURCE < 199506L || defined( HB_OS_DARWIN_5 )
|
|
ft = *localtime( &ftime );
|
|
# else
|
|
localtime_r( &ftime, &ft );
|
|
# endif
|
|
|
|
*plJulian = hb_dateEncode( ft.tm_year + 1900, ft.tm_mon + 1, ft.tm_mday );
|
|
*plMillisec = hb_timeStampEncode( ft.tm_hour, ft.tm_min, ft.tm_sec, 0 );
|
|
|
|
fResult = TRUE;
|
|
}
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
|
|
if( fFree )
|
|
hb_xfree( pszFileName );
|
|
}
|
|
#else
|
|
{
|
|
int TODO; /* TODO: for given platform */
|
|
|
|
HB_SYMBOL_UNUSED( pszFileName );
|
|
HB_SYMBOL_UNUSED( plJulian );
|
|
HB_SYMBOL_UNUSED( plMillisec );
|
|
}
|
|
#endif
|
|
|
|
return fResult;
|
|
}
|
|
|
|
BOOL hb_fsGetAttr( BYTE * pszFileName, ULONG * pulAttr )
|
|
{
|
|
BOOL fResult;
|
|
BOOL fFree;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsGetAttr(%s, %p)", pszFileName, pulAttr));
|
|
|
|
*pulAttr = 0;
|
|
fResult = FALSE;
|
|
pszFileName = hb_fsNameConv( pszFileName, &fFree );
|
|
|
|
#if defined( HB_OS_WIN_32 )
|
|
{
|
|
DWORD dwAttr;
|
|
|
|
hb_vmUnlock();
|
|
dwAttr = GetFileAttributesA( ( char * ) pszFileName );
|
|
|
|
if( dwAttr != INVALID_FILE_ATTRIBUTES )
|
|
{
|
|
*pulAttr = hb_fsAttrFromRaw( dwAttr );
|
|
fResult = TRUE;
|
|
}
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
}
|
|
#elif defined( HB_OS_DOS )
|
|
hb_vmUnlock();
|
|
{
|
|
#if defined( __DJGPP__ ) || defined(__BORLANDC__)
|
|
int attr = _chmod( ( char * ) pszFileName, 0, 0 );
|
|
if( attr != -1 )
|
|
#else
|
|
unsigned int attr = 0;
|
|
if( _dos_getfileattr( ( char * ) pszFileName, &attr ) == 0 )
|
|
#endif
|
|
{
|
|
*pulAttr = hb_fsAttrFromRaw( attr );
|
|
fResult = TRUE;
|
|
}
|
|
hb_fsSetIOError( fResult, 0 );
|
|
}
|
|
hb_vmLock();
|
|
#elif defined( HB_OS_OS2 )
|
|
{
|
|
FILESTATUS3 fs3;
|
|
APIRET ulrc;
|
|
|
|
hb_vmUnlock();
|
|
ulrc = DosQueryPathInfo( ( PCSZ ) pszFileName, FIL_STANDARD, &fs3, sizeof( fs3 ) );
|
|
if( ulrc == NO_ERROR )
|
|
{
|
|
*pulAttr = hb_fsAttrFromRaw( fs3.attrFile );
|
|
fResult = TRUE;
|
|
}
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
}
|
|
#elif defined( HB_OS_UNIX )
|
|
{
|
|
struct stat sStat;
|
|
|
|
hb_vmUnlock();
|
|
if( stat( ( char * ) pszFileName, &sStat ) == 0 )
|
|
{
|
|
*pulAttr = hb_fsAttrFromRaw( sStat.st_mode );
|
|
fResult = TRUE;
|
|
}
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
}
|
|
#else
|
|
{
|
|
int TODO; /* TODO: for given platform */
|
|
|
|
HB_SYMBOL_UNUSED( pszFileName );
|
|
HB_SYMBOL_UNUSED( pulAttr );
|
|
}
|
|
#endif
|
|
|
|
if( fFree )
|
|
hb_xfree( pszFileName );
|
|
|
|
return fResult;
|
|
}
|
|
|
|
BOOL hb_fsSetFileTime( BYTE * pszFileName, LONG lJulian, LONG lMillisec )
|
|
{
|
|
BOOL fResult;
|
|
int iYear, iMonth, iDay;
|
|
int iHour, iMinute, iSecond, iMSec;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsSetFileTime(%s, %ld, %ld)", pszFileName, lJulian, lMillisec));
|
|
|
|
hb_dateDecode( lJulian, &iYear, &iMonth, &iDay );
|
|
hb_timeStampDecode( lMillisec, &iHour, &iMinute, &iSecond, &iMSec );
|
|
|
|
#if defined( HB_OS_WIN_32 ) && !defined( __CYGWIN__ )
|
|
{
|
|
HB_FHANDLE hFile = hb_fsOpen( pszFileName, FO_READWRITE | FO_SHARED );
|
|
|
|
fResult = hFile != FS_ERROR;
|
|
if( fResult )
|
|
{
|
|
FILETIME ft, local_ft;
|
|
SYSTEMTIME st;
|
|
|
|
hb_vmUnlock();
|
|
if( lJulian <= 0 || lMillisec < 0 )
|
|
GetLocalTime( &st );
|
|
else
|
|
memset( &st, 0, sizeof( st ) );
|
|
|
|
if( lJulian > 0 )
|
|
{
|
|
st.wYear = ( WORD ) iYear;
|
|
st.wMonth = ( WORD ) iMonth;
|
|
st.wDay = ( WORD ) iDay;
|
|
}
|
|
if( lMillisec >= 0 )
|
|
{
|
|
st.wHour = ( WORD ) iHour;
|
|
st.wMinute = ( WORD ) iMinute;
|
|
st.wSecond = ( WORD ) iSecond;
|
|
st.wMilliseconds = ( WORD ) iMSec;
|
|
}
|
|
SystemTimeToFileTime( &st, &local_ft );
|
|
LocalFileTimeToFileTime( &local_ft, &ft );
|
|
fResult = SetFileTime( DosToWinHandle( hFile ), NULL, &ft, &ft ) != 0;
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
hb_fsClose( hFile );
|
|
}
|
|
}
|
|
#elif defined( HB_OS_OS2 )
|
|
{
|
|
FILESTATUS3 fs3;
|
|
APIRET ulrc;
|
|
BOOL fFree;
|
|
|
|
pszFileName = hb_fsNameConv( pszFileName, &fFree );
|
|
|
|
hb_vmUnlock();
|
|
ulrc = DosQueryPathInfo( ( PCSZ ) pszFileName, FIL_STANDARD, &fs3, sizeof( fs3 ) );
|
|
if( ulrc == NO_ERROR )
|
|
{
|
|
FDATE fdate;
|
|
FTIME ftime;
|
|
|
|
if( lJulian <= 0 || lMillisec < 0 )
|
|
{
|
|
DATETIME dt;
|
|
|
|
DosGetDateTime( &dt );
|
|
|
|
fdate.year = dt.year - 1980;
|
|
fdate.month = dt.month;
|
|
fdate.day = dt.day;
|
|
ftime.hours = dt.hours;
|
|
ftime.minutes = dt.minutes;
|
|
ftime.twosecs = dt.seconds / 2;
|
|
}
|
|
if( lJulian > 0 )
|
|
{
|
|
fdate.year = iYear - 1980;
|
|
fdate.month = iMonth;
|
|
fdate.day = iDay;
|
|
}
|
|
if( lMillisec >= 0 )
|
|
{
|
|
ftime.hours = iHour;
|
|
ftime.minutes = iMinute;
|
|
ftime.twosecs = iSecond / 2;
|
|
}
|
|
|
|
fs3.fdateCreation = fs3.fdateLastAccess = fs3.fdateLastWrite = fdate;
|
|
fs3.ftimeCreation = fs3.ftimeLastAccess = fs3.ftimeLastWrite = ftime;
|
|
ulrc = DosSetPathInfo( ( PCSZ ) pszFileName, FIL_STANDARD,
|
|
&fs3, sizeof( fs3 ), DSPI_WRTTHRU );
|
|
}
|
|
fResult = ulrc == NO_ERROR;
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
if( fFree )
|
|
hb_xfree( pszFileName );
|
|
}
|
|
#elif defined( HB_OS_UNIX_COMPATIBLE ) || defined( HB_OS_DOS )
|
|
{
|
|
BOOL fFree;
|
|
|
|
pszFileName = hb_fsNameConv( pszFileName, &fFree );
|
|
|
|
hb_vmUnlock();
|
|
if( lJulian <= 0 && lMillisec )
|
|
{
|
|
fResult = utime( ( char * ) pszFileName, NULL ) == 0;
|
|
}
|
|
else
|
|
{
|
|
struct utimbuf buf;
|
|
struct tm new_value;
|
|
time_t tim;
|
|
|
|
if( lJulian <= 0 || lMillisec < 0 )
|
|
{
|
|
time_t current_time;
|
|
|
|
current_time = time( NULL );
|
|
# if _POSIX_C_SOURCE < 199506L || defined( HB_OS_DARWIN_5 )
|
|
new_value = *localtime( ¤t_time );
|
|
# else
|
|
localtime_r( ¤t_time, &new_value );
|
|
# endif
|
|
}
|
|
else
|
|
memset( &new_value, 0, sizeof( new_value ) );
|
|
|
|
if( lJulian > 0 )
|
|
{
|
|
new_value.tm_year = iYear - 1900;
|
|
new_value.tm_mon = iMonth - 1;
|
|
new_value.tm_mday = iDay;
|
|
}
|
|
if( lMillisec >= 0 )
|
|
{
|
|
new_value.tm_hour = iHour;
|
|
new_value.tm_min = iMinute;
|
|
new_value.tm_sec = iSecond;
|
|
}
|
|
tim = mktime( &new_value );
|
|
# if _POSIX_C_SOURCE < 199506L || defined( HB_OS_DARWIN_5 )
|
|
new_value = *gmtime( &tim );
|
|
# else
|
|
gmtime_r( &tim, &new_value );
|
|
# endif
|
|
buf.actime = buf.modtime = mktime( &new_value );
|
|
fResult = utime( ( char * ) pszFileName, &buf ) == 0;
|
|
}
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
if( fFree )
|
|
hb_xfree( pszFileName );
|
|
}
|
|
#else
|
|
{
|
|
int TODO; /* To force warning */
|
|
|
|
fResult = FALSE;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
}
|
|
#endif
|
|
|
|
return fResult;
|
|
}
|
|
|
|
BOOL hb_fsSetAttr( BYTE * pszFileName, ULONG ulAttr )
|
|
{
|
|
BOOL fResult;
|
|
BOOL fFree;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsSetAttr(%s, %lu)", pszFileName, ulAttr));
|
|
|
|
pszFileName = hb_fsNameConv( pszFileName, &fFree );
|
|
|
|
#if defined( HB_OS_WIN_32 )
|
|
{
|
|
DWORD dwFlags = FILE_ATTRIBUTE_ARCHIVE;
|
|
|
|
if( ulAttr & HB_FA_READONLY )
|
|
dwFlags |= FILE_ATTRIBUTE_READONLY;
|
|
if( ulAttr & HB_FA_HIDDEN )
|
|
dwFlags |= FILE_ATTRIBUTE_HIDDEN;
|
|
if( ulAttr & HB_FA_SYSTEM )
|
|
dwFlags |= FILE_ATTRIBUTE_SYSTEM;
|
|
if( ulAttr & HB_FA_NORMAL )
|
|
dwFlags |= FILE_ATTRIBUTE_NORMAL;
|
|
hb_vmUnlock();
|
|
fResult = SetFileAttributesA( ( char * ) pszFileName, dwFlags );
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
}
|
|
#elif defined( HB_OS_OS2 )
|
|
{
|
|
FILESTATUS3 fs3;
|
|
APIRET ulrc;
|
|
ULONG ulOsAttr = FILE_NORMAL;
|
|
|
|
if( ulAttr & HB_FA_READONLY )
|
|
ulOsAttr |= FILE_READONLY;
|
|
if( ulAttr & HB_FA_HIDDEN )
|
|
ulOsAttr |= FILE_HIDDEN;
|
|
if( ulAttr & HB_FA_SYSTEM )
|
|
ulOsAttr |= FILE_SYSTEM;
|
|
if( ulAttr & HB_FA_ARCHIVE )
|
|
ulOsAttr |= FILE_ARCHIVED;
|
|
|
|
hb_vmUnlock();
|
|
ulrc = DosQueryPathInfo( ( PCSZ ) pszFileName, FIL_STANDARD, &fs3, sizeof( fs3 ) );
|
|
if( ulrc == NO_ERROR )
|
|
{
|
|
fs3.attrFile = ulOsAttr;
|
|
ulrc = DosSetPathInfo( ( PCSZ ) pszFileName, FIL_STANDARD,
|
|
&fs3, sizeof( fs3 ), DSPI_WRTTHRU );
|
|
}
|
|
fResult = ulrc == NO_ERROR;
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
}
|
|
#elif defined( HB_OS_DOS )
|
|
|
|
ulAttr &= ~( HB_FA_ARCHIVE | HB_FA_HIDDEN | HB_FA_READONLY | HB_FA_SYSTEM );
|
|
hb_vmUnlock();
|
|
# if defined( __DJGPP__ ) || defined( __BORLANDC__ )
|
|
fResult = _chmod( ( char * ) pszFileName, 1, ulAttr ) != -1;
|
|
# else
|
|
fResult = _dos_setfileattr( ( char * ) pszFileName, ulAttr ) != -1;
|
|
# endif
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#elif defined( HB_OS_UNIX_COMPATIBLE )
|
|
{
|
|
int iAttr = HB_FA_POSIX_ATTR( ulAttr );
|
|
if( iAttr == 0 )
|
|
{
|
|
iAttr = ( ulAttr & HB_FA_HIDDEN ) ? S_IRUSR : ( S_IRUSR | S_IRGRP | S_IROTH );
|
|
if( !( ulAttr & HB_FA_READONLY ) )
|
|
{
|
|
if( iAttr & S_IRUSR ) iAttr |= S_IWUSR;
|
|
if( iAttr & S_IRGRP ) iAttr |= S_IWGRP;
|
|
if( iAttr & S_IROTH ) iAttr |= S_IWOTH;
|
|
}
|
|
if( ulAttr & HB_FA_SYSTEM )
|
|
{
|
|
if( iAttr & S_IRUSR ) iAttr |= S_IXUSR;
|
|
if( iAttr & S_IRGRP ) iAttr |= S_IXGRP;
|
|
if( iAttr & S_IROTH ) iAttr |= S_IXOTH;
|
|
}
|
|
}
|
|
hb_vmUnlock();
|
|
fResult = chmod( ( char * ) pszFileName, iAttr ) != -1;
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
}
|
|
#else
|
|
{
|
|
int TODO; /* To force warning */
|
|
|
|
fResult = FALSE;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
}
|
|
#endif
|
|
|
|
if( fFree )
|
|
hb_xfree( pszFileName );
|
|
|
|
return fResult;
|
|
}
|
|
|
|
USHORT hb_fsRead( HB_FHANDLE hFileHandle, BYTE * pBuff, USHORT uiCount )
|
|
{
|
|
USHORT uiRead;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsRead(%p, %p, %hu)", ( void * ) ( HB_PTRDIFF ) hFileHandle, pBuff, uiCount));
|
|
|
|
#if defined(HB_FS_FILE_IO)
|
|
|
|
#if defined(HB_IO_WIN)
|
|
{
|
|
DWORD dwRead;
|
|
BOOL fResult;
|
|
|
|
hb_vmUnlock();
|
|
fResult = ReadFile( DosToWinHandle( hFileHandle ), pBuff, ( DWORD ) uiCount, &dwRead, NULL );
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
|
|
uiRead = fResult ? ( USHORT ) dwRead : 0;
|
|
}
|
|
#else
|
|
hb_vmUnlock();
|
|
uiRead = read( hFileHandle, pBuff, uiCount );
|
|
hb_fsSetIOError( uiRead != ( USHORT ) -1, 0 );
|
|
hb_vmLock();
|
|
#endif
|
|
|
|
if( uiRead == ( USHORT ) -1 )
|
|
uiRead = 0;
|
|
|
|
#else
|
|
|
|
uiRead = 0;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
return uiRead;
|
|
}
|
|
|
|
USHORT hb_fsWrite( HB_FHANDLE hFileHandle, const BYTE * pBuff, USHORT uiCount )
|
|
{
|
|
USHORT uiWritten;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsWrite(%p, %p, %hu)", ( void * ) ( HB_PTRDIFF ) hFileHandle, pBuff, uiCount));
|
|
|
|
#if defined(HB_FS_FILE_IO)
|
|
|
|
#if defined(HB_IO_WIN)
|
|
{
|
|
DWORD dwWritten = 0;
|
|
BOOL fResult;
|
|
|
|
hb_vmUnlock();
|
|
if( uiCount )
|
|
{
|
|
fResult = WriteFile( DosToWinHandle( hFileHandle ), pBuff, uiCount, &dwWritten, NULL );
|
|
}
|
|
else
|
|
{
|
|
dwWritten = 0;
|
|
fResult = SetEndOfFile( DosToWinHandle( hFileHandle ) );
|
|
}
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
|
|
uiWritten = fResult ? ( USHORT ) dwWritten : 0;
|
|
}
|
|
#else
|
|
if( uiCount )
|
|
{
|
|
hb_vmUnlock();
|
|
uiWritten = write( hFileHandle, pBuff, uiCount );
|
|
hb_fsSetIOError( uiWritten != ( USHORT ) -1, 0 );
|
|
if( uiWritten == ( USHORT ) -1 )
|
|
uiWritten = 0;
|
|
hb_vmLock();
|
|
}
|
|
else
|
|
{
|
|
hb_vmUnlock();
|
|
#if defined(HB_USE_LARGEFILE64)
|
|
hb_fsSetIOError( ftruncate64( hFileHandle, lseek64( hFileHandle, 0L, SEEK_CUR ) ) != -1, 0 );
|
|
#else
|
|
hb_fsSetIOError( ftruncate( hFileHandle, lseek( hFileHandle, 0L, SEEK_CUR ) ) != -1, 0 );
|
|
#endif
|
|
uiWritten = 0;
|
|
hb_vmLock();
|
|
}
|
|
#endif
|
|
#else
|
|
|
|
uiWritten = 0;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
return uiWritten;
|
|
}
|
|
|
|
ULONG hb_fsReadLarge( HB_FHANDLE hFileHandle, BYTE * pBuff, ULONG ulCount )
|
|
{
|
|
ULONG ulRead;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsReadLarge(%p, %p, %lu)", ( void * ) ( HB_PTRDIFF ) hFileHandle, pBuff, ulCount));
|
|
|
|
#if defined(HB_FS_FILE_IO)
|
|
|
|
#if defined(HB_IO_WIN)
|
|
{
|
|
hb_vmUnlock();
|
|
hb_fsSetIOError( ReadFile( DosToWinHandle( hFileHandle ),
|
|
pBuff, ulCount, &ulRead, NULL ), 0 );
|
|
hb_vmLock();
|
|
}
|
|
#elif defined(HB_FS_LARGE_OPTIMIZED)
|
|
{
|
|
hb_vmUnlock();
|
|
ulRead = read( hFileHandle, pBuff, ulCount );
|
|
hb_fsSetIOError( ulRead != (ULONG) -1, 0 );
|
|
if( ulRead == ( ULONG ) -1 )
|
|
ulRead = 0;
|
|
hb_vmLock();
|
|
}
|
|
#else
|
|
{
|
|
ULONG ulLeftToRead = ulCount;
|
|
USHORT uiToRead;
|
|
USHORT uiRead;
|
|
BYTE * pPtr = pBuff;
|
|
|
|
ulRead = 0;
|
|
|
|
hb_vmUnlock();
|
|
while( ulLeftToRead )
|
|
{
|
|
/* Determine how much to read this time */
|
|
if( ulLeftToRead > ( ULONG ) INT_MAX )
|
|
{
|
|
uiToRead = INT_MAX;
|
|
ulLeftToRead -= ( ULONG ) uiToRead;
|
|
}
|
|
else
|
|
{
|
|
uiToRead = ( USHORT ) ulLeftToRead;
|
|
ulLeftToRead = 0;
|
|
}
|
|
|
|
uiRead = read( hFileHandle, pPtr, uiToRead );
|
|
/* -1 on bad hFileHandle
|
|
0 on disk full
|
|
*/
|
|
|
|
if( uiRead == 0 )
|
|
break;
|
|
|
|
if( uiRead == ( USHORT ) -1 )
|
|
{
|
|
uiRead = 0;
|
|
break;
|
|
}
|
|
|
|
ulRead += ( ULONG ) uiRead;
|
|
pPtr += uiRead;
|
|
}
|
|
hb_fsSetIOError( ulLeftToRead == 0, 0 );
|
|
hb_vmLock();
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
|
|
ulRead = 0;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
return ulRead;
|
|
}
|
|
|
|
ULONG hb_fsWriteLarge( HB_FHANDLE hFileHandle, const BYTE * pBuff, ULONG ulCount )
|
|
{
|
|
ULONG ulWritten;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsWriteLarge(%p, %p, %lu)", ( void * ) ( HB_PTRDIFF ) hFileHandle, pBuff, ulCount));
|
|
|
|
#if defined(HB_FS_FILE_IO)
|
|
|
|
#if defined(HB_IO_WIN)
|
|
{
|
|
ulWritten = 0;
|
|
hb_vmUnlock();
|
|
if( ulCount )
|
|
{
|
|
hb_fsSetIOError( WriteFile( DosToWinHandle( hFileHandle), pBuff, ulCount, &ulWritten, NULL ), 0 );
|
|
}
|
|
else
|
|
{
|
|
hb_fsSetIOError( SetEndOfFile( DosToWinHandle( hFileHandle ) ), 0 );
|
|
}
|
|
hb_vmLock();
|
|
}
|
|
#else
|
|
if( ulCount )
|
|
#if defined(HB_FS_LARGE_OPTIMIZED)
|
|
{
|
|
hb_vmUnlock();
|
|
ulWritten = write( hFileHandle, pBuff, ulCount );
|
|
hb_fsSetIOError( ulWritten != ( ULONG ) -1, 0 );
|
|
if( ulWritten == ( ULONG ) -1 )
|
|
ulWritten = 0;
|
|
hb_vmLock();
|
|
}
|
|
#else
|
|
{
|
|
ULONG ulLeftToWrite = ulCount;
|
|
USHORT uiToWrite;
|
|
USHORT uiWritten;
|
|
BYTE * pPtr = ( BYTE * ) pBuff;
|
|
|
|
ulWritten = 0;
|
|
|
|
hb_vmUnlock();
|
|
while( ulLeftToWrite )
|
|
{
|
|
/* Determine how much to write this time */
|
|
if( ulLeftToWrite > ( ULONG ) INT_MAX )
|
|
{
|
|
uiToWrite = INT_MAX;
|
|
ulLeftToWrite -= ( ULONG ) uiToWrite;
|
|
}
|
|
else
|
|
{
|
|
uiToWrite = ( USHORT ) ulLeftToWrite;
|
|
ulLeftToWrite = 0;
|
|
}
|
|
|
|
uiWritten = write( hFileHandle, pPtr, uiToWrite );
|
|
|
|
/* -1 on bad hFileHandle
|
|
0 on disk full
|
|
*/
|
|
|
|
if( uiWritten == 0 )
|
|
break;
|
|
|
|
if( uiWritten == ( USHORT ) -1 )
|
|
{
|
|
uiWritten = 0;
|
|
break;
|
|
}
|
|
|
|
ulWritten += ( ULONG ) uiWritten;
|
|
pPtr += uiWritten;
|
|
}
|
|
hb_fsSetIOError( ulLeftToWrite == 0, 0 );
|
|
hb_vmLock();
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
hb_vmUnlock();
|
|
#if defined(HB_USE_LARGEFILE64)
|
|
hb_fsSetIOError( ftruncate64( hFileHandle, lseek64( hFileHandle, 0L, SEEK_CUR ) ) != -1, 0 );
|
|
#else
|
|
hb_fsSetIOError( ftruncate( hFileHandle, lseek( hFileHandle, 0L, SEEK_CUR ) ) != -1, 0 );
|
|
#endif
|
|
ulWritten = 0;
|
|
hb_vmLock();
|
|
}
|
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
return ulWritten;
|
|
}
|
|
|
|
ULONG hb_fsReadAt( HB_FHANDLE hFileHandle, BYTE * pBuff, ULONG ulCount, HB_FOFFSET llOffset )
|
|
{
|
|
ULONG ulRead;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsReadAt(%p, %p, %lu, %" PFHL "i)", ( void * ) ( HB_PTRDIFF ) hFileHandle, pBuff, ulCount, llOffset));
|
|
|
|
#if defined(HB_FS_FILE_IO)
|
|
|
|
#if defined(HB_OS_UNIX) && !defined(__WATCOMC__)
|
|
{
|
|
hb_vmUnlock();
|
|
#if defined(HB_USE_LARGEFILE64)
|
|
ulRead = pread64( hFileHandle, pBuff, ulCount, llOffset );
|
|
#else
|
|
ulRead = pread( hFileHandle, pBuff, ulCount, llOffset );
|
|
#endif
|
|
hb_fsSetIOError( ulRead != (ULONG) -1, 0 );
|
|
if( ulRead == ( ULONG ) -1 )
|
|
ulRead = 0;
|
|
hb_vmLock();
|
|
}
|
|
#else
|
|
#if defined(HB_IO_WIN)
|
|
if( hb_iswinnt() )
|
|
{
|
|
OVERLAPPED Overlapped;
|
|
hb_vmUnlock();
|
|
memset( &Overlapped, 0, sizeof( Overlapped ) );
|
|
Overlapped.Offset = ( DWORD ) ( llOffset & 0xFFFFFFFF ),
|
|
Overlapped.OffsetHigh = ( DWORD ) ( llOffset >> 32 ),
|
|
hb_fsSetIOError( ReadFile( DosToWinHandle( hFileHandle ),
|
|
pBuff, ulCount, &ulRead, &Overlapped ), 0 );
|
|
hb_vmLock();
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
hb_vmUnlock();
|
|
/* TOFIX: this is not atom operation. It has to be fixed for RDD
|
|
* file access with shared file handles in aliased work areas
|
|
*/
|
|
if( hb_fsSeekLarge( hFileHandle, llOffset, FS_SET ) == llOffset )
|
|
ulRead = hb_fsReadLarge( hFileHandle, pBuff, ulCount );
|
|
else
|
|
ulRead = 0;
|
|
hb_vmLock();
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
|
|
ulRead = 0;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
return ulRead;
|
|
}
|
|
|
|
ULONG hb_fsWriteAt( HB_FHANDLE hFileHandle, const BYTE * pBuff, ULONG ulCount, HB_FOFFSET llOffset )
|
|
{
|
|
ULONG ulWritten;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsWriteAt(%p, %p, %lu, %" PFHL "i)", ( void * ) ( HB_PTRDIFF ) hFileHandle, pBuff, ulCount, llOffset));
|
|
|
|
#if defined(HB_FS_FILE_IO)
|
|
|
|
#if defined(HB_OS_UNIX) && !defined(__WATCOMC__)
|
|
{
|
|
hb_vmUnlock();
|
|
#if defined(HB_USE_LARGEFILE64)
|
|
ulWritten = pwrite64( hFileHandle, pBuff, ulCount, llOffset );
|
|
#else
|
|
ulWritten = pwrite( hFileHandle, pBuff, ulCount, llOffset );
|
|
#endif
|
|
hb_fsSetIOError( ulWritten != (ULONG) -1, 0 );
|
|
if( ulWritten == ( ULONG ) -1 )
|
|
ulWritten = 0;
|
|
hb_vmLock();
|
|
}
|
|
#else
|
|
#if defined(HB_IO_WIN)
|
|
if( hb_iswinnt() )
|
|
{
|
|
OVERLAPPED Overlapped;
|
|
hb_vmUnlock();
|
|
memset( &Overlapped, 0, sizeof( Overlapped ) );
|
|
Overlapped.Offset = ( DWORD ) ( llOffset & 0xFFFFFFFF ),
|
|
Overlapped.OffsetHigh = ( DWORD ) ( llOffset >> 32 ),
|
|
hb_fsSetIOError( WriteFile( DosToWinHandle( hFileHandle ),
|
|
pBuff, ulCount, &ulWritten, &Overlapped ), 0 );
|
|
hb_vmLock();
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
hb_vmUnlock();
|
|
/* TOFIX: this is not atom operation. It has to be fixed for RDD
|
|
* file access with shared file handles in aliased work areas
|
|
*/
|
|
if( hb_fsSeekLarge( hFileHandle, llOffset, FS_SET ) == llOffset )
|
|
ulWritten = hb_fsWriteLarge( hFileHandle, pBuff, ulCount );
|
|
else
|
|
ulWritten = 0;
|
|
hb_vmLock();
|
|
}
|
|
#endif
|
|
|
|
#else
|
|
|
|
ulWritten = 0;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
return ulWritten;
|
|
}
|
|
|
|
BOOL hb_fsTruncAt( HB_FHANDLE hFileHandle, HB_FOFFSET llOffset )
|
|
{
|
|
BOOL fResult;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsReadAt(%p, %" PFHL "i)", ( void * ) ( HB_PTRDIFF ) hFileHandle, llOffset));
|
|
|
|
#if defined(HB_FS_FILE_IO)
|
|
|
|
hb_vmUnlock();
|
|
#if defined(HB_IO_WIN)
|
|
{
|
|
ULONG ulOffsetLow = ( ULONG ) ( llOffset & ULONG_MAX ),
|
|
ulOffsetHigh = ( ULONG ) ( llOffset >> 32 );
|
|
|
|
/* This is not atom operation anyhow if someone want to truncate
|
|
* file then he has to made necessary synchronizations in upper level
|
|
* code. We have such situation in our RDD drivers and for us such
|
|
* version is enough. [druzus]
|
|
*/
|
|
ulOffsetLow = SetFilePointer( DosToWinHandle( hFileHandle ),
|
|
ulOffsetLow, ( PLONG ) &ulOffsetHigh,
|
|
( DWORD ) SEEK_SET );
|
|
if( ( ( ( HB_FOFFSET ) ulOffsetHigh << 32 ) | ulOffsetLow ) == llOffset )
|
|
fResult = SetEndOfFile( DosToWinHandle( hFileHandle ) );
|
|
else
|
|
fResult = FALSE;
|
|
}
|
|
#elif defined(HB_USE_LARGEFILE64)
|
|
fResult = ftruncate64( hFileHandle, llOffset ) != -1;
|
|
#else
|
|
fResult = ftruncate( hFileHandle, llOffset ) != -1;
|
|
#endif
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#else
|
|
|
|
fResult = FALSE;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
return fResult;
|
|
}
|
|
|
|
void hb_fsCommit( HB_FHANDLE hFileHandle )
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsCommit(%p)", ( void * ) ( HB_PTRDIFF ) hFileHandle));
|
|
|
|
#if defined(HB_OS_WIN_32)
|
|
{
|
|
hb_vmUnlock();
|
|
#if defined(HB_IO_WIN)
|
|
hb_fsSetIOError( FlushFileBuffers( ( HANDLE ) DosToWinHandle( hFileHandle ) ), 0 );
|
|
#else
|
|
#if defined(__WATCOMC__)
|
|
hb_fsSetIOError( fsync( hFileHandle ) == 0, 0 );
|
|
#else
|
|
hb_fsSetIOError( _commit( hFileHandle ) == 0, 0 );
|
|
#endif
|
|
#endif
|
|
hb_vmLock();
|
|
}
|
|
|
|
#elif defined(HB_OS_OS2)
|
|
|
|
{
|
|
hb_vmUnlock();
|
|
hb_fsSetIOError( DosResetBuffer( hFileHandle ) == 0, 0 );
|
|
hb_vmLock();
|
|
}
|
|
|
|
#elif defined(HB_OS_UNIX)
|
|
|
|
/* NOTE: close() functions releases all lock regardles if it is an
|
|
* original or duplicated file handle
|
|
*/
|
|
hb_vmUnlock();
|
|
#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO + 0 > 0
|
|
/* faster - flushes data buffers only, without updating directory info
|
|
*/
|
|
hb_fsSetIOError( fdatasync( hFileHandle ) == 0, 0 );
|
|
#else
|
|
/* slower - flushes all file data buffers and i-node info
|
|
*/
|
|
hb_fsSetIOError( fsync( hFileHandle ) == 0, 0 );
|
|
#endif
|
|
hb_vmLock();
|
|
|
|
#elif defined(__WATCOMC__)
|
|
|
|
hb_vmUnlock();
|
|
hb_fsSetIOError( fsync( hFileHandle ) == 0, 0 );
|
|
hb_vmLock();
|
|
|
|
#elif defined(HB_FS_FILE_IO) && !defined(HB_OS_OS2) && !defined(HB_OS_UNIX)
|
|
|
|
/* This hack is very dangerous. POSIX standard define that if _ANY_
|
|
file handle is closed all locks set by the process on the file
|
|
pointed by this descriptor are removed. It doesn't matter they
|
|
were done using different descriptor. It means that we now clean
|
|
all locks on hFileHandle with the code below if the OS is POSIX
|
|
compilant. I vote to disable it.
|
|
*/
|
|
{
|
|
int dup_handle;
|
|
BOOL fResult = FALSE;
|
|
|
|
hb_vmUnlock();
|
|
dup_handle = dup( hFileHandle );
|
|
if( dup_handle != -1 )
|
|
{
|
|
close( dup_handle );
|
|
fResult = TRUE;
|
|
}
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
}
|
|
|
|
#else
|
|
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
}
|
|
|
|
BOOL hb_fsLock( HB_FHANDLE hFileHandle, ULONG ulStart,
|
|
ULONG ulLength, USHORT uiMode )
|
|
{
|
|
BOOL bResult;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsLock(%p, %lu, %lu, %hu)", ( void * ) ( HB_PTRDIFF ) hFileHandle, ulStart, ulLength, uiMode));
|
|
|
|
#if defined(HB_IO_WIN)
|
|
hb_vmUnlock();
|
|
switch( uiMode & FL_MASK )
|
|
{
|
|
case FL_LOCK:
|
|
{
|
|
if( hb_iswinnt() )
|
|
{
|
|
OVERLAPPED sOlap;
|
|
DWORD dwFlags;
|
|
memset( &sOlap, 0, sizeof( OVERLAPPED ) );
|
|
sOlap.Offset = ( ULONG ) ulStart;
|
|
dwFlags = ( uiMode & FLX_SHARED ) ? 0 : LOCKFILE_EXCLUSIVE_LOCK;
|
|
if( !s_fUseWaitLocks || !( uiMode & FLX_WAIT ) )
|
|
{
|
|
dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
|
|
}
|
|
bResult = LockFileEx( DosToWinHandle( hFileHandle ), dwFlags, 0, ulLength, 0, &sOlap );
|
|
}
|
|
else
|
|
{
|
|
bResult = LockFile( DosToWinHandle( hFileHandle ), ulStart, 0, ulLength,0 );
|
|
}
|
|
break;
|
|
}
|
|
case FL_UNLOCK:
|
|
{
|
|
if( hb_iswinnt() )
|
|
{
|
|
OVERLAPPED sOlap;
|
|
memset( &sOlap, 0, sizeof( OVERLAPPED ) );
|
|
sOlap.Offset = ( ULONG ) ulStart;
|
|
bResult = UnlockFileEx( DosToWinHandle( hFileHandle ), 0, ulLength,0, &sOlap );
|
|
}
|
|
else
|
|
{
|
|
bResult = UnlockFile( DosToWinHandle( hFileHandle ), ulStart, 0, ulLength,0 );
|
|
}
|
|
break;
|
|
|
|
}
|
|
default:
|
|
bResult = FALSE;
|
|
}
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
#elif defined(HB_OS_OS2)
|
|
{
|
|
struct _FILELOCK fl, ful;
|
|
|
|
hb_vmUnlock();
|
|
switch( uiMode & FL_MASK )
|
|
{
|
|
case FL_LOCK:
|
|
|
|
fl.lOffset = ulStart;
|
|
fl.lRange = ulLength;
|
|
ful.lOffset = 0;
|
|
ful.lRange = 0;
|
|
|
|
/* lock region, 2 seconds timeout, exclusive access - no atomic */
|
|
bResult = ( DosSetFileLocks( hFileHandle, &ful, &fl, 2000L, 0L ) == 0 );
|
|
break;
|
|
|
|
case FL_UNLOCK:
|
|
|
|
fl.lOffset = 0;
|
|
fl.lRange = 0;
|
|
ful.lOffset = ulStart;
|
|
ful.lRange = ulLength;
|
|
|
|
/* unlock region, 2 seconds timeout, exclusive access - no atomic */
|
|
bResult = ( DosSetFileLocks( hFileHandle, &ful, &fl, 2000L, 0L ) == 0 );
|
|
break;
|
|
|
|
default:
|
|
bResult = FALSE;
|
|
}
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
}
|
|
#elif defined(_MSC_VER) || defined(__DMC__)
|
|
{
|
|
ULONG ulOldPos;
|
|
|
|
hb_vmUnlock();
|
|
ulOldPos = lseek( hFileHandle, 0L, SEEK_CUR );
|
|
lseek( hFileHandle, ulStart, SEEK_SET );
|
|
switch( uiMode & FL_MASK )
|
|
{
|
|
case FL_LOCK:
|
|
bResult = ( locking( hFileHandle, _LK_NBLCK, ulLength ) == 0 );
|
|
break;
|
|
|
|
case FL_UNLOCK:
|
|
bResult = ( locking( hFileHandle, _LK_UNLCK, ulLength ) == 0 );
|
|
break;
|
|
|
|
default:
|
|
bResult = FALSE;
|
|
}
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
lseek( hFileHandle, ulOldPos, SEEK_SET );
|
|
}
|
|
#elif defined(__MINGW32__)
|
|
{
|
|
ULONG ulOldPos;
|
|
|
|
hb_vmUnlock();
|
|
ulOldPos = lseek( hFileHandle, 0L, SEEK_CUR );
|
|
lseek( hFileHandle, ulStart, SEEK_SET );
|
|
switch( uiMode & FL_MASK )
|
|
{
|
|
case FL_LOCK:
|
|
bResult = ( _locking( hFileHandle, _LK_LOCK, ulLength ) == 0 );
|
|
break;
|
|
|
|
case FL_UNLOCK:
|
|
bResult = ( _locking( hFileHandle, _LK_UNLCK, ulLength ) == 0 );
|
|
break;
|
|
|
|
default:
|
|
bResult = FALSE;
|
|
}
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
lseek( hFileHandle, ulOldPos, SEEK_SET );
|
|
}
|
|
#elif defined(HB_OS_UNIX)
|
|
{
|
|
/* TODO: check for append locks (SEEK_END)
|
|
*/
|
|
struct flock lock_info;
|
|
|
|
hb_vmUnlock();
|
|
switch( uiMode & FL_MASK )
|
|
{
|
|
case FL_LOCK:
|
|
|
|
lock_info.l_type = (uiMode & FLX_SHARED) ? F_RDLCK : F_WRLCK;
|
|
lock_info.l_start = ulStart;
|
|
lock_info.l_len = ulLength;
|
|
lock_info.l_whence = SEEK_SET; /* start from the beginning of the file */
|
|
lock_info.l_pid = getpid();
|
|
|
|
bResult = ( fcntl( hFileHandle,
|
|
(uiMode & FLX_WAIT) ? F_SETLKW: F_SETLK,
|
|
&lock_info ) >= 0 );
|
|
break;
|
|
|
|
case FL_UNLOCK:
|
|
|
|
lock_info.l_type = F_UNLCK; /* unlock */
|
|
lock_info.l_start = ulStart;
|
|
lock_info.l_len = ulLength;
|
|
lock_info.l_whence = SEEK_SET;
|
|
lock_info.l_pid = getpid();
|
|
|
|
bResult = ( fcntl( hFileHandle, F_SETLK, &lock_info ) >= 0 );
|
|
break;
|
|
|
|
default:
|
|
bResult = FALSE;
|
|
}
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
}
|
|
#elif defined(HAVE_POSIX_IO) && !defined(__IBMCPP__) && ( !defined(__GNUC__) || defined(__DJGPP__) )
|
|
|
|
hb_vmUnlock();
|
|
switch( uiMode & FL_MASK )
|
|
{
|
|
case FL_LOCK:
|
|
bResult = ( lock( hFileHandle, ulStart, ulLength ) == 0 );
|
|
break;
|
|
|
|
case FL_UNLOCK:
|
|
bResult = ( unlock( hFileHandle, ulStart, ulLength ) == 0 );
|
|
break;
|
|
|
|
default:
|
|
bResult = FALSE;
|
|
}
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#else
|
|
|
|
bResult = FALSE;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL hb_fsLockLarge( HB_FHANDLE hFileHandle, HB_FOFFSET ulStart,
|
|
HB_FOFFSET ulLength, USHORT uiMode )
|
|
{
|
|
BOOL bResult;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsLockLarge(%p, %" PFHL "u, %" PFHL "i, %hu)", ( void * ) ( HB_PTRDIFF ) hFileHandle, ulStart, ulLength, uiMode));
|
|
|
|
#if defined(HB_IO_WIN)
|
|
{
|
|
DWORD dwOffsetLo = ( DWORD ) ( ulStart & 0xFFFFFFFF ),
|
|
dwOffsetHi = ( DWORD ) ( ulStart >> 32 ),
|
|
dwLengthLo = ( DWORD ) ( ulLength & 0xFFFFFFFF ),
|
|
dwLengthHi = ( DWORD ) ( ulLength >> 32 );
|
|
|
|
hb_vmUnlock();
|
|
switch( uiMode & FL_MASK )
|
|
{
|
|
case FL_LOCK:
|
|
if( hb_iswinnt() )
|
|
{
|
|
OVERLAPPED sOlap;
|
|
DWORD dwFlags;
|
|
|
|
dwFlags = ( ( uiMode & FLX_SHARED ) ? 0 : LOCKFILE_EXCLUSIVE_LOCK );
|
|
if( !s_fUseWaitLocks || !( uiMode & FLX_WAIT ) )
|
|
{
|
|
dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
|
|
}
|
|
|
|
memset( &sOlap, 0, sizeof( OVERLAPPED ) );
|
|
sOlap.Offset = dwOffsetLo;
|
|
sOlap.OffsetHigh = dwOffsetHi;
|
|
|
|
bResult = LockFileEx( DosToWinHandle( hFileHandle ), dwFlags, 0,
|
|
dwLengthLo, dwLengthHi, &sOlap );
|
|
}
|
|
else
|
|
{
|
|
bResult = LockFile( DosToWinHandle( hFileHandle ),
|
|
dwOffsetLo, dwOffsetHi,
|
|
dwLengthLo, dwLengthHi );
|
|
}
|
|
break;
|
|
|
|
case FL_UNLOCK:
|
|
if( hb_iswinnt() )
|
|
{
|
|
OVERLAPPED sOlap;
|
|
|
|
memset( &sOlap, 0, sizeof( OVERLAPPED ) );
|
|
sOlap.Offset = dwOffsetLo;
|
|
sOlap.OffsetHigh = dwOffsetHi;
|
|
|
|
bResult = UnlockFileEx( DosToWinHandle( hFileHandle ), 0,
|
|
dwLengthLo, dwLengthHi, &sOlap );
|
|
}
|
|
else
|
|
{
|
|
bResult = UnlockFile( DosToWinHandle( hFileHandle ),
|
|
dwOffsetLo, dwOffsetHi,
|
|
dwLengthLo, dwLengthHi );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
bResult = FALSE;
|
|
}
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
}
|
|
#elif defined(HB_USE_LARGEFILE64)
|
|
{
|
|
struct flock64 lock_info;
|
|
|
|
hb_vmUnlock();
|
|
switch( uiMode & FL_MASK )
|
|
{
|
|
case FL_LOCK:
|
|
|
|
lock_info.l_type = (uiMode & FLX_SHARED) ? F_RDLCK : F_WRLCK;
|
|
lock_info.l_start = ulStart;
|
|
lock_info.l_len = ulLength;
|
|
lock_info.l_whence = SEEK_SET; /* start from the beginning of the file */
|
|
lock_info.l_pid = getpid();
|
|
|
|
bResult = ( fcntl( hFileHandle,
|
|
(uiMode & FLX_WAIT) ? F_SETLKW64: F_SETLK64,
|
|
&lock_info ) != -1 );
|
|
break;
|
|
|
|
case FL_UNLOCK:
|
|
|
|
lock_info.l_type = F_UNLCK; /* unlock */
|
|
lock_info.l_start = ulStart;
|
|
lock_info.l_len = ulLength;
|
|
lock_info.l_whence = SEEK_SET;
|
|
lock_info.l_pid = getpid();
|
|
|
|
bResult = ( fcntl( hFileHandle, F_SETLK64, &lock_info ) != -1 );
|
|
break;
|
|
|
|
default:
|
|
bResult = FALSE;
|
|
}
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
}
|
|
#else
|
|
bResult = hb_fsLock( hFileHandle, (ULONG) ulStart, (ULONG) ulLength, uiMode );
|
|
#endif
|
|
|
|
return bResult;
|
|
}
|
|
|
|
ULONG hb_fsSeek( HB_FHANDLE hFileHandle, LONG lOffset, USHORT uiFlags )
|
|
{
|
|
ULONG ulPos;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsSeek(%p, %ld, %hu)", ( void * ) ( HB_PTRDIFF ) hFileHandle, lOffset, uiFlags));
|
|
|
|
#if defined(HB_FS_FILE_IO)
|
|
{
|
|
USHORT Flags = convert_seek_flags( uiFlags );
|
|
|
|
hb_vmUnlock();
|
|
#if defined(HB_OS_OS2)
|
|
{
|
|
APIRET ret;
|
|
|
|
/* This DOS hack creates 2GB file size limit, Druzus */
|
|
if( lOffset < 0 && Flags == SEEK_SET )
|
|
{
|
|
ret = 1;
|
|
hb_fsSetError( 25 ); /* 'Seek Error' */
|
|
}
|
|
else
|
|
{
|
|
ret = DosSetFilePtr( hFileHandle, lOffset, Flags, &ulPos );
|
|
/* TODO: what we should do with this error code? Is it DOS compatible? */
|
|
hb_fsSetError( ( USHORT ) ret );
|
|
}
|
|
if( ret != 0 )
|
|
{
|
|
/* FIXME: it should work if DosSetFilePtr is lseek compatible
|
|
but maybe OS2 has DosGetFilePtr too, if not then remove this
|
|
comment, Druzus */
|
|
if( DosSetFilePtr( hFileHandle, 0, SEEK_CUR, &ulPos ) != 0 )
|
|
{
|
|
ulPos = 0;
|
|
}
|
|
}
|
|
}
|
|
#elif defined(HB_IO_WIN)
|
|
/* This DOS hack creates 2GB file size limit, Druzus */
|
|
if( lOffset < 0 && Flags == SEEK_SET )
|
|
{
|
|
ulPos = (ULONG) INVALID_SET_FILE_POINTER;
|
|
hb_fsSetError( 25 ); /* 'Seek Error' */
|
|
}
|
|
else
|
|
{
|
|
ulPos = (DWORD) SetFilePointer( DosToWinHandle( hFileHandle ), lOffset, NULL, ( DWORD ) Flags );
|
|
hb_fsSetIOError( (DWORD) ulPos != INVALID_SET_FILE_POINTER, 0 );
|
|
}
|
|
|
|
if( (DWORD) ulPos == INVALID_SET_FILE_POINTER )
|
|
{
|
|
ulPos = (DWORD) SetFilePointer( DosToWinHandle( hFileHandle ), 0, NULL, SEEK_CUR );
|
|
}
|
|
#else
|
|
/* This DOS hack creates 2GB file size limit, Druzus */
|
|
if( lOffset < 0 && Flags == SEEK_SET )
|
|
{
|
|
ulPos = (ULONG) -1;
|
|
hb_fsSetError( 25 ); /* 'Seek Error' */
|
|
}
|
|
else
|
|
{
|
|
ulPos = lseek( hFileHandle, lOffset, Flags );
|
|
hb_fsSetIOError( ulPos != (ULONG) -1, 0 );
|
|
}
|
|
if( ulPos == (ULONG) -1 )
|
|
{
|
|
ulPos = lseek( hFileHandle, 0L, SEEK_CUR );
|
|
if( ulPos == (ULONG) -1 )
|
|
{
|
|
ulPos = 0;
|
|
}
|
|
}
|
|
#endif
|
|
hb_vmLock();
|
|
}
|
|
#else
|
|
hb_fsSetError( 25 );
|
|
ulPos = 0;
|
|
#endif
|
|
|
|
return ulPos;
|
|
}
|
|
|
|
HB_FOFFSET hb_fsSeekLarge( HB_FHANDLE hFileHandle, HB_FOFFSET llOffset, USHORT uiFlags )
|
|
{
|
|
HB_FOFFSET llPos;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsSeekLarge(%p, %" PFHL "i, %hu)", ( void * ) ( HB_PTRDIFF ) hFileHandle, llOffset, uiFlags));
|
|
|
|
#if defined(HB_IO_WIN)
|
|
{
|
|
USHORT Flags = convert_seek_flags( uiFlags );
|
|
|
|
ULONG ulOffsetLow = ( ULONG ) ( llOffset & ULONG_MAX ),
|
|
ulOffsetHigh = ( ULONG ) ( llOffset >> 32 );
|
|
|
|
hb_vmUnlock();
|
|
if( llOffset < 0 && Flags == SEEK_SET )
|
|
{
|
|
llPos = ( HB_FOFFSET ) INVALID_SET_FILE_POINTER;
|
|
hb_fsSetError( 25 ); /* 'Seek Error' */
|
|
}
|
|
else
|
|
{
|
|
ulOffsetLow = SetFilePointer( DosToWinHandle( hFileHandle ),
|
|
ulOffsetLow, (PLONG) &ulOffsetHigh,
|
|
( DWORD ) Flags );
|
|
llPos = ( ( HB_FOFFSET ) ulOffsetHigh << 32 ) | ulOffsetLow;
|
|
hb_fsSetIOError( llPos != ( HB_FOFFSET ) INVALID_SET_FILE_POINTER, 0 );
|
|
}
|
|
|
|
if( llPos == ( HB_FOFFSET ) INVALID_SET_FILE_POINTER )
|
|
{
|
|
ulOffsetHigh = 0;
|
|
ulOffsetLow = SetFilePointer( DosToWinHandle( hFileHandle ),
|
|
0, (PLONG) &ulOffsetHigh, SEEK_CUR );
|
|
llPos = ( ( HB_FOFFSET ) ulOffsetHigh << 32 ) | ulOffsetLow;
|
|
}
|
|
hb_vmLock();
|
|
}
|
|
#elif defined(HB_USE_LARGEFILE64)
|
|
{
|
|
USHORT Flags = convert_seek_flags( uiFlags );
|
|
|
|
hb_vmUnlock();
|
|
if( llOffset < 0 && Flags == SEEK_SET )
|
|
{
|
|
llPos = (HB_FOFFSET) -1;
|
|
hb_fsSetError( 25 ); /* 'Seek Error' */
|
|
}
|
|
else
|
|
{
|
|
llPos = lseek64( hFileHandle, llOffset, Flags );
|
|
hb_fsSetIOError( llPos != (HB_FOFFSET) -1, 0 );
|
|
}
|
|
|
|
if( llPos == (HB_FOFFSET) -1 )
|
|
{
|
|
llPos = lseek64( hFileHandle, 0L, SEEK_CUR );
|
|
}
|
|
hb_vmLock();
|
|
}
|
|
#else
|
|
llPos = (HB_FOFFSET) hb_fsSeek( hFileHandle, (LONG) llOffset, uiFlags );
|
|
#endif
|
|
|
|
return llPos;
|
|
}
|
|
|
|
ULONG hb_fsTell( HB_FHANDLE hFileHandle )
|
|
{
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsTell(%p)", ( void * ) ( HB_PTRDIFF ) hFileHandle));
|
|
|
|
return hb_fsSeek( hFileHandle, 0, FS_RELATIVE );
|
|
}
|
|
|
|
BOOL hb_fsDelete( BYTE * pFilename )
|
|
{
|
|
BOOL bResult;
|
|
BOOL fFree;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsDelete(%s)", (char*) pFilename));
|
|
|
|
pFilename = hb_fsNameConv( pFilename, &fFree );
|
|
|
|
#if defined(HB_OS_WIN_32)
|
|
|
|
hb_vmUnlock();
|
|
bResult = DeleteFileA( ( char * ) pFilename );
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#elif defined(HB_FS_FILE_IO)
|
|
|
|
hb_vmUnlock();
|
|
bResult = ( remove( ( char * ) pFilename ) == 0 );
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#else
|
|
|
|
bResult = FALSE;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
if( fFree )
|
|
hb_xfree( pFilename );
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL hb_fsRename( BYTE * pOldName, BYTE * pNewName )
|
|
{
|
|
BOOL bResult;
|
|
BOOL fFreeOld, fFreeNew;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsRename(%s, %s)", (char*) pOldName, (char*) pNewName));
|
|
|
|
pOldName = hb_fsNameConv( pOldName, &fFreeOld );
|
|
pNewName = hb_fsNameConv( pNewName, &fFreeNew );
|
|
|
|
#if defined(HB_OS_WIN_32)
|
|
|
|
hb_vmUnlock();
|
|
bResult = MoveFileA( ( char * ) pOldName, ( char * ) pNewName );
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#elif defined(HB_FS_FILE_IO)
|
|
|
|
hb_vmUnlock();
|
|
bResult = ( rename( ( char * ) pOldName, ( char * ) pNewName ) == 0 );
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#else
|
|
|
|
bResult = FALSE;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
if( fFreeOld )
|
|
hb_xfree( pOldName );
|
|
if( fFreeNew )
|
|
hb_xfree( pNewName );
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL hb_fsMkDir( BYTE * pDirname )
|
|
{
|
|
BOOL bResult;
|
|
BOOL fFree;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsMkDir(%s)", (char*) pDirname));
|
|
|
|
pDirname = hb_fsNameConv( pDirname, &fFree );
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsMkDir(%s)", (char*) pDirname));
|
|
|
|
#if defined(HB_OS_WIN_32)
|
|
|
|
hb_vmUnlock();
|
|
bResult = CreateDirectoryA( ( char * ) pDirname, NULL );
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#elif defined(HAVE_POSIX_IO) || defined(__MINGW32__)
|
|
|
|
hb_vmUnlock();
|
|
# if ! defined(HB_OS_UNIX) && \
|
|
( defined(__WATCOMC__) || defined(__BORLANDC__) || \
|
|
defined(__IBMCPP__) || defined(__MINGW32__) )
|
|
bResult = ( mkdir( ( char * ) pDirname ) == 0 );
|
|
# else
|
|
bResult = ( mkdir( ( char * ) pDirname, S_IRWXU | S_IRWXG | S_IRWXO ) == 0 );
|
|
# endif
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#else
|
|
|
|
bResult = FALSE;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
if( fFree )
|
|
hb_xfree( pDirname );
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL hb_fsChDir( BYTE * pDirname )
|
|
{
|
|
BOOL bResult;
|
|
BOOL fFree;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsChDir(%s)", (char*) pDirname));
|
|
|
|
pDirname = hb_fsNameConv( pDirname, &fFree );
|
|
|
|
#if defined(HB_OS_WIN_32)
|
|
|
|
hb_vmUnlock();
|
|
bResult = SetCurrentDirectoryA( ( char * ) pDirname );
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#elif defined(HAVE_POSIX_IO) || defined(__MINGW32__)
|
|
|
|
hb_vmUnlock();
|
|
bResult = ( chdir( ( char * ) pDirname ) == 0 );
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#else
|
|
|
|
bResult = FALSE;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
if( fFree )
|
|
hb_xfree( pDirname );
|
|
|
|
return bResult;
|
|
}
|
|
|
|
BOOL hb_fsRmDir( BYTE * pDirname )
|
|
{
|
|
BOOL bResult;
|
|
BOOL fFree;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsRmDir(%s)", (char*) pDirname));
|
|
|
|
pDirname = hb_fsNameConv( pDirname, &fFree );
|
|
|
|
#if defined(HB_OS_WIN_32)
|
|
|
|
hb_vmUnlock();
|
|
bResult = RemoveDirectoryA( ( char * ) pDirname );
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#elif defined(HAVE_POSIX_IO) || defined(__MINGW32__)
|
|
|
|
hb_vmUnlock();
|
|
bResult = ( rmdir( ( char * ) pDirname ) == 0 );
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#else
|
|
|
|
bResult = FALSE;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
if( fFree )
|
|
hb_xfree( pDirname );
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/* NOTE: This is not thread safe function, it's there for compatibility. */
|
|
/* NOTE: 0 = current drive, 1 = A, 2 = B, 3 = C, etc. */
|
|
|
|
BYTE * hb_fsCurDir( USHORT uiDrive )
|
|
{
|
|
BYTE * pbyDirBuffer;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsCurDir(%hu)", uiDrive));
|
|
|
|
pbyDirBuffer = hb_stackDirBuffer();
|
|
hb_fsCurDirBuff( uiDrive, pbyDirBuffer, _POSIX_PATH_MAX + 1 );
|
|
|
|
return ( BYTE * ) pbyDirBuffer;
|
|
}
|
|
|
|
/* NOTE: Thread safe version of hb_fsCurDir() */
|
|
/* NOTE: 0 = current drive, 1 = A, 2 = B, 3 = C, etc. */
|
|
|
|
USHORT hb_fsCurDirBuff( USHORT uiDrive, BYTE * pbyBuffer, ULONG ulLen )
|
|
{
|
|
USHORT uiCurDrv = uiDrive, usError;
|
|
BOOL fResult;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsCurDirBuff(%hu)", uiDrive));
|
|
|
|
pbyBuffer[ 0 ] = '\0';
|
|
|
|
/*
|
|
* do not cover this code by HB_OS_HAS_DRIVE_LETTER macro
|
|
* It will allow us to add drive emulation in hb_fsCurDrv()/hb_fsChDrv()
|
|
* and hb_fsNameConv()
|
|
*/
|
|
#if !( defined(__GNUC__) && ( defined(HB_OS_OS2) || !defined(__MINGW32__) ) )
|
|
if( uiDrive )
|
|
{
|
|
uiCurDrv = hb_fsCurDrv() + 1;
|
|
if( uiDrive != uiCurDrv )
|
|
hb_fsChDrv( ( BYTE ) ( uiDrive - 1 ) );
|
|
}
|
|
#endif
|
|
|
|
#if defined(HB_OS_WIN_32)
|
|
|
|
hb_vmUnlock();
|
|
fResult = GetCurrentDirectoryA( ulLen, ( char * ) pbyBuffer );
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#elif defined(HB_OS_OS2) && defined(__GNUC__)
|
|
|
|
hb_vmUnlock();
|
|
fResult = ( _getcwd1( ( char * ) pbyBuffer, uiDrive + 'A' - 1 ) == 0 );
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#elif defined(HAVE_POSIX_IO)
|
|
|
|
hb_vmUnlock();
|
|
fResult = ( getcwd( ( char * ) pbyBuffer, ulLen ) != NULL );
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#elif defined(__MINGW32__)
|
|
|
|
hb_vmUnlock();
|
|
fResult = ( _getdcwd( uiDrive, pbyBuffer, ulLen ) != NULL );
|
|
hb_fsSetIOError( fResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#else
|
|
|
|
fResult = FALSE;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
usError = hb_fsError();
|
|
|
|
if( uiDrive != uiCurDrv )
|
|
{
|
|
hb_fsChDrv( ( BYTE ) ( uiCurDrv - 1 ) );
|
|
hb_fsSetError( usError );
|
|
}
|
|
|
|
pbyBuffer[ ulLen - 1 ] = '\0';
|
|
|
|
if( usError == 0 && pbyBuffer[ 0 ] )
|
|
{
|
|
BYTE * pbyStart = pbyBuffer;
|
|
|
|
/* Strip the leading drive spec, and leading backslash if there's one. */
|
|
/* NOTE: A trailing underscore is not returned on this platform,
|
|
so we don't need to strip it. [vszakats] */
|
|
|
|
ulLen = strlen( ( char * ) pbyBuffer );
|
|
|
|
#if defined(HB_OS_HAS_DRIVE_LETTER)
|
|
if( pbyStart[ 1 ] == HB_OS_DRIVE_DELIM_CHR )
|
|
{
|
|
pbyStart += 2;
|
|
ulLen -= 2;
|
|
}
|
|
#endif
|
|
if( strchr( HB_OS_PATH_DELIM_CHR_LIST, pbyStart[ 0 ] ) )
|
|
{
|
|
pbyStart++;
|
|
ulLen--;
|
|
}
|
|
|
|
/* Strip the trailing (back)slash if there's one */
|
|
if( ulLen && strchr( HB_OS_PATH_DELIM_CHR_LIST, pbyStart[ ulLen - 1 ] ) )
|
|
ulLen--;
|
|
|
|
if( ulLen && pbyBuffer != pbyStart )
|
|
memmove( pbyBuffer, pbyStart, ulLen );
|
|
|
|
pbyBuffer[ ulLen ] = '\0';
|
|
|
|
/* Convert from OS codepage */
|
|
{
|
|
BOOL fFree;
|
|
BYTE * pbyResult = hb_osDecode( pbyBuffer, &fFree );
|
|
|
|
if( fFree )
|
|
{
|
|
hb_strncpy( ( char * ) pbyBuffer, ( char * ) pbyResult, ulLen - 1 );
|
|
hb_xfree( pbyResult );
|
|
}
|
|
}
|
|
}
|
|
|
|
return usError;
|
|
}
|
|
|
|
/* NOTE: 0=A:, 1=B:, 2=C:, 3=D:, ... */
|
|
|
|
USHORT hb_fsChDrv( BYTE nDrive )
|
|
{
|
|
USHORT uiResult;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsChDrv(%d)", (int) nDrive));
|
|
|
|
#if defined(HB_OS_HAS_DRIVE_LETTER)
|
|
{
|
|
/* 'unsigned int' _have to_ be used in Watcom */
|
|
UINT uiSave, uiNewDrive;
|
|
|
|
hb_vmUnlock();
|
|
|
|
HB_FS_GETDRIVE( uiSave );
|
|
HB_FS_SETDRIVE( nDrive );
|
|
HB_FS_GETDRIVE( uiNewDrive );
|
|
|
|
if( ( UINT ) nDrive == uiNewDrive )
|
|
{
|
|
uiResult = 0;
|
|
hb_fsSetError( 0 );
|
|
}
|
|
else
|
|
{
|
|
HB_FS_SETDRIVE( uiSave );
|
|
|
|
uiResult = ( USHORT ) FS_ERROR;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
}
|
|
hb_vmLock();
|
|
}
|
|
#else
|
|
|
|
HB_SYMBOL_UNUSED( nDrive );
|
|
uiResult = ( USHORT ) FS_ERROR;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
return uiResult;
|
|
}
|
|
|
|
/* NOTE: 0=A:, 1=B:, 2=C:, 3=D:, ... */
|
|
|
|
/* TOFIX: This isn't fully compliant because CA-Cl*pper doesn't access
|
|
the drive before checking. hb_fsIsDrv only returns TRUE
|
|
if there is a disk in the drive. */
|
|
|
|
USHORT hb_fsIsDrv( BYTE nDrive )
|
|
{
|
|
USHORT uiResult;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsIsDrv(%d)", (int) nDrive));
|
|
|
|
#if defined(HB_OS_WIN_32) && !defined(HB_WINCE)
|
|
{
|
|
char buffer[ 4 ];
|
|
UINT type;
|
|
|
|
buffer[ 0 ] = nDrive + 'A';
|
|
buffer[ 1 ] = ':';
|
|
buffer[ 2 ] = '\\';
|
|
buffer[ 3 ] = '\0';
|
|
|
|
hb_vmUnlock();
|
|
type = GetDriveTypeA( ( LPCSTR ) buffer );
|
|
hb_vmLock();
|
|
uiResult = ( type == DRIVE_UNKNOWN || type == DRIVE_NO_ROOT_DIR ) ? F_ERROR : 0;
|
|
hb_fsSetError( 0 );
|
|
}
|
|
#elif defined(HB_OS_HAS_DRIVE_LETTER)
|
|
{
|
|
/* 'unsigned int' _have to_ be used in Watcom
|
|
*/
|
|
UINT uiSave, uiNewDrive;
|
|
|
|
hb_vmUnlock();
|
|
|
|
HB_FS_GETDRIVE( uiSave );
|
|
HB_FS_SETDRIVE( nDrive );
|
|
HB_FS_GETDRIVE( uiNewDrive );
|
|
if( ( UINT ) nDrive != uiNewDrive )
|
|
{
|
|
uiResult = ( USHORT ) FS_ERROR;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
}
|
|
else
|
|
{
|
|
uiResult = 0;
|
|
hb_fsSetError( 0 );
|
|
}
|
|
HB_FS_SETDRIVE( uiSave );
|
|
|
|
hb_vmLock();
|
|
}
|
|
#else
|
|
|
|
HB_SYMBOL_UNUSED( nDrive );
|
|
uiResult = ( USHORT ) FS_ERROR;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
return uiResult;
|
|
}
|
|
|
|
BOOL hb_fsIsDevice( HB_FHANDLE hFileHandle )
|
|
{
|
|
BOOL bResult;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsIsDevice(%p)", ( void * ) ( HB_PTRDIFF ) hFileHandle));
|
|
|
|
#if defined(HB_OS_WIN_32)
|
|
|
|
hb_vmUnlock();
|
|
bResult = GetFileType( DosToWinHandle( hFileHandle ) ) == FILE_TYPE_CHAR;
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#elif defined(HB_FS_FILE_IO)
|
|
|
|
hb_vmUnlock();
|
|
#if defined( _MSC_VER ) || defined( __MINGW32__ )
|
|
bResult = _isatty( hFileHandle ) != 0;
|
|
#else
|
|
bResult = isatty( hFileHandle ) != 0;
|
|
#endif
|
|
hb_fsSetIOError( bResult, 0 );
|
|
hb_vmLock();
|
|
|
|
#else
|
|
|
|
bResult = FALSE;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
HB_SYMBOL_UNUSED( hFileHandle );
|
|
|
|
#endif
|
|
|
|
return bResult;
|
|
}
|
|
|
|
/* NOTE: 0=A:, 1=B:, 2=C:, 3=D:, ... */
|
|
|
|
BYTE hb_fsCurDrv( void )
|
|
{
|
|
UINT uiResult;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsCurDrv()"));
|
|
|
|
#if defined(HB_OS_HAS_DRIVE_LETTER)
|
|
|
|
hb_vmUnlock();
|
|
HB_FS_GETDRIVE( uiResult );
|
|
hb_vmLock();
|
|
|
|
#else
|
|
|
|
uiResult = 0;
|
|
hb_fsSetError( ( USHORT ) FS_ERROR );
|
|
|
|
#endif
|
|
|
|
return ( BYTE ) uiResult; /* Return the drive number, base 0. */
|
|
}
|
|
|
|
/* convert file name for hb_fsExtOpen
|
|
* caller must free the returned buffer
|
|
*/
|
|
BYTE * hb_fsExtName( BYTE * pFilename, BYTE * pDefExt,
|
|
USHORT uiExFlags, BYTE * pPaths )
|
|
{
|
|
HB_PATHNAMES * pNextPath;
|
|
PHB_FNAME pFilepath;
|
|
BOOL fIsFile = FALSE;
|
|
BYTE * szPath;
|
|
|
|
szPath = ( BYTE * ) hb_xgrab( _POSIX_PATH_MAX + 1 );
|
|
|
|
pFilepath = hb_fsFNameSplit( ( char * ) pFilename );
|
|
|
|
if( pDefExt && ( ( uiExFlags & FXO_FORCEEXT ) || !pFilepath->szExtension ) )
|
|
{
|
|
pFilepath->szExtension = ( char * ) pDefExt;
|
|
}
|
|
|
|
if( pFilepath->szPath )
|
|
{
|
|
hb_fsFNameMerge( ( char * ) szPath, pFilepath );
|
|
}
|
|
else if( uiExFlags & FXO_DEFAULTS )
|
|
{
|
|
char * szDefault = hb_setGetDefault();
|
|
if( szDefault )
|
|
{
|
|
pFilepath->szPath = szDefault;
|
|
hb_fsFNameMerge( ( char * ) szPath, pFilepath );
|
|
fIsFile = hb_fsFile( szPath );
|
|
}
|
|
if( !fIsFile &&
|
|
( uiExFlags & ( FXO_TRUNCATE | FXO_APPEND | FXO_UNIQUE ) ) == 0 &&
|
|
hb_setGetPath() )
|
|
{
|
|
pNextPath = hb_setGetFirstSetPath();
|
|
while( !fIsFile && pNextPath )
|
|
{
|
|
pFilepath->szPath = pNextPath->szPath;
|
|
hb_fsFNameMerge( ( char * ) szPath, pFilepath );
|
|
fIsFile = hb_fsFile( szPath );
|
|
pNextPath = pNextPath->pNext;
|
|
}
|
|
}
|
|
if( !fIsFile )
|
|
{
|
|
pFilepath->szPath = szDefault ? szDefault : NULL;
|
|
hb_fsFNameMerge( ( char * ) szPath, pFilepath );
|
|
}
|
|
}
|
|
else if( pPaths && *pPaths )
|
|
{
|
|
HB_PATHNAMES * pSearchPath = NULL;
|
|
hb_fsAddSearchPath( ( char * ) pPaths, &pSearchPath );
|
|
pNextPath = pSearchPath;
|
|
while( !fIsFile && pNextPath )
|
|
{
|
|
pFilepath->szPath = pNextPath->szPath;
|
|
hb_fsFNameMerge( ( char * ) szPath, pFilepath );
|
|
fIsFile = hb_fsFile( szPath );
|
|
pNextPath = pNextPath->pNext;
|
|
}
|
|
hb_fsFreeSearchPath( pSearchPath );
|
|
if( !fIsFile )
|
|
{
|
|
pFilepath->szPath = NULL;
|
|
hb_fsFNameMerge( ( char * ) szPath, pFilepath );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hb_fsFNameMerge( ( char * ) szPath, pFilepath );
|
|
}
|
|
hb_xfree( pFilepath );
|
|
|
|
return szPath;
|
|
}
|
|
|
|
HB_FHANDLE hb_fsExtOpen( BYTE * pFilename, BYTE * pDefExt,
|
|
USHORT uiExFlags, BYTE * pPaths,
|
|
PHB_ITEM pError )
|
|
{
|
|
HB_FHANDLE hFile;
|
|
USHORT uiFlags;
|
|
BYTE * szPath;
|
|
|
|
HB_TRACE(HB_TR_DEBUG, ("hb_fsExtOpen(%s, %s, %hu, %p, %p)", pFilename, pDefExt, uiExFlags, pPaths, pError));
|
|
|
|
#if 0
|
|
#define FXO_TRUNCATE 0x0100 /* Create (truncate if exists) */
|
|
#define FXO_APPEND 0x0200 /* Create (append if exists) */
|
|
#define FXO_UNIQUE 0x0400 /* Create unique file FO_EXCL ??? */
|
|
#define FXO_FORCEEXT 0x0800 /* Force default extension */
|
|
#define FXO_DEFAULTS 0x1000 /* Use SET command defaults */
|
|
#define FXO_DEVICERAW 0x2000 /* Open devices in raw mode */
|
|
/* Harbour extension */
|
|
#define FXO_SHARELOCK 0x4000 /* emulate DOS SH_DENY* mode in POSIX OS */
|
|
#define FXO_COPYNAME 0x8000 /* copy final szPath into pFilename */
|
|
|
|
hb_errGetFileName( pError );
|
|
#endif
|
|
|
|
szPath = hb_fsExtName( pFilename, pDefExt, uiExFlags, pPaths );
|
|
|
|
uiFlags = uiExFlags & 0xff;
|
|
if( uiExFlags & ( FXO_TRUNCATE | FXO_APPEND | FXO_UNIQUE ) )
|
|
{
|
|
uiFlags |= FO_CREAT;
|
|
if( uiExFlags & FXO_UNIQUE )
|
|
uiFlags |= FO_EXCL;
|
|
#if !defined( HB_USE_SHARELOCKS )
|
|
else if( uiExFlags & FXO_TRUNCATE )
|
|
uiFlags |= FO_TRUNC;
|
|
#endif
|
|
}
|
|
|
|
hFile = hb_fsOpen( szPath, uiFlags );
|
|
|
|
#if defined( HB_USE_SHARELOCKS )
|
|
if( hFile != FS_ERROR && uiExFlags & FXO_SHARELOCK )
|
|
{
|
|
#if defined( HB_USE_BSDLOCKS )
|
|
int iLock;
|
|
if( ( uiFlags & ( FO_READ | FO_WRITE | FO_READWRITE ) ) == FO_READ ||
|
|
( uiFlags & ( FO_DENYREAD | FO_DENYWRITE | FO_EXCLUSIVE ) ) == 0 )
|
|
iLock = LOCK_SH | LOCK_NB;
|
|
else
|
|
iLock = LOCK_EX | LOCK_NB;
|
|
hb_vmUnlock();
|
|
iLock = flock( hFile, iLock );
|
|
hb_vmLock();
|
|
if( iLock != 0 )
|
|
#else
|
|
USHORT uiLock;
|
|
if( ( uiFlags & ( FO_READ | FO_WRITE | FO_READWRITE ) ) == FO_READ ||
|
|
( uiFlags & ( FO_DENYREAD | FO_DENYWRITE | FO_EXCLUSIVE ) ) == 0 )
|
|
uiLock = FL_LOCK | FLX_SHARED;
|
|
else
|
|
uiLock = FL_LOCK | FLX_EXCLUSIVE;
|
|
|
|
if( !hb_fsLockLarge( hFile, HB_SHARELOCK_POS, HB_SHARELOCK_SIZE, uiLock ) )
|
|
#endif
|
|
{
|
|
hb_fsClose( hFile );
|
|
hFile = FS_ERROR;
|
|
/*
|
|
* fix for neterr() support and Clipper compatibility,
|
|
* should be revised with a better multi platform solution.
|
|
*/
|
|
hb_fsSetError( ( uiExFlags & FXO_TRUNCATE ) ? 5 : 32 );
|
|
}
|
|
else if( uiExFlags & FXO_TRUNCATE )
|
|
{
|
|
/* truncate the file only if properly locked */
|
|
hb_fsSeek( hFile, 0, FS_SET );
|
|
hb_fsWrite( hFile, NULL, 0 );
|
|
if( hb_fsError() != 0 )
|
|
{
|
|
hb_fsClose( hFile );
|
|
hFile = FS_ERROR;
|
|
hb_fsSetError( 5 );
|
|
}
|
|
}
|
|
}
|
|
#elif 1
|
|
/*
|
|
* Temporary fix for neterr() support and Clipper compatibility,
|
|
* should be revised with a better solution.
|
|
*/
|
|
if( ( uiExFlags & ( FXO_TRUNCATE | FXO_APPEND | FXO_UNIQUE ) ) == 0 &&
|
|
hb_fsError() == 5 )
|
|
{
|
|
hb_fsSetError( 32 );
|
|
}
|
|
#endif
|
|
|
|
if( pError )
|
|
{
|
|
hb_errPutFileName( pError, ( char * ) szPath );
|
|
if( hFile == FS_ERROR )
|
|
{
|
|
hb_errPutOsCode( pError, hb_fsError() );
|
|
hb_errPutGenCode( pError, ( USHORT ) ( ( uiExFlags & FXO_TRUNCATE ) ? EG_CREATE : EG_OPEN ) );
|
|
}
|
|
}
|
|
|
|
if( uiExFlags & FXO_COPYNAME && hFile != FS_ERROR )
|
|
hb_strncpy( ( char * ) pFilename, ( char * ) szPath, _POSIX_PATH_MAX );
|
|
|
|
hb_xfree( szPath );
|
|
return hFile;
|
|
}
|
|
|
|
BOOL hb_fsEof( HB_FHANDLE hFileHandle )
|
|
{
|
|
BOOL fResult;
|
|
|
|
hb_vmUnlock();
|
|
|
|
#if defined(__DJGPP__) || defined(__CYGWIN__) || \
|
|
defined(HB_IO_WIN) || defined(HB_WINCE) || \
|
|
defined(HB_OS_UNIX_COMPATIBLE)
|
|
{
|
|
HB_FOFFSET curPos;
|
|
HB_FOFFSET endPos;
|
|
HB_FOFFSET newPos;
|
|
|
|
curPos = hb_fsSeekLarge( hFileHandle, 0L, SEEK_CUR );
|
|
if( curPos != -1 )
|
|
{
|
|
endPos = hb_fsSeekLarge( hFileHandle, 0L, SEEK_END );
|
|
newPos = hb_fsSeekLarge( hFileHandle, curPos, SEEK_SET );
|
|
fResult = ( endPos != -1 && newPos == curPos );
|
|
}
|
|
else
|
|
{
|
|
endPos = -1;
|
|
fResult = FALSE;
|
|
}
|
|
hb_fsSetIOError( fResult, 0 );
|
|
fResult = !fResult || curPos == endPos;
|
|
}
|
|
#else
|
|
fResult = eof( hFileHandle ) != 0;
|
|
hb_fsSetIOError( fResult, 0 );
|
|
#endif
|
|
|
|
hb_vmLock();
|
|
|
|
return fResult;
|
|
}
|
|
|
|
BYTE * hb_fsNameConv( BYTE * szFileName, BOOL * pfFree )
|
|
{
|
|
int iFileCase, iDirCase;
|
|
char cDirSep;
|
|
BOOL fTrim;
|
|
BOOL bCPConv;
|
|
/*
|
|
Convert file and dir case. The allowed SET options are:
|
|
LOWER - Convert all caracters of file to lower
|
|
UPPER - Convert all caracters of file to upper
|
|
MIXED - Leave as is
|
|
|
|
The allowed environment options are:
|
|
FILECASE - define the case of file
|
|
DIRCASE - define the case of path
|
|
DIRSEPARATOR - define separator of path (Ex. "/")
|
|
TRIMFILENAME - strip trailing and leading spaces (also from extension)
|
|
*/
|
|
|
|
if( !hb_stackId() )
|
|
{
|
|
if( pfFree )
|
|
*pfFree = FALSE;
|
|
return szFileName;
|
|
}
|
|
|
|
fTrim = hb_setGetTrimFileName();
|
|
cDirSep = ( char ) hb_setGetDirSeparator();
|
|
iFileCase = hb_setGetFileCase();
|
|
iDirCase = hb_setGetDirCase();
|
|
bCPConv = hb_setGetOSCODEPAGE() && hb_setGetOSCODEPAGE()[ 0 ];
|
|
|
|
if( fTrim ||
|
|
cDirSep != HB_OS_PATH_DELIM_CHR ||
|
|
iFileCase != HB_SET_CASE_MIXED ||
|
|
iDirCase != HB_SET_CASE_MIXED ||
|
|
bCPConv )
|
|
{
|
|
PHB_FNAME pFileName;
|
|
ULONG ulLen;
|
|
|
|
if( pfFree )
|
|
{
|
|
BYTE * szNew = ( BYTE * ) hb_xgrab( _POSIX_PATH_MAX + 1 );
|
|
hb_strncpy( ( char * ) szNew, ( char * ) szFileName, _POSIX_PATH_MAX );
|
|
szFileName = szNew;
|
|
*pfFree = TRUE;
|
|
}
|
|
|
|
if( cDirSep != HB_OS_PATH_DELIM_CHR || bCPConv )
|
|
{
|
|
BYTE * p = szFileName;
|
|
|
|
while( *p )
|
|
{
|
|
if( cDirSep != HB_OS_PATH_DELIM_CHR && *p == cDirSep )
|
|
*p = HB_OS_PATH_DELIM_CHR;
|
|
p++;
|
|
}
|
|
}
|
|
|
|
if( bCPConv )
|
|
{
|
|
BOOL fFree;
|
|
BYTE * pbyResult = hb_osEncode( ( BYTE * ) szFileName, &fFree );
|
|
|
|
if( fFree )
|
|
{
|
|
hb_strncpy( ( char * ) szFileName, ( char * ) pbyResult, _POSIX_PATH_MAX );
|
|
hb_xfree( pbyResult );
|
|
}
|
|
}
|
|
|
|
pFileName = hb_fsFNameSplit( ( char * ) szFileName );
|
|
|
|
/* strip trailing and leading spaces */
|
|
if( fTrim )
|
|
{
|
|
if( pFileName->szName )
|
|
{
|
|
ulLen = strlen( pFileName->szName );
|
|
ulLen = hb_strRTrimLen( pFileName->szName, ulLen, FALSE );
|
|
pFileName->szName = hb_strLTrim( pFileName->szName, &ulLen );
|
|
( ( char * ) pFileName->szName )[ ulLen ] = '\0';
|
|
}
|
|
if( pFileName->szExtension )
|
|
{
|
|
ulLen = strlen( pFileName->szExtension );
|
|
ulLen = hb_strRTrimLen( pFileName->szExtension, ulLen, FALSE );
|
|
pFileName->szExtension = hb_strLTrim( pFileName->szExtension, &ulLen );
|
|
( ( char * ) pFileName->szExtension )[ ulLen ] = '\0';
|
|
}
|
|
}
|
|
|
|
/* FILECASE */
|
|
if( iFileCase == HB_SET_CASE_LOWER )
|
|
{
|
|
if( pFileName->szName )
|
|
hb_strLower( ( char * ) pFileName->szName, strlen( pFileName->szName ) );
|
|
if( pFileName->szExtension )
|
|
hb_strLower( ( char * ) pFileName->szExtension, strlen( pFileName->szExtension ) );
|
|
}
|
|
else if( iFileCase == HB_SET_CASE_UPPER )
|
|
{
|
|
if( pFileName->szName )
|
|
hb_strUpper( ( char * ) pFileName->szName, strlen( pFileName->szName ) );
|
|
if( pFileName->szExtension )
|
|
hb_strUpper( ( char * ) pFileName->szExtension, strlen( pFileName->szExtension ) );
|
|
}
|
|
|
|
/* DIRCASE */
|
|
if( pFileName->szPath )
|
|
{
|
|
if( iDirCase == HB_SET_CASE_LOWER )
|
|
hb_strLower( ( char * ) pFileName->szPath, strlen( pFileName->szPath ) );
|
|
else if( iDirCase == HB_SET_CASE_UPPER )
|
|
hb_strUpper( ( char * ) pFileName->szPath, strlen( pFileName->szPath ) );
|
|
}
|
|
|
|
hb_fsFNameMerge( ( char * ) szFileName, pFileName );
|
|
hb_xfree( pFileName );
|
|
}
|
|
else if( pfFree )
|
|
*pfFree = FALSE;
|
|
|
|
return szFileName;
|
|
}
|
|
|
|
#ifdef HB_LEGACY_LEVEL
|
|
|
|
BYTE * hb_fileNameConv( char * szFileName )
|
|
{
|
|
BOOL fFree;
|
|
BYTE * szNew;
|
|
|
|
szNew = hb_fsNameConv( ( BYTE * ) szFileName, &fFree );
|
|
if( fFree )
|
|
{
|
|
hb_strncpy( szFileName, ( char * ) szNew, strlen( szFileName ) );
|
|
hb_xfree( szNew );
|
|
}
|
|
|
|
return ( BYTE * ) szFileName;
|
|
}
|
|
|
|
#endif
|
|
|
|
/* NOTE: pbyBuffer must be _POSIX_PATH_MAX + 1 long. */
|
|
void hb_fsBaseDirBuff( BYTE * pbyBuffer )
|
|
{
|
|
/* TOFIX: In *NIX systems, this will return the dir specified in the
|
|
program invocation command line. Some suggest that cwd
|
|
should be prepended, although this doesn't solve the
|
|
problem if the program is executed from the path. [vszakats] */
|
|
PHB_FNAME pFName = hb_fsFNameSplit( hb_cmdargARGV()[ 0 ] );
|
|
|
|
pFName->szName = NULL;
|
|
pFName->szExtension = NULL;
|
|
|
|
hb_fsFNameMerge( ( char * ) pbyBuffer, pFName );
|
|
hb_xfree( pFName );
|
|
|
|
/* Convert from OS codepage */
|
|
{
|
|
BOOL fFree;
|
|
BYTE * pbyResult = hb_osDecode( pbyBuffer, &fFree );
|
|
|
|
if( fFree )
|
|
{
|
|
hb_strncpy( ( char * ) pbyBuffer, ( char * ) pbyResult, _POSIX_PATH_MAX );
|
|
hb_xfree( pbyResult );
|
|
}
|
|
}
|
|
}
|
|
|
|
static BOOL hb_fsDisableWaitLocks( int iSet )
|
|
{
|
|
BOOL fRetVal = s_fUseWaitLocks;
|
|
|
|
if( iSet >= 0 )
|
|
s_fUseWaitLocks = ( iSet == 0 );
|
|
|
|
return fRetVal;
|
|
}
|
|
|
|
HB_FUNC( HB_DISABLEWAITLOCKS )
|
|
{
|
|
hb_retl( hb_fsDisableWaitLocks( ISLOG( 1 ) ? ( hb_parl( 1 ) ? 1 : 0 ) : -1 ) );
|
|
}
|