{$MODE DELPHI} uses type_fixes, classes, data, Windows_Resource, BaseUNIX, FUSE, sysutils; var VBUseFileNameSuffix : TBoolean = True; VInputStream : TStream; vResourceTypeInfos : IInterfaceList {of IResourceTypeBlock}; VWIN16AlignmentShiftCount : TUINT16; VInputStat : TStat; //VFontSuffix : TString = '.FON'; function GetSuffix(aTypeID : TString) : TString; begin Result := ''; if VBUseFileNameSuffix then begin if aTypeID = 'font' then Result := '.FON' end; end; function GetNode(aNameC : PChar) : IInterface; var i : Integer; j : Integer; VResourceTypeInfo : IResourceTypeBlock; VResourceInfo : IResourceBlock; aName : TString; VPrefix : TString; VSuffix : TString; begin aName := aNameC; Result := nil; for i := 0 to VResourceTypeInfos.Count - 1 do begin VResourceTypeInfo := VResourceTypeInfos[i] as IResourceTypeBlock; VPrefix := '/' + VResourceTypeInfo.TypeID; if aName = VPrefix then begin Result := VResourceTypeInfo as IInterface; Exit; end else begin VPrefix := VPrefix + '/'; VSuffix := GetSuffix(VResourceTypeInfo.TypeID); if Copy(aName, 1, Length(VPrefix)) = VPrefix then begin aName := Copy(aName, Length(VPrefix) + 1, Length(aName)); if VBUseFileNameSuffix then begin if Copy(aName, Length(aName) + 1 - Length(VSuffix), Length(VSuffix)) = VSuffix then begin aName := Copy(aName, 1, Length(aName) - Length(VSuffix)); end else Exit; end; for j := 0 to VResourceTypeInfo.Count - 1 do begin VResourceInfo := VResourceTypeInfo.Item[j]; if VResourceInfo.ID = aName then begin Result := VResourceInfo as IInterface; Exit; end; end; end; end; end; end; function hello_getattr(aNameC : PChar; aSTAT : TStatP) : Integer; cdecl; var VResourceTypeInfo : IResourceTypeBlock; VResourceInfo : IResourceBlock; VNode : IInterface; begin Result := -ESysENOENT; FillChar(aStat^, Sizeof(TStat), 0); aSTAT^.st_mtime := VInputStat.st_mtime; aSTAT^.st_mtime_nsec := VInputStat.st_mtime_nsec; aSTAT^.st_ctime := VInputStat.st_mtime; aSTAT^.st_ctime_nsec := VInputStat.st_mtime_nsec; aSTAT^.st_atime := VInputStat.st_atime; aSTAT^.st_atime_nsec := VInputStat.st_atime_nsec; if (aNameC[0] = '/') and (aNameC[1] = #0) then begin aSTAT^.st_mode := S_IFDIR or 493; // 0755; aSTAT^.st_nlink := 2; Result := 0; end else begin aSTAT^.st_nlink := 1; VNode := GetNode(aNameC); if Assigned(VNode) then begin if Supports(VNode, IResourceBlock, VResourceInfo) then begin aSTAT^.st_mode := S_IFREG or 292; aSTAT^.st_size := VResourceInfo.DataSize shl VWIN16AlignmentShiftCount; aSTAT^.st_ino := VResourceInfo.DataOffset; Result := 0; end else if Supports(VNode, IResourceTypeBlock, VResourceTypeInfo) then begin if Assigned(VResourceTypeInfo) then begin aSTAT^.st_mode := S_IFDIR or 493; // 0755; aSTAT^.st_size := VResourceTypeInfo.Count; aSTAT^.st_nlink := aSTAT^.st_size + 2; Result := 0; end; end; end; end; end; function hello_readdir(aNameC : PChar; aBuffer : Pointer; filler : TDirectoryFiller; aFileOffset : off_t; aFileInfo : TFileInfoP) : Integer; cdecl; var aName : TString; VResourceTypeInfo : IResourceTypeBlock; i : Integer; j : Integer; VResourceInfo : IResourceBlock; VID : String; begin Result := -ESysENOENT; aName := aNameC; if aName = '/' then begin Result := 0; filler(aBuffer, '.', nil, 0); filler(aBuffer, '..', nil, 0); for i := 0 to vResourceTypeInfos.Count - 1 do begin VResourceTypeInfo := VResourceTypeInfos[i] as IResourceTypeBlock; VID := VResourceTypeInfo.TypeID; filler(aBuffer, PChar(VID), nil, 0); end; end else begin for i := 0 to vResourceTypeInfos.Count - 1 do begin VResourceTypeInfo := vResourceTypeInfos[i] as IResourceTypeBlock; if aName = '/' + VResourceTypeInfo.TypeID then begin Result := 0; filler(aBuffer, '.', nil, 0); filler(aBuffer, '..', nil, 0); for j := 0 to VResourceTypeInfo.Count - 1 do begin VResourceInfo := VResourceTypeInfo.Item[j]; VID := VResourceInfo.ID + GetSuffix(VResourceTypeInfo.TypeID); filler(aBuffer, PChar(VID), nil, 0); end; end; end; end; end; function hello_open(aNameC : PChar; aFileInfo : TFileInfoP) : Integer; cdecl; var VResourceTypeInfo : IResourceTypeBlock; VResourceInfo : IResourceBlock; VNode : IInterface; begin Result := -ESysENOENT; VNode := GetNode(aNameC); if Assigned(VNode) then begin if Supports(VNode, IResourceBlock, VResourceInfo) then begin if ((aFileInfo^.flags and 3) <> O_RDONLY) then Result := -ESysEACCES else Result := 0; end else if Supports(VNode, IResourceTypeBlock, VResourceTypeInfo) then begin if Assigned(VResourceTypeInfo) then Result := -ESysEISDIR; end; end; if Result = 0 then VInputStat.st_atime := fptime(); // TODO st_atime_nsec ? end; function Min(aA, aB : off_t) : off_t; inline; begin if aA < aB then Result := aA else Result := aB; end; function hello_read(aNameC : PChar; aBuffer : Pointer; aBufferSize : size_t; aFileOffset : off_t; aFileInfo : TFileInfoP) : Integer; cdecl; var VResourceTypeInfo : IResourceTypeBlock; VResourceInfo : IResourceBlock; VNode : IInterface; begin Result := -ESysENOENT; VNode := GetNode(aNameC); if Assigned(VNode) then begin if Supports(VNode, IResourceBlock, VResourceInfo) then begin if ((aFileInfo^.flags and 3) <> O_RDONLY) then Result := -ESysEACCES else begin // actually do something. Result := 0; if aFileOffset >= 0 then begin // TODO read data. VInputStream.Seek((VResourceInfo.DataOffset shl VWIN16AlignmentShiftCount) + aFileOffset, soBeginning); Result := VInputStream.Read(aBuffer^, Min(aBufferSize, VResourceInfo.DataSize shl VWIN16AlignmentShiftCount - aFileOffset)); end; end; end else if Supports(VNode, IResourceTypeBlock, VResourceTypeInfo) then begin Result := -ESysEISDIR; end; end; end; var hello_oper : TOperations = ( getattr : hello_getattr; readlink : nil; getdir : nil; mknod : nil; mkdir : nil; unlink : nil; rmdir : nil; symlink : nil; rename : nil; link : nil; chmod : nil; chown : nil; truncate : nil; utime : nil; open : hello_open; read : hello_read; write : nil; statfs : nil; flush : nil; release : nil; fsync : nil; setxattr : nil; getxattr : nil; listxattr : nil; removexattr : nil; opendir : nil; { TODO just update atime in there } readdir : hello_readdir; releasedir : nil; fsyncdir : nil; init : nil; destroy : nil; access : nil; create : nil; ftruncate : nil; fgetattr : nil; lock : nil; utimens : nil; bmap : nil; ); var VFileName : TString; begin VFileName := ParamStr(1); VInputStream := TFileStream.Create(VFileName, fmOpenRead); FillChar(VInputStat, Sizeof(VInputStat), 0); FpStat(VFileName, VInputStat); // can fail? vResourceTypeInfos := Windows_Resource.ParseHeader(VInputStream, VWIN16AlignmentShiftCount); Dec(argc); Inc(argv); Halt(fuse_main(argc, argv, @hello_oper, Sizeof(hello_oper), nil)); end.