dclinux.pas 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. {
  2. Double Commander
  3. -------------------------------------------------------------------------
  4. This unit contains Linux specific functions
  5. Copyright (C) 2023 Alexander Koblov ([email protected])
  6. This library is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU Lesser General Public
  8. License as published by the Free Software Foundation; either
  9. version 2.1 of the License, or (at your option) any later version.
  10. This library is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. Lesser General Public License for more details.
  14. You should have received a copy of the GNU Lesser General Public
  15. License along with this program. If not, see <https://www.gnu.org/licenses/>
  16. }
  17. unit DCLinux;
  18. {$mode objfpc}{$H+}
  19. {$packrecords c}
  20. interface
  21. uses
  22. Classes, SysUtils, BaseUnix, Unix;
  23. const
  24. CLOSE_RANGE_CLOEXEC = (1 << 2);
  25. const
  26. FS_IOC_GETFLAGS = $80086601;
  27. FS_IOC_SETFLAGS = $40086602;
  28. (*
  29. * Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS)
  30. *)
  31. FS_SECRM_FL = $00000001; //* Secure deletion */
  32. FS_UNRM_FL = $00000002; //* Undelete */
  33. FS_COMPR_FL = $00000004; //* Compress file */
  34. FS_SYNC_FL = $00000008; //* Synchronous updates */
  35. FS_IMMUTABLE_FL = $00000010; //* Immutable file */
  36. FS_APPEND_FL = $00000020; //* Writes to file may only append */
  37. FS_NODUMP_FL = $00000040; //* Do not dump file */
  38. FS_NOATIME_FL = $00000080; //* Do not update atime */
  39. FS_FL_USER_VISIBLE = $0003DFFF; //* User visible flags */
  40. FS_FL_USER_MODIFIABLE = $000380FF; //* User modifiable flags */
  41. type
  42. TFlagName = record
  43. Flag: UInt32;
  44. Name: AnsiChar;
  45. end;
  46. const
  47. FlagsName: array[1..8] of TFlagName = (
  48. (Flag: FS_SECRM_FL; Name: 's'),
  49. (Flag: FS_UNRM_FL; Name: 'u'),
  50. (Flag: FS_SYNC_FL; Name: 'S'),
  51. (Flag: FS_IMMUTABLE_FL; Name: 'i'),
  52. (Flag: FS_APPEND_FL; Name: 'a'),
  53. (Flag: FS_NODUMP_FL; Name: 'd'),
  54. (Flag: FS_NOATIME_FL; Name: 'A'),
  55. (Flag: FS_COMPR_FL; Name: 'c')
  56. );
  57. function FormatFileFlags(Flags: UInt32): String;
  58. function FileGetFlags(Handle: THandle; out Flags: UInt32): Boolean;
  59. function mbFileGetFlags(const FileName: String; out Flags: UInt32): Boolean;
  60. function mbFileGetXattr(const FileName: String): TStringArray;
  61. function mbFileCopyXattr(const Source, Target: String): Boolean;
  62. implementation
  63. uses
  64. InitC, DCConvertEncoding, DCOSUtils;
  65. function lremovexattr(const path, name: PAnsiChar): cint; cdecl; external clib;
  66. function llistxattr(const path: PAnsiChar; list: PAnsiChar; size: csize_t): ssize_t; cdecl; external clib;
  67. function lgetxattr(const path, name: PAnsiChar; value: Pointer; size: csize_t): ssize_t; cdecl; external clib;
  68. function lsetxattr(const path, name: PAnsiChar; const value: Pointer; size: csize_t; flags: cint): cint; cdecl; external clib;
  69. function FormatFileFlags(Flags: UInt32): String;
  70. var
  71. Index: Integer;
  72. begin
  73. Result:=StringOfChar('-', Length(FlagsName));
  74. for Index:= 1 to High(FlagsName) do
  75. begin
  76. if Flags and FlagsName[Index].Flag <> 0 then
  77. begin
  78. Result[Index]:= FlagsName[Index].Name;
  79. end;
  80. end;
  81. end;
  82. function FileGetFlags(Handle: THandle; out Flags: UInt32): Boolean;
  83. begin
  84. Result:= (FpIOCtl(Handle, FS_IOC_GETFLAGS, @Flags) >= 0);
  85. end;
  86. function mbFileGetFlags(const FileName: String; out Flags: UInt32): Boolean;
  87. var
  88. Handle: THandle;
  89. begin
  90. Handle:= mbFileOpen(FileName, fmOpenRead or fmShareDenyNone);
  91. Result:= Handle <> feInvalidHandle;
  92. if Result then
  93. begin
  94. Result:= (FpIOCtl(Handle, FS_IOC_GETFLAGS, @Flags) >= 0);
  95. FileClose(Handle);
  96. end;
  97. end;
  98. function mbFileGetXattr(const FileName: String): TStringArray;
  99. var
  100. AList: String;
  101. ALength: ssize_t;
  102. AFileName: String;
  103. begin
  104. SetLength(AList, MaxSmallint);
  105. Result:= Default(TStringArray);
  106. AFileName:= CeUtf8ToSys(FileName);
  107. ALength:= llistxattr(PAnsiChar(AFileName), Pointer(AList), Length(AList));
  108. if (ALength < 0) then
  109. begin
  110. if (fpgetCerrno <> ESysERANGE) then
  111. begin
  112. fpseterrno(fpgetCerrno);
  113. Exit;
  114. end
  115. else begin
  116. ALength:= llistxattr(PAnsiChar(AFileName), nil, 0);
  117. if ALength < 0 then
  118. begin
  119. fpseterrno(fpgetCerrno);
  120. Exit;
  121. end;
  122. SetLength(AList, ALength);
  123. ALength:= llistxattr(PAnsiChar(AFileName), Pointer(AList), ALength);
  124. if ALength < 0 then
  125. begin
  126. fpseterrno(fpgetCerrno);
  127. Exit;
  128. end;
  129. end;
  130. end;
  131. if (ALength > 0) then
  132. begin
  133. SetLength(AList, ALength - 1);
  134. Result:= AList.Split(#0);
  135. end;
  136. end;
  137. function mbFileCopyXattr(const Source, Target: String): Boolean;
  138. var
  139. Value: String;
  140. Index: Integer;
  141. ALength: ssize_t;
  142. Names: TStringArray;
  143. ASource, ATarget: String;
  144. begin
  145. Result:= True;
  146. ASource:= CeUtf8ToSys(Source);
  147. ATarget:= CeUtf8ToSys(Target);
  148. // Remove attributes from target
  149. Names:= mbFileGetXattr(Target);
  150. for Index:= 0 to High(Names) do
  151. begin
  152. lremovexattr(PAnsiChar(ATarget), PAnsiChar(Names[Index]));
  153. end;
  154. SetLength(Value, MaxSmallint);
  155. Names:= mbFileGetXattr(Source);
  156. for Index:= 0 to High(Names) do
  157. begin
  158. ALength:= lgetxattr(PAnsiChar(ASource), PAnsiChar(Names[Index]), Pointer(Value), Length(Value));
  159. if (ALength < 0) then
  160. begin
  161. if (fpgetCerrno <> ESysERANGE) then
  162. begin
  163. fpseterrno(fpgetCerrno);
  164. Exit(False);
  165. end
  166. else begin
  167. ALength:= lgetxattr(PAnsiChar(ASource), PAnsiChar(Names[Index]), nil, 0);
  168. if ALength < 0 then
  169. begin
  170. fpseterrno(fpgetCerrno);
  171. Exit(False);
  172. end;
  173. SetLength(Value, ALength);
  174. ALength:= lgetxattr(PAnsiChar(ASource), PAnsiChar(Names[Index]), Pointer(Value), Length(Value));
  175. if ALength < 0 then
  176. begin
  177. fpseterrno(fpgetCerrno);
  178. Exit(False);
  179. end;
  180. end;
  181. end;
  182. if (lsetxattr(PAnsiChar(ATarget), PAnsiChar(Names[Index]), Pointer(Value), ALength, 0) < 0) then
  183. begin
  184. fpseterrno(fpgetCerrno);
  185. Exit(fpgeterrno = ESysEOPNOTSUPP);
  186. end;
  187. end;
  188. end;
  189. end.