sysfile.inc 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2001 by Free Pascal development team
  4. Low leve file functions
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {*****************************************************************************
  12. Low Level File Routines
  13. *****************************************************************************}
  14. function do_isdevice(handle:thandle):boolean;
  15. begin
  16. do_isdevice:=(handle = StdInputHandle) or (handle = StdOutputHandle) or (handle = StdErrorHandle);
  17. end;
  18. procedure do_close(h : thandle);
  19. begin
  20. if do_isdevice(h) then
  21. exit;
  22. if CloseHandle(h)=0 then
  23. Errno2InOutRes(GetLastError);
  24. end;
  25. procedure do_erase(p: pwidechar; pchangeable: boolean);
  26. var
  27. oldp: pwidechar;
  28. err: longword;
  29. begin
  30. oldp:=p;
  31. DoDirSeparators(p,pchangeable);
  32. if DeleteFileW(p)=0 then
  33. Begin
  34. err:=GetLastError;
  35. if err=5 then
  36. begin
  37. if ((GetFileAttributesW(p) and FILE_ATTRIBUTE_DIRECTORY)=FILE_ATTRIBUTE_DIRECTORY) then
  38. err:=2;
  39. end;
  40. Errno2InoutRes(err);
  41. end;
  42. if p<>oldp then
  43. freemem(p);
  44. end;
  45. procedure do_rename(p1,p2: pwidechar; p1changeable, p2changeable: boolean);
  46. var
  47. oldp1,oldp2: pwidechar;
  48. begin
  49. oldp1:=p1;
  50. oldp2:=p2;
  51. DoDirSeparators(p1,p1changeable);
  52. DoDirSeparators(p2,p2changeable);
  53. if MoveFileW(p1,p2)=0 then
  54. Begin
  55. Errno2InoutRes(GetLastError);
  56. end;
  57. if p1<>oldp1 then
  58. freemem(p1);
  59. if p2<>oldp2 then
  60. freemem(p2);
  61. end;
  62. function do_write(h:thandle;addr:pointer;len : longint) : longint;
  63. var
  64. size:longint;
  65. {$ifndef WINCE}
  66. ConsoleMode : dword;
  67. CodePage : UInt;
  68. accept_smaller_size : boolean;
  69. {$endif ndef WINCE}
  70. begin
  71. if writefile(h,addr,len,size,nil)=0 then
  72. Begin
  73. Errno2InoutRes(GetLastError);
  74. {$ifndef WINCE}
  75. end
  76. else if (size<len) then
  77. Begin
  78. if GetConsoleMode (h, @ConsoleMode) then
  79. Begin
  80. accept_smaller_size:=false;
  81. { GetConsoleMode success means that we do have a
  82. console handle that might return less than
  83. LEN because a UTF-8 with length LEN input was
  84. transformed into a shorter string of size SIZE }
  85. CodePage:=GetConsoleOutputCP;
  86. Case CodePage of
  87. 1200, {utf-16}
  88. 1201, {unicodeFFFE}
  89. 12000, {utf-32}
  90. 12001, {utf-32BE}
  91. 65000, {utf-7}
  92. 65001: {utf-8}
  93. accept_smaller_size:=true;
  94. end;
  95. if accept_smaller_size then
  96. size:=len;
  97. end;
  98. {$endif ndef WINCE}
  99. end;
  100. do_write:=size;
  101. end;
  102. function do_read(h:thandle;addr:pointer;len : longint) : longint;
  103. var
  104. _result:longint;
  105. err: longword;
  106. begin
  107. if readfile(h,addr,len,_result,nil)=0 then
  108. Begin
  109. err:=GetLastError;
  110. if err<>ERROR_BROKEN_PIPE then
  111. Errno2InoutRes(err);
  112. end;
  113. do_read:=_result;
  114. end;
  115. type
  116. tint64rec = record
  117. low, high: dword;
  118. end;
  119. function do_filepos(handle : thandle) : Int64;
  120. var
  121. rslt: tint64rec;
  122. begin
  123. rslt.high := 0;
  124. rslt.low := SetFilePointer(handle, 0, @rslt.high, FILE_CURRENT);
  125. if (rslt.low = $FFFFFFFF) and (GetLastError <> 0) then
  126. begin
  127. Errno2InoutRes(GetLastError);
  128. end;
  129. do_filepos := int64(rslt);
  130. end;
  131. procedure do_seek(handle: thandle; pos: Int64);
  132. var
  133. posHigh: LongInt;
  134. begin
  135. posHigh := tint64rec(pos).high;
  136. if (SetFilePointer(handle, pos, @posHigh, FILE_BEGIN)=-1) and
  137. { return value of -1 is valid unless GetLastError is non-zero }
  138. (GetLastError <> 0) then
  139. begin
  140. Errno2InoutRes(GetLastError);
  141. end;
  142. end;
  143. function do_seekend(handle:thandle):Int64;
  144. var
  145. rslt: tint64rec;
  146. begin
  147. rslt.high := 0;
  148. rslt.low := SetFilePointer(handle, 0, @rslt.high, FILE_END);
  149. if (rslt.low = $FFFFFFFF) and (GetLastError <> 0) then
  150. begin
  151. Errno2InoutRes(GetLastError);
  152. end;
  153. do_seekend := int64(rslt);
  154. end;
  155. function do_filesize(handle : thandle) : Int64;
  156. var
  157. aktfilepos : Int64;
  158. begin
  159. aktfilepos:=do_filepos(handle);
  160. do_filesize:=do_seekend(handle);
  161. do_seek(handle,aktfilepos);
  162. end;
  163. procedure do_truncate (handle:thandle;pos:Int64);
  164. begin
  165. do_seek(handle,pos);
  166. if not(SetEndOfFile(handle)) then
  167. begin
  168. Errno2InoutRes(GetLastError);
  169. end;
  170. end;
  171. procedure do_open(var f; p: pwidechar; flags: longint; pchangeable: boolean);
  172. {
  173. filerec and textrec have both handle and mode as the first items so
  174. they could use the same routine for opening/creating.
  175. when (flags and $100) the file will be append
  176. when (flags and $1000) the file will be truncate/rewritten
  177. when (flags and $10000) there is no check for close (needed for textfiles)
  178. }
  179. Const
  180. file_Share_Read = $00000001;
  181. file_Share_Write = $00000002;
  182. file_Share_Delete = $00000004;
  183. Var
  184. shflags,
  185. oflags,cd : longint;
  186. security : TSecurityAttributes;
  187. oldp : pwidechar;
  188. begin
  189. { close first if opened }
  190. if ((flags and $10000)=0) then
  191. begin
  192. case filerec(f).mode of
  193. fminput,fmoutput,fminout : Do_Close(filerec(f).handle);
  194. fmclosed : ;
  195. else
  196. begin
  197. {not assigned}
  198. inoutres:=102;
  199. exit;
  200. end;
  201. end;
  202. end;
  203. oldp:=p;
  204. DoDirSeparators(p,pchangeable);
  205. { reset file handle }
  206. filerec(f).handle:=UnusedHandle;
  207. { convert filesharing }
  208. shflags:=0;
  209. if ((filemode and fmshareExclusive) = fmshareExclusive) then
  210. { no sharing }
  211. else
  212. if ((filemode and $f0) = fmShareCompat) or ((filemode and fmshareDenyWrite) = fmshareDenyWrite) then
  213. shflags := file_Share_Read
  214. else
  215. if ((filemode and fmshareDenyRead) = fmshareDenyRead) then
  216. shflags := file_Share_Write
  217. else
  218. if ((filemode and fmshareDenyNone) = fmshareDenyNone) then
  219. shflags :=
  220. {$ifdef WINCE}
  221. { WinCE does not know file_share_delete }
  222. file_Share_Read or file_Share_Write;
  223. {$else WINCE}
  224. fmShareDenyNoneFlags;
  225. {$endif WINCE}
  226. { convert filemode to filerec modes }
  227. case (flags and 3) of
  228. 0 : begin
  229. filerec(f).mode:=fminput;
  230. oflags:=longint(GENERIC_READ);
  231. end;
  232. 1 : begin
  233. filerec(f).mode:=fmoutput;
  234. oflags:=longint(GENERIC_WRITE);
  235. end;
  236. 2 : begin
  237. filerec(f).mode:=fminout;
  238. oflags:=longint(GENERIC_WRITE or GENERIC_READ);
  239. end;
  240. end;
  241. { create it ? }
  242. if (flags and $1000)<>0 then
  243. cd:=CREATE_ALWAYS
  244. { or Append/Open ? }
  245. else
  246. cd:=OPEN_EXISTING;
  247. { empty name is special }
  248. if p[0]=#0 then
  249. begin
  250. case FileRec(f).mode of
  251. fminput :
  252. FileRec(f).Handle:=StdInputHandle;
  253. fminout, { this is set by rewrite }
  254. fmoutput :
  255. FileRec(f).Handle:=StdOutputHandle;
  256. fmappend :
  257. begin
  258. FileRec(f).Handle:=StdOutputHandle;
  259. FileRec(f).mode:=fmoutput; {fool fmappend}
  260. end;
  261. end;
  262. { no dirseparators can have been replaced in the empty string -> no need
  263. to check whether we have to free p }
  264. exit;
  265. end;
  266. security.nLength := Sizeof(TSecurityAttributes);
  267. security.bInheritHandle:=true;
  268. security.lpSecurityDescriptor:=nil;
  269. filerec(f).handle:=CreateFileW(p,oflags,shflags,@security,cd,FILE_ATTRIBUTE_NORMAL,0);
  270. { append mode }
  271. if ((flags and $100)<>0) and
  272. (filerec(f).handle<>0) and
  273. (filerec(f).handle<>UnusedHandle) then
  274. begin
  275. do_seekend(filerec(f).handle);
  276. filerec(f).mode:=fmoutput; {fool fmappend}
  277. end;
  278. { get errors }
  279. { handle -1 is returned sometimes !! (PM) }
  280. if (filerec(f).handle=0) or (filerec(f).handle=UnusedHandle) then
  281. begin
  282. Errno2InoutRes(GetLastError);
  283. FileRec(f).mode:=fmclosed;
  284. end;
  285. if oldp<>p then
  286. freemem(p);
  287. end;