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 80 static LONG uLastFileErr= 0; 81 82 static void 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