source: branches/2.20_branch/Library/FileUtilsUnit.pas

Last change on this file was 357, checked in by RBRi, 16 years ago

copyright fix

  • Property svn:eol-style set to native
File size: 33.4 KB
Line 
1Unit FileUtilsUnit;
2
3// NewView - a new OS/2 Help Viewer
4// Copyright 2003-2006 Aaron Lawrence
5// Copyright 2006-2009 Ronald Brill (rbri at rbri dot de)
6// This software is released under the GNU Public License - see readme.txt
7
8// Helper functions for file handling
9
10Interface
11
12uses
13 Classes,
14 ACLUtility;
15
16
17const
18 DIRECTORY_SEPARATOR = '\';
19 PATH_SEPARATOR = ';';
20 CURRENT_DIRECTORY = '.';
21 PARENT_DIRECTORY = '..';
22 FILE_EXTENSION_DELIMITER = '.';
23
24 // Drive numbers are one based
25 MinDriveNumber = 1;
26 MaxDriveNumber = 26;
27
28
29 // TODO
30 HelpPathEnvironmentVar = 'HELP';
31 BookshelfEnvironmentVar = 'BOOKSHELF';
32 LanguageEnvironmentVar = 'LANG';
33 DEFAULT_LANGUAGE = 'EN_US';
34 HELP_FILE_DELIMITER = '+';
35 HELP_FILE_EXTENSION = FILE_EXTENSION_DELIMITER + 'hlp';
36 INF_FILE_EXTENSION = FILE_EXTENSION_DELIMITER + 'inf';
37
38
39type
40 TDriveType =
41 (
42 dtNone,
43 dtFloppy,
44 dtHard,
45 dtCD,
46 dtNetwork,
47 dtRemovable
48 );
49
50
51 // Adds a slash to the end of dir if not present
52 // if aDir is empty this returns '\'
53 Function AddDirectorySeparator(aDirectory : String) : String;
54
55 // Adds a slash to the end of dir if not present
56 // if aDir is empty this returns ''
57 Function AddDirectorySeparatorIfNotEmpty(aDirectory: String) : String;
58
59 // Removes a directory seperator from the end of aDirectory
60 // (if present)
61 Function RemoveRightDirectorySeparator(aDirectory : String) : String;
62
63 // Expands the path given, relative to aBaseDirectory
64 // Handles leading \ for root dir,
65 // .. for parent, . (ignored),
66 // drive spec at start,
67 // ignores repeated \ e.g. \\
68 Function ExpandPath(aBaseDirectory : String; aPath : String): String;
69
70 Function GetLogFilesDir: String;
71
72 Function SearchPath(const aPathEnvVar: String; const aFilename: String; var aResultFilename: String) : boolean;
73
74 Function SearchHelpPaths(const aFilename: String; var aResultFilename: String; const anIncludeAppDir: boolean) : boolean;
75
76 // Find the help file for the current app based on LANG
77 Function FindDefaultLanguageHelpFile(const anApplicationName: String; const aLanguage : String) : String;
78
79 // Breaks up specified Env var path
80 // this always clears the list at the beginning
81 Procedure GetDirsInPath(const aPathEnvVar: String; var aList: TStrings);
82
83 // Breaks up specified Env var path
84 // then adds all matching files to the list
85 Procedure GetFilesInPath( const aPathEnvVar: String;
86 const aFilter: String;
87 var aList: TStrings );
88
89 // searches for all files in aDirectory matching aFilter and add
90 // them to aList
91 // it is possible to define different filter if you separate them by semicolon
92 Procedure ListFilesInDirectory( const aDirectory : String;
93 const aFilter : String;
94 const aWithDirectoryFlag : boolean;
95 var aList : TStrings);
96
97 // searches for all directories in aDirectory and add them to aList
98 Procedure ListSubDirectories(const aDirectory: String; const anIncludeSystemAndHiddenFlag: boolean; var aList: TStrings);
99
100 Procedure ListFilesInDirectoryRecursiveWithTermination(const aDirectory : String;
101 const aFilter : String;
102 const aWithDirectoryFlag : boolean;
103 const anIncludeSystemAndHiddenFlag: boolean;
104 var aList : TStrings;
105 const aTerminateCheck : TTerminateCheck;
106 const aUseTerminateCheck : boolean);
107
108 Function ParentDir(const aDirectory : String) : String;
109
110 // In the directory startpath, create directory and subdirectories
111 // specified in DirsString
112 // e.g. bob\bill\fred will make bob, then bill in bob, then fred in bob
113 // returns path to lowest dir created
114 Function MakeDirs(const aFullDirectoryPath: String) : String;
115
116
117 // Checks if a directory exists
118 Function DirectoryExists(const aDirectory : String) : boolean;
119
120 Function DriveLetterToDriveNumber(const aDriveLetter : char) : longint;
121 Function DriveNumberToDriveLetter(const aDriveNumber : longint) : char;
122
123 Function GetVolumeLabel(aDrive: char) : String;
124
125 Function GetBootDriveLetter: char;
126
127 // Returns true if file exists and is read only
128 Function FileIsReadOnly(const aFilename : String) : boolean;
129
130
131 // TODO
132 Function IsFloppyDrive( DriveNumber: longint ): Boolean;
133 Function GetLocalDriveType( DriveNumber: longint ): TDriveType;
134 Function GetDriveType( DriveNumber: longint ): TDriveType;
135 Function GetNetworkDriveRemotePath( DriveNumber: longint ): String;
136
137
138Implementation
139
140uses
141 Dos,
142 BseDos,
143 BseErr,
144 BseDev,
145 Os2Def,
146 SysUtils,
147 StringUtilsUnit,
148 CharUtilsUnit;
149
150imports
151 FUNCTION _DosQueryFSAttach( VAR pszDeviceName: CSTRING;
152 ulOrdinal: ULONG;
153 ulFSAInfoLevel:ULONG;
154 pfsqb: PFSQBUFFER2;
155 VAR pcbBuffLength: ULONG ): APIRET; APIENTRY;
156 'DOSCALLS' index 277;
157end;
158
159
160type
161 TWord = Record // Bytes of a Word
162 LoByte, HiByte : Byte;
163 End;
164
165 TBPB = Array[0..30] Of Byte; // Puffer fuer BPB-Struktur
166
167 TDeviceParameters = Record
168 BPB: TBPB;
169 Cylinders: word;
170 DeviceType: Byte;
171 Attributes: Word;
172 End;
173
174
175
176 Function AddDirectorySeparator(aDirectory : String) : String;
177 begin
178 if aDirectory = '' then
179 begin
180 Result:= DIRECTORY_SEPARATOR;
181 exit;
182 end;
183
184 if aDirectory[length(aDirectory)] <> DIRECTORY_SEPARATOR then
185 begin
186 Result := aDirectory + DIRECTORY_SEPARATOR;
187 exit;
188 end;
189
190 Result := aDirectory;
191 end;
192
193
194 Function AddDirectorySeparatorIfNotEmpty(aDirectory: String): String;
195 begin
196 if aDirectory = '' then
197 begin
198 Result := '';
199 exit;
200 end;
201 Result := AddDirectorySeparator(aDirectory);
202 end;
203
204
205 Function RemoveRightDirectorySeparator(aDirectory : String) : String;
206 begin
207 Result := StrTrimRightChars(aDirectory, [DIRECTORY_SEPARATOR]);
208 end;
209
210
211 Function ExpandPath(aBaseDirectory : String; aPath : String): String;
212 var
213 tmpDirectory: String;
214 tmpDirectories : TStringList;
215 i : integer;
216 begin
217 Result:= aBaseDirectory;
218
219 if aPath = '' then
220 begin
221 Result := StrTrimRightChars(Result, [DIRECTORY_SEPARATOR]);
222 exit;
223 end;
224
225 aPath := trim(aPath);
226 if Length(aPath) > 1 then
227 begin
228 // check for drive spec
229 if aPath[2] = ':' then
230 begin
231 Result := AddDirectorySeparator(aPath);
232 if Length(aPath) > 3 then
233 begin
234 Result := StrTrimRightChars(Result, [DIRECTORY_SEPARATOR]);
235 end;
236 exit;
237 end
238 end;
239
240 if Length(aPath) > 0 then
241 begin
242 // check for root dir spec
243 if aPath[1] = DIRECTORY_SEPARATOR then
244 begin
245 // take just the drive from the basedir
246 if aBaseDirectory[2] = ':' then
247 begin
248 Result := StrLeft(aBaseDirectory, 2);
249 end
250 else
251 begin
252 Result := DIRECTORY_SEPARATOR;
253 end;
254 aPath := StrTrimLeftChars(aPath, [DIRECTORY_SEPARATOR]);
255 end;
256 end;
257
258 tmpDirectories := TStringList.Create;
259 StrExtractStringsIgnoreEmpty(tmpDirectories, aPath, [DIRECTORY_SEPARATOR], #0);
260 for i := 0 to tmpDirectories.count-1 do
261 begin
262 tmpDirectory := tmpDirectories[i];
263 if tmpDirectory = PARENT_DIREcTORY then
264 begin
265 if NOT ((Length(Result) = 2) AND (Result[2] = ':')) then
266 begin
267 Result := ParentDir(Result);
268 end;
269 end
270 else if tmpDirectory = CURRENT_DIRECTORY then
271 begin
272 ; // nothing to do
273 end
274 else
275 begin
276 Result := AddDirectorySeparator(Result) + tmpDirectory;
277 end;
278
279 // strip any extra leading slashes
280 aPath := StrTrimLeftChars(aPath, [DIRECTORY_SEPARATOR]);
281 end;
282 tmpDirectories.Destroy;
283
284 if Length(Result) = 2 then
285 begin
286 if Result[2] = ':' then
287 begin
288 // just a drive spec X:, so add a slash
289 Result := Result + DIRECTORY_SEPARATOR;
290 end;
291 end;
292 end;
293
294 Function GetLogFilesDir: String;
295 begin
296 // ecomstation 1.1 compat
297 Result := GetEnv('LOGFILES');
298 if Result <> '' then
299 begin
300 Result := AddDirectorySeparator(Result);
301 exit;
302 end;
303 // TODO
304 Result := AddDirectorySeparator(GetApplicationDir);
305 end;
306
307
308 Function SearchPath(const aPathEnvVar: String;
309 const aFilename: String;
310 var aResultFilename: String) : boolean;
311 var
312 tmpSzEnvVar : CString;
313 tmpSzFilename : CString;
314 tmpSzFilenameFound : CString;
315 tmpRC: APIRET;
316 begin
317 Result := false;
318 aResultFilename := '';
319
320 tmpSzEnvVar := aPathEnvVar;
321 tmpSzFilename := aFilename;
322 tmpRC := DosSearchPath( SEARCH_IGNORENETERRS
323 + SEARCH_ENVIRONMENT
324 + SEARCH_CUR_DIRECTORY,
325 tmpSzEnvVar,
326 tmpSzFilename,
327 tmpSzFilenameFound,
328 sizeof(tmpSzFilenameFound));
329 if tmpRC = 0 then
330 begin
331 Result := true;
332 aResultFilename := tmpSzFilenameFound;
333 end;
334 end;
335
336
337 Function SearchHelpPaths(const aFilename: String;
338 var aResultFilename: String;
339 const anIncludeAppDir: boolean) : boolean;
340 begin
341 Result := SearchPath(HelpPathEnvironmentVar, aFileName, aResultFilename);
342 if not Result then
343 begin
344 Result := SearchPath(BookshelfEnvironmentVar, aFileName, aResultFilename);
345 end;
346
347 if (not Result) and anIncludeAppDir then
348 begin
349 aResultFilename := AddDirectorySeparator(GetApplicationDir) + aFilename;
350 Result := FileExists(aResultFilename);
351 if not Result then
352 begin
353 aResultFilename := '';
354 end;
355 end;
356 end;
357
358
359 Function FindDefaultLanguageHelpFile(const anApplicationName: String; const aLanguage : String) : String;
360 var
361 tmpLanguage : String;
362 tmpLanguageParts : TStringList;
363 tmpMajorLanguage : String;
364 tmpMinorLanguage : String;
365 begin
366 Result := '';
367
368 tmpLanguage := aLanguage;
369 if aLanguage = '' then
370 begin
371 tmpLanguage := DEFAULT_LANGUAGE;
372 end;
373
374 tmpLanguageParts := TStringList.Create;
375 StrExtractStrings(tmpLanguageParts, tmpLanguage, ['_'], #0);
376
377 tmpMajorLanguage := '';
378 if tmpLanguageParts.count > 0 then
379 begin
380 tmpMajorLanguage := tmpLanguageParts[0];
381 end;
382
383 tmpMinorLanguage := '';
384 if tmpLanguageParts.count > 1 then
385 begin
386 tmpMinorLanguage := tmpMinorLanguage[1];
387 end;
388
389 tmpLanguageParts.Destroy;
390
391 // note there might be some other stuff on the end of LANG
392 // such as ES_ES_EURO...
393 if tmpMinorLanguage <> '' then
394 begin
395 if SearchHelpPaths( anApplicationName
396 + '_' + tmpMajorLanguage
397 + '_' + tmpMinorLanguage
398 + HELP_FILE_EXTENSION,
399 Result,
400 true ) then
401 begin
402 // found a specifc language
403 exit;
404 end;
405 end;
406
407 // try generic language?
408 if SearchHelpPaths( anApplicationName
409 + '_' + tmpMajorLanguage
410 + HELP_FILE_EXTENSION,
411 Result,
412 true ) then
413 begin
414 exit;
415 end;
416
417 // nothing specific, search for default
418 SearchHelpPaths(anApplicationName + HELP_FILE_EXTENSION, Result, true);
419 end;
420
421
422 Procedure GetDirsInPath(const aPathEnvVar: String; var aList: TStrings);
423 var
424 tmpRC : APIRET;
425 tmpPszPathEnvVar : PChar;
426 tmpSzEnvVar : CString;
427 begin
428 // do this in any case also if there is an error
429 // to garantie a defined behavior
430 aList.Clear;
431
432 tmpSzEnvVar := aPathEnvVar;
433 tmpRC := DosScanEnv(tmpSzEnvVar, tmpPszPathEnvVar);
434
435 if tmpRC <> 0 then
436 begin
437 exit;
438 end;
439
440 StrExtractStringsIgnoreEmpty(aList, StrPas(tmpPszPathEnvVar), [PATH_SEPARATOR], #0);
441 end;
442
443
444 Procedure GetFilesInPath( const aPathEnvVar: String;
445 const aFilter: String;
446 var aList: TStrings );
447 var
448 tmpDirectories : TStringList;
449 i : integer;
450 begin
451 tmpDirectories := TStringList.Create;
452 GetDirsInPath(aPathEnvVar, tmpDirectories);
453
454 for i:=0 to tmpDirectories.count-1 do
455 begin
456 ListFilesInDirectory(tmpDirectories[i], aFilter, false, aList);
457 end;
458
459 tmpDirectories.Destroy;
460 end;
461
462
463 Procedure ListFilesInDirectory( const aDirectory: String;
464 const aFilter: String;
465 const aWithDirectoryFlag: boolean;
466 var aList: TStrings);
467 var
468 tmpRC : APIRET;
469 tmpSearchResults: TSearchRec;
470 tmpMask: String;
471 tmpFilterParts : TStringList;
472 tmpDirectory : String;
473 i : integer;
474 begin
475 tmpFilterParts := TStringList.Create;
476 StrExtractStrings(tmpFilterParts, aFilter, [PATH_SEPARATOR], #0);
477
478 for i:=0 to tmpFilterParts.count-1 do
479 begin
480 tmpMask := tmpFilterParts[i];
481 tmpDirectory := AddDirectorySeparator(aDirectory);
482 tmpRC := FindFirst(tmpDirectory + tmpMask, faAnyFile, tmpSearchResults);
483
484 while tmpRC = 0 do
485 begin
486 if tmpSearchResults.Attr And faDirectory = 0 then
487 begin
488 if (aWithDirectoryFlag) then
489 begin
490 aList.Add(tmpDirectory + tmpSearchResults.Name);
491 end
492 else
493 begin
494 aList.Add(tmpSearchResults.Name);
495 end;
496 end;
497
498 tmpRC := FindNext(tmpSearchResults);
499 end;
500
501 FindClose(tmpSearchResults);
502 end;
503 tmpFilterParts.Destroy;
504 end;
505
506
507 Procedure ListSubDirectories(const aDirectory: String; const anIncludeSystemAndHiddenFlag: boolean; var aList: TStrings);
508 var
509 tmpRC : APIRET;
510 tmpSearchResults: TSearchRec;
511 tmpName : String;
512 tmpFileAttributes : ULONG;
513 begin
514
515 if anIncludeSystemAndHiddenFlag then
516 begin
517 tmpFileAttributes := faArchive or faReadonly or faHidden or faSysFile or faDirectory or faMustDirectory;
518 end
519 else
520 begin
521 tmpFileAttributes := faArchive or faReadonly or faDirectory or faMustDirectory;
522 end;
523
524 tmpRC := FindFirst(AddDirectorySeparator(aDirectory) + '*', tmpFileAttributes, tmpSearchResults);
525 if (tmpRC <> 0) then
526 begin
527 exit;
528 end;
529
530 while tmpRC = 0 do
531 begin
532 tmpName := tmpSearchResults.Name;
533 if (tmpName <> CURRENT_DIRECTORY) AND (tmpName <> PARENT_DIRECTORY) then
534 begin
535 aList.Add(AddDirectorySeparatorIfNotEmpty(aDirectory) + tmpSearchResults.Name );
536 end;
537 tmpRC := FindNext(tmpSearchResults);
538 end;
539 FindClose(tmpSearchResults);
540 end;
541
542
543 Procedure ListFilesInDirectoryRecursiveWithTermination(const aDirectory : String;
544 const aFilter : String;
545 const aWithDirectoryFlag : boolean;
546 const anIncludeSystemAndHiddenFlag: boolean;
547 var aList : TStrings;
548 const aTerminateCheck : TTerminateCheck;
549 const aUseTerminateCheck : boolean);
550 var
551 i : integer;
552 tmpSubDirectories : TStringList;
553 tmpSubDirectory : String;
554 begin
555 // at first add all files from the directory itself
556 ListFilesInDirectory(aDirectory, aFilter, aWithDirectoryFlag, aList);
557
558 // now determine all subdirectories
559 tmpSubDirectories := TStringList.Create;
560 ListSubDirectories(aDirectory, anIncludeSystemAndHiddenFlag, tmpSubDirectories);
561
562 for i := 0 to tmpSubDirectories.Count - 1 do
563 begin
564 // if Assigned( TerminateCheck ) then - doesn't work in sibyl
565 if aUseTerminateCheck then
566 if aTerminateCheck then
567 break;
568
569 tmpSubDirectory := tmpSubDirectories[i];
570
571 ListFilesInDirectoryRecursiveWithTermination( tmpSubDirectory,
572 aFilter,
573 aWithDirectoryFlag,
574 anIncludeSystemAndHiddenFlag,
575 aList,
576 aTerminateCheck,
577 aUseTerminateCheck);
578 end;
579 tmpSubDirectories.Destroy;
580 end;
581
582
583 Function ParentDir(const aDirectory : String) : String;
584 var
585 tmpPos: integer;
586 begin
587 tmpPos := Length(aDirectory);
588
589 // ends with slash
590 while (aDirectory[tmpPos] = DIRECTORY_SEPARATOR) AND (tmpPos > 0) do
591 begin
592 dec(tmpPos);
593 end;
594
595 // find slash
596 while (aDirectory[tmpPos] <> DIRECTORY_SEPARATOR) AND (tmpPos > 0) do
597 begin
598 dec(tmpPos);
599 end;
600
601 result:= StrLeft(aDirectory, tmpPos-1);
602 end;
603
604
605 Function MakeDirs(const aFullDirectoryPath: String) : String;
606 Var
607 tmpDirectoryParts : TStringList;
608 tmpDirectoryPart : String;
609 tmpCompletePart : String;
610 i : integer;
611 begin
612 tmpDirectoryParts := TStringList.Create;
613 StrExtractStringsIgnoreEmpty(tmpDirectoryParts, aFullDirectoryPath, [DIRECTORY_SEPARATOR], #0);
614
615 tmpCompletePart := '';
616 for i:=0 to tmpDirectoryParts.count-1 do
617 begin
618 tmpDirectoryPart := trim(tmpDirectoryParts[i]);
619
620 if tmpDirectoryPart <> '' then
621 begin
622 tmpCompletePart := AddDirectorySeparatorIfNotEmpty(tmpCompletePart) + tmpDirectoryPart;
623
624 if not DirectoryExists(tmpCompletePart) then
625 begin
626 MkDir(tmpCompletePart);
627 end;
628 end;
629 end;
630
631 Result := tmpCompletePart;
632 end;
633
634
635 Function DirectoryExists(const aDirectory : String) : boolean;
636 Var
637 tmpRC : APIRET;
638 tmpSearchResults : TSearchRec;
639 tmpDriveMap : ULONG;
640 tmpActualDrive : ULONG;
641 tmpDrive : Char;
642 tmpDriveNum : integer;
643 tmpDriveBit : longword;
644 tmpDirectory : String;
645 Begin
646 Result := false;
647 tmpDirectory := RemoveRightDirectorySeparator(aDirectory);
648 if tmpDirectory = '' then
649 begin
650 Result := true;
651 exit;
652 end;
653
654 if Length(tmpDirectory) = 2 then
655 begin
656 if tmpDirectory[2] = ':' then
657 begin
658 // a drive only has been specified
659 tmpDrive := UpCase(tmpDirectory[1] );
660 if (tmpDrive < 'A') or (tmpDrive > 'Z') then
661 begin
662 // invalid drive; return false;
663 exit;
664 end;
665
666 DosQueryCurrentDisk(tmpActualDrive, tmpDriveMap);
667 tmpDriveNum := Ord(tmpDrive) - Ord('A') + 1; // A -> 1, B -> 2...
668 tmpDriveBit := 1 shl (tmpDriveNum-1); // 2^DriveNum
669
670 Result := tmpDriveMap and (tmpDriveBit) > 0;
671 exit;
672 end;
673 end;
674
675 tmpRC := FindFirst( tmpDirectory,
676 faArchive or faReadonly or faHidden or faSysFile or faDirectory or faMustDirectory,
677 tmpSearchResults);
678 if tmpRC = 0 then
679 begin
680 Result:= true;
681 FindClose(tmpSearchResults);
682 end;
683 end;
684
685
686 Function DriveLetterToDriveNumber(const aDriveLetter : char) : longint;
687 begin
688 if (aDriveLetter >= 'a')
689 and (aDriveLetter <= 'z') then
690 begin
691 Result := Ord(aDriveLetter) - Ord('a') + 1;
692 exit;
693 end;
694
695 if (aDriveLetter >= 'A')
696 and (aDriveLetter <= 'Z') then
697 begin
698 Result := Ord(aDriveLetter) - Ord('A') + 1;
699 exit;
700 end;
701
702 // not a valid drive letter
703 Result := 0;
704 end;
705
706
707 Function DriveNumberToDriveLetter(const aDriveNumber: longint) : char;
708 begin
709 Result := Chr(aDriveNumber - 1 + Ord('A'));
710 end;
711
712
713 Function GetVolumeLabel(aDrive: char) : String;
714 var
715 tmpRC : APIRET;
716 tmpFileSystemInfo : FSINFO;
717 e : EInOutError;
718 begin
719 DosErrorAPI( FERR_DISABLEHARDERR );
720 Result := '';
721 tmpRC := DosQueryFSInfo( DriveLetterToDriveNumber(aDrive),
722 FSIL_VOLSER,
723 tmpFileSystemInfo,
724 sizeof(tmpFileSystemInfo));
725 if tmpRC = 0 then
726 begin
727 Result := StrPasWithLength(Addr(tmpFileSystemInfo.vol.szVolLabel), tmpFileSystemInfo.vol.cch);
728 Result := LowerCase(Result);
729 end;
730 DosErrorAPI( FERR_ENABLEHARDERR );
731
732 if tmpRC <> 0 then
733 begin
734 e := EInOutError.Create( 'Cannot read drive ' + aDrive + ':');
735 e.ErrorCode := tmpRC;
736 raise e;
737 end;
738 end;
739
740
741 Function GetBootDriveLetter: char;
742 var
743 tmpBuffer: longword;
744 begin
745 DosQuerySysInfo( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, tmpBuffer, sizeof(tmpBuffer));
746 Result := Chr(ord('A') + tmpBuffer - 1);
747 end;
748
749
750 Function FileIsReadOnly(const aFilename : String ) : boolean;
751 begin
752 Result :=(FileGetAttr(aFilename) AND faReadonly) > 0;
753 end;
754
755
756
757
758 // TODO
759
760
761Function IsFloppyDrive( DriveNumber: longint ): Boolean;
762Var
763 bResult : Byte;
764Begin
765 DosDevConfig( bResult, DEVINFO_FLOPPY );
766 Result := ( Abs( DriveNumber ) <= bResult);
767End;
768
769// -------------------------------------------------------------------------
770// Funktion/Function: QueryCDRoms()
771//
772// Beschreibung:
773// Die Funktion QueryCDRom ermittelt ueber eine nicht dokumentierte
774// Schnittstelle die Anzahl der CDRom-Laufwerke und den ersten, fuer
775// ein CDRom-Laufwerk, vergebenen UnitIdentifier.
776// Der Treiber OS2CDROM.DMD stellt dem System zwei Devices (CD-ROM1$
777// und CD-ROM2$) zur Verfuegung. Die beiden Devices unterscheiden sich
778// durch DeviceAttribute. Beide Devices unterstuetzen (zumindest unter
779// Warp) den undokumentierten Generic IOCtl 0x82/0x60, welcher Infor-
780// mationen ueber die angeschlossenen CDRom-Laufwerke liefert.
781//
782// Description:
783// This Functions finds out how many CD-Rom Drives are present in System
784// and which Drive Letter is the first occupied by a CD-Rom. It uses an
785// undocumented Interface to OS2CDROM.DMD.
786// OS2CDROM.DMD presents two Devices (CD-ROM1$ and CD-ROM2$). These De-
787// vices are distinguished by their Device-Attributes. Both Devices sup-
788// port (under Warp) the undocumented generic IOCtl-Call 0x82/0x60 which
789// deliver some Information about the connected CD-Rom Drives.
790//
791// Parameter:
792// Var ulCDRomCount ULONG Anzahl CD-Rom Laufwerke im System
793// Number of CD-Rom Drives in System
794//
795// Var ulFirstCDRomDiskNo ULONG erste Laufwerksnummer, die an ein
796// CD-Rom vergeben ist
797// first Drive-Letter occupied by a
798// CD-Rom Drive
799//
800// Rueckgabe/Returnvalue: keine/none
801// -------------------------------------------------------------------------
802Procedure QueryCDRoms(Var ulCDRomCount, ulFirstCDRomDiskNo: ULONG);
803
804Const cszDriverName : CSTRING = 'CD-ROM?$';
805
806Var cCurDriver : Char; // Indexvariable fuer aktuell bearbeites Device (1 oder 2)
807 // Index for current Device (1 or 2)
808
809 hDevHandle : HFILE; // Handle fuer Device
810 // Device handle
811
812 ulAction : ULONG; // Aktionscode (DosOpen())
813 // Actioncode (DosOpen())
814
815 ulParams : ULONG; // Anzahl Bytes von IOCtl gelieferter Parameterdaten
816 // Number of Bytes for delivered Parameterdata
817
818 ulData : ULONG; // Anzahl Bytes von IOCtl gelieferter Daten
819 // Number of Bytes delivered by IOCtl
820
821 rCDInfo : Record // Ergebnisstruktur der IOCtl-Funktion (s.o.)
822 // Record for Results of IOCtl-Call (see above)
823 usCDRomCount : USHORT; // Anzahl CD-Roms / Number of CD-Rom Drives
824 usFirstUnitNo: USHORT; // erste vergebene Laufwerksnummer / first Driver Letter
825 End;
826
827Begin (* uQueryCDRom *)
828 /************************************
829 * Vorbelegungen
830 *
831 * initial assignments
832 ************************************/
833 ulCDRomCount := 0;
834 ulFirstCDRomDiskNo := 0;
835
836 ulParams := 0;
837
838 /************************************
839 * die beiden Devices abarbeiten
840 *
841 * accessing both Devices
842 ************************************/
843 For cCurDriver := '1' To '2' Do
844 Begin
845 /************************************
846 * Device oeffnen
847 *
848 * open Device
849 ************************************/
850 cszDriverName[6] := cCurDriver;
851 If (DosOpen(cszDriverName, // Devicename
852 hDevHandle, // Handle
853 ulAction, // Aktionscode
854 0, // DateigrӇe
855 FILE_NORMAL, // Attribute: read/write
856 OPEN_ACTION_OPEN_IF_EXISTS, // OpenFlag: ”ffnen, wenn vorhanden
857 OPEN_FLAGS_FAIL_ON_ERROR Or // Modus: Fehlermeldung per Returncode
858 OPEN_SHARE_DENYNONE Or // keine Einschr„nkungen fr Dritte
859 OPEN_ACCESS_READONLY, // nur lesender Zugriff
860 NIL)=NO_ERROR) Then // keine EA
861 Begin
862 /************************************
863 * IOCtl-Funktion aufrufen
864 *
865 * Call to IOCtl
866 ************************************/
867 If (DosDevIOCtl(hDevHandle, // Handle / Handle
868 $82, // Kategorie / Category
869 $60, // Funktion / Function
870 NIL, // keine Parameterliste / No Parameterlist
871 0, // Laenge Parameterliste / Length of Parameterlist
872 ulParams, // Groesse der gelieferten Parameterdaten
873 // / Number of Bytes for Parameterdata
874 rCDInfo, // Puffer fuer gelieferte Daten
875 // / Buffer for returned Data
876 SizeOf(rCDInfo), // Groesse des Datenpuffers
877 // / Size of Databuffer
878 ulData)=NO_ERROR) Then // Groesse der gelieferten Daten
879 // / Number of Bytes for returned Data
880 Begin
881 ulCDRomCount := rCDInfo.usCDRomCount;
882 ulFirstCDRomDiskNo := Succ(rCDInfo.usFirstUnitNo);
883 End;
884
885 DosClose(hDevHandle);
886 End;
887
888 End; (* For *)
889
890End; (* uQueryCDRom *)
891
892
893Function GetLocalDriveType( DriveNumber: longint ): TDriveType;
894var
895 IOCtlParameters: Word;
896 rc: APIRET;
897 ParameterLength: longWord;
898 DataLength: longword;
899 DeviceData: TDeviceParameters;
900 Fixed: boolean;
901 FirstCDDrive: ULONG;
902 NumCDDrives: ULONG;
903begin
904
905 TWord( IOCtlParameters ).LoByte := 0; // BPB of physical Device
906 TWord( IOCtlParameters ).HiByte := DriveNumber - 1; // drive number, zero base
907
908 ParameterLength := SizeOf( IOCtlParameters ); // input length of parameters
909 DataLength := 0; // input length of data (none)
910
911 rc := DosDevIOCTL( HFILE(-1), // Open Device (not a file)
912 IOCTL_DISK, // Category
913 DSK_GETDEVICEPARAMS, // Function
914 IOCtlParameters, // Parameters
915 SizeOf( IOCtlParameters ), // (max) size of parameters
916 ParameterLength, // parameters length
917 DeviceData, // results
918 SizeOf( DeviceData ), // (max) size of data block
919 DataLength ); // data block length
920
921 Fixed := ( DeviceData.Attributes and 1 ) > 0; // bit 0 indicates fixed (1) or removable (0)
922 if not Fixed then
923 begin
924 result := dtRemovable;
925
926 QueryCDRoms( FirstCDDrive,
927 NumCDDrives );
928
929 if ( DriveNumber >= FirstCDDrive )
930 and ( DriveNumber < FirstCDDrive + NumCDDrives ) then
931 result := dtCD;
932
933 exit;
934 end;
935
936 result := dtHard;
937end;
938
939// Takes a one-based drive number
940Function GetDriveType( DriveNumber: longint ): TDriveType;
941var
942 szDrive: CString;
943
944 FSData: array[ 0..sizeof( FSQBuffer) + 3*_MAX_PATH ] of char;
945 pBuffer: PFSQBUFFER2;
946 FSDataLength: ULONG;
947
948 rc: APIRET;
949begin
950 assert( DriveNumber >= 1 );
951 assert( DriveNumber <= 26 );
952
953 if ( DriveNumber >=1 ) and ( DriveNumber <= 2 ) then
954 begin
955 if IsFloppyDrive( DriveNumber ) then
956 begin
957 result := dtFloppy;
958 exit;
959 end;
960
961 result := dtNone; // don't let OS/2 try a fake B: drive
962 exit;
963 end;
964
965 DosErrorAPI( FERR_DISABLEHARDERR );
966
967 szDrive := DriveNumberToDriveLetter( DriveNumber ) + ':';
968 FSDataLength := sizeof( FSData );
969 pBuffer := Addr( FSData );
970 rc := _DosQueryFSAttach( szDrive,
971 0, // ignored
972 FSAIL_QUERYNAME,
973 pBuffer,
974 FSDataLength );
975
976 if rc = 0 then
977 begin
978 case pBuffer^.iType of
979 FSAT_REMOTEDRV:
980 result := dtNetwork;
981
982 FSAT_LOCALDRV:
983 // Figure out what kind of local drive it is...
984 result := GetLocalDriveType( DriveNumber );
985
986 else
987 begin
988 // should never happen
989 result := dtNone;
990 exit;
991 end;
992 end;
993 end
994 else if rc = ERROR_NOT_READY then
995 begin
996 // No media?
997 // Have a look for a local disk anyway.
998 result := GetLocalDriveType( DriveNumber );
999 end
1000 else
1001 begin
1002 result := dtNone;
1003 end;
1004
1005 DosErrorAPI( FERR_ENABLEHARDERR );
1006end;
1007
1008const
1009 DEVLEN = 8;
1010 CNLEN = 15; // Computer name length
1011 UNCLEN = (CNLEN+2); // UNC computer name length
1012 NNLEN = 12; // 8.3 Net name length (share name length)
1013 RMLEN = (UNCLEN+1+NNLEN); // Maximum remote name length
1014
1015type
1016 use_info_0 = record
1017 ui0_local: cstring[ DEVLEN ]; // note this is of size DEVLEN + 1
1018 ui0_pad_1: char;
1019 ui0_remote: pchar;
1020 space: array[ 0..RMLEN ] of char; // remote path is written to somewhere in here
1021 end;
1022
1023 use_info_1 = record
1024 ui0_local: cstring[ DEVLEN ];
1025 ui0_pad_1: char;
1026 ui0_remote: pchar; // address of a buffer to hold remote path
1027 ui1_password: pchar; //
1028 ui1_status: USHORT;
1029 ui1_asg_type: SHORT;
1030 ui1_refcount: USHORT;
1031 ui1_usecount: USHORT;
1032 space: array[ 0..RMLEN ] of char; // remote path is written to somewhere in here
1033 end;
1034
1035 TNet32UseGetInfo = Function( pszServer: pchar;
1036 pszUseName: pchar; // e.g. drive x:
1037 ulLevel: ULONG;
1038 pbBuffer: pointer; // pointer to output buffer
1039 ulBuffer: ULONG; // size of output in buffer
1040 Var pulTotalAvail: ULONG )
1041 : word; CDecl;
1042
1043Var
1044 Net32UseGetInfo: TNet32UseGetInfo;
1045 hNetAPI32DLL: HMODULE;
1046 TriedLoading: boolean;
1047
1048// 129 Net32UseGetInfo
1049Function GetNetworkDriveRemotePath( DriveNumber: longint ): string;
1050var
1051 ErrorName: array[ 0..255 ] of char;
1052 dummy: cstring;
1053 rc: word;
1054 UseName: array[ 0..255 ] of char;
1055 UseInfo: use_info_0;
1056 pUseInfo: pointer;
1057 TotalBytesNeeded: ULONG;
1058 RemotePath: array[ 0..255 ] of char;
1059 Dummy2: array[ 0..4096 ] of char; // try to fix stack probs
1060begin
1061 Result := '';
1062
1063 if not TriedLoading then
1064 begin
1065 TriedLoading := true;
1066 rc := DosLoadModule( ErrorName,
1067 sizeof( ErrorName ),
1068 'NETAPI32',
1069 hNetAPI32DLL );
1070 if rc = NO_ERROR then
1071 begin
1072 // NetAPI32.DLL loaded OK
1073 rc := DosQueryProcAddr( hNetAPI32DLL,
1074 129,
1075 dummy,
1076 pointer( Net32UseGetInfo ) );
1077 if rc <> 0 then
1078 Net32UseGetInfo := nil;
1079 end;
1080 end;
1081
1082 if Assigned( Net32UseGetInfo ) then
1083 begin
1084 UseName[ 0 ] := DriveNumberToDriveLetter( DriveNumber );
1085 UseName[ 1 ] := ':';
1086 UseName[ 2 ] := #0;
1087
1088 RemotePath[ 0 ] := #0;
1089// UseInfo.ui0_remote := Addr( RemotePath );
1090
1091 pUseInfo := Addr( UseInfo );
1092 rc := Net32UseGetInfo( nil, // server - always nil
1093 Addr( UseName ),
1094 0, // info level 0
1095 pUseInfo,
1096 sizeof( UseInfo ),
1097 TotalBytesNeeded );
1098
1099 if rc = 0 then
1100 Result := StrPas( UseInfo.ui0_remote );
1101
1102 end;
1103end;
1104
1105
1106Initialization
1107End.
Note: See TracBrowser for help on using the repository browser.