1/* Win32API/File.xs */
2
3#include "EXTERN.h"
4#include "perl.h"
5#include "XSUB.h"
6/*#include "patchlevel.h"*/
7
8/* Uncomment the next line unless set "WRITE_PERL=>1" in Makefile.PL: */
9#define NEED_newCONSTSUB
10#include "ppport.h"
11
12#ifdef WORD
13# undef WORD
14#endif
15
16#define  WIN32_LEAN_AND_MEAN	/* Tell windows.h to skip much */
17#include <wchar.h>
18#include <windows.h>
19#include <winioctl.h>
20
21/*CONSTS_DEFINED*/
22
23#ifndef INVALID_SET_FILE_POINTER
24#   define INVALID_SET_FILE_POINTER	((DWORD)-1)
25#endif
26
27#define oDWORD DWORD
28
29#if (PERL_REVISION <= 5 && PERL_VERSION < 5) || defined(__CYGWIN__)
30# define win32_get_osfhandle _get_osfhandle
31# ifdef __CYGWIN__
32#  define win32_open_osfhandle(handle,mode) \
33	(Perl_croak(aTHX_ "_open_osfhandle not implemented on Cygwin!"), -1)
34# else
35#  define win32_open_osfhandle _open_osfhandle
36# endif
37# ifdef _get_osfhandle
38#  undef _get_osfhandle	/* stolen_get_osfhandle() isn't available here */
39# endif
40# ifdef _open_osfhandle
41#  undef _open_osfhandle /* stolen_open_osfhandle() isn't available here */
42# endif
43#endif
44
45#ifndef XST_mUV
46# define XST_mUV(i,v)  (ST(i) = sv_2mortal(newSVuv(v))  )
47#endif
48
49#ifndef XSRETURN_UV
50# define XSRETURN_UV(v) STMT_START { XST_mUV(0,v);  XSRETURN(1); } STMT_END
51#endif
52
53#ifndef DEBUGGING
54# define	Debug(list)	/*Nothing*/
55#else
56# define	Debug(list)	ErrPrintf list
57# include <stdarg.h>
58    static void
59    ErrPrintf( const char *sFmt, ... )
60    {
61      va_list pAList;
62      static char *sEnv= NULL;
63      DWORD uErr= GetLastError();
64	if(  NULL == sEnv  ) {
65	    if(  NULL == ( sEnv= getenv("DEBUG_WIN32API_FILE") )  )
66		sEnv= "";
67	}
68	if(  '\0' == *sEnv  )
69	    return;
70	va_start( pAList, sFmt );
71	vfprintf( stderr, sFmt, pAList );
72	va_end( pAList );
73	SetLastError( uErr );
74    }
75#endif /* DEBUGGING */
76
77
78#include "buffers.h"	/* Include this after DEBUGGING setup finished */
79
80static LONG uLastFileErr= 0;
81
82static void
83SaveErr( BOOL bFailed )
84{
85    if(  bFailed  ) {
86	uLastFileErr= GetLastError();
87    }
88}
89
90MODULE = Win32API::File		PACKAGE = Win32API::File
91
92PROTOTYPES: DISABLE
93
94
95LONG
96_fileLastError( uError=0 )
97	DWORD	uError
98    CODE:
99	if(  1 <= items  ) {
100	    uLastFileErr= uError;
101	}
102	RETVAL= uLastFileErr;
103    OUTPUT:
104	RETVAL
105
106
107BOOL
108CloseHandle( hObject )
109	HANDLE	hObject
110    CODE:
111        RETVAL = CloseHandle( hObject );
112	SaveErr( !RETVAL );
113    OUTPUT:
114	RETVAL
115
116
117BOOL
118CopyFileA( sOldFileName, sNewFileName, bFailIfExists )
119	char *	sOldFileName
120	char *	sNewFileName
121	BOOL	bFailIfExists
122    CODE:
123        RETVAL = CopyFileA( sOldFileName, sNewFileName, bFailIfExists );
124	SaveErr( !RETVAL );
125    OUTPUT:
126	RETVAL
127
128
129BOOL
130CopyFileW( swOldFileName, swNewFileName, bFailIfExists )
131	WCHAR *	swOldFileName
132	WCHAR *	swNewFileName
133	BOOL	bFailIfExists
134    CODE:
135        RETVAL = CopyFileW( swOldFileName, swNewFileName, bFailIfExists );
136	SaveErr( !RETVAL );
137    OUTPUT:
138	RETVAL
139
140
141HANDLE
142CreateFileA( sPath, uAccess, uShare, pSecAttr, uCreate, uFlags, hModel )
143	char *	sPath
144	DWORD	uAccess
145	DWORD	uShare
146	void *	pSecAttr
147	DWORD	uCreate
148	DWORD	uFlags
149	HANDLE	hModel
150    CODE:
151	RETVAL= CreateFileA( sPath, uAccess, uShare,
152	  (LPSECURITY_ATTRIBUTES)pSecAttr, uCreate, uFlags, hModel );
153	if(  INVALID_HANDLE_VALUE == RETVAL  ) {
154	    SaveErr( 1 );
155	    XSRETURN_NO;
156	} else if(  0 == RETVAL  ) {
157	    XSRETURN_PV( "0 but true" );
158	} else {
159	    XSRETURN_UV( PTR2UV(RETVAL) );
160	}
161
162
163HANDLE
164CreateFileW( swPath, uAccess, uShare, pSecAttr, uCreate, uFlags, hModel )
165	WCHAR *	swPath
166	DWORD	uAccess
167	DWORD	uShare
168	void *	pSecAttr
169	DWORD	uCreate
170	DWORD	uFlags
171	HANDLE	hModel
172    CODE:
173	RETVAL= CreateFileW( swPath, uAccess, uShare,
174	  (LPSECURITY_ATTRIBUTES)pSecAttr, uCreate, uFlags, hModel );
175	if(  INVALID_HANDLE_VALUE == RETVAL  ) {
176	    SaveErr( 1 );
177	    XSRETURN_NO;
178	} else if(  0 == RETVAL  ) {
179	    XSRETURN_PV( "0 but true" );
180	} else {
181	    XSRETURN_UV( PTR2UV(RETVAL) );
182	}
183
184
185BOOL
186DefineDosDeviceA( uFlags, sDosDeviceName, sTargetPath )
187	DWORD	uFlags
188	char *	sDosDeviceName
189	char *	sTargetPath
190    CODE:
191        RETVAL = DefineDosDeviceA( uFlags, sDosDeviceName, sTargetPath );
192	SaveErr( !RETVAL );
193    OUTPUT:
194	RETVAL
195
196
197BOOL
198DefineDosDeviceW( uFlags, swDosDeviceName, swTargetPath )
199	DWORD	uFlags
200	WCHAR *	swDosDeviceName
201	WCHAR *	swTargetPath
202    CODE:
203        RETVAL = DefineDosDeviceW( uFlags, swDosDeviceName, swTargetPath );
204	SaveErr( !RETVAL );
205    OUTPUT:
206	RETVAL
207
208
209BOOL
210DeleteFileA( sFileName )
211	char *	sFileName
212    CODE:
213        RETVAL = DeleteFileA( sFileName );
214	SaveErr( !RETVAL );
215    OUTPUT:
216	RETVAL
217
218
219BOOL
220DeleteFileW( swFileName )
221	WCHAR *	swFileName
222    CODE:
223        RETVAL = DeleteFileW( swFileName );
224	SaveErr( !RETVAL );
225    OUTPUT:
226	RETVAL
227
228
229BOOL
230DeviceIoControl( hDevice, uIoControlCode, pInBuf, lInBuf, opOutBuf, lOutBuf, olRetBytes, pOverlapped )
231	HANDLE	hDevice
232	DWORD	uIoControlCode
233	char *	pInBuf
234	DWORD	lInBuf		= init_buf_l($arg);
235	char *	opOutBuf	= NO_INIT
236	DWORD	lOutBuf		= init_buf_l($arg);
237	oDWORD	&olRetBytes
238	void *	pOverlapped
239    CODE:
240	if(  NULL != pInBuf  ) {
241	    if(  0 == lInBuf  ) {
242		lInBuf= SvCUR(ST(2));
243	    } else if(  SvCUR(ST(2)) < lInBuf  ) {
244		croak( "%s: pInBuf shorter than specified (%d < %d)",
245		  "Win32API::File::DeviceIoControl", SvCUR(ST(2)), lInBuf );
246	    }
247	}
248	grow_buf_l( opOutBuf,ST(4),char *, lOutBuf,ST(5) );
249	RETVAL= DeviceIoControl( hDevice, uIoControlCode, pInBuf, lInBuf,
250		  opOutBuf, lOutBuf, &olRetBytes, (LPOVERLAPPED)pOverlapped );
251	SaveErr( !RETVAL );
252    OUTPUT:
253	RETVAL
254	opOutBuf	trunc_buf_l( RETVAL, opOutBuf,ST(4), olRetBytes );
255	olRetBytes
256
257
258HANDLE
259FdGetOsFHandle( ivFd )
260	int	ivFd
261    CODE:
262	RETVAL= (HANDLE) win32_get_osfhandle( ivFd );
263	SaveErr( INVALID_HANDLE_VALUE == RETVAL );
264    OUTPUT:
265	RETVAL
266
267
268DWORD
269GetDriveTypeA( sRootPath )
270	char *	sRootPath
271    CODE:
272        RETVAL = GetDriveTypeA( sRootPath );
273	SaveErr( !RETVAL );
274    OUTPUT:
275	RETVAL
276
277
278DWORD
279GetDriveTypeW( swRootPath )
280	WCHAR *	swRootPath
281    CODE:
282        RETVAL = GetDriveTypeW( swRootPath );
283	SaveErr( !RETVAL );
284    OUTPUT:
285	RETVAL
286
287
288DWORD
289GetFileAttributesA( sPath )
290	char *	sPath
291    CODE:
292        RETVAL = GetFileAttributesA( sPath );
293	SaveErr( !RETVAL );
294    OUTPUT:
295	RETVAL
296
297
298DWORD
299GetFileAttributesW( swPath )
300	WCHAR *	swPath
301    CODE:
302        RETVAL = GetFileAttributesW( swPath );
303	SaveErr( !RETVAL );
304    OUTPUT:
305	RETVAL
306
307
308DWORD
309GetFileType( hFile )
310	HANDLE	hFile
311    CODE:
312        RETVAL = GetFileType( hFile );
313	SaveErr( !RETVAL );
314    OUTPUT:
315	RETVAL
316
317
318BOOL
319GetHandleInformation( hObject, ouFlags )
320	HANDLE		hObject
321	oDWORD *	ouFlags
322    CODE:
323        RETVAL = GetHandleInformation( hObject, ouFlags );
324	SaveErr( !RETVAL );
325    OUTPUT:
326	RETVAL
327	ouFlags
328
329
330DWORD
331GetLogicalDrives()
332    CODE:
333        RETVAL = GetLogicalDrives();
334	SaveErr( !RETVAL );
335    OUTPUT:
336	RETVAL
337
338
339DWORD
340GetLogicalDriveStringsA( lBufSize, osBuffer )
341	DWORD	lBufSize	= init_buf_l($arg);
342	char *	osBuffer	= NO_INIT
343    CODE:
344	grow_buf_l( osBuffer,ST(1),char *, lBufSize,ST(0) );
345	RETVAL= GetLogicalDriveStringsA( lBufSize, osBuffer );
346	if(  lBufSize < RETVAL  &&  autosize(ST(0))  ) {
347	    lBufSize= RETVAL;
348	    grow_buf_l( osBuffer,ST(1),char *, lBufSize,ST(0) );
349	    RETVAL= GetLogicalDriveStringsA( lBufSize, osBuffer );
350	}
351	if(  0 == RETVAL  ||  lBufSize < RETVAL  ) {
352	    SaveErr( 1 );
353	} else {
354	    trunc_buf_l( 1, osBuffer,ST(1), RETVAL );
355	}
356    OUTPUT:
357	RETVAL
358	osBuffer	;/* The code for this appears above. */
359
360
361DWORD
362GetLogicalDriveStringsW( lwBufSize, oswBuffer )
363	DWORD	lwBufSize	= init_buf_lw($arg);
364	WCHAR *	oswBuffer	= NO_INIT
365    CODE:
366	grow_buf_lw( oswBuffer,ST(1), lwBufSize,ST(0) );
367	RETVAL= GetLogicalDriveStringsW( lwBufSize, oswBuffer );
368	if(  lwBufSize < RETVAL  &&  autosize(ST(0))  ) {
369	    lwBufSize= RETVAL;
370	    grow_buf_lw( oswBuffer,ST(1), lwBufSize,ST(0) );
371	    RETVAL= GetLogicalDriveStringsW( lwBufSize, oswBuffer );
372	}
373	if(  0 == RETVAL  ||  lwBufSize < RETVAL  ) {
374	    SaveErr( 1 );
375	} else {
376	    trunc_buf_lw( 1, oswBuffer,ST(1), RETVAL );
377	}
378    OUTPUT:
379	RETVAL
380	oswBuffer	;/* The code for this appears above. */
381
382
383BOOL
384GetVolumeInformationA( sRootPath, osVolName, lVolName, ouSerialNum, ouMaxNameLen, ouFsFlags, osFsType, lFsType )
385	char *	sRootPath
386	char *	osVolName	= NO_INIT
387	DWORD	lVolName	= init_buf_l($arg);
388	oDWORD	&ouSerialNum	= optUV($arg);
389	oDWORD	&ouMaxNameLen	= optUV($arg);
390	oDWORD	&ouFsFlags	= optUV($arg);
391	char *	osFsType	= NO_INIT
392	DWORD	lFsType		= init_buf_l($arg);
393    CODE:
394	grow_buf_l( osVolName,ST(1),char *, lVolName,ST(2) );
395	grow_buf_l( osFsType,ST(6),char *, lFsType,ST(7) );
396	RETVAL= GetVolumeInformationA( sRootPath, osVolName, lVolName,
397		  &ouSerialNum, &ouMaxNameLen, &ouFsFlags, osFsType, lFsType );
398	SaveErr( !RETVAL );
399    OUTPUT:
400	RETVAL
401	osVolName	trunc_buf_z( RETVAL, osVolName,ST(1) );
402	osFsType	trunc_buf_z( RETVAL, osFsType,ST(6) );
403	ouSerialNum
404	ouMaxNameLen
405	ouFsFlags
406
407
408BOOL
409GetVolumeInformationW( swRootPath, oswVolName, lwVolName, ouSerialNum, ouMaxNameLen, ouFsFlags, oswFsType, lwFsType )
410	WCHAR *	swRootPath
411	WCHAR *	oswVolName	= NO_INIT
412	DWORD	lwVolName	= init_buf_lw($arg);
413	oDWORD	&ouSerialNum	= optUV($arg);
414	oDWORD	&ouMaxNameLen	= optUV($arg);
415	oDWORD	&ouFsFlags	= optUV($arg);
416	WCHAR *	oswFsType	= NO_INIT
417	DWORD	lwFsType	= init_buf_lw($arg);
418    CODE:
419	grow_buf_lw( oswVolName,ST(1), lwVolName,ST(2) );
420	grow_buf_lw( oswFsType,ST(6), lwFsType,ST(7) );
421	RETVAL= GetVolumeInformationW( swRootPath, oswVolName, lwVolName,
422	  &ouSerialNum, &ouMaxNameLen, &ouFsFlags, oswFsType, lwFsType );
423	SaveErr( !RETVAL );
424    OUTPUT:
425	RETVAL
426	oswVolName	trunc_buf_zw( RETVAL, oswVolName,ST(1) );
427	oswFsType	trunc_buf_zw( RETVAL, oswFsType,ST(6) );
428	ouSerialNum
429	ouMaxNameLen
430	ouFsFlags
431
432
433BOOL
434IsRecognizedPartition( ivPartitionType )
435	int	ivPartitionType
436    CODE:
437        RETVAL = IsRecognizedPartition( ivPartitionType );
438	SaveErr( !RETVAL );
439    OUTPUT:
440	RETVAL
441
442
443BOOL
444IsContainerPartition( ivPartitionType )
445	int	ivPartitionType
446    CODE:
447        RETVAL = IsContainerPartition( ivPartitionType );
448	SaveErr( !RETVAL );
449    OUTPUT:
450	RETVAL
451
452
453BOOL
454MoveFileA( sOldName, sNewName )
455	char *	sOldName
456	char *	sNewName
457    CODE:
458        RETVAL = MoveFileA( sOldName, sNewName );
459	SaveErr( !RETVAL );
460    OUTPUT:
461	RETVAL
462
463
464BOOL
465MoveFileW( swOldName, swNewName )
466	WCHAR *	swOldName
467	WCHAR *	swNewName
468    CODE:
469        RETVAL = MoveFileW( swOldName, swNewName );
470	SaveErr( !RETVAL );
471    OUTPUT:
472	RETVAL
473
474
475BOOL
476MoveFileExA( sOldName, sNewName, uFlags )
477	char *	sOldName
478	char *	sNewName
479	DWORD	uFlags
480    CODE:
481        RETVAL = MoveFileExA( sOldName, sNewName, uFlags );
482	SaveErr( !RETVAL );
483    OUTPUT:
484	RETVAL
485
486
487BOOL
488MoveFileExW( swOldName, swNewName, uFlags )
489	WCHAR *	swOldName
490	WCHAR *	swNewName
491	DWORD	uFlags
492    CODE:
493        RETVAL = MoveFileExW( swOldName, swNewName, uFlags );
494	SaveErr( !RETVAL );
495    OUTPUT:
496	RETVAL
497
498
499long
500OsFHandleOpenFd( hOsFHandle, uMode )
501	long	hOsFHandle
502	DWORD	uMode
503    CODE:
504	RETVAL= win32_open_osfhandle( hOsFHandle, uMode );
505	if(  RETVAL < 0  ) {
506	    SaveErr( 1 );
507	    XSRETURN_NO;
508	} else if(  0 == RETVAL  ) {
509	    XSRETURN_PV( "0 but true" );
510	} else {
511	    XSRETURN_IV( (IV) RETVAL );
512	}
513
514
515DWORD
516QueryDosDeviceA( sDeviceName, osTargetPath, lTargetBuf )
517	char *	sDeviceName
518	char *	osTargetPath	= NO_INIT
519	DWORD	lTargetBuf	= init_buf_l($arg);
520    CODE:
521	grow_buf_l( osTargetPath,ST(1),char *, lTargetBuf,ST(2) );
522	RETVAL= QueryDosDeviceA( sDeviceName, osTargetPath, lTargetBuf );
523	SaveErr( 0 == RETVAL );
524    OUTPUT:
525	RETVAL
526	osTargetPath	trunc_buf_l( 1, osTargetPath,ST(1), RETVAL );
527
528
529DWORD
530QueryDosDeviceW( swDeviceName, oswTargetPath, lwTargetBuf )
531	WCHAR *	swDeviceName
532	WCHAR *	oswTargetPath	= NO_INIT
533	DWORD	lwTargetBuf	= init_buf_lw($arg);
534    CODE:
535	grow_buf_lw( oswTargetPath,ST(1), lwTargetBuf,ST(2) );
536	RETVAL= QueryDosDeviceW( swDeviceName, oswTargetPath, lwTargetBuf );
537	SaveErr( 0 == RETVAL );
538    OUTPUT:
539	RETVAL
540	oswTargetPath	trunc_buf_lw( 1, oswTargetPath,ST(1), RETVAL );
541
542
543BOOL
544ReadFile( hFile, opBuffer, lBytes, olBytesRead, pOverlapped )
545	HANDLE	hFile
546	BYTE *	opBuffer	= NO_INIT
547	DWORD	lBytes		= init_buf_l($arg);
548	oDWORD	&olBytesRead
549	void *	pOverlapped
550    CODE:
551	grow_buf_l( opBuffer,ST(1),BYTE *, lBytes,ST(2) );
552	/* Don't read more bytes than asked for if buffer is already big: */
553	lBytes= init_buf_l(ST(2));
554	if(  0 == lBytes  &&  autosize(ST(2))  ) {
555	    lBytes= SvLEN( ST(1) ) - 1;
556	}
557	RETVAL= ReadFile( hFile, opBuffer, lBytes, &olBytesRead,
558		  (LPOVERLAPPED)pOverlapped );
559	SaveErr( !RETVAL );
560    OUTPUT:
561	RETVAL
562	opBuffer	trunc_buf_l( RETVAL, opBuffer,ST(1), olBytesRead );
563	olBytesRead
564
565
566BOOL
567GetOverlappedResult( hFile, lpOverlapped, lpNumberOfBytesTransferred, bWait)
568	HANDLE hFile
569	LPOVERLAPPED lpOverlapped
570	LPDWORD lpNumberOfBytesTransferred
571	BOOL bWait
572    CODE:
573    	RETVAL= GetOverlappedResult( hFile, lpOverlapped,
574	 lpNumberOfBytesTransferred, bWait);
575	SaveErr( !RETVAL );
576    OUTPUT:
577    	RETVAL
578	lpOverlapped
579	lpNumberOfBytesTransferred
580
581DWORD
582GetFileSize( hFile, lpFileSizeHigh )
583	HANDLE hFile
584	LPDWORD lpFileSizeHigh
585    CODE:
586    	RETVAL= GetFileSize( hFile, lpFileSizeHigh );
587	SaveErr( NO_ERROR != GetLastError() );
588    OUTPUT:
589    	RETVAL
590	lpFileSizeHigh
591
592UINT
593SetErrorMode( uNewMode )
594	UINT	uNewMode
595
596
597LONG
598SetFilePointer( hFile, ivOffset, ioivOffsetHigh, uFromWhere )
599	HANDLE	hFile
600	LONG	ivOffset
601	LONG *	ioivOffsetHigh
602	DWORD	uFromWhere
603    CODE:
604	RETVAL= SetFilePointer( hFile, ivOffset, ioivOffsetHigh, uFromWhere );
605	if(  RETVAL == INVALID_SET_FILE_POINTER && (GetLastError() != NO_ERROR)  ) {
606	    SaveErr( 1 );
607	    XST_mNO(0);
608	} else if(  0 == RETVAL  ) {
609	    XST_mPV(0,"0 but true");
610	} else {
611	    XST_mIV(0,RETVAL);
612	}
613    OUTPUT:
614	ioivOffsetHigh
615
616
617BOOL
618SetHandleInformation( hObject, uMask, uFlags )
619	HANDLE	hObject
620	DWORD	uMask
621	DWORD	uFlags
622    CODE:
623        RETVAL = SetHandleInformation( hObject, uMask, uFlags );
624	SaveErr( !RETVAL );
625    OUTPUT:
626	RETVAL
627
628
629BOOL
630WriteFile( hFile, pBuffer, lBytes, ouBytesWritten, pOverlapped )
631	HANDLE		hFile
632	BYTE *		pBuffer
633	DWORD		lBytes		= init_buf_l($arg);
634	oDWORD	&ouBytesWritten
635	void *		pOverlapped
636    CODE:
637	/* SvCUR(ST(1)) might "panic" if pBuffer isn't valid */
638	if(  0 == lBytes  ) {
639	    lBytes= SvCUR(ST(1));
640	} else if(  SvCUR(ST(1)) < lBytes  ) {
641	    croak( "%s: pBuffer value too short (%d < %d)",
642	      "Win32API::File::WriteFile", SvCUR(ST(1)), lBytes );
643	}
644	RETVAL= WriteFile( hFile, pBuffer, lBytes,
645		  &ouBytesWritten, (LPOVERLAPPED)pOverlapped );
646	SaveErr( !RETVAL );
647    OUTPUT:
648	RETVAL
649	ouBytesWritten
650
651void
652GetStdHandle(fd)
653    DWORD fd
654PPCODE:
655#ifdef _WIN64
656    XSRETURN_IV((DWORD_PTR)GetStdHandle(fd));
657#else
658    XSRETURN_IV((DWORD)GetStdHandle(fd));
659#endif
660
661void
662SetStdHandle(fd,handle)
663    DWORD fd
664    HANDLE handle
665PPCODE:
666    if (SetStdHandle(fd, handle))
667	XSRETURN_YES;
668    else
669	XSRETURN_NO;
670