{$X+,B-,V-} {essential compiler directives} Unit nwFile; { nwFile unit as of 950301 / NwTP 0.6 API. (c) 1993,1995, R. Spronk } INTERFACE { Primary Functions Interrupt: comments: Volume Management (Volume Tables) --------------------------------- * ClearObjectVolRestriction (F216/22) (3) [aka ClearVolumeRestrictions/RemoveObjectDiskRestrictions] * GetObjectVolRestriction (F216/29) (3) [aka GetObjDiskRestrictions/GetObjectDiskUsageAndRestrictions] * GetVolumeName (F216/06) * GetVolumeNameWithHandle (F216/15) [aka GetVolumeInfoWithHandle] * GetVolumeNumber (F216/05) * GetVolumeUsage (F216/2C) (3) [aka GetExtendedVolumeInformation] * IsVolumeRemovable (F212) [aka GetVolumeInfoWithNumber] * ScanVolForRestrictions (F216/20) (3) * SetObjectVolRestriction (F216/21) (3) [aka SetVolumeRestrictions/SetObjectVolSpaceLimit /AddUserDiskspaceRestriction] Directory Handles (Directory Handle Table/Drive tables) ------------------------------------------------------- * AllocPermanentDirHandle (F216/12) * AllocTemporaryDirHandle (F216/13) * DeallocateDirHandle (F216/14) * DeleteFakeRootDirectory (E906) * GetDirectoryHandle (E900) * GetDriveConnectionId (EF02) * GetDirectoryPath (F216/01) * GetDriveFlag (EF01) (6) * GetDriveHandle (EF00) (6) * GetRelativeDriveDepth (E907) * GetSearchDriveVector (E901) * MapFakeRootDirectory (E905) * SetDirectoryHandle (F216/00) * SetDriveConnectionId (EF02) * SetDriveFlag (EF01) * SetDriveHandle (EF00) * SetSearchDriveVector (E902) Secondary Functions * DeleteConnectionsDriveMappings * DeleteDriveMapping * GetEnvPath (BA..) * IsSearchDrive (BA..) * IsNetworkDrive (4409) * MapDrive * MapPermanentDrive * MapSearchDrive * SetEnvPath (BA..) Entries (directory/file management) ----------------------------------- * ChangeDirectory (3B..) (DOS) * ConvertPathToDirEntryId (F217/F4) * CreateDirectory (F216/0A) * DeleteDirectory (F216/0B) * EraseFiles (F244) . FileServerFileCopy (F3..) GetDirectoryInfo (F216/2D) (3) * GetDirectoryEntry (F216/1F) (3) . GetExtendedFileAttributes (B600) =F24E ??? . GetFileAttributes (4300) (DOS) * GetTrueEntryName (60..) (DOS) * MapDirentryIdToPath (F217/F3) MoveEntry (F216/2E) (3) dir and files * PurgeSalvagableFile (F216/1D) (3) * RecoverSalvagebleFile (F216/1C) (3) * RenameDirectory (F216/0F) * ScanDirectoryInformation (F216/02) * ScanDirectoryEntry (F216/1E) (3) * ScanFileInformation (F217/0F) ScanFilePhysical (F216/28) (3) * ScanSalvagableFiles (F216/1B) (3) * SetEntry (F216/25) (3) dir and files . SetExtendedFileAttributes (B601) =F24F . SetFileAttributes (F246) [4301] * SetFileInformation (F217/10) * ScanDirRestrictions (F216/23) (3) * SetDirRestriction (F216/24) (3) Secondary functions: DeleteFile GetFileHandle IsFileShareable FlagFileShareable PurgeFiles (by dirHandle,fileMask) SalvageFiles (by dirHandle,fileMask) PurgeAllErasedFiles Trustees/Max. Rights Mask ------------------------- * DeleteTrustee (F216/2B) (3) * GetEffectiveRights (F216/2A) (3) . ModifyMaximumRightsMask (F216/04) . ScanBinderyObjectTrusteePaths (F217/47) * ScanEntryForTrustees (F216/26) (3) * SetTrustee (F216/27) (3) Not Implemented: ---------------- - AddTrusteeToDirectory (F216/0D) (10) - AllocSpecialDirHandle (F216/16) (2) - DeleteTrusteeFromDirectory (F216/0E) (10) - FileServerFileCopy (E6..) (8) - GetEffectiveDirectoryRights (F216/03) (10) - GetPathFromDirEntryID (F216/1A) (12) - GetVolumeInformation (F217/E9) (1) - GetVolumeInfoWithHandle (F216/15) (5) - GetVolumeInfoWithNumber (F212) (4) [DA..] - PurgeErasedFiles (F216/10) (8) - PurgeAllErasedFiles (F217/CE) (8) - RestoreDirectoryHandle (F216/18) (2) - RestoreErasedFile (F216/11) (8) - SaveDirectoryHandle (F216/17) (2) - ScanDirectoryForTrustees (F216/0C) (9) - SetDirectoryInformation (F216/19) (11) - SetFileAttributes (E4..) (7) - UpdateFileSize (E5..) (7) Notes: (1) GetVolumeInformation. This call is NOT available in all 3.x versions. (only with Nw 2.1 & 3.1x and CLIB.NLM dated before 11-11-92 ) This call is not implemented here. Replaced by GetVolumeUsage. (2) not available in (all versions of) NW 3.x. (3) NW 3.x (and upwards) only. (4) Replaced by GetVolumeUsage and IsVolumeRemovable. (5) Replaced by GetVolumeUsage and GetVolumeNameWithHandle. (6) Information can also be obtained by calling GetDirectoryHandle. (DOS) 'Normal' DOS call, extended by NetWare shell. (7) Not supported by Adv.NW 3.x. Not implemented here. These are functions using FCB's. If another function with the same name is listed here, that function performs the same action. (8) Not supported by Adv.NW 3.x. Not implemented here. These functions have been replaced with calls marked (3) (9) Replaced by a newer version: ScanEntryForTrustees. (10) Replaced by DeleteTrustee, GetEffectiveRights and SetTrustee. (11) Replaced by SetEntry (12) Replaced by MapDirEntryIDtoPath } Uses nwIntr,nwMisc,nwBindry,nwConn; Var Result:Word; Type TsearchDriveVector=array [1..17] of byte; CONST DRIVE_UNUSED = $00; DRIVE_PERMANENT = $01; { Drive permanently assigned to fileserver directory } DRIVE_TEMPORARY = $02; { Drive temporary assigned to FS dir. Released by EOJ } DRIVE_NETWORK = $03; { Normal drive mapping } DRIVE_LOCAL = $80; { Drive is local. ! By ORing with one of the above bits, it can be reassigned to a FS directory.} {Name Space Type constants} NS_DOS =0; NS_MAC =1; NS_NFS =2; NS_FTAM =3; NS_HPFS =4; { Attributes / Netware directory & file attributes } A_NORMAL = $00; {file} A_READ_ONLY = $01; {file} A_HIDDEN = $02; {file/dir} A_SYSTEM = $04; {file/dir} A_EXECUTE_ONLY = $08; {file} A_DIRECTORY = $10; {file} A_NEEDS_ARCHIVED = $20; {file} A_undocumented = $40; A_SHAREABLE = $80; {file} A_LO_SEARCH = $0100; {file} A_MID_SEARCH = $0200; {file} A_HI_SEARCH = $0400; {file} A_RESERVED = $0800; {file/dir} A_TRANSACTIONAL = $1000; {file} A_INDEXED = $2000; {file} A_READ_AUDIT = $4000; {file} A_WRITE_AUDIT = $8000; {file} A_PURGE = $010000; {file/dir} A_RENAME_INHIBIT = $020000; {file/dir} A_DELETE_INHIBIT = $040000; {file/dir} A_COPY_INHIBIT = $080000; {file} { Trustee Attributes / directory access rights } TA_NONE = $00; TA_READ = $01; {R open/read} TA_WRITE = $02; {W open/write} TA_RESERVED = $04; { reserved, set to 0 } TA_CREATE = $08; {C create files or dirs} TA_DELETE = $10; {E delete files/dirs} TA_ACCESS = $20; {A set /delete trustees} TA_SEARCH = $40; {F directory can be searched/file is visible} TA_MODIFY = $80; {M modify dir/file attributes} TA_SUPERVISOR =$100; {S supervisor rights to file or directory } { Entry Modify flags / see SetEntry } EM_ENTRYNAME = $00000001; EM_ATTRIBUTES = $00000002; EM_CREATIONTIME = $0000000C; { date = $04, time = $08 } EM_OWNERID = $00000010; EM_ARCHIVETIME = $00000060; { date = $20, time = $40 } EM_ARCHIVERID = $00000080; EM_MODIFYTIME = $00000300; { date = $0100, time =$0200 } EM_MODIFIERID = $00000400; EM_LASTACCESSTIME = $00000800; { date = $0800 } EM_RIGHTSMASK = $00001000; EM_MAXDISKSPACE = $00002000; Type TvolUsage=record totalBlocks, {static info} freeBlocks, {dynamic} purgableBlocks, {dynamic} notYetPurgableBlocks, {dynamic} totalDirEntries, {static} availDirEntries, {dynamic} Flags :LongInt; {dynamic} SectorsPerBlock :byte; {static/number of 512 byte sectors per block} volumeName :string[16];{static} end; { used By ScanVolForRestrictions } TobjVolRestr=array[1..64] of record objId :LongInt; MaxAllowedBlocks:LongInt; end; Type Tentry=record EntryName :String[16]; NSType :byte; {namespace number} DataForkSize :Longint; { =FileSize when NStype=0 (dos) } {ResourceForkSize:Longint; (Mac data) =0 when NStype=0 (dos) } FileSize :Longint; {FileSize=Resource+Data forksize } Attributes :Longint; RightsMask :word; {(4)} CreationTime, ArchiveTime, ModifyTime, LastAccessTime, DeleteTime :TnovTime; {salvagable file only} OwnerId, ArchiverId, ModifierId, DeletorId :Longint; {salvagable file only} end; { Note: (4) When used with ScanDirectoryInfo, this field contains the MaximumRightsMask. Otherwise, the InheritedRightsMask } Type TdirRestrList=array[1..56] of record Level:Byte; MaxBlocks, AvailableBlocks:Longint; end; {when MaxBlocks and Availableblocks are set to to $7FFFFFFF, no restrictions are enforced -at this level-} Type TtrusteeInformation=record NumberOfTrustees:Byte; TrusteeID :array[1..20] of Longint; TrusteeRights:array[1..20] of Word; end; {-------------------- Volumes----------------------- } {F216/05 [2.15c+]} Function GetVolumeNumber( volumeName:String; Var volumeNumber:Byte ):boolean; { Returns the volume number of a given volume name } {F216/06 [2.15c+]} Function GetVolumeName( volumeNumber:Byte; Var volumeName:String ):boolean; { Returns the volume name of a give volume number [0..31]. If the volume is not mounted at the time of this call, a null-string is returned. } {F216/2C [2.15c+]} Function GetVolumeUsage(volumeNumber:byte; Var VolUsage: TvolUsage):boolean; {F212 [2.15c+]} Function IsVolumeRemovable( volumeNumber:Byte; Var volIsRemoveable:Boolean):boolean; {F216/15 [2.15c+]} Function GetVolumeNameWithHandle( dirHandle:Byte; Var volumeName:String ):boolean; {F216/29 [3.x]} Function GetObjectVolRestriction(VolumeNumber:byte; objId:LongInt; Var MaxAllowedBlocks,BlocksInUse:LongInt):boolean; {F216/21 [3.x]} Function SetObjectVolRestriction(VolumeNumber:byte; objId, MaxAllowedBlocks:LongInt):boolean; {F216/22 [3.x]} Function ClearObjectVolRestriction(VolumeNumber:byte; objId:LongInt):boolean; {F216/20 [3.x]} Function ScanVolForRestrictions(VolumeNumber:byte; {i/o} Var sequenceNbr:LongInt; {out} Var NbrOfObjects:byte; Var ResultBuffer:TobjVolRestr):boolean; { 1st call: sequenceNbr=0, after last call: sequenceNbr=0 again. } {-------------------- Directory Handles/ Drives -------------} {F216/01} Function GetDirectoryPath(DirHandle:byte; Var PathName:string):boolean; {EF00 [2.0/2.1/3.x]} Function GetDriveHandle( DriveNumber:Byte; Var DirHandle:Byte ):boolean; { The call returns a pointer to the shell's Drive Handle Table. (32 bytes) (Drives A..Z and temporary drives [\]^_' ) If a drive has been assigned a directory handle on the file server, the handle can be found in the DHT at the position corresponding with the drive letter.} {EF00 [2.0/2.1/3.x]} Function SetDriveHandle( DriveNumber:Byte; DirHandle:Byte ):boolean; {E900 [2.0/2.1/3.x]} Function GetDirectoryHandle( DriveNumber:Byte; Var dirHandle,status:byte):Boolean; { Returns directory handle and status flags for a drive. } { Drivenumber = 0..31 (A..Z = 0..25) and temp drives (26..31) } {EF01 [2.0/2.1/3.x]} Function GetDriveFlag( DriveNumber:Byte; Var DriveStatus:Byte ):Boolean; { This call returns a pointer to the shell's Drive Flag Table (32 Bytes) Each entry indicates a drive's status (permanent,temporary,local,unassigned) For further explanation see the DRIVE_xxx constants.} {EF01 [2.0/2.1/3.x]} Function SetDriveFlag( DriveNumber:Byte; DriveStatus:Byte ):Boolean; {F216/14 [2.15c+]} function DeallocateDirHandle(DirHandle : Byte) : Boolean; { This function deletes a directory handle } {EF02 [2.0/2.1/3.x]} Function GetDriveConnectionID( DriveNumber:Byte; Var connID:Byte):boolean; { returns the servernumber (1..8) associated with a drive. } {EF02 [2.0/2.1/3.x]} Function SetDriveConnectionID( DriveNumber:Byte; connID:Byte):boolean; {F216/00 [2.15c+]} Function SetDirectoryHandle( sourceDirHandle:Byte; sourceDirPath:String; targetDirHandle:Byte ):boolean; { make handle 'targetHandle' point to the directory provided by sourceHandle and/or sourceDirPath. } {F216/12 [2.15c+]} FUNCTION AllocPermanentDirHandle( DriveNumber:Byte; DirHandle : byte; DirPath : string ; var NewDirHandle, EffectiveRights: byte ) :boolean; {F216/13 [2.15c+]} function AllocTemporaryDirHandle( DriveNumber:byte; DirHandle : Byte; DirPath : String; var NewDirHandle,EffectiveRights : Byte) : Boolean; { Allocates a temporary directory handle, deleted automatically by EOJ. } {E901} Function GetSearchDriveVector(Var vector:TsearchDriveVector):boolean; {E902 } Function SetSearchDriveVector(vector:TsearchDriveVector):boolean; {E905 (shell 3.01+)} Function MapFakeRootDirectory(DriveNumber:byte; DirPath:string):boolean; {E906 (shell 3.01+)} Function DeleteFakeRootDirectory(DriveNumber:byte):boolean; {E907 (shell 3.01+)} Function GetRelativeDriveDepth(DriveNumber:byte; Var depth:byte):boolean; {BA.. } Function GetEnvPath(Var EnvPath:string):boolean; {BA.. } Function SetEnvPath(EnvPath:string):boolean; {secondary } FUNCTION MapDrive(DriveNumber:byte; DirectoryPath:string; Root, Permanent:boolean):boolean; {secondary } FUNCTION MapPermanentDrive(DriveNumber:byte; DirectoryPath:string; Root:boolean):boolean; {secondary} Function MapSearchDrive(DriveNumber:byte; DirPath:string; PathPosition:byte; Insert,Root,Permanent:Boolean):boolean; {secondary} Function DeleteDriveMapping(DriveNumber:Byte):boolean; {secondary} Function DeleteConnectionsDriveMappings(ConnId:Byte):Boolean; {secondary} Function IsSearchDrive(DriveNumber:byte):boolean; {4409 } Function IsNetworkDrive(driveNumber:Byte):boolean; { isNetworkDrive is set to TRUE if the drive is a) a network drive, and b) a legal drive letter was used. } {------------------------- entries -----------------------------------------} {F217/0F [2.15c+]} Function ScanFileInformation(DirHandle:Byte; FilePath:string; SearchAttrib:Byte; {i/o} VAR SequenceNbr:Integer; {out} VAR fileInfo:Tentry):Boolean; {F217/F4 [3.0+]} Function ConvertPathToDirEntryId(dirHandle:Byte; dirPath:string; Var VolNbr :byte; Var dirEntryID:LongInt):boolean; { aka ConvertPathToDirEntry / requires console rights } {F216/02} Function ScanDirectoryInformation(dirHandle:byte; searchDirPath:string; {i/o} Var sequenceNumber:word; {out:} Var dirInfo:Tentry ):boolean; {F216/1F [2.15c+]} Function GetDirectoryEntry(DirHandle:byte; Var dirEntry:Tentry):boolean; {F216/1E [2.15c+]} Function ScanDirectoryEntry(DirHandle:Byte; EntryName:string; SearchFlags:Longint; {i/o} Var EntryId:Longint; {out} Var Entry:Tentry ):boolean; {F217/F3 [3.0+]} Function MapDirEntryIdToPath(VolNbr:byte;DirEntryId:Longint; NStype:byte; Var ExtPath:string):boolean; {F216/25 [2.15c+] } Function SetEntry(DirHandle:Byte;EntryId:Longint;SearchFlags:Byte; ModFlags:Longint; Entry:Tentry ):boolean; {F217/10 [2.15c+]} Function SetFileInformation(DirHandle:Byte; FilePath:string; SearchAttrib:Byte; fileInfo:TEntry):boolean; {F216/1B [2.15c+]} Function ScanSalvagableFiles(DirHandle:Byte; {i/o} Var EntryId:Longint; {out} Var Entry:Tentry ):boolean; {F216/1D [3.0+]} Function PurgeSalvagableFile(DirHandle:Byte; EntryId:Longint; FileName:string):boolean; {F216/1C [3.0+] } Function RecoverSalvagableFile(dirHandle:Byte; EntryId:Longint; OldName,NewName:string):boolean; {F244 [2.1x/3.x]} Function EraseFiles(dirHandle, searchAttrib:Byte; filePath:string ):boolean; {60.. (extended DOS call)} Function GetTrueEntryName(DirPath:string; Var CanonicalPath:string):boolean; {F216/0F [2.0/2.1/3.x]} Function RenameDirectory( dirHandle:Byte; dirPath, newDirName :String):Boolean; {F216/0B [2.15c+]} Function DeleteDirectory(DirHandle:Byte; DirPath:string):boolean; {F216/0A [2.15+]} Function CreateDirectory(DirHandle:Byte; DirPath:string; MaxRightsMask:byte):boolean; {3B.. } Function ChangeDirectory(DirPath:string):boolean; {F216/24 [3.0+]} Function SetDirRestriction(DirHandle:Byte; DiskSpaceLimit:Longint):boolean; {F216/23 [3.0+]} Function ScanDirRestrictions(DirHandle:Byte; Var NumberOfEntries:Byte; Var RestrInfo:TdirRestrList):boolean; {--------------------------- Rights/trustees ---------------------------} {F216/27 [3.0+]} Function SetTrustee(DirHandle:Byte;DirPath:string; TrusteeObjectID:Longint; RightsMask:Word ):boolean; {F216/2B [3.0+]} Function DeleteTrustee(DirHandle:Byte;DirPath:String; TrusteeObjectId:Longint):boolean; {F216/2A [3.0+]} function GetEffectiveRights(DirHandle:Byte;DirPath:String; var Rights:Word) : Boolean; {F216/04 [2.15c+]} Function ModifyMaximumRightsMask(DirHandle:Byte;DirPath:string; RevokeRightsMask,GrantRightsMask:Word):boolean; {F217/47 [2.15c+]} Function ScanBinderyObjectTrusteePaths(TrusteeObjectId:Longint; VolumeNumber:Byte; {i/o} Var SequenceNumber:word; {out} Var AccessMask:Word; Var Path:string ):boolean; {F216/26 [3.0+]} Function ScanEntryForTrustees(DirHandle:Byte;DirPath:String; {i/o} Var SequenceNumber:Byte; {out} Var TrusteeInfo: TtrusteeInformation):boolean; IMPLEMENTATION{============================================================} {$IFDEF MSDOS} uses dos; { file handles / 'normal' file attributes } {$ENDIF} Type TintEntry=record { Unit internal Entry type } { 0} _res1 :Longint; { low word = Dir Id of parent Dir } { 4} _attrib :Longint; { 8} _res2 :word; { 10} _NStype :Byte; { 11} _name :string[12]; { 24} _creationTime :Longint; { 28} _OwnerId :Longint; { hi-lo} { 32} _ArchiveTime :Longint; { 36} _ArchiverId :Longint; { hi-lo} { 40} _modifyTime :Longint; { 44} _ModifierId :Longint; { files only } { 48} _ForkSize :Longint; { files only } { 52} _res3 :array[1..44] of byte; { Trustee obj IDs and Tr. rights } { 96} _FileRightsMask:word; { files only } { 98} _AccessDate :word; { files only } {100} _DirRightsMask :word; { directories only } {102} _res4 :word; {Unique Dir ID, hi-lo} { directories only } {104} _DeleteTime :Longint; { salvageable files only } {108} _DeletorID :LongInt; { salvageable files only } {112} _res5 :array[1..16] of byte; {128} end; Procedure Convert2ExtEntry(Var Ie:TintEntry;Var Oe:Tentry); begin FillChar(Oe,Sizeof(Tentry),#$0); with Ie,Oe do begin Attributes:=_Attrib; NStype:=_NStype; Entryname:=_name; DosTime2NovTime(_CreationTime,CreationTime); OwnerId:=Lswap(_OwnerId); {force lo-hi} DosTime2NovTime(_ArchiveTime,ArchiveTime); ArchiverId:=Lswap(_ArchiverID); {force lo-hi} DosTime2NovTime(_ModifyTime,ModifyTime); if (_attrib and $10)>0 { is entry a directory ? } then begin RightsMask:=_DirRightsMask; end else begin ModifierId:=LSwap(_ModifierId); {force lo-hi} DataForksize:=_Forksize; if _NSType=0 then FileSize:=_ForkSize; RightsMask:=_FileRightsMask; DosTime2NovTime(MakeLong(_accessDate,0),LastAccessTime); DosTime2NovTime(_DeleteTime,DeleteTime); DeletorId:=Lswap(_DeletorID); {force lo-hi} end; end; end; Procedure Convert2IntEntry(Var Oe:TEntry;Var Ie:TIntEntry); Var TempTime:Longint; begin FillChar(Ie,Sizeof(Tentry),#$0); with Ie,Oe do begin _Attrib:=Attributes; _NStype:=NStype; _Name:=EntryName; NovTime2DosTime(CreationTime,_CreationTime); _OwnerId:=Lswap(OwnerId); {force hi-lo} NovTime2DosTime(ArchiveTime,_ArchiveTime); _ArchiverId:=Lswap(ArchiverId); {force hi-lo} NovTime2DosTime(ModifyTime,_ModifyTime); if (Attributes and $10)>0 { is entry a directory ? } then begin _DirRightsMask:=RightsMask; end else begin _ModifierId:=Lswap(ModifierId); { force hi-lo } _ForkSize:=DataForkSize; _FileRightsMask:=RightsMask; NovTime2DosTime(LastAccessTime,TempTime); _AccessDate:=HiLong(TempTime); NovTime2DosTime(DeleteTime,_DeleteTime); _DeletorID:=Lswap(DeletorId); { force hi-lo } end; end; end; Procedure ConvertPathToVolFormat(Var path:string); { reformat \\server\vol\path to VOL:PATH server/vol:path to VOL:PATH } Var pcolon,pslash:byte; begin if (Path[0]>#1) and (Path[1]='\') and (Path[2]='\') then begin delete(Path,1,2); Path:=Path+'\'; pslash:=pos('\',Path); if pslash>0 then begin delete(Path,1,pslash); { remove servername from path } pslash:=pos('\',Path); if pslash>0 then Path:=copy(Path,1,pslash-1)+':'+copy(Path,pslash+1,255); end; while Path[ord(Path[0])]='\' do dec(Path[0]); end else begin pcolon:=pos(':',path); if (path[0]>#3) and (pcolon>3) then begin pslash:=pos('/',path); if (pslash=0) or (pslash>pcolon) then pslash:=pos('\',path); if (pslash>0) and (pslash#16 then volumeName[0]:=#16; volName:=volumeName; if volname[ord(volName[0])]=':' then dec(volName[0]); len:=2+ord(volName[0]); F2SystemCall($16,len+2,SizeOf(Trep),result); end; volumenumber:=TPrep(GlobalReplyBuf)^.volNbr; getVolumeNumber:=(result=0) {resultcodes: 00 success; 98h volume doesn't exist } end; {F216/15 [2.15c+]} Function GetVolumeNameWithHandle( dirHandle:Byte; Var volumeName:String ):boolean; Type Treq=record len :word; subFunc :byte; _dirHandle :Byte; end; Trep=record _sectPerBlock :Word; {hi-lo} _TotalBlocks :Word; {hi-lo} _availBlocks :Word; {hi-lo} { Use GetVolumeUsage for the other fields } _TotalDirSlots:Word; {hi-lo} _availDirSlots:Word; {hi-lo} _volName :array[1..16] of byte; _volRemoveable:Word; {hi-lo} end; TPreq=^Treq; TPrep=^Trep; Begin WITH TPreq(GlobalReqBuf)^ do begin len:=SizeOf(Treq)-2; subFunc:=$15; _dirHandle:=dirHandle; end; F2SystemCall($16,Sizeof(Treq),SizeOf(Trep),result); ZStrCopy(volumeName,TPrep(GlobalReplyBuf)^._volName,16); if volumeName='' then result:=$9B; { Invalid directory handle } getVolumeNameWithHandle:=(result=0) { resultcodes: 00 success; $9B invalid directory handle } end; {F212 [2.15c+]} Function IsVolumeRemovable( volumeNumber:Byte; Var volIsRemoveable:Boolean):boolean; { stripped down version of the GetVolumeInfoWithNumber call } Type Treq=Byte; Trep=record _sectPerBlock :Word; {hi-lo} _TotalBlocks :Word; {hi-lo} _availBlocks :Word; {hi-lo} _TotalDirSlots :Word; {hi-lo} _availDirSlots :Word; {hi-lo} _volName :array[1..16] of byte; _volRemoveable :Word; {hi-lo} end; TPreq=^Treq; TPrep=^Trep; Begin TPreq(GlobalReqBuf)^:=volumeNumber; F2SystemCall($12,SizeOf(Treq),SizeOf(Trep),result); With TPrep(GlobalReplyBuf)^ do begin volIsRemoveable:=(_volRemoveable>0); if _volName[1]=0 then result:=$98; end; IsVolumeRemovable:=(result=0); { resultcodes: 00 success; 98h Invalid volume number / volume not mounted } end; {F216/22 [3.x]} Function ClearObjectVolRestriction(VolumeNumber:byte; objId:LongInt):boolean; { If the objId doesn't exist, no error is returned. } Type Treq=record len:word; subFunc:byte; _volNbr:byte; _objId:LongInt; { hi-lo } end; TPreq=^Treq; Begin WITH TPreq(GlobalReqBuf)^ do begin len:=SizeOf(Treq)-2; subFunc:=$22; _volNbr:=VolumeNumber; _objId:=Lswap(objId); { force hi-lo } end; F2SystemCall($16,SizeOf(Treq),0,result); ClearObjectVolRestriction:=(result=0) { $8C No supervisor rights } end; {F216/29 [3.x]} Function GetObjectVolRestriction(VolumeNumber:byte; objId:LongInt; Var MaxAllowedBlocks,BlocksInUse:LongInt):boolean; { If MaxAllowedBlocks is equal to $40000000 on return, there are no disk restrictions for the object on this volume. } { You need not be logged in to use this call. } Type Treq=record len :word; subFunc:byte; _volNbr:byte; _objId :Longint; {hi-lo} end; Trep=record _MaxAllowedBlocks, _BlocksInUse :Longint; end; TPreq=^Treq; TPrep=^Trep; Var objName:string; objType:word; Begin WITH TPreq(GlobalReqBuf)^ do begin len :=SizeOf(Treq)-2; subFunc:=$29; _volNbr:=VolumeNumber; _objId :=Lswap(objId); {force hi-lo} end; F2SystemCall($16,SizeOf(Treq),SizeOf(Trep),result); With TPrep(GlobalReplyBuf)^ do begin MaxAllowedBlocks:=_MaxAllowedBlocks; BlocksInUse:=_BlocksInUse; If BlocksInUse=0 then if NOT nwBindry.GetBinderyObjectName(objId,objName,objType) then result:=$FF; end; GetObjectVolRestriction:=(result=0) {resultcodes: 00 success; $FF Invalid objectId } end; {F216/20 [3.x]} Function ScanVolForRestrictions(VolumeNumber:byte; {i/o} Var sequenceNbr:LongInt; {out} Var NbrOfObjects:byte; Var ResultBuffer:TobjVolRestr):boolean; { 1st call: sequenceNbr=0, // n-th call: sequenceNbr(n):=sequenceNbr(n-1)+NbrOfObjects // (addition done by function itself) after last call: sequenceNbr=0 again. } Type Treq=record len:word; subFunc:byte; _volNbr:byte; _seqNbr:LongInt; { lo-hi !} end; Trep=record _NbrOfObjects:byte; _buff :TobjVolRestr; end; TPreq=^Treq; TPrep=^Trep; Var t:byte; Begin WITH TPreq(GlobalReqBuf)^ do begin len:=SizeOf(Treq)-2; subFunc:=$20; _volNbr:=VolumeNumber; _seqNbr:=sequenceNbr; end; F2SystemCall($16,SizeOf(Treq),SizeOf(Trep),result); if result=0 then begin With TPrep(GlobalReplyBuf)^ do begin NbrOfObjects:=_NbrOfObjects; ResultBuffer:=_buff; For t:=1 to NbrOfObjects do ResultBuffer[t].objId:=Lswap(_buff[t].ObjId); if _NbrOfObjects=0 then result:=$FF else sequenceNbr:=sequenceNbr+_NbrOfObjects; end end else NbrOfObjects:=0; ScanVolForRestrictions:=(result=0) { $98 VolumeNumber doesn't exist; $FF No New restriction data (end of iteration) } end; {F216/21 [3.x]} Function SetObjectVolRestriction(VolumeNumber:byte; objId,MaxAllowedBlocks:LongInt):boolean; { If the objId doesn't exist, no error is returned. } Type Treq=record len :word; subFunc:byte; _volNbr:byte; _objId :Longint; {hi-lo} _maxBlocks:LongInt; {lo-hi !!} end; TPreq=^Treq; Begin WITH TPreq(GlobalreqBuf)^ do begin len:=SizeOf(Treq)-2; subFunc:=$21; _volNbr:=VolumeNumber; _objId:=Lswap(objId); { force hi-lo } _maxBlocks:=MaxAllowedBlocks; end; F2SystemCall($16,SizeOf(Treq),0,result); SetObjectVolRestriction:=(result=0) { $8C No supervisor Rights } end; {--------------Dir handles/ drive mappings----------------------------------} {BA.. } Function GetEnvPath(Var EnvPath:string):boolean; {#d} Type Tarr=array[1..2048] of byte; Var regs:TTregisters; penv:^Tarr; i,envSize:word; state:byte; begin regs.ah:=$BA; RealModeIntr($21,regs); envSize:=byte(nwPtr(regs.dx-1,3)^) SHL 4; penv:=nwPtr(regs.dx,0); i:=1; state:=0; while (i0) do begin EnvPath:=EnvPath+chr(penv^[i]); inc(i); end; if i>envSize then begin result:=$301; GetEnvPath:=false; exit; end; result:=0; GetEnvPath:=true; { 00 successful 300 'Path' not found 301 Path value could not be read } end; {BA.. } Function SetEnvPath(EnvPath:string):boolean; {#d} Type Tarr=array[1..2048] of byte; Var regs:TTregisters; penv:^Tarr; i,t,envSize:word; state:byte; pbegin,pend:word; NewPathSize,OldPathSize:byte; diff:integer; sVector:TsearchDriveVector; Vecind,p:byte; dn:Byte; begin Upstring(EnvPath); If pos('PATH=',envPath)=1 then delete(EnvPath,1,5); regs.ah:=$BA; RealModeIntr($21,regs); envSize:=word(nwPtr(regs.dx-1,3)^) SHL 4; penv:=nwPtr(regs.dx,0); i:=1; state:=0; while (i0) do inc(i); if i>envSize then begin result:=$301; SetEnvPath:=false; exit; end; dec(i); pend:=i; { determine end of 'active' environment / marked by $00 00} while (ienvSize then begin result:=$302; SetEnvPath:=false; exit; end; diff:=NewPathSize-OldPathSize; if diff>0 then for t:=i downto pend do penv^[t+diff]:=penv^[t]; if diff<0 then for t:=pend to i do penv^[t+diff]:=penv^[t]; Move(EnvPath[1],penv^[pbegin],NewPathSize); FillChar(Svector,SizeOf(TsearchDriveVector),#$FF); VecInd:=1; REPEAT p:=pos(':',envPath); if p>0 then begin dn:=ord(ord(envPath[p-1])-ord('A')); p:=pos(';',envPath); if p=0 then envPath:='' else delete(envPath,1,p); IF IsNetworkDrive(dn) then begin Svector[VecInd]:=dn; inc(VecInd) end; end; UNTIL (p=0) or (VecInd=17); SetSearchDriveVector(Svector); result:=0; SetEnvPath:=true; { 00 successful 300 'Path' not found 301 Environment failure 302 Environment overflow (new path too large) } end; {F216/01} Function GetDirectoryPath(DirHandle:byte; Var PathName:string):boolean; { path includes volumename } Type Treq=record len :word; subFunc:byte; _dh :byte; end; Trep=record DirPath:string[255]; end; TPreq=^Treq; TPrep=^Trep; Begin WITH TPreq(GlobalReqBuf)^ do begin len:=SizeOf(Treq)-2; subFunc:=$01; _dh:=DirHandle; end; F2SystemCall($16,SizeOf(Treq),SizeOf(Trep),result); PathName:=TPrep(GlobalReplyBuf)^.DirPath; GetDirectoryPath:=(result=0) { 00 Successful 9B Bad directory handle } end; {EF02 [2.0/2.1/3.x]} Function GetDriveConnectionID( DriveNumber:Byte; Var connID:Byte):boolean; { returns the servernumber (1..8) associated with a drive. } Type pArr=^arr; arr=array[0..31] of byte; Var regs:TTregisters; begin regs.ax:=$EF02; RealModeIntr($21,Regs); If DriveNumber>31 then result:=$0105 else begin connID:=Parr(nwPtr(Regs.es,regs.si))^[DriveNumber]; Result:=0; end; GetDriveConnectionID:=(Result=0); end; {EF02 [2.0/2.1/3.x]} Function SetDriveConnectionID( DriveNumber:Byte; connID:Byte):boolean; Type pArr=^arr; arr=array[0..31] of byte; Var regs:TTregisters; begin regs.ax:=$EF02; RealModeIntr($21,Regs); If DriveNumber>31 then result:=$0105 else begin Parr(nwPtr(Regs.es,regs.si))^[DriveNumber]:=connId; Result:=0; end; SetDriveConnectionID:=(Result=0); end; {EF00 [2.0/2.1/3.x]} Function GetDriveHandle( DriveNumber:Byte; Var DirHandle:Byte ):boolean; { The call returns a pointer to the shell's Drive Handle Table. (32 bytes) (Drives A..Z and temporary drives [\]^_' ) If a drive has been assigned a directory handle on the file server, the handle can be found in the DHT at the position corresponding with the drive letter.} Type pArr=^arr; arr=array[0..31] of byte; Var regs:TTregisters; begin regs.ax:=$EF00; RealModeIntr($21,regs); if DriveNumber>31 then result:=$0105 else begin DirHandle:=Parr(nwPtr(Regs.Es,Regs.Si))^[DriveNumber]; Result:=0; end; GetDriveHandle:=(Result=0); end; {EF00 [2.0/2.1/3.x]} Function SetDriveHandle( DriveNumber:Byte; DirHandle:Byte ):boolean; Type pArr=^arr; arr=array[0..31] of byte; Var regs:TTregisters; begin regs.ax:=$EF00; RealModeIntr($21,regs); if DriveNumber>31 then result:=$0105 else begin Parr(nwPtr(Regs.Es,Regs.Si))^[DriveNumber]:=DirHandle; Result:=0; end; SetDriveHandle:=(Result=0); end; {EF01 [2.0/2.1/3.x]} Function GetDriveFlag( DriveNumber:Byte; Var DriveStatus:Byte ):Boolean; { This call returns a pointer to the shell's Drive Flag Table (32 Bytes) Each entry indicates a drive's status (permanent,temporary,local,unassigned) For further explanation see the DRIVE_xxx constants.} Type pArr=^arr; arr=array[0..31] of byte; Var regs:TTregisters; begin regs.ax:=$EF01; RealModeIntr($21,Regs); If DriveNumber>31 then result:=$0105 else begin DriveStatus:=Parr(nwPtr(Regs.es,regs.si))^[DriveNumber]; Result:=0; end; GetDriveFlag:=(Result=0); end; {EF01 [2.0/2.1/3.x]} Function SetDriveFlag( DriveNumber:Byte; DriveStatus:Byte ):Boolean; Type pArr=^arr; arr=array[0..31] of byte; Var regs:TTregisters; begin regs.ax:=$EF01; RealModeIntr($21,Regs); If DriveNumber>31 then result:=$0105 else begin Parr(nwPtr(Regs.es,regs.si))^[DriveNumber]:=DriveStatus; Result:=0; end; SetDriveFlag:=(Result=0); end; {E900 [2.0/2.1/3.x]} Function GetDirectoryHandle( DriveNumber:Byte; Var dirHandle,status:byte):Boolean; { Returns directory handle and status flags for a drive. } { Drivenumber = 0..31 (A..Z = 0..25) and temp drives (26..31) } { Status Byte 7 6 5 4 3 2 1 0 | | +-Permenant Directory Handle | +----Temporary Directory Handle +----------------------Mapped to a local drive } { in case of an invalid driveNumber, handle and status will be set to 0 } Var Regs:TTRegisters; begin With Regs do begin AX:=$E900; DX:=DriveNumber; RealModeIntr($21,Regs); { AH = Status Flags; 01 mapped to a permanent dir handle; 02 mapped to a temporary dir handle; 80 local drive. } dirHandle:=AL; status:=AH; If dirHandle=0 then begin status:=0;Result:=$FF end {INVALID_DRIVE_NUMBER} else Result:=0; GetDirectoryHandle:=(Result=0) end; { result: $00 success; $FF Invalid Drive Number } end; {F216/00 [2.15c+]} Function SetDirectoryHandle( sourceDirHandle:Byte; sourceDirPath:String; targetDirHandle:Byte ):boolean; { make handle 'targetHandle' point to the directory provided by sourceHandle and/or sourceDirPath. ( "Volume:dir\subdir" ) } Type Treq=record len :word; subFunc :byte; _TargetDH :Byte; _SourceDH :Byte; _SourceDP :String[255] end; TPreq=^Treq; Var p:Byte; Begin WITH TPreq(GlobalReqBuf)^ do begin subFunc:=$00; _TargetDH:=targetDirHandle; _SourceDH:=SourceDirHandle; if SourceDirHandle=0 then ConvertPathToVolFormat(SourceDirPath); _sourceDP:=sourceDirPath; UpString(_sourceDP); len:=4+ord(_SourceDP[0]); F2SystemCall($16,len+2,0,result); end; SetDirectoryHandle:=(result=0) { resultcodes: 00 Success; 98h Volume does not exist; 9Bh Bad directory handle; 9Ch Invalid Path. } end; {F216/12 [2.15c+]} FUNCTION AllocPermanentDirHandle( DriveNumber:Byte; DirHandle : byte; DirPath : string ; var NewDirHandle, EffectiveRights: byte ) :boolean; { Effective server must be the server involved, i.e. where the dir is stored } Type Treq=record len : word; subf : byte; _dirHandle : byte; _driveLetter : char; _DirectoryPath: String[255]; end; Trep=record _newDirHandle : byte; _EffectiveRights : byte; { e.r. mask } end; TPreq=^Treq; TPrep=^Trep; Var p:Byte; BEGIN With TPreq(GlobalReqBuf)^ do begin subf := $12; _dirHandle := dirHandle; _driveLetter := chr(DriveNumber+ord('A')); if Dirhandle=0 then ConvertPathToVolFormat(DirPath); _DirectoryPath:=DirPath; UpString(_DirectoryPath); len:=4+ord(_DirectoryPath[0]); F2SystemCall($16,len+2,sizeof(Trep),result); end; if result = 0 then with TPrep(GlobalReplyBuf)^ do begin effectiveRights := _effectiveRights; newDirHandle := _newDirHandle; end; AllocPermanentDirHandle:=(result=0); { $00 Successful $98 Volume doen't exist $9C Invalid path } end; {F216/13 [2.15c+]} function AllocTemporaryDirHandle( DriveNumber:byte; DirHandle : Byte; DirPath : String; var NewDirHandle,EffectiveRights : Byte) : Boolean; { Allocates a temporary directory handle, deleted automatically by EOJ. } { Effective server must be the server involved, i.e. where the dir is stored } Type TReq=record Len : Word; SubF : Byte; Handle : Byte; Letter : Char; _DirectoryPath : String; end; TRep=record NewH : Byte; Mask : Byte; end; TPreq=^Treq; TPrep=^Trep; Var p:Byte; begin with TPReq(GlobalReqBuf)^ do begin SubF := $13; Handle := DirHandle; Letter := chr(DriveNumber+ord('A')); { Allocating handles requires paths to be in the VOL:path format.. NOT canonical } if handle=0 then ConvertPathToVolFormat(DirPath); _DirectoryPath:=DirPath; UpString(_DirectoryPath); Len:=4+length(_DirectoryPath); F2SystemCall($16,len+2,SizeOf(Trep),result); end; with TPrep(GlobalReplyBuf)^ do begin NewDirHandle := NewH; EffectiveRights := Mask; end; AllocTemporaryDirHandle:=(result=0); { result: 00 success; 98h Volume doesn't exist; 9Ch Invalid Path } end; {F216/14 [2.15c+]} function DeallocateDirHandle(DirHandle : Byte) : Boolean; { This function deletes a directory handle } Type TReq=record Len : Word; SubF : Byte; Handle : Byte; end; TPreq=^Treq; begin with TPReq(GlobalReqBuf)^ do begin Len := 2; SubF := $14; Handle:= DirHandle; end; F2SystemCall($16,Sizeof(Treq),0,result); DeallocateDirHandle:=(result=0); { result: 00h - Success; 9Bh - Bad directory handle } end; {E901 } Function GetSearchDriveVector(Var vector:TsearchDriveVector):boolean; Var regs:TTregisters; tmp1,tmp2:word; begin regs.ax:=$E901; GetGlobalBufferAddress(tmp1,tmp2,regs.ds,regs.dx); { DS:DX real-mode address of GlobalReplyBuffer } RealModeIntr($21,regs); result:=0; Move(GlobalReplyBuf^,vector,sizeof(TsearchDriveVector)); vector[17]:=$FF; GetSearchDriveVector:=True; end; {E902 } Function SetSearchDriveVector(vector:TsearchDriveVector):boolean; Var regs:TTregisters; tmp1,tmp2:word; begin regs.ax:=$E902; Move(vector,GlobalReqBuf^,sizeof(TsearchDriveVector)); GetGlobalBufferAddress(regs.ds,regs.dx,tmp1,tmp2); { DS:DX real-mode address of GlobalRequestBuffer } RealModeIntr($21,regs); result:=0; SetSearchDriveVector:=True; end; Function IsSearchDrive(DriveNumber:byte):boolean; Var pth:string; begin IsSearchDrive:=(getEnvPath(pth) and (pos(chr(DriveNumber+ord('A'))+':',pth)>0)); end; {E905 (shell 3.00+)} Function MapFakeRootDirectory(DriveNumber:byte; DirPath:string):boolean; { Dirpath may include server and volumename } Var regs:TTregisters; tmp1,tmp2:word; PName:string; begin with regs do begin ax:=$E905; bl:=driveNumber+1; { FF default, 0=A, 2= B etc. } GetGlobalBufferAddress(ds,dx,tmp1,tmp2); { VLM patch for SERVER/VOL: and VOL: type paths } if (DirPath[0]>#2) and (pos(':',DirPath)>2) then GetTrueEntryName(DirPath,PName) else PName:=DirPath; Pname:=Pname+#0; move(PName[1],GlobalReqBuf^,ord(PName[1])); { DS:DX real-mode address of GlobalRequestBuffer holding new path } RealModeIntr($21,regs); if (flags and 1 {carry})>0 then result:=al else result:=0; end; MapFakeRootDirectory:=(result=0); { $00 Successful $03 Invalid path $0F Invalid Drive $11 Not same device } end; {E906 (shell 3.00+)} Function DeleteFakeRootDirectory(DriveNumber:byte):boolean; Var regs:TTregisters; begin with regs do begin ax:=$E906; bl:=DriveNumber+1; RealModeIntr($21,regs); result:=0; end; DeleteFakeRootDirectory:=(result=0); end; {E907 (shell 3.00+)} Function GetRelativeDriveDepth(DriveNumber:byte; Var depth:byte):boolean; Var regs:TTregisters; begin with regs do begin ax:=$E907; bl:=DriveNumber+1; RealModeIntr($21,regs); depth:=al; if al<$FF then result:=0 else result:=$FF; { no fake root assigned } end; GetRelativeDriveDepth:=(result=0); { 00 Succesful $FF No fake root assigned } end; {secondary} Function DeleteDriveMapping(DriveNumber:Byte):boolean; Var dirHandle,status:byte; pth:string; ch:char; p:byte; DDepth,Dflag:byte; begin { if searchdrive, remove drive from searchtable and PATH environment string } IF GetEnvPath(pth) then begin if pth[ord(pth[0])]<>';' then pth:=pth+';'; p:=pos(chr(DriveNumber+ord('A'))+':',pth); if p>0 then begin { it is a searchdrive, remove from path } Repeat ch:=pth[p]; delete(pth,p,1); UNTIL ch=';'; SetEnvPath(pth); { also creates a new searchdriveVector } end; end; IF (result=0) and GetDirectoryHandle(DriveNumber,dirHandle,status) then begin IF GetRelativeDriveDepth(DriveNumber,DDepth) { is it a fake root ? } then DeleteFakeRootDirectory(DriveNumber); GetDriveFlag(DriveNumber,Dflag); SetDriveFlag(DriveNumber,(Dflag and $F0) or DRIVE_UNUSED); SetDriveHandle(DriveNumber,0); SetDriveConnectionId(DriveNumber,0); DeallocateDirHandle(dirHandle); end; DeleteDriveMapping:=(result=0); end; {secondary } FUNCTION MapPermanentDrive(DriveNumber:byte; DirectoryPath:string; Root:boolean):boolean; var pth : string; DriveHandle: Byte; begin IF GetTrueEntryName(DirectoryPath,pth) then begin while pth[ord(pth[0])] IN ['\','.','*','?'] do dec(pth[0]); if pth[1]<>'\' then result:=$104 { attempt to map network drive to local drive } else begin If GetDriveHandle(DriveNumber,DriveHandle) and (DriveHandle<>0) then DeleteDriveMapping(DriveNumber); IF MapFakeRootDirectory(DriveNumber,pth) then begin if (not root) then DeleteFakeRootDirectory(DriveNumber); { does not delete the mapping itself, only the fake root. } end; end; end else result:=$101; { direcory not locatable } MapPermanentDrive:=(result=0); end; {secondary} FUNCTION MapDrive(DriveNumber:Byte; DirectoryPath:string; Root, Permanent:boolean):boolean; var rights : byte; newHandle : byte; HandlePth,pth,srvr,vol: string; OldConnId,VolConnId:byte; p:byte; VolNbr:byte; Dflag:byte; begin IF Permanent then begin MapDrive:=MapPermanentDrive(DriveNumber,DirectoryPath,Root); exit; end; { map temporary drive } IF GetTrueEntryName(DirectoryPath,pth) then begin if pth[ord(pth[0])]<>'\' then pth:=pth+'\'; if pth[1]<>'\' then result:=$104 { attempt to map network drive to local drive } else begin delete(pth,1,2); p:=pos('\',pth); if p=0 then result:=$106; srvr:=copy(pth,1,p-1); delete(pth,1,p); p:=pos('\',pth); if p=0 then result:=$105; { volume does not exist } vol:=copy(pth,1,p-1); delete(pth,1,p); IF NOT GetConnectionId(srvr,VolConnId) then result:=$106; { server does not exist } end; end else result:=$101; { direcory not locatable } if (result=0) then begin while pth[ord(pth[0])] IN ['\','.','*','?'] do dec(pth[0]); { rebuild path: Alloc handle requires VOL:path format } HandlePth:=vol+':\'+pth; GetPreferredConnectionId(OldConnId); SetPreferredConnectionId(VolConnId); { IF Permanent then AllocPermanentDirHandle(DriveNumber,0,HandlePth, newHandle,rights) else} AllocTemporaryDirHandle(DriveNumber,0,HandlePth, newHandle,rights); if (result=0) then begin GetDriveFlag(DriveNumber,Dflag); {If Permanent then SetDriveFlag(DriveNumber,(Dflag and $F0) or DRIVE_PERMANENT) else} SetDriveFlag(DriveNumber,(Dflag and $F0) or DRIVE_TEMPORARY); SetDriveHandle(DriveNumber,newHandle); SetDriveConnectionId(DriveNumber,VolConnId); IF root then MapFakeRootDirectory(DriveNumber,'\\'+srvr+'\'+vol+'\'+pth); end; SetPreferredConnectionId(OldConnId); end; MapDrive:=(result=0); end; Function MapSearchDrive(DriveNumber:byte; DirPath:string; PathPosition:byte; Insert,Root,Permanent:Boolean):boolean; Var pth:string; p,scCount:byte; ch:char; begin IF MapDrive(DriveNumber,DirPath,Root,Permanent) then begin GetEnvPath(pth); if pth[ord(pth[0])]<>';' then pth:=pth+';'; scCount:=1;p:=1; while (scCount=ord(pth[0])); pth:=copy(pth,1,p-1)+chr(DriveNumber+ord('A')) +':.;'+copy(pth,p,255); end else pth:=pth+chr(DriveNumber+ord('A'))+':.;'; SetEnvPath(pth); end; MapSearchDrive:=(result=0); end; {secondary} Function DeleteConnectionsDriveMappings(ConnId:Byte):Boolean; Var t,connId2,res:Byte; begin res:=$FF; for t:=0 to 31 do if GetDriveConnectionId(t,connId2) and (connId2=connId) then begin DeleteDriveMapping(t); if result=0 then res:=0; end; result:=res; DeleteConnectionsDriveMappings:=(result=0); {00 successful FF No mappings affected OR Invalid connectionId } end; {4409 / implemented as a secondary function } Function IsNetworkDrive(driveNumber:Byte):boolean; { isNetworkDrive is set to TRUE if the drive is a) a network drive, and b) a legal drive letter was used. } Var regs:TTRegisters; begin With regs do begin AX:=$4409; BL:=DriveNumber+1; RealModeIntr($21,Regs); IsNetworkDrive:=(DX and $1000)<>0 end; end; {--======================-- Entries --===============================--} {60.. (extended DOS call)} Function GetTrueEntryName(DirPath:string; Var CanonicalPath:string):boolean; { SERVER/VOL:[\]Path -> \\SERVER\VOL\path VOL:[\]Path -> \\effective_server_name\VOL\path D:\ -> D:\. { if a volumename is supplied without a servername, the name of the effective server will be returned. } { Format of returned string: a) D:\path\file.ext or b) \\servername\volumename\path\file.ext } LABEL skip; Var reply :array[1..128] of byte; regs :TTregisters; pcolon, pslash :byte; srvr, volname:string[47]; connId :Byte; begin { ----- Pre processing } if DirPath[0]>#2 then begin if ((DirPath[1]='\') and (DirPath[2]='\')) then begin CanonicalPath:=DirPath; UpString(Canonicalpath); goto skip end; pcolon:=pos(':',DirPath); if (pcolon=2) and (DirPath[0]=#3) and (DirPath[3]='\') then DirPath:=DirPath+'.'; { fix known problem of netware: D:\. instead of D:\ } if (pcolon=2) and (DirPath[0]=#2) then DirPath:=DirPath+'.'; { fix know problem of -among others- OS/2-dos: D:. instead of D: } end; pcolon:=pos(':',DirPath); if pcolon>2 then begin { format must be VOL:[\]path or SERVER/VOL:[\]Path } pslash:=pos('/',DirPath); if pslash=0 then pslash:=$FF; if (pslash#0) and (dirPath[1]='\') then delete(DirPath,1,1); DirPath:='\\'+srvr+'\'+volname+'\'+DirPath; end; if dirPath='' then dirPath:='\'; { ----- actual call } dirPath:=dirPath+#0; { zero terminate } WITH regs do begin Move(dirPath[1],GlobalReqBuf^,ord(dirPath[0])); GetGlobalBufferAddress(ds,si,es,di); { DS:SI real mode pointer to GlobalRequestBuffer holding asciiz path ; ES:DI real mode pointer to GlbalReplyBuffer } ah:=$60; RealModeIntr($21,regs); Move(GlobalReplyBuf^,reply[1],128); if (regs.flags and 1 {carry})>0 then begin result:=ax; reply[1]:=0; end else result:=0; end; ZstrCopy(CanonicalPath,reply[1],128); { ----- post-processing -- strip \ and . } skip: ; While CanonicalPath[ord(CanonicalPath[0])] in ['\','.'] do dec(CanonicalPath[0]); GetTrueEntryName:=(result=0); { $00 successful $02 Invalid component in directory path OR drive letter only $03 Malformed path OR invalid drive letter } end; {3B.. } Function ChangeDirectory(DirPath:string):boolean; { does not change the default drive } Var regs:TTregisters; tmp1,tmp2:word; begin if DirPath[0]>#63 then result:=$110 { length of path too long } else begin DirPath:=DirPath+#0; with regs do begin ah:=$3b; Move(DirPath[1],GlobalReqBuf^,ord(DirPath[0])); GetGlobalBufferAddress(ds,dx,tmp1,tmp2); { DS:DX real-mode pointer to GlobalRequestBuffer holding DirPath } RealModeIntr($21,regs); If (flags and 1 {carry})>0 then result:=$111 { invalid pathname } else result:=0; end; end; ChangeDirectory:=(result=0); end; {F216/0A [2.15+]} Function CreateDirectory(DirHandle:Byte; DirPath:string; MaxRightsMask:byte):boolean; Type Treq=record len :word; subFunc :byte; _DirHandle:byte; _MRM :byte; _dirPath :string[255]; end; TPreq=^Treq; Begin WITH TPreq(GlobalreqBuf)^ do begin subFunc:=$0A; _dirHandle:=DirHandle; _MRM:=MaxRightsMask; _DirPath:=DirPath; len:=4+ord(_dirPath[0]); F2SystemCall($16,len+2,0,result); end; CreateDirectory:=(result=0) { 00 successful 84 No create privileges 98 Volume doesn't exist FF directory already exists } end; {F216/0B [2.15c+]} Function DeleteDirectory(DirHandle:Byte; DirPath:string):boolean; Type Treq=record len :word; subFunc :byte; _DirHandle:byte; unused :byte; _DirPath :string[255]; end; TPreq=^Treq; Begin WITH TPreq(GlobalreqBuf)^ do begin subFunc:=$0B; _DirHandle:=DirHandle; _DirPath:=DirPath; unused:=0; len:=4+ord(_DirPath[0]); F2SystemCall($16,len+2,0,result); end; DeleteDirectory:=(result=0) { 00 successful 8A No delete privileges 98 Volume doesn't exist 9B Bad directory handle 9C Invalid path 9F Directory in use A0 Directory not empty } end; {F217/F4 [3.0+]} Function ConvertPathToDirEntryId(dirHandle:Byte; dirPath:string; Var VolNbr :byte; Var dirEntryID:LongInt):boolean; { aka ConvertPathToDirEntry } Type Treq=record len :word; subFunc :byte; _dirHandle:byte; _DirPath :string[255]; end; Trep=record _volNbr:Byte; _EntryId:Longint; {hi-lo} end; TPreq=^Treq; TPrep=^Trep; Begin WITH TPreq(GlobalReqBuf)^ do begin subFunc:=$F4; _dirHandle:=DirHandle; _dirPath:=DirPath; UpString(_DirPath); If DirHandle=0 then ConvertPathToVolFormat(_DirPath); len:=3+ord(_DirPath[0]); F2SystemCall($17,len+2,SizeOf(Trep),result); end; With TPrep(GlobalReplyBuf)^ do begin VolNbr :=_volNbr; dirEntryId:=_EntryId; end; ConvertPathToDirEntryId:=(result=0) { 00 Successful 9B Bad directory Handle 9C Invalid Path C6 No console rights } end; {F217/F3 [3.0+]} Function MapDirEntryIdToPath(VolNbr:byte;DirEntryId:Longint; NStype:byte; Var ExtPath:string):boolean; {aka MapDirectoryNumberToPath } { Returns full path/ with nameSpace information; Doesn't return server or volumename. } Type Treq=record len :word; subFunc :byte; _VolNbr :byte; _EntryId:longint; {hi-lo} _NameSp :byte; end; Trep=record _path:array[1..255] of byte; {!! maximum: 512 bytes in path ! } end; TPreq=^Treq; TPrep=^Trep; Var TempPath:string; Begin WITH TPreq(GlobalReqBuf)^ do begin len:=SizeOf(Treq)-2; subFunc:=$F3; _VolNbr:=VolNbr; _EntryId:=DirEntryId; _NameSp:=NStype; end; F2SystemCall($17,SizeOf(Treq),SizeOf(Trep),result); if result=0 then begin With TPrep(GlobalReplyBuf)^ do ZstrCopy(TempPath,_path,255); { TempPath according to the 'new' Novell format; translate into a 'DOS' style path } NovPath2DOSPath(TempPath,ExtPath); { dir\subdir (no server or volume name) } end; MapDirentryIdtoPath:=(result=0) { 00 Successful C6 No console rights FF ? } end; {F216/02} Function ScanDirectoryInformation(dirHandle:byte; searchDirPath:string; {i/o} Var sequenceNumber:word; {out:} Var dirInfo:Tentry ):boolean; { set sequenceNumber to 0 before the first call. If wildcards (* or ?) are included in the searchDirPath: Iterate until a $9C error is returned. If you don't include a wildcard in the searchDirPath, only use this call once. Do not iterate, the same entry will be returned eternaly. } Type Treq=record len :word; subFunc :byte; _dirHandle :byte; _subDirNumber:word; {hi-lo} _dirPath :string[255] end; Trep=record _subDirName :array[1..16] of byte; _creationDate :word; _creationTime :word; _ownerObjId :LongInt; {hi-lo} _maxRightsMask:word; _SubDirNbr :word; {hi-lo} end; TPreq=^Treq; TPrep=^Trep; Begin WITH TPreq(GlobalReqBuf)^ do begin subFunc:=$02; _dirHandle:=dirHandle; _subDirNumber:=swap(sequenceNumber); { force hi-lo} _dirPath:=searchDirPath; UpString(_dirPath); len:=5+ord(searchDirPath[0]); F2SystemCall($16,len+2,SizeOf(Trep),result); end; With TPrep(GlobalReplyBuf)^ do begin FillChar(dirInfo,SizeOf(Tentry),0); ZstrCopy(dirInfo.EntryName,_SubDirName,16); DosTime2NovTime(MakeLong(swap(_CreationDate),swap(_CreationTime)), dirInfo.creationTime); dirInfo.ownerId:=Lswap(_ownerObjId); dirInfo.RightsMask:=_maxRightsMask; sequenceNumber:=swap(_SubDirNbr)+1; end; ScanDirectoryInformation:=(result=0) {resultcodes: $00 success; $98 Volume does not exist; $9B Bad directory Handle $9C Invalid Path } end; {F216/0F [2.0/2.1/3.x]} Function RenameDirectory( dirHandle:Byte; dirPath, newDirName :String):Boolean; { The new directory name must be a regular (legal) directory name, max 14 chars long. The user must have Parental and Modify rights in the parent directory of the directory to be renamed. } Type Treq=record len :word; subFunc :byte; _dirHandle :Byte; _dirNames :Array[0..255+1+14] of byte; { _dirpath[0] is allowed to be 0 } end; TPreq=^Treq; Begin WITH TPreq(GlobalReqBuf)^ do begin subFunc:=$0F; _dirHandle:=dirHandle; Upstring(dirPath); UpString(newDirName); Move(DirPath[0],_DirNames[0],ord(DirPath[0])+1); Move(newDirName[0],_DirNames[1+_DirNames[0]],ord(newDirName[0])+1); len:=4+ord(dirPath[0])+ord(newDirName[0]); F2SystemCall($16,len+2,0,result); end; RenameDirectory:=(result=0) { Possible ResultCodes: 8B No Rename Privileges; 9B Bad Directory Handle; 9C Invalid Path; 9E Invalid (new) Dir Name. } end; {F216/1F [2.15c+]} Function GetDirectoryEntry(DirHandle:byte; Var dirEntry:Tentry):boolean; Type Treq=record len:word; subFunc:byte; _dirHandle:byte; end; Trep=record _Entry :TintEntry; end; TPreq=^Treq; TPrep=^Trep; Begin WITH TPreq(GlobalReqBuf)^ do begin len:=SizeOf(Treq)-2; subFunc:=$1F; _dirHandle:=dirHandle; end; F2SystemCall($16,SizeOf(Treq),SizeOf(Trep),result); With TPrep(GlobalReplyBuf)^ do begin Convert2ExtEntry(_entry,dirEntry); end; GetDirectoryEntry:=(result=0) { 00 successful 98 Volume doesn't exist 9B Bad directory handle 9C Invalid path } end; {B601 [2.0+] } function SetExtendedFileAttributes(FilePath:String; Attr:Byte) : Boolean; { See GetExtFAttr for meaning of Attr the Attribute Function result code: 00h Success; FFh File not found; FEh Access denied } Var Novregs:TTRegisters; tmp1,tmp2:word; begin with NovRegs do begin AX := $B601; if FilePath[0]=#255 then FilePath[255]:=#0 else FilePath:=FilePath+#0; Move(FilePath[1],GlobalReqBuf^,ord(FilePath[0])); GetGlobalBufferAddress(ds,dx,tmp1,tmp2); { DS:DX real mode pointer to GlobalRequestBuffer holding FilePath } CL := Attr; RealModeIntr($21,NovRegs); IF (Flags AND 1 {carry})>0 then Result:=AL else Result:=$00; Result := AL end; SetExtendedFileAttributes:=(Result=0); end; {B600 [2.0+]} function GetExtendedFileAttributes(FilePath:String; var Attributes:Byte) : Boolean; { Meaning of Attributes: 7 6 5 4 3 2 1 0 | | | | | | | | | | | +---+---+------Search mode | | | +----------------------transactional bit A_TRANSACTIONAL | | +--------------------------Indexing bit A_INDEXED | +------------------------------Read Audit bit A_READ_AUDIT +----------------------------------Write Audit bit A_WRITE_AUDIT } Var NovRegs:TTRegisters; tmp1,tmp2:word; begin with NovRegs do begin AX := $B600; if FilePath[0]=#255 then FilePath[255]:=#0 else FilePath:=FilePath+#0; { null terminate string } Move(FilePath[1],GlobalReqBuf^,ord(FilePath[0])); GetGlobalBufferAddress(ds,dx,tmp1,tmp2); { DS:DX real mode pointer to GlobalRequestBuffer hloding FilePath } RealModeIntr($21,NovRegs); IF (Flags and 1 {carry})>0 then Result := AL else Result:=$00; Attributes := CL; end; GetExtendedFileAttributes:=(Result=0); { $8C caller lacks privileges FEh not permitted to search directory FFh file not found } end; {F3.. [2.x/3.x]} Function FileServerFileCopy( sourceFileHandle, destFileHandle:word; sourceFileOffset, destFileOffset:Longint; numberOfBytesToCopy :Longint; VAR numberOfBytesCopied :Longint ):boolean; {Note: both source and destination must be on the same file server SeeAlso: 3C..,3F..} Type Treq=record _sFH,_dFH :word; {lo-hi} {as returned by GetFileHandle.} _sFoffs,_dfOffs:Longint; {lo-hi} _NbrOfBytes :Longint; {lo-hi} end; TPreq=^Treq; Var regs:TTRegisters; tmp1,tmp2:word; begin with TPreq(GlobalReqBuf)^ do begin _sFH:=sourceFileHandle; _dFH:=destFileHandle; _sFoffs:=sourceFileOffset; _dFoffs:=destFileOffset; _NbrOfBytes:=numberOfBytesToCopy; end; with regs do begin AH:=$F3; GetGlobalBufferAddress(es,di,tmp1,tmp2); { ES:DI real mode pointer to GlobalRequestBuffer } RealModeIntr($21,regs); result:=AL; end; numberOfBytesCopied:=MakeLong(regs.cx,regs.dx); { ? swap those regs for correct byte order ? } FileServerFileCopy:=(Result=0); end; {level-0 function. See GetFileAttributes and SetFileAttributes } Function DoFileAttributes(subf:byte;FilePath:string;VAR attr:byte):boolean; Var regs:TTregisters; tmp1,tmp2:word; begin with regs do begin AH:=$43; AL:=subf; if subf=$01 then CX:=attr; if filePath[0]=#255 then filePath[255]:=#0 else filePath:=filePath+#0; Move(FilePath[1],GlobalReqBuf^,ord(FilePath[0])); GetGlobalBufferAddress(ds,dx,tmp1,tmp2); { DS:DX real mode pointer to GlobalRequestBuffer holding FilePath } RealModeIntr($21,regs); IF ((Flags and 1 {Fcarry})<>0) then result:=AL else begin result:=$00; if subf=$00 then attr:=CX end; end; DoFileAttributes:=(result=$00); { resultcodes: 00 success; 01 invalid function; 03 path not found; 05 access denied. } end; {4300 [1.x/2.x/3.x]} Function GetFileAttributes(FilePath:string; Var attr:byte):boolean; { A_READ_ONLY,A_HIDDEN,A_SYSTEM and A_SHAREABLE only. } begin GetFileAttributes:=DoFileAttributes($00,FilePath,attr); end; {4301 [1.x/2.x/3.x]} Function SetFileAttributes(FilePath:string; attr:byte):boolean; { A_READ_ONLY,A_HIDDEN,A_SYSTEM and A_SHAREABLE only. } Var _attr:byte; begin _attr:=attr; SetFileAttributes:=DoFileAttributes($01,FilePath,_attr); end; {F217/0F [2.15c+]} Function ScanFileInformation(DirHandle:Byte; FilePath:string; SearchAttrib:Byte; {i/o} VAR SequenceNbr:Integer; {out} VAR fileInfo:Tentry):Boolean; { To be called Iteratatively; initial value for seqNbr=-1 } { wildcards in filename allowed. Iterate util an error $FF occurs } Type Treq=record len :word; subFunc :byte; _seqNbr :word; {hi-lo} _dirHandle :byte; _searchAttrib:Byte; _filePath :string; end; Trep=record _seqNbr :word; {hi-lo} _fileName :array[1..14] of byte; _Fattr, _ExtFattr :Byte; _Fsize :LongInt; {hi-lo} _Crdate :word; {hi-lo} _LastAccDate :word; {hi-lo} _LastUpdDate, _LastUpdTime :Word; _ownerObjId :Longint; {hi-lo} _LastArchDate, _lastArchTime:Word; _reserved :array[1..56] of byte; end; TPreq=^Treq; TPrep=^Trep; Begin WITH TPreq(GlobalReqBuf)^ do begin subFunc:=$0F; _seqNbr:=swap(word(SequenceNbr)); { force hi-lo } _dirHandle:=dirHandle; _searchAttrib:=searchAttrib; _filePath:=FilePath; len:=6+ord(_filePath[0]); F2SystemCall($17,len+2,SizeOf(Trep),result); end; with TPrep(GlobalReplyBuf)^ do begin FillChar(fileInfo,sizeOf(fileInfo),#0); SequenceNbr:=Integer(swap(_seqNbr)); { force lo-hi } ZstrCopy(fileInfo.EntryName,_filename,15); fileInfo.Attributes:=(_ExtFattr SHL 8)+_Fattr; fileInfo.filesize:=Lswap(_Fsize); { force lo-hi} fileinfo.OwnerID:=Lswap(_ownerObjID); { force lo-hi} DosTime2NovTime(MakeLong(swap(_CrDate),0),fileinfo.creationTime); DosTime2NovTime(MakeLong(swap(_LastAccDate),0),fileinfo.lastAccessTime); DosTime2NovTime(MakeLong(swap(_LastUpdDate),swap(_LastUpdTime)) ,fileinfo.ModifyTime); DosTime2NovTime(MakeLong(swap(_LastArchDate),swap(_lastArchTime)) ,fileinfo.ArchiveTime); end; ScanFileInformation:=(result=0) { 89 No search privileges FF No more matching files } end; {F217/10 [2.15c+]} Function SetFileInformation(DirHandle:Byte; FilePath:string; SearchAttrib:Byte; fileInfo:TEntry):boolean; Type Treq=record len :word; subFunc :byte; _Fattr, _ExtFattr :Byte; reserved1 :LongInt; {hi-lo} _crDate :word; {hi-lo} _lastAccDate :word; {hi-lo} _lastUpdTime :Longint; _ownerObjId :Longint; {hi-lo} _lastArchTime:Longint; reserved2 :array[1..56] of byte; _dirHandle :Byte; _searchAttr :byte; _filePath :string; end; TPreq=^Treq; Var DummyDate:Longint; Begin WITH TPreq(GlobalReqBuf)^ do begin subFunc:=$10; _Fattr:=Lo(LowLong(fileInfo.Attributes)); _ExtFattr:=Hi(LowLong(fileinfo.Attributes)); _ownerObjId:=Lswap(fileinfo.OwnerId); {force hi-lo} _dirHandle:=DirHandle; _searchAttr:=SearchAttrib; _filePath:=FilePath; If Dirhandle=0 then ConvertPathToVolFormat(_FilePath); UpString(_filePath); NovTime2DosTime(fileinfo.CreationTime,dummyDate); _crDate:=HiLong(dummyDate); NovTime2DosTime(fileinfo.LastAccessTime,dummyDate); _lastAccDate:=HiLong(dummyDate); NovTime2DosTime(fileinfo.ModifyTime,_lastUpdTime); NovTime2DosTime(fileinfo.ArchiveTime,_lastArchTime); len:=82+ord(_filepath[0]); F2SystemCall($17,len+2,0,result); end; SetFileInformation:=(result=0); { result codes: 00 Success } end; {F244 [2.1x/3.x]} Function EraseFiles(dirHandle, searchAttrib:Byte; filePath:string ):boolean; { marks files for deletion / in DOS parlance: delete file, file remains purgable } Type Treq=record _dirHandle:Byte; _Sattr:Byte; _filePath:string; end; TPreq=^Treq; Begin WITH TPreq(GlobalReqBuf)^ do begin _dirHandle:=dirHandle; _Sattr:=searchAttrib; _filePath:=filePath; F2SystemCall($44,3+ord(_filepath[0]),0,result); end; EraseFiles:=(result=0); { resultcodes: 00 Success; 98h Volume doesn't exist; 9Bh bad directory handle; 9Ch invalid path; FFh no files found error. } end; {F216/1B [3.0+]} Function ScanSalvagableFiles(DirHandle:Byte; {i/o} Var EntryId:Longint; {out} Var Entry:Tentry ):boolean; { Iterate (with entryId set to -1 at first) until an error $FF occurs } Type Treq=record len :word; subFunc :byte; _DirHandle:Byte; _EntryId :Longint; {low_word-hi_word & each word lo-hi } end; Trep=record _EntryId :Longint; _Entry :TintEntry; end; TPreq=^Treq; TPrep=^Trep; Begin WITH TPreq(GlobalReqBuf)^ do begin len:=SizeOf(Treq)-2; subFunc:=$1B; _DirHandle:=DirHandle; _EntryId:=EntryId; end; F2SystemCall($16,SizeOf(Treq),Sizeof(Trep),result); With TPrep(GlobalReplyBuf)^ do begin EntryId:=_EntryId; {return next EntryId for iteration} {low_word-hi_word & each word lo-hi } Convert2ExtEntry(_Entry,Entry); end; ScanSalvagableFiles:=(result=0) { 98 Volume does not exist FF No more erased files } end; {F216/1D [3.0+]} Function PurgeSalvagableFile(DirHandle:Byte; EntryId:Longint; FileName:string):boolean; { either supply an entryId and an empty filename, or supply an entryId of -1 and a filename. Note that the filename may not be unique: there may be more than one old deleted versions of a filename. } Type Treq=record len :word; subFunc :byte; _DirHandle:Byte; _EntryId :Longint; {low_word-hi_word & each word lo-hi } _Name :string[255]; end; TPreq=^Treq; Begin WITH TPreq(GlobalReqBuf)^ do begin subFunc:=$1D; _DirHandle:=DirHandle; _EntryId:=EntryId; _Name:=FileName; UpString(_name); len:=7+ord(_Name[0]); F2SystemCall($16,len+2,0,result); end; PurgeSalvagableFile:=(result=0) end; {F216/1C [3.0+] } Function RecoverSalvagableFile(dirHandle:Byte; EntryId:Longint; OldName,NewName:string):boolean; { entryId may be set to -1 OldName is the name of the file before it was deleted. NewName is the name to be assigned to the recovered file } Type Treq=record len :word; subFunc :byte; _DirHandle :Byte; _EntryId :Longint; {low_word-hi_word & each word lo-hi } _OldAndNewName:string[255]; end; TPreq=^Treq; Begin WITH TPreq(GlobalReqBuf)^ do begin subFunc:=$1C; _DirHandle:=DirHandle; _EntryId:=EntryId; UpString(OldName); UpString(NewName); _OldAndNewName:=OldName; move(NewName[0],_OldAndNewName[ord(oldname[0])+1],ord(NewName[0])+1); len:=8+ord(oldName[0])+ord(NewName[0]); F2SystemCall($16,len+2,0,result); end; RecoverSalvagableFile:=(result=0) { 98 Volume does not exist FF No more erased files } end; {F216/24 [3.0+]} Function SetDirRestriction(DirHandle:Byte; DiskSpaceLimit:Longint):boolean; { limit expressed in Blocks. set limit to 0 to lift limit. use a negative number if limit should be equal to 0 } Type Treq=record len :word; subFunc :byte; _DirHandle:Byte; _Limit :Longint; end; TPreq=^Treq; Begin WITH TPreq(GlobalReqBuf)^ do begin len:=SizeOf(Treq)-2; subFunc:=$24; _DirHandle:=DirHandle; _Limit:=DiskSpaceLimit; end; F2SystemCall($16,SizeOf(Treq),0,result); SetDirRestriction:=(result=0) end; {F216/23 [3.0+]} Function ScanDirRestrictions(DirHandle:Byte; Var NumberOfEntries:Byte; Var RestrInfo:TdirRestrList):boolean; Type Treq=record len:word; subFunc:byte; _DirHandle:Byte; end; Trep=record _Entries:Byte; _Info:TdirRestrList; end; TPreq=^Treq; TPrep=^Trep; Begin WITH TPreq(GlobalReqBuf)^ do begin len:=SizeOf(Treq)-2; subFunc:=$23; _DirHandle:=DirHandle; end; F2SystemCall($16,SizeOf(Treq),Sizeof(Trep),result); With TPrep(GlobalReplyBuf)^ do begin NumberOfEntries:=_Entries; RestrInfo:=_Info; end; ScanDirRestrictions:=(result=0) end; Procedure FixEntryNameFormat(Var s:string); Var res:string; p:byte; begin res:=''; for p:=1 to ord(s[0]) do begin if s[p]='?' then res:=res+#$FF+#$BF else if s[p]='*' then res:=res+#$FF+'*' else res:=res+s[p] end; s:=res; end; {F216/1E [2.15c+]} Function ScanDirectoryEntry(DirHandle:Byte; EntryName:string; SearchFlags:Longint; {i/o} Var EntryId:Longint; {out} Var Entry:Tentry ):boolean; Type Treq=record len :word; subFunc :byte; _DirHandle :Byte; _SearchFlags:Byte; { standard: $16 for dirs / $06 for files } _SeqNbr :Longint; { lo-hi , set to -1 initially } _EntryName :string; end; Trep=record { len = 84h = 132 dec. } _EntryID :Longint; { lo-hi } _Entry :TintEntry; end; TPreq=^Treq; TPrep=^Trep; Begin WITH TPreq(GlobalReqBuf)^ do begin subFunc:=$1E; _DirHandle:=DirHandle; _SearchFlags:=SearchFlags; _SeqNbr:=EntryId; _EntryName:=EntryName;UpString(_EntryName); FixEntryNameFormat(_EntryName); len:=8+ord(_EntryName[0]); F2SystemCall($16,len+2,Sizeof(Trep),result); end; With TPrep(GlobalReplyBuf)^ do begin EntryId:=_EntryId; {return next EntryId for iteration} Convert2ExtEntry(_Entry,entry); end; ScanDirectoryEntry:=(result=0) end; {F216/25 [2.15c+] } Function SetEntry(DirHandle:Byte;EntryId:Longint;SearchFlags:Byte; ModFlags:Longint; Entry:Tentry ):boolean; Type Treq=record len :word; subFunc :byte; _dirHandle:Byte; _SFlags :Byte; _EntryId :Longint; {lo-hi} _ModFlags :Longint; {lo-hi} _Entry :TintEntry; end; TPreq=^Treq; Begin WITH TPreq(GlobalReqBuf)^ do begin len:=SizeOf(Treq)-2; subFunc:=$25; _dirHandle:=DirHandle; _EntryId:=EntryId; _ModFlags:=ModFlags; Convert2IntEntry(Entry,_Entry); end; F2SystemCall($16,SizeOf(Treq),0,result); SetEntry:=(result=0) end; {------------------ Secondary Functions ----------------------------} Function IsFileShareable(Path : String):boolean; var F: File; FAttr : Word; begin { Assign(F, Path); GetFAttr(F, FAttr); result:=DOSerror; } IsFileShareable:=(result=0) and ((FAttr and $80)>0) end; function FlagFileShareable(Path : String) : Boolean; { when the file could NOT be made shareable, false is returned as the function result, a doserror# is returned as the result code. } var F : File; Attr : Word; ErrCode : word; Share : Boolean; begin if NOT IsFileShareable(Path) { Share: is it sharable? } then begin Assign(F,Path); {SetFAttr(F,Attr or A_SHAREABLE); OR existing atrib. with SHARE bit } {Result := DOSError;} end; FlagFileShareable := (Result=0); end; Function GetFileHandle(Var f):word; begin {GetFileHandle:=filerec(f).handle;} end; {------===================-- Trustee/Max. Rights masks --=================--} {F216/27 [3.0+]} Function SetTrustee(DirHandle:Byte;DirPath:string; TrusteeObjectID:Longint; RightsMask:Word ):boolean; Type Treq=record len :word; subFunc :byte; _DirHandle:byte; _ObjId :Longint; { hi-lo } _Rights :Word; { lo-hi } _DirPath :string; end; TPreq=^Treq; Begin WITH TPreq(GlobalReqBuf)^ do begin subFunc:=$27; _DirHandle:=DirHandle; if DirHandle=0 then ConvertPathToVolFormat(DirPath); _DirPath:=DirPath;UpString(_DirPath); _ObjId:=Lswap(TrusteeObjectId); _Rights:=RightsMask; len:=9+ord(_DirPath[0]); F2SystemCall($16,len+2,0,result); end; SetTrustee:=(result=0) { Possible resultcodes: 8C No modify privileges; 98 Volume doesn't exist; 9B Bad directory handle 9C Invalid path; FC No such bindery object } end; {F216/2B [3.0+]} Function DeleteTrustee(DirHandle:Byte;DirPath:String; TrusteeObjectId:Longint):boolean; { If DirHandle equals 0, DirPath should be according to the VOL:\path format. All other path formats will result in an resultcode of 98h (No such volume) } Type Treq=record len :word; subFunc :byte; _DirHandle:byte; _ObjId :Longint; { hi-lo } _Unused :Byte; _DirPath :string; end; TPreq=^Treq; Begin WITH TPreq(GlobalReqBuf)^ do begin subFunc:=$2B; _DirHandle:=DirHandle; if DirHandle=0 then ConvertPathToVolFormat(DirPath); _DirPath:=DirPath;UpString(_DirPath); _ObjId:=Lswap(TrusteeObjectId); _Unused:=0; len:=8+ord(_DirPath[0]); F2SystemCall($16,len+2,0,result); end; DeleteTrustee:=(result=0); { Possible resultcodes: 98 Volume doesn't exist 9B Bad directory handle; 9C Invalid path FE no such trustee } end; {F216/2A [3.0+]} function GetEffectiveRights(DirHandle:Byte;DirPath:String; var Rights:Word) : Boolean; { returns the requesting workstation's effective directory rights } Type Treq=record Len : word; SubF : Byte; _DirHandle : Byte; _DirName : String; end; TRep=record _RightsMask : Word; end; TPreq=^Treq; TPrep=^Trep; begin with TPreq(GlobalReqBuf)^ do begin SubF := $2A; _DirHandle := DirHandle; if DirHandle=0 then ConvertPathToVolFormat(DirPath); _DirName := DirPath;UpString(_DirName); Len := 3+ord(DirPath[0]); F2SystemCall($16,len+2,SizeOf(Trep),result); end; with TPrep(GlobalReplyBuf)^ do Rights:=_RightsMask; GetEffectiveRights:=(Result=0); { return byte 00h - Success 98h - Volume Does Not Exist 9Bh - Bad Directory Handle } end; {F216/04 [2.15c+]} Function ModifyMaximumRightsMask(DirHandle:Byte;DirPath:string; RevokeRightsMask,GrantRightsMask:Word):boolean; Type Treq=record len:word; subFunc:byte; _DirHandle:Byte; _GrantRM, _RevokeRM:Byte; _DirPath:String; end; Trep=record _EffectiveRightsMask:Byte; end; TPreq=^Treq; TPrep=^Trep; Begin WITH TPreq(GlobalReqBuf)^ do begin len:=5+ord(DirPath[0]); subFunc:=$04; _DirHandle:=DirHandle; if DirHandle=0 then ConvertPathToVolFormat(DirPath); _GrantRM:=MapV3RightsToV2(GrantRightsMask); _RevokeRM:=MapV3RightsToV2(RevokeRightsMask); _DirPath:=DirPath; F2SystemCall($16,len+2,Sizeof(Trep),result); end; {With TPrep(GlobalReplyBuf)^ do begin --- nothing is done with the returned value--- end;} ModifyMaximumRightsMask:=(result=0) { result codes: 8C No modify privileges; 98 Volume dosn't exist; 9C Invalid path } end; {F217/47 [2.15c+]} Function ScanBinderyObjectTrusteePaths(TrusteeObjectId:Longint; VolumeNumber:Byte; {i/o} Var SequenceNumber:word; {out} Var AccessMask:Word; Var Path:string ):boolean; { You must be supervisor (-equivalent) or the TrusteeObject itself to use this function. Initially, sequencenumber should be set to 0. } Type Treq=record len :word; subFunc:byte; _VolNbr:Byte; _SeqNbr:word; {hi-lo} _ObjId :Longint; {hi-lo} end; Trep=record _NextSeqNbr:Word; {hi-lo} _ObjId :Longint; {hi-lo} _AccMask :byte; _Path :string; end; TPreq=^Treq; TPrep=^Trep; Begin WITH TPreq(GlobalReqBuf)^ do begin len:=SizeOf(Treq)-2; subFunc:=$47; _VolNbr:=VolumeNumber; _SeqNbr:=swap(SequenceNumber); _ObjId:=Lswap(TrusteeObjectId); end; F2SystemCall($17,SizeOf(Treq),Sizeof(Trep),result); With TPrep(GlobalReplyBuf)^ do begin SequenceNumber:=Lswap(_NextSeqNbr); Accessmask:=_AccMask; {MapV2RightsToV3(_accMask);} Path:=_Path; end; ScanBinderyObjectTrusteePaths:=(result=0) { resultcodes: $96 Server out of memory; $F0 Wildcard not allowed; $F1 Invalid bindery security; $FC No such object; $FE Server bindery locked; $FF Bindery failure } end; {F216/26 [3.0+]} Function ScanEntryForTrustees(DirHandle:Byte;DirPath:String; {i/o} Var SequenceNumber:Byte; {out} Var TrusteeInfo: TtrusteeInformation):boolean; { Set SequenceNumber to 0 initially, iterate until error $9C (no more trustees) is returned } { see GETTR in the XFILE archive for an example } Type Treq=record len:word; subFunc:byte; _DirHandle:Byte; _SeqNbr:Byte; _DirPath:String; end; Trep=record _Info:TtrusteeInformation; end; TPreq=^Treq; TPrep=^Trep; Var t:Byte; Begin WITH TPreq(GlobalReqBuf)^ do begin len:=4+ord(DirPath[0]); subFunc:=$26; _DirHandle:=DirHandle; if DirHandle=0 then ConvertPathToVolFormat(DirPath); _SeqNbr:=SequenceNumber; _DirPath:=DirPath;UpString(_DirPath); F2SystemCall($16,len+2,Sizeof(Trep),result); end; With TPrep(GlobalReplyBuf)^ do begin inc(SequenceNumber); TrusteeInfo.NumberOfTrustees:=_Info.NumberOfTrustees; for t:=1 to 20 do begin TrusteeInfo.TrusteeId[t]:=Lswap(_Info.TrusteeId[t]); TrusteeInfo.TrusteeRights[t]:=_Info.TrusteeRights[t]; end; end; ScanEntryForTrustees:=(result=0) { resultcodes: $9C No more trustees } end; {F2 [2.15c+] Function ( ):boolean; Type Treq=record len:word; subFunc:byte; end; Trep=record end; TPreq=^Treq; TPrep=^Trep; Begin WITH TPreq(GlobalReqBuf)^ do begin len:=SizeOf(Treq)-2; subFunc:=$ end; F2SystemCall($ ,SizeOf(Treq),Sizeof(Trep),result); With TPrep(GlobalReplyBuf)^ do begin end; :=(result=0) end; } end.