sysfile.inc 7.7 KB

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