Changeset 187 for trunk/Library/FileUtilsUnit.pas
- Timestamp:
- Jun 5, 2007, 8:28:05 PM (18 years ago)
- File:
-
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/Library/FileUtilsUnit.pas
r97 r187 15 15 16 16 const 17 D irectorySeparator= '\';17 DIRECTORY_SEPARATOR = '\'; 18 18 PATH_SEPARATOR = ';'; 19 20 // Drive numbers are one based 21 MinDriveNumber = 1; 22 MaxDriveNumber = 26; 23 19 24 20 25 // TODO … … 26 31 27 32 33 type 34 TDriveType = 35 ( 36 dtNone, 37 dtFloppy, 38 dtHard, 39 dtCD, 40 dtNetwork, 41 dtRemovable 42 ); 43 44 28 45 // Adds a slash to the end of dir if not present 29 46 // if aDir is empty this returns '\' … … 57 74 // this always clears the list at the beginning 58 75 Procedure GetDirsInPath(const aPathEnvVar: String; var aList: TStrings); 76 77 // Breaks up specified Env var path 78 // then adds all matching files to the list 79 Procedure GetFilesInPath( const aPathEnvVar: String; 80 const aFilter: String; 81 var aList: TStrings ); 59 82 60 83 // searches for all files in aDirectory matching aFilter and add … … 78 101 Function ParentDir(const aDirectory : String) : String; 79 102 103 // In the directory startpath, create directory and subdirectories 104 // specified in DirsString 105 // e.g. bob\bill\fred will make bob, then bill in bob, then fred in bob 106 // returns path to lowest dir created 107 Function MakeDirs(const aFullDirectoryPath: String) : String; 108 109 110 80 111 Function DirectoryExists(const aDirectory : String) : boolean; 112 113 Function DriveLetterToDriveNumber(const aDriveLetter : char) : longint; 114 Function DriveNumberToDriveLetter(const aDriveNumber : longint) : char; 115 116 Function GetVolumeLabel(aDrive: char) : String; 117 118 Function GetBootDriveLetter: char; 119 120 // Returns true if file exists and is read only 121 Function FileIsReadOnly(const aFilename : String) : boolean; 122 123 124 // TODO 125 Function IsFloppyDrive( DriveNumber: longint ): Boolean; 126 Function GetLocalDriveType( DriveNumber: longint ): TDriveType; 127 Function GetDriveType( DriveNumber: longint ): TDriveType; 128 Function GetNetworkDriveRemotePath( DriveNumber: longint ): String; 129 81 130 82 131 Implementation … … 85 134 Dos, 86 135 BseDos, 136 BseErr, 137 BseDev, 87 138 Os2Def, 88 139 SysUtils, 89 StringUtilsUnit; 140 StringUtilsUnit, 141 CharUtilsUnit; 142 143 imports 144 FUNCTION _DosQueryFSAttach( VAR pszDeviceName: CSTRING; 145 ulOrdinal: ULONG; 146 ulFSAInfoLevel:ULONG; 147 pfsqb: PFSQBUFFER2; 148 VAR pcbBuffLength: ULONG ): APIRET; APIENTRY; 149 'DOSCALLS' index 277; 150 end; 151 152 153 type 154 TWord = Record // Bytes of a Word 155 LoByte, HiByte : Byte; 156 End; 157 158 TBPB = Array[0..30] Of Byte; // Puffer fuer BPB-Struktur 159 160 TDeviceParameters = Record 161 BPB: TBPB; 162 Cylinders: word; 163 DeviceType: Byte; 164 Attributes: Word; 165 End; 166 167 90 168 91 169 Function AddDirectorySeparator(aDirectory : String) : String; … … 93 171 if aDirectory = '' then 94 172 begin 95 Result:= D irectorySeparator;96 exit; 97 end; 98 99 if aDirectory[length(aDirectory)] <> D irectorySeparatorthen100 begin 101 Result := aDirectory + D irectorySeparator;173 Result:= DIRECTORY_SEPARATOR; 174 exit; 175 end; 176 177 if aDirectory[length(aDirectory)] <> DIRECTORY_SEPARATOR then 178 begin 179 Result := aDirectory + DIRECTORY_SEPARATOR; 102 180 exit; 103 181 end; … … 120 198 Function RemoveRightDirectorySeparator(aDirectory : String) : String; 121 199 begin 122 Result := StrTrimRightChars(aDirectory, [D irectorySeparator]);200 Result := StrTrimRightChars(aDirectory, [DIRECTORY_SEPARATOR]); 123 201 end; 124 202 … … 134 212 if aPath = '' then 135 213 begin 136 Result := StrTrimRightChars(Result, [D irectorySeparator]);214 Result := StrTrimRightChars(Result, [DIRECTORY_SEPARATOR]); 137 215 exit; 138 216 end; … … 147 225 if Length(aPath) > 3 then 148 226 begin 149 Result := StrTrimRightChars(Result, [D irectorySeparator]);227 Result := StrTrimRightChars(Result, [DIRECTORY_SEPARATOR]); 150 228 end; 151 229 exit; … … 156 234 begin 157 235 // check for root dir spec 158 if aPath[1] = D irectorySeparatorthen236 if aPath[1] = DIRECTORY_SEPARATOR then 159 237 begin 160 238 // take just the drive from the basedir … … 165 243 else 166 244 begin 167 Result := D irectorySeparator;245 Result := DIRECTORY_SEPARATOR; 168 246 end; 169 aPath := StrTrimLeftChars(aPath, [D irectorySeparator]);247 aPath := StrTrimLeftChars(aPath, [DIRECTORY_SEPARATOR]); 170 248 end; 171 249 end; 172 250 173 251 tmpDirectories := TStringList.Create; 174 StrExtractStringsIgnoreEmpty(tmpDirectories, aPath, [D irectorySeparator], #0);252 StrExtractStringsIgnoreEmpty(tmpDirectories, aPath, [DIRECTORY_SEPARATOR], #0); 175 253 for i := 0 to tmpDirectories.count-1 do 176 254 begin … … 193 271 194 272 // strip any extra leading slashes 195 aPath := StrTrimLeftChars(aPath, [D irectorySeparator]);273 aPath := StrTrimLeftChars(aPath, [DIRECTORY_SEPARATOR]); 196 274 end; 197 275 tmpDirectories.Destroy; … … 202 280 begin 203 281 // just a drive spec X:, so add a slash 204 Result := Result + D irectorySeparator;282 Result := Result + DIRECTORY_SEPARATOR; 205 283 end; 206 284 end; … … 354 432 355 433 StrExtractStringsIgnoreEmpty(aList, StrPas(tmpPszPathEnvVar), [PATH_SEPARATOR], #0); 434 end; 435 436 437 Procedure GetFilesInPath( const aPathEnvVar: String; 438 const aFilter: String; 439 var aList: TStrings ); 440 var 441 tmpDirectories : TStringList; 442 i : integer; 443 begin 444 tmpDirectories := TStringList.Create; 445 GetDirsInPath(aPathEnvVar, tmpDirectories); 446 447 for i:=0 to tmpDirectories.count-1 do 448 begin 449 ListFilesInDirectory(tmpDirectories[i], aFilter, false, aList); 450 end; 451 452 tmpDirectories.Destroy; 356 453 end; 357 454 … … 467 564 468 565 // ends with slash 469 while (aDirectory[tmpPos] = D irectorySeparator) AND (tmpPos > 0) do566 while (aDirectory[tmpPos] = DIRECTORY_SEPARATOR) AND (tmpPos > 0) do 470 567 begin 471 568 dec(tmpPos); … … 473 570 474 571 // find slash 475 while (aDirectory[tmpPos] <> D irectorySeparator) AND (tmpPos > 0) do572 while (aDirectory[tmpPos] <> DIRECTORY_SEPARATOR) AND (tmpPos > 0) do 476 573 begin 477 574 dec(tmpPos); … … 479 576 480 577 result:= StrLeft(aDirectory, tmpPos-1); 578 end; 579 580 581 Function MakeDirs(const aFullDirectoryPath: String) : String; 582 Var 583 tmpDirectoryParts : TStringList; 584 tmpDirectoryPart : String; 585 tmpCompletePart : String; 586 i : integer; 587 begin 588 tmpDirectoryParts := TStringList.Create; 589 StrExtractStringsIgnoreEmpty(tmpDirectoryParts, aFullDirectoryPath, [DIRECTORY_SEPARATOR], #0); 590 591 tmpCompletePart := ''; 592 for i:=0 to tmpDirectoryParts.count-1 do 593 begin 594 tmpDirectoryPart := trim(tmpDirectoryParts[i]); 595 596 if tmpDirectoryPart <> '' then 597 begin 598 tmpCompletePart := AddDirectorySeparatorIfNotEmpty(tmpCompletePart) + tmpDirectoryPart; 599 600 if not DirectoryExists(tmpCompletePart) then 601 begin 602 MkDir(tmpCompletePart); 603 end; 604 end; 605 end; 606 607 Result := tmpCompletePart; 481 608 end; 482 609 … … 531 658 532 659 660 Function DriveLetterToDriveNumber(const aDriveLetter : char) : longint; 661 begin 662 if (aDriveLetter >= 'a') 663 and (aDriveLetter <= 'z') then 664 begin 665 Result := Ord(aDriveLetter) - Ord('a') + 1; 666 exit; 667 end; 668 669 if (aDriveLetter >= 'A') 670 and (aDriveLetter <= 'Z') then 671 begin 672 Result := Ord(aDriveLetter) - Ord('A') + 1; 673 exit; 674 end; 675 676 // not a valid drive letter 677 Result := 0; 678 end; 679 680 681 Function DriveNumberToDriveLetter(const aDriveNumber: longint) : char; 682 begin 683 Result := Chr(aDriveNumber - 1 + Ord('A')); 684 end; 685 686 687 Function GetVolumeLabel(aDrive: char) : String; 688 var 689 tmpRC : APIRET; 690 tmpFileSystemInfo : FSINFO; 691 e : EInOutError; 692 begin 693 DosErrorAPI( FERR_DISABLEHARDERR ); 694 Result := ''; 695 tmpRC := DosQueryFSInfo( DriveLetterToDriveNumber(aDrive), 696 FSIL_VOLSER, 697 tmpFileSystemInfo, 698 sizeof(tmpFileSystemInfo)); 699 if tmpRC = 0 then 700 begin 701 Result := StrPasWithLength(Addr(tmpFileSystemInfo.vol.szVolLabel), tmpFileSystemInfo.vol.cch); 702 Result := LowerCase(Result); 703 end; 704 DosErrorAPI( FERR_ENABLEHARDERR ); 705 706 if tmpRC <> 0 then 707 begin 708 e := EInOutError.Create( 'Cannot read drive ' + aDrive + ':'); 709 e.ErrorCode := tmpRC; 710 raise e; 711 end; 712 end; 713 714 715 Function GetBootDriveLetter: char; 716 var 717 tmpBuffer: longword; 718 begin 719 DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, tmpBuffer, sizeof(tmpBuffer)); 720 Result := Chr(ord('A') + tmpBuffer - 1); 721 end; 722 723 724 Function FileIsReadOnly(const aFilename : String ) : boolean; 725 begin 726 Result :=(FileGetAttr(aFilename) AND faReadonly) > 0; 727 end; 728 729 730 731 732 // TODO 733 734 735 Function IsFloppyDrive( DriveNumber: longint ): Boolean; 736 Var 737 bResult : Byte; 738 Begin 739 DosDevConfig( bResult, DEVINFO_FLOPPY ); 740 Result := ( Abs( DriveNumber ) <= bResult); 741 End; 742 743 // ------------------------------------------------------------------------- 744 // Funktion/Function: QueryCDRoms() 745 // 746 // Beschreibung: 747 // Die Funktion QueryCDRom ermittelt ueber eine nicht dokumentierte 748 // Schnittstelle die Anzahl der CDRom-Laufwerke und den ersten, fuer 749 // ein CDRom-Laufwerk, vergebenen UnitIdentifier. 750 // Der Treiber OS2CDROM.DMD stellt dem System zwei Devices (CD-ROM1$ 751 // und CD-ROM2$) zur Verfuegung. Die beiden Devices unterscheiden sich 752 // durch DeviceAttribute. Beide Devices unterstuetzen (zumindest unter 753 // Warp) den undokumentierten Generic IOCtl 0x82/0x60, welcher Infor- 754 // mationen ueber die angeschlossenen CDRom-Laufwerke liefert. 755 // 756 // Description: 757 // This Functions finds out how many CD-Rom Drives are present in System 758 // and which Drive Letter is the first occupied by a CD-Rom. It uses an 759 // undocumented Interface to OS2CDROM.DMD. 760 // OS2CDROM.DMD presents two Devices (CD-ROM1$ and CD-ROM2$). These De- 761 // vices are distinguished by their Device-Attributes. Both Devices sup- 762 // port (under Warp) the undocumented generic IOCtl-Call 0x82/0x60 which 763 // deliver some Information about the connected CD-Rom Drives. 764 // 765 // Parameter: 766 // Var ulCDRomCount ULONG Anzahl CD-Rom Laufwerke im System 767 // Number of CD-Rom Drives in System 768 // 769 // Var ulFirstCDRomDiskNo ULONG erste Laufwerksnummer, die an ein 770 // CD-Rom vergeben ist 771 // first Drive-Letter occupied by a 772 // CD-Rom Drive 773 // 774 // Rueckgabe/Returnvalue: keine/none 775 // ------------------------------------------------------------------------- 776 Procedure QueryCDRoms(Var ulCDRomCount, ulFirstCDRomDiskNo: ULONG); 777 778 Const cszDriverName : CSTRING = 'CD-ROM?$'; 779 780 Var cCurDriver : Char; // Indexvariable fuer aktuell bearbeites Device (1 oder 2) 781 // Index for current Device (1 or 2) 782 783 hDevHandle : HFILE; // Handle fuer Device 784 // Device handle 785 786 ulAction : ULONG; // Aktionscode (DosOpen()) 787 // Actioncode (DosOpen()) 788 789 ulParams : ULONG; // Anzahl Bytes von IOCtl gelieferter Parameterdaten 790 // Number of Bytes for delivered Parameterdata 791 792 ulData : ULONG; // Anzahl Bytes von IOCtl gelieferter Daten 793 // Number of Bytes delivered by IOCtl 794 795 rCDInfo : Record // Ergebnisstruktur der IOCtl-Funktion (s.o.) 796 // Record for Results of IOCtl-Call (see above) 797 usCDRomCount : USHORT; // Anzahl CD-Roms / Number of CD-Rom Drives 798 usFirstUnitNo: USHORT; // erste vergebene Laufwerksnummer / first Driver Letter 799 End; 800 801 Begin (* uQueryCDRom *) 802 /************************************ 803 * Vorbelegungen 804 * 805 * initial assignments 806 ************************************/ 807 ulCDRomCount := 0; 808 ulFirstCDRomDiskNo := 0; 809 810 ulParams := 0; 811 812 /************************************ 813 * die beiden Devices abarbeiten 814 * 815 * accessing both Devices 816 ************************************/ 817 For cCurDriver := '1' To '2' Do 818 Begin 819 /************************************ 820 * Device oeffnen 821 * 822 * open Device 823 ************************************/ 824 cszDriverName[6] := cCurDriver; 825 If (DosOpen(cszDriverName, // Devicename 826 hDevHandle, // Handle 827 ulAction, // Aktionscode 828 0, // Dateigráe 829 FILE_NORMAL, // Attribute: read/write 830 OPEN_ACTION_OPEN_IF_EXISTS, // OpenFlag: ffnen, wenn vorhanden 831 OPEN_FLAGS_FAIL_ON_ERROR Or // Modus: Fehlermeldung per Returncode 832 OPEN_SHARE_DENYNONE Or // keine Einschrnkungen fr Dritte 833 OPEN_ACCESS_READONLY, // nur lesender Zugriff 834 NIL)=NO_ERROR) Then // keine EA 835 Begin 836 /************************************ 837 * IOCtl-Funktion aufrufen 838 * 839 * Call to IOCtl 840 ************************************/ 841 If (DosDevIOCtl(hDevHandle, // Handle / Handle 842 $82, // Kategorie / Category 843 $60, // Funktion / Function 844 NIL, // keine Parameterliste / No Parameterlist 845 0, // Laenge Parameterliste / Length of Parameterlist 846 ulParams, // Groesse der gelieferten Parameterdaten 847 // / Number of Bytes for Parameterdata 848 rCDInfo, // Puffer fuer gelieferte Daten 849 // / Buffer for returned Data 850 SizeOf(rCDInfo), // Groesse des Datenpuffers 851 // / Size of Databuffer 852 ulData)=NO_ERROR) Then // Groesse der gelieferten Daten 853 // / Number of Bytes for returned Data 854 Begin 855 ulCDRomCount := rCDInfo.usCDRomCount; 856 ulFirstCDRomDiskNo := Succ(rCDInfo.usFirstUnitNo); 857 End; 858 859 DosClose(hDevHandle); 860 End; 861 862 End; (* For *) 863 864 End; (* uQueryCDRom *) 865 866 867 Function GetLocalDriveType( DriveNumber: longint ): TDriveType; 868 var 869 IOCtlParameters: Word; 870 rc: APIRET; 871 ParameterLength: longWord; 872 DataLength: longword; 873 DeviceData: TDeviceParameters; 874 Fixed: boolean; 875 FirstCDDrive: ULONG; 876 NumCDDrives: ULONG; 877 begin 878 879 TWord( IOCtlParameters ).LoByte := 0; // BPB of physical Device 880 TWord( IOCtlParameters ).HiByte := DriveNumber - 1; // drive number, zero base 881 882 ParameterLength := SizeOf( IOCtlParameters ); // input length of parameters 883 DataLength := 0; // input length of data (none) 884 885 rc := DosDevIOCTL( HFILE(-1), // Open Device (not a file) 886 IOCTL_DISK, // Category 887 DSK_GETDEVICEPARAMS, // Function 888 IOCtlParameters, // Parameters 889 SizeOf( IOCtlParameters ), // (max) size of parameters 890 ParameterLength, // parameters length 891 DeviceData, // results 892 SizeOf( DeviceData ), // (max) size of data block 893 DataLength ); // data block length 894 895 Fixed := ( DeviceData.Attributes and 1 ) > 0; // bit 0 indicates fixed (1) or removable (0) 896 if not Fixed then 897 begin 898 result := dtRemovable; 899 900 QueryCDRoms( FirstCDDrive, 901 NumCDDrives ); 902 903 if ( DriveNumber >= FirstCDDrive ) 904 and ( DriveNumber < FirstCDDrive + NumCDDrives ) then 905 result := dtCD; 906 907 exit; 908 end; 909 910 result := dtHard; 911 end; 912 913 // Takes a one-based drive number 914 Function GetDriveType( DriveNumber: longint ): TDriveType; 915 var 916 szDrive: CString; 917 918 FSData: array[ 0..sizeof( FSQBuffer) + 3*_MAX_PATH ] of char; 919 pBuffer: PFSQBUFFER2; 920 FSDataLength: ULONG; 921 922 rc: APIRET; 923 begin 924 assert( DriveNumber >= 1 ); 925 assert( DriveNumber <= 26 ); 926 927 if ( DriveNumber >=1 ) and ( DriveNumber <= 2 ) then 928 begin 929 if IsFloppyDrive( DriveNumber ) then 930 begin 931 result := dtFloppy; 932 exit; 933 end; 934 935 result := dtNone; // don't let OS/2 try a fake B: drive 936 exit; 937 end; 938 939 DosErrorAPI( FERR_DISABLEHARDERR ); 940 941 szDrive := DriveNumberToDriveLetter( DriveNumber ) + ':'; 942 FSDataLength := sizeof( FSData ); 943 pBuffer := Addr( FSData ); 944 rc := _DosQueryFSAttach( szDrive, 945 0, // ignored 946 FSAIL_QUERYNAME, 947 pBuffer, 948 FSDataLength ); 949 950 if rc = 0 then 951 begin 952 case pBuffer^.iType of 953 FSAT_REMOTEDRV: 954 result := dtNetwork; 955 956 FSAT_LOCALDRV: 957 // Figure out what kind of local drive it is... 958 result := GetLocalDriveType( DriveNumber ); 959 960 else 961 begin 962 // should never happen 963 result := dtNone; 964 exit; 965 end; 966 end; 967 end 968 else if rc = ERROR_NOT_READY then 969 begin 970 // No media? 971 // Have a look for a local disk anyway. 972 result := GetLocalDriveType( DriveNumber ); 973 end 974 else 975 begin 976 result := dtNone; 977 end; 978 979 DosErrorAPI( FERR_ENABLEHARDERR ); 980 end; 981 982 const 983 DEVLEN = 8; 984 CNLEN = 15; // Computer name length 985 UNCLEN = (CNLEN+2); // UNC computer name length 986 NNLEN = 12; // 8.3 Net name length (share name length) 987 RMLEN = (UNCLEN+1+NNLEN); // Maximum remote name length 988 989 type 990 use_info_0 = record 991 ui0_local: cstring[ DEVLEN ]; // note this is of size DEVLEN + 1 992 ui0_pad_1: char; 993 ui0_remote: pchar; 994 space: array[ 0..RMLEN ] of char; // remote path is written to somewhere in here 995 end; 996 997 use_info_1 = record 998 ui0_local: cstring[ DEVLEN ]; 999 ui0_pad_1: char; 1000 ui0_remote: pchar; // address of a buffer to hold remote path 1001 ui1_password: pchar; // 1002 ui1_status: USHORT; 1003 ui1_asg_type: SHORT; 1004 ui1_refcount: USHORT; 1005 ui1_usecount: USHORT; 1006 space: array[ 0..RMLEN ] of char; // remote path is written to somewhere in here 1007 end; 1008 1009 TNet32UseGetInfo = Function( pszServer: pchar; 1010 pszUseName: pchar; // e.g. drive x: 1011 ulLevel: ULONG; 1012 pbBuffer: pointer; // pointer to output buffer 1013 ulBuffer: ULONG; // size of output in buffer 1014 Var pulTotalAvail: ULONG ) 1015 : word; CDecl; 1016 1017 Var 1018 Net32UseGetInfo: TNet32UseGetInfo; 1019 hNetAPI32DLL: HMODULE; 1020 TriedLoading: boolean; 1021 1022 // 129 Net32UseGetInfo 1023 Function GetNetworkDriveRemotePath( DriveNumber: longint ): string; 1024 var 1025 ErrorName: array[ 0..255 ] of char; 1026 dummy: cstring; 1027 rc: word; 1028 UseName: array[ 0..255 ] of char; 1029 UseInfo: use_info_0; 1030 pUseInfo: pointer; 1031 TotalBytesNeeded: ULONG; 1032 RemotePath: array[ 0..255 ] of char; 1033 Dummy2: array[ 0..4096 ] of char; // try to fix stack probs 1034 begin 1035 Result := ''; 1036 1037 if not TriedLoading then 1038 begin 1039 TriedLoading := true; 1040 rc := DosLoadModule( ErrorName, 1041 sizeof( ErrorName ), 1042 'NETAPI32', 1043 hNetAPI32DLL ); 1044 if rc = NO_ERROR then 1045 begin 1046 // NetAPI32.DLL loaded OK 1047 rc := DosQueryProcAddr( hNetAPI32DLL, 1048 129, 1049 dummy, 1050 pointer( Net32UseGetInfo ) ); 1051 if rc <> 0 then 1052 Net32UseGetInfo := nil; 1053 end; 1054 end; 1055 1056 if Assigned( Net32UseGetInfo ) then 1057 begin 1058 UseName[ 0 ] := DriveNumberToDriveLetter( DriveNumber ); 1059 UseName[ 1 ] := ':'; 1060 UseName[ 2 ] := #0; 1061 1062 RemotePath[ 0 ] := #0; 1063 // UseInfo.ui0_remote := Addr( RemotePath ); 1064 1065 pUseInfo := Addr( UseInfo ); 1066 rc := Net32UseGetInfo( nil, // server - always nil 1067 Addr( UseName ), 1068 0, // info level 0 1069 pUseInfo, 1070 sizeof( UseInfo ), 1071 TotalBytesNeeded ); 1072 1073 if rc = 0 then 1074 Result := StrPas( UseInfo.ui0_remote ); 1075 1076 end; 1077 end; 1078 1079 533 1080 Initialization 534 1081 End.
Note:
See TracChangeset
for help on using the changeset viewer.