From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

/* Win32API/File.xs */
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
/*#include "patchlevel.h"*/
/* Uncomment the next line unless set "WRITE_PERL=>1" in Makefile.PL: */
#define NEED_newCONSTSUB
#include "ppport.h"
#ifdef WORD
# undef WORD
#endif
#define WIN32_LEAN_AND_MEAN /* Tell windows.h to skip much */
#include <wchar.h>
#include <windows.h>
#include <winioctl.h>
/*CONSTS_DEFINED*/
#ifndef INVALID_SET_FILE_POINTER
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
#endif
#define oDWORD DWORD
#if (PERL_REVISION <= 5 && PERL_VERSION < 5) || defined(__CYGWIN__)
# define win32_get_osfhandle _get_osfhandle
# ifdef __CYGWIN__
# define win32_open_osfhandle(handle,mode) \
(Perl_croak(aTHX_ "_open_osfhandle not implemented on Cygwin!"), -1)
# else
# define win32_open_osfhandle _open_osfhandle
# endif
# ifdef _get_osfhandle
# undef _get_osfhandle /* stolen_get_osfhandle() isn't available here */
# endif
# ifdef _open_osfhandle
# undef _open_osfhandle /* stolen_open_osfhandle() isn't available here */
# endif
#endif
#ifndef XST_mUV
# define XST_mUV(i,v) (ST(i) = sv_2mortal(newSVuv(v)) )
#endif
#ifndef XSRETURN_UV
# define XSRETURN_UV(v) STMT_START { XST_mUV(0,v); XSRETURN(1); } STMT_END
#endif
#ifndef DEBUGGING
# define Debug(list) /*Nothing*/
#else
# define Debug(list) ErrPrintf list
# include <stdarg.h>
static void
ErrPrintf( const char *sFmt, ... )
{
va_list pAList;
static char *sEnv= NULL;
DWORD uErr= GetLastError();
if( NULL == sEnv ) {
if( NULL == ( sEnv= getenv("DEBUG_WIN32API_FILE") ) )
sEnv= "";
}
if( '\0' == *sEnv )
return;
va_start( pAList, sFmt );
vfprintf( stderr, sFmt, pAList );
va_end( pAList );
SetLastError( uErr );
}
#endif /* DEBUGGING */
#include "buffers.h" /* Include this after DEBUGGING setup finished */
static LONG uLastFileErr= 0;
static void
SaveErr( BOOL bFailed )
{
if( bFailed ) {
uLastFileErr= GetLastError();
}
}
MODULE = Win32API::File PACKAGE = Win32API::File
PROTOTYPES: DISABLE
LONG
_fileLastError( uError=0 )
DWORD uError
CODE:
if( 1 <= items ) {
uLastFileErr= uError;
}
RETVAL= uLastFileErr;
OUTPUT:
RETVAL
BOOL
CloseHandle( hObject )
HANDLE hObject
CODE:
RETVAL = CloseHandle( hObject );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
BOOL
CopyFileA( sOldFileName, sNewFileName, bFailIfExists )
char * sOldFileName
char * sNewFileName
BOOL bFailIfExists
CODE:
RETVAL = CopyFileA( sOldFileName, sNewFileName, bFailIfExists );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
BOOL
CopyFileW( swOldFileName, swNewFileName, bFailIfExists )
WCHAR * swOldFileName
WCHAR * swNewFileName
BOOL bFailIfExists
CODE:
RETVAL = CopyFileW( swOldFileName, swNewFileName, bFailIfExists );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
HANDLE
CreateFileA( sPath, uAccess, uShare, pSecAttr, uCreate, uFlags, hModel )
char * sPath
DWORD uAccess
DWORD uShare
void * pSecAttr
DWORD uCreate
DWORD uFlags
HANDLE hModel
CODE:
RETVAL= CreateFileA( sPath, uAccess, uShare,
(LPSECURITY_ATTRIBUTES)pSecAttr, uCreate, uFlags, hModel );
if( INVALID_HANDLE_VALUE == RETVAL ) {
SaveErr( 1 );
XSRETURN_NO;
} else if( 0 == RETVAL ) {
XSRETURN_PV( "0 but true" );
} else {
XSRETURN_UV( PTR2UV(RETVAL) );
}
HANDLE
CreateFileW( swPath, uAccess, uShare, pSecAttr, uCreate, uFlags, hModel )
WCHAR * swPath
DWORD uAccess
DWORD uShare
void * pSecAttr
DWORD uCreate
DWORD uFlags
HANDLE hModel
CODE:
RETVAL= CreateFileW( swPath, uAccess, uShare,
(LPSECURITY_ATTRIBUTES)pSecAttr, uCreate, uFlags, hModel );
if( INVALID_HANDLE_VALUE == RETVAL ) {
SaveErr( 1 );
XSRETURN_NO;
} else if( 0 == RETVAL ) {
XSRETURN_PV( "0 but true" );
} else {
XSRETURN_UV( PTR2UV(RETVAL) );
}
BOOL
DefineDosDeviceA( uFlags, sDosDeviceName, sTargetPath )
DWORD uFlags
char * sDosDeviceName
char * sTargetPath
CODE:
RETVAL = DefineDosDeviceA( uFlags, sDosDeviceName, sTargetPath );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
BOOL
DefineDosDeviceW( uFlags, swDosDeviceName, swTargetPath )
DWORD uFlags
WCHAR * swDosDeviceName
WCHAR * swTargetPath
CODE:
RETVAL = DefineDosDeviceW( uFlags, swDosDeviceName, swTargetPath );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
BOOL
DeleteFileA( sFileName )
char * sFileName
CODE:
RETVAL = DeleteFileA( sFileName );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
BOOL
DeleteFileW( swFileName )
WCHAR * swFileName
CODE:
RETVAL = DeleteFileW( swFileName );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
BOOL
DeviceIoControl( hDevice, uIoControlCode, pInBuf, lInBuf, opOutBuf, lOutBuf, olRetBytes, pOverlapped )
HANDLE hDevice
DWORD uIoControlCode
char * pInBuf
DWORD lInBuf = init_buf_l($arg);
char * opOutBuf = NO_INIT
DWORD lOutBuf = init_buf_l($arg);
oDWORD &olRetBytes
void * pOverlapped
CODE:
if( NULL != pInBuf ) {
if( 0 == lInBuf ) {
lInBuf= SvCUR(ST(2));
} else if( SvCUR(ST(2)) < lInBuf ) {
croak( "%s: pInBuf shorter than specified (%d < %d)",
"Win32API::File::DeviceIoControl", SvCUR(ST(2)), lInBuf );
}
}
grow_buf_l( opOutBuf,ST(4),char *, lOutBuf,ST(5) );
RETVAL= DeviceIoControl( hDevice, uIoControlCode, pInBuf, lInBuf,
opOutBuf, lOutBuf, &olRetBytes, (LPOVERLAPPED)pOverlapped );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
opOutBuf trunc_buf_l( RETVAL, opOutBuf,ST(4), olRetBytes );
olRetBytes
HANDLE
FdGetOsFHandle( ivFd )
int ivFd
CODE:
RETVAL= (HANDLE) win32_get_osfhandle( ivFd );
SaveErr( INVALID_HANDLE_VALUE == RETVAL );
OUTPUT:
RETVAL
DWORD
GetDriveTypeA( sRootPath )
char * sRootPath
CODE:
RETVAL = GetDriveTypeA( sRootPath );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
DWORD
GetDriveTypeW( swRootPath )
WCHAR * swRootPath
CODE:
RETVAL = GetDriveTypeW( swRootPath );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
DWORD
GetFileAttributesA( sPath )
char * sPath
CODE:
RETVAL = GetFileAttributesA( sPath );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
DWORD
GetFileAttributesW( swPath )
WCHAR * swPath
CODE:
RETVAL = GetFileAttributesW( swPath );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
DWORD
GetFileType( hFile )
HANDLE hFile
CODE:
RETVAL = GetFileType( hFile );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
BOOL
GetHandleInformation( hObject, ouFlags )
HANDLE hObject
oDWORD * ouFlags
CODE:
RETVAL = GetHandleInformation( hObject, ouFlags );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
ouFlags
DWORD
GetLogicalDrives()
CODE:
RETVAL = GetLogicalDrives();
SaveErr( !RETVAL );
OUTPUT:
RETVAL
DWORD
GetLogicalDriveStringsA( lBufSize, osBuffer )
DWORD lBufSize = init_buf_l($arg);
char * osBuffer = NO_INIT
CODE:
grow_buf_l( osBuffer,ST(1),char *, lBufSize,ST(0) );
RETVAL= GetLogicalDriveStringsA( lBufSize, osBuffer );
if( lBufSize < RETVAL && autosize(ST(0)) ) {
lBufSize= RETVAL;
grow_buf_l( osBuffer,ST(1),char *, lBufSize,ST(0) );
RETVAL= GetLogicalDriveStringsA( lBufSize, osBuffer );
}
if( 0 == RETVAL || lBufSize < RETVAL ) {
SaveErr( 1 );
} else {
trunc_buf_l( 1, osBuffer,ST(1), RETVAL );
}
OUTPUT:
RETVAL
osBuffer ;/* The code for this appears above. */
DWORD
GetLogicalDriveStringsW( lwBufSize, oswBuffer )
DWORD lwBufSize = init_buf_lw($arg);
WCHAR * oswBuffer = NO_INIT
CODE:
grow_buf_lw( oswBuffer,ST(1), lwBufSize,ST(0) );
RETVAL= GetLogicalDriveStringsW( lwBufSize, oswBuffer );
if( lwBufSize < RETVAL && autosize(ST(0)) ) {
lwBufSize= RETVAL;
grow_buf_lw( oswBuffer,ST(1), lwBufSize,ST(0) );
RETVAL= GetLogicalDriveStringsW( lwBufSize, oswBuffer );
}
if( 0 == RETVAL || lwBufSize < RETVAL ) {
SaveErr( 1 );
} else {
trunc_buf_lw( 1, oswBuffer,ST(1), RETVAL );
}
OUTPUT:
RETVAL
oswBuffer ;/* The code for this appears above. */
BOOL
GetVolumeInformationA( sRootPath, osVolName, lVolName, ouSerialNum, ouMaxNameLen, ouFsFlags, osFsType, lFsType )
char * sRootPath
char * osVolName = NO_INIT
DWORD lVolName = init_buf_l($arg);
oDWORD &ouSerialNum = optUV($arg);
oDWORD &ouMaxNameLen = optUV($arg);
oDWORD &ouFsFlags = optUV($arg);
char * osFsType = NO_INIT
DWORD lFsType = init_buf_l($arg);
CODE:
grow_buf_l( osVolName,ST(1),char *, lVolName,ST(2) );
grow_buf_l( osFsType,ST(6),char *, lFsType,ST(7) );
RETVAL= GetVolumeInformationA( sRootPath, osVolName, lVolName,
&ouSerialNum, &ouMaxNameLen, &ouFsFlags, osFsType, lFsType );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
osVolName trunc_buf_z( RETVAL, osVolName,ST(1) );
osFsType trunc_buf_z( RETVAL, osFsType,ST(6) );
ouSerialNum
ouMaxNameLen
ouFsFlags
BOOL
GetVolumeInformationW( swRootPath, oswVolName, lwVolName, ouSerialNum, ouMaxNameLen, ouFsFlags, oswFsType, lwFsType )
WCHAR * swRootPath
WCHAR * oswVolName = NO_INIT
DWORD lwVolName = init_buf_lw($arg);
oDWORD &ouSerialNum = optUV($arg);
oDWORD &ouMaxNameLen = optUV($arg);
oDWORD &ouFsFlags = optUV($arg);
WCHAR * oswFsType = NO_INIT
DWORD lwFsType = init_buf_lw($arg);
CODE:
grow_buf_lw( oswVolName,ST(1), lwVolName,ST(2) );
grow_buf_lw( oswFsType,ST(6), lwFsType,ST(7) );
RETVAL= GetVolumeInformationW( swRootPath, oswVolName, lwVolName,
&ouSerialNum, &ouMaxNameLen, &ouFsFlags, oswFsType, lwFsType );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
oswVolName trunc_buf_zw( RETVAL, oswVolName,ST(1) );
oswFsType trunc_buf_zw( RETVAL, oswFsType,ST(6) );
ouSerialNum
ouMaxNameLen
ouFsFlags
BOOL
IsRecognizedPartition( ivPartitionType )
int ivPartitionType
CODE:
RETVAL = IsRecognizedPartition( ivPartitionType );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
BOOL
IsContainerPartition( ivPartitionType )
int ivPartitionType
CODE:
RETVAL = IsContainerPartition( ivPartitionType );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
BOOL
MoveFileA( sOldName, sNewName )
char * sOldName
char * sNewName
CODE:
RETVAL = MoveFileA( sOldName, sNewName );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
BOOL
MoveFileW( swOldName, swNewName )
WCHAR * swOldName
WCHAR * swNewName
CODE:
RETVAL = MoveFileW( swOldName, swNewName );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
BOOL
MoveFileExA( sOldName, sNewName, uFlags )
char * sOldName
char * sNewName
DWORD uFlags
CODE:
RETVAL = MoveFileExA( sOldName, sNewName, uFlags );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
BOOL
MoveFileExW( swOldName, swNewName, uFlags )
WCHAR * swOldName
WCHAR * swNewName
DWORD uFlags
CODE:
RETVAL = MoveFileExW( swOldName, swNewName, uFlags );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
long
OsFHandleOpenFd( hOsFHandle, uMode )
long hOsFHandle
DWORD uMode
CODE:
RETVAL= win32_open_osfhandle( hOsFHandle, uMode );
if( RETVAL < 0 ) {
SaveErr( 1 );
XSRETURN_NO;
} else if( 0 == RETVAL ) {
XSRETURN_PV( "0 but true" );
} else {
XSRETURN_IV( (IV) RETVAL );
}
DWORD
QueryDosDeviceA( sDeviceName, osTargetPath, lTargetBuf )
char * sDeviceName
char * osTargetPath = NO_INIT
DWORD lTargetBuf = init_buf_l($arg);
CODE:
grow_buf_l( osTargetPath,ST(1),char *, lTargetBuf,ST(2) );
RETVAL= QueryDosDeviceA( sDeviceName, osTargetPath, lTargetBuf );
SaveErr( 0 == RETVAL );
OUTPUT:
RETVAL
osTargetPath trunc_buf_l( 1, osTargetPath,ST(1), RETVAL );
DWORD
QueryDosDeviceW( swDeviceName, oswTargetPath, lwTargetBuf )
WCHAR * swDeviceName
WCHAR * oswTargetPath = NO_INIT
DWORD lwTargetBuf = init_buf_lw($arg);
CODE:
grow_buf_lw( oswTargetPath,ST(1), lwTargetBuf,ST(2) );
RETVAL= QueryDosDeviceW( swDeviceName, oswTargetPath, lwTargetBuf );
SaveErr( 0 == RETVAL );
OUTPUT:
RETVAL
oswTargetPath trunc_buf_lw( 1, oswTargetPath,ST(1), RETVAL );
BOOL
ReadFile( hFile, opBuffer, lBytes, olBytesRead, pOverlapped )
HANDLE hFile
BYTE * opBuffer = NO_INIT
DWORD lBytes = init_buf_l($arg);
oDWORD &olBytesRead
void * pOverlapped
CODE:
grow_buf_l( opBuffer,ST(1),BYTE *, lBytes,ST(2) );
/* Don't read more bytes than asked for if buffer is already big: */
lBytes= init_buf_l(ST(2));
if( 0 == lBytes && autosize(ST(2)) ) {
lBytes= SvLEN( ST(1) ) - 1;
}
RETVAL= ReadFile( hFile, opBuffer, lBytes, &olBytesRead,
(LPOVERLAPPED)pOverlapped );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
opBuffer trunc_buf_l( RETVAL, opBuffer,ST(1), olBytesRead );
olBytesRead
BOOL
GetOverlappedResult( hFile, lpOverlapped, lpNumberOfBytesTransferred, bWait)
HANDLE hFile
LPOVERLAPPED lpOverlapped
LPDWORD lpNumberOfBytesTransferred
BOOL bWait
CODE:
RETVAL= GetOverlappedResult( hFile, lpOverlapped,
lpNumberOfBytesTransferred, bWait);
SaveErr( !RETVAL );
OUTPUT:
RETVAL
lpOverlapped
lpNumberOfBytesTransferred
DWORD
GetFileSize( hFile, lpFileSizeHigh )
HANDLE hFile
LPDWORD lpFileSizeHigh
CODE:
RETVAL= GetFileSize( hFile, lpFileSizeHigh );
SaveErr( NO_ERROR != GetLastError() );
OUTPUT:
RETVAL
lpFileSizeHigh
UINT
SetErrorMode( uNewMode )
UINT uNewMode
LONG
SetFilePointer( hFile, ivOffset, ioivOffsetHigh, uFromWhere )
HANDLE hFile
LONG ivOffset
LONG * ioivOffsetHigh
DWORD uFromWhere
CODE:
RETVAL= SetFilePointer( hFile, ivOffset, ioivOffsetHigh, uFromWhere );
if( RETVAL == INVALID_SET_FILE_POINTER && (GetLastError() != NO_ERROR) ) {
SaveErr( 1 );
XST_mNO(0);
} else if( 0 == RETVAL ) {
XST_mPV(0,"0 but true");
} else {
XST_mIV(0,RETVAL);
}
OUTPUT:
ioivOffsetHigh
BOOL
SetHandleInformation( hObject, uMask, uFlags )
HANDLE hObject
DWORD uMask
DWORD uFlags
CODE:
RETVAL = SetHandleInformation( hObject, uMask, uFlags );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
BOOL
WriteFile( hFile, pBuffer, lBytes, ouBytesWritten, pOverlapped )
HANDLE hFile
BYTE * pBuffer
DWORD lBytes = init_buf_l($arg);
oDWORD &ouBytesWritten
void * pOverlapped
CODE:
/* SvCUR(ST(1)) might "panic" if pBuffer isn't valid */
if( 0 == lBytes ) {
lBytes= SvCUR(ST(1));
} else if( SvCUR(ST(1)) < lBytes ) {
croak( "%s: pBuffer value too short (%d < %d)",
"Win32API::File::WriteFile", SvCUR(ST(1)), lBytes );
}
RETVAL= WriteFile( hFile, pBuffer, lBytes,
&ouBytesWritten, (LPOVERLAPPED)pOverlapped );
SaveErr( !RETVAL );
OUTPUT:
RETVAL
ouBytesWritten
void
GetStdHandle(fd)
DWORD fd
PPCODE:
#ifdef _WIN64
XSRETURN_IV((DWORD_PTR)GetStdHandle(fd));
#else
XSRETURN_IV((DWORD)GetStdHandle(fd));
#endif
void
SetStdHandle(fd,handle)
DWORD fd
HANDLE handle
PPCODE:
if (SetStdHandle(fd, handle))
XSRETURN_YES;
else
XSRETURN_NO;