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
ErrPrintf(const char * sFmt,...)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
80 static LONG uLastFileErr= 0;
81
82 static void
SaveErr(BOOL bFailed)83 SaveErr( BOOL bFailed )
84 {
85 if( bFailed ) {
86 uLastFileErr= GetLastError();
87 }
88 }
89
90 MODULE = Win32API::File PACKAGE = Win32API::File
91
92 PROTOTYPES: DISABLE
93
94
95 LONG
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
107 BOOL
108 CloseHandle( hObject )
109 HANDLE hObject
110 CODE:
111 RETVAL = CloseHandle( hObject );
112 SaveErr( !RETVAL );
113 OUTPUT:
114 RETVAL
115
116
117 BOOL
118 CopyFileA( 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
129 BOOL
130 CopyFileW( 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
141 HANDLE
142 CreateFileA( 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
163 HANDLE
164 CreateFileW( 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
185 BOOL
186 DefineDosDeviceA( 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
197 BOOL
198 DefineDosDeviceW( 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
209 BOOL
210 DeleteFileA( sFileName )
211 char * sFileName
212 CODE:
213 RETVAL = DeleteFileA( sFileName );
214 SaveErr( !RETVAL );
215 OUTPUT:
216 RETVAL
217
218
219 BOOL
220 DeleteFileW( swFileName )
221 WCHAR * swFileName
222 CODE:
223 RETVAL = DeleteFileW( swFileName );
224 SaveErr( !RETVAL );
225 OUTPUT:
226 RETVAL
227
228
229 BOOL
230 DeviceIoControl( 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
258 HANDLE
259 FdGetOsFHandle( 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
268 DWORD
269 GetDriveTypeA( sRootPath )
270 char * sRootPath
271 CODE:
272 RETVAL = GetDriveTypeA( sRootPath );
273 SaveErr( !RETVAL );
274 OUTPUT:
275 RETVAL
276
277
278 DWORD
279 GetDriveTypeW( swRootPath )
280 WCHAR * swRootPath
281 CODE:
282 RETVAL = GetDriveTypeW( swRootPath );
283 SaveErr( !RETVAL );
284 OUTPUT:
285 RETVAL
286
287
288 DWORD
289 GetFileAttributesA( sPath )
290 char * sPath
291 CODE:
292 RETVAL = GetFileAttributesA( sPath );
293 SaveErr( !RETVAL );
294 OUTPUT:
295 RETVAL
296
297
298 DWORD
299 GetFileAttributesW( swPath )
300 WCHAR * swPath
301 CODE:
302 RETVAL = GetFileAttributesW( swPath );
303 SaveErr( !RETVAL );
304 OUTPUT:
305 RETVAL
306
307
308 DWORD
309 GetFileType( hFile )
310 HANDLE hFile
311 CODE:
312 RETVAL = GetFileType( hFile );
313 SaveErr( !RETVAL );
314 OUTPUT:
315 RETVAL
316
317
318 BOOL
319 GetHandleInformation( 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
330 DWORD
331 GetLogicalDrives()
332 CODE:
333 RETVAL = GetLogicalDrives();
334 SaveErr( !RETVAL );
335 OUTPUT:
336 RETVAL
337
338
339 DWORD
340 GetLogicalDriveStringsA( 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
361 DWORD
362 GetLogicalDriveStringsW( 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
383 BOOL
384 GetVolumeInformationA( 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
408 BOOL
409 GetVolumeInformationW( 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
433 BOOL
434 IsRecognizedPartition( ivPartitionType )
435 int ivPartitionType
436 CODE:
437 RETVAL = IsRecognizedPartition( ivPartitionType );
438 SaveErr( !RETVAL );
439 OUTPUT:
440 RETVAL
441
442
443 BOOL
444 IsContainerPartition( ivPartitionType )
445 int ivPartitionType
446 CODE:
447 RETVAL = IsContainerPartition( ivPartitionType );
448 SaveErr( !RETVAL );
449 OUTPUT:
450 RETVAL
451
452
453 BOOL
454 MoveFileA( sOldName, sNewName )
455 char * sOldName
456 char * sNewName
457 CODE:
458 RETVAL = MoveFileA( sOldName, sNewName );
459 SaveErr( !RETVAL );
460 OUTPUT:
461 RETVAL
462
463
464 BOOL
465 MoveFileW( swOldName, swNewName )
466 WCHAR * swOldName
467 WCHAR * swNewName
468 CODE:
469 RETVAL = MoveFileW( swOldName, swNewName );
470 SaveErr( !RETVAL );
471 OUTPUT:
472 RETVAL
473
474
475 BOOL
476 MoveFileExA( 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
487 BOOL
488 MoveFileExW( 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
499 long
500 OsFHandleOpenFd( 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
515 DWORD
516 QueryDosDeviceA( 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
529 DWORD
530 QueryDosDeviceW( 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
543 BOOL
544 ReadFile( 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
566 BOOL
567 GetOverlappedResult( 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
581 DWORD
582 GetFileSize( 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
592 UINT
593 SetErrorMode( uNewMode )
594 UINT uNewMode
595
596
597 LONG
598 SetFilePointer( 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
617 BOOL
618 SetHandleInformation( 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
629 BOOL
630 WriteFile( 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
651 void
652 GetStdHandle(fd)
653 DWORD fd
654 PPCODE:
655 #ifdef _WIN64
656 XSRETURN_IV((DWORD_PTR)GetStdHandle(fd));
657 #else
658 XSRETURN_IV((DWORD)GetStdHandle(fd));
659 #endif
660
661 void
662 SetStdHandle(fd,handle)
663 DWORD fd
664 HANDLE handle
665 PPCODE:
666 if (SetStdHandle(fd, handle))
667 XSRETURN_YES;
668 else
669 XSRETURN_NO;
670