1 ! Copyright (C) 2008 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: alien.c-types io.binary io.backend io.files io.buffers
4 io.encodings.utf16n io.ports io.windows kernel math splitting
5 fry alien.strings windows windows.kernel32 windows.time calendar
6 combinators math.functions sequences namespaces make words
7 symbols system destructors accessors math.bitwise continuations
8 windows.errors arrays byte-arrays generalizations ;
11 : open-file ( path access-mode create-mode flags -- handle )
13 [ share-mode default-security-attributes ] 2dip
14 CreateFile-flags f CreateFile opened-file
17 : open-pipe-r/w ( path -- win32-file )
18 { GENERIC_READ GENERIC_WRITE } flags
19 OPEN_EXISTING 0 open-file ;
21 : open-read ( path -- win32-file )
22 GENERIC_READ OPEN_EXISTING 0 open-file 0 >>ptr ;
24 : open-write ( path -- win32-file )
25 GENERIC_WRITE CREATE_ALWAYS 0 open-file 0 >>ptr ;
27 : (open-append) ( path -- win32-file )
28 GENERIC_WRITE OPEN_ALWAYS 0 open-file ;
30 : open-existing ( path -- win32-file )
31 { GENERIC_READ GENERIC_WRITE } flags
35 FILE_FLAG_BACKUP_SEMANTICS
36 f CreateFileW dup win32-error=0/f <win32-file> ;
38 : maybe-create-file ( path -- win32-file ? )
39 #! return true if file was just created
40 { GENERIC_READ GENERIC_WRITE } flags
45 f CreateFileW dup win32-error=0/f <win32-file>
46 GetLastError ERROR_ALREADY_EXISTS = not ;
48 : set-file-pointer ( handle length method -- )
49 [ dupd d>w/w <uint> ] dip SetFilePointer
50 INVALID_SET_FILE_POINTER = [
51 CloseHandle "SetFilePointer failed" throw
54 HOOK: open-append os ( path -- win32-file )
57 hFile lpBuffer nNumberOfBytesToRead
58 lpNumberOfBytesRet lpOverlapped ;
60 C: <FileArgs> FileArgs
62 : make-FileArgs ( port -- <FileArgs> )
64 [ handle>> check-disposed ]
67 [ buffer>> buffer-length ]
68 [ drop "DWORD" <c-object> ]
69 [ FileArgs-overlapped ]
72 : setup-read ( <FileArgs> -- hFile lpBuffer nNumberOfBytesToRead lpNumberOfBytesRead lpOverlapped )
75 [ lpBuffer>> buffer-end ]
76 [ lpBuffer>> buffer-capacity ]
77 [ lpNumberOfBytesRet>> ]
81 : setup-write ( <FileArgs> -- hFile lpBuffer nNumberOfBytesToWrite lpNumberOfBytesWritten lpOverlapped )
84 [ lpBuffer>> buffer@ ]
85 [ lpBuffer>> buffer-length ]
86 [ lpNumberOfBytesRet>> ]
90 M: windows (file-reader) ( path -- stream )
91 open-read <input-port> ;
93 M: windows (file-writer) ( path -- stream )
94 open-write <output-port> ;
96 M: windows (file-appender) ( path -- stream )
97 open-append <output-port> ;
99 M: windows move-file ( from to -- )
100 [ normalize-path ] bi@ MoveFile win32-error=0/f ;
102 M: windows delete-file ( path -- )
103 normalize-path DeleteFile win32-error=0/f ;
105 M: windows copy-file ( from to -- )
106 dup parent-directory make-directories
107 [ normalize-path ] bi@ 0 CopyFile win32-error=0/f ;
109 M: windows make-directory ( path -- )
111 f CreateDirectory win32-error=0/f ;
113 M: windows delete-directory ( path -- )
115 RemoveDirectory win32-error=0/f ;
117 : find-first-file ( path -- WIN32_FIND_DATA handle )
118 "WIN32_FIND_DATA" <c-object> tuck
120 [ INVALID_HANDLE_VALUE = [ win32-error-string throw ] when ] keep ;
122 : find-next-file ( path -- WIN32_FIND_DATA/f )
123 "WIN32_FIND_DATA" <c-object> tuck
125 GetLastError ERROR_NO_MORE_FILES = [
130 M: windows (directory-entries) ( path -- seq )
131 "\\" ?tail drop "\\*" append
132 find-first-file [ >directory-entry ] dip
135 [ _ find-next-file dup ]
138 over name>> "." = [ nip ] [ swap prefix ] if
140 ] [ '[ _ FindClose win32-error=0/f ] ] bi [ ] cleanup ;
142 SYMBOLS: +read-only+ +hidden+ +system+
143 +archive+ +device+ +normal+ +temporary+
144 +sparse-file+ +reparse-point+ +compressed+ +offline+
145 +not-content-indexed+ +encrypted+ ;
147 TUPLE: windows-file-info < file-info attributes ;
149 : win32-file-attribute ( n attr symbol -- )
150 rot mask? [ , ] [ drop ] if ;
152 : win32-file-attributes ( n -- seq )
155 [ +read-only+ FILE_ATTRIBUTE_READONLY win32-file-attribute ]
156 [ +hidden+ FILE_ATTRIBUTE_HIDDEN win32-file-attribute ]
157 [ +system+ FILE_ATTRIBUTE_SYSTEM win32-file-attribute ]
158 [ +directory+ FILE_ATTRIBUTE_DIRECTORY win32-file-attribute ]
159 [ +archive+ FILE_ATTRIBUTE_ARCHIVE win32-file-attribute ]
160 [ +device+ FILE_ATTRIBUTE_DEVICE win32-file-attribute ]
161 [ +normal+ FILE_ATTRIBUTE_NORMAL win32-file-attribute ]
162 [ +temporary+ FILE_ATTRIBUTE_TEMPORARY win32-file-attribute ]
163 [ +sparse-file+ FILE_ATTRIBUTE_SPARSE_FILE win32-file-attribute ]
164 [ +reparse-point+ FILE_ATTRIBUTE_REPARSE_POINT win32-file-attribute ]
165 [ +compressed+ FILE_ATTRIBUTE_COMPRESSED win32-file-attribute ]
166 [ +offline+ FILE_ATTRIBUTE_OFFLINE win32-file-attribute ]
167 [ +not-content-indexed+ FILE_ATTRIBUTE_NOT_CONTENT_INDEXED win32-file-attribute ]
168 [ +encrypted+ FILE_ATTRIBUTE_ENCRYPTED win32-file-attribute ]
172 : win32-file-type ( n -- symbol )
173 FILE_ATTRIBUTE_DIRECTORY mask? +directory+ +regular-file+ ? ;
175 TUPLE: windows-directory-entry < directory-entry attributes ;
177 M: windows >directory-entry ( byte-array -- directory-entry )
178 [ WIN32_FIND_DATA-cFileName utf16n alien>string ]
179 [ WIN32_FIND_DATA-dwFileAttributes win32-file-type ]
180 [ WIN32_FIND_DATA-dwFileAttributes win32-file-attributes ]
182 dupd remove windows-directory-entry boa ;
184 : WIN32_FIND_DATA>file-info ( WIN32_FIND_DATA -- file-info )
185 [ \ windows-file-info new ] dip
187 [ WIN32_FIND_DATA-dwFileAttributes win32-file-type >>type ]
188 [ WIN32_FIND_DATA-dwFileAttributes win32-file-attributes >>attributes ]
190 [ WIN32_FIND_DATA-nFileSizeLow ]
191 [ WIN32_FIND_DATA-nFileSizeHigh ] bi >64bit >>size
193 [ WIN32_FIND_DATA-dwFileAttributes >>permissions ]
194 [ WIN32_FIND_DATA-ftCreationTime FILETIME>timestamp >>created ]
195 [ WIN32_FIND_DATA-ftLastWriteTime FILETIME>timestamp >>modified ]
196 [ WIN32_FIND_DATA-ftLastAccessTime FILETIME>timestamp >>accessed ]
199 : find-first-file-stat ( path -- WIN32_FIND_DATA )
200 "WIN32_FIND_DATA" <c-object> [
202 [ INVALID_HANDLE_VALUE = [ win32-error ] when ] keep
203 FindClose win32-error=0/f
206 : BY_HANDLE_FILE_INFORMATION>file-info ( HANDLE_FILE_INFORMATION -- file-info )
207 [ \ windows-file-info new ] dip
209 [ BY_HANDLE_FILE_INFORMATION-dwFileAttributes win32-file-type >>type ]
210 [ BY_HANDLE_FILE_INFORMATION-dwFileAttributes win32-file-attributes >>attributes ]
212 [ BY_HANDLE_FILE_INFORMATION-nFileSizeLow ]
213 [ BY_HANDLE_FILE_INFORMATION-nFileSizeHigh ] bi >64bit >>size
215 [ BY_HANDLE_FILE_INFORMATION-dwFileAttributes >>permissions ]
217 BY_HANDLE_FILE_INFORMATION-ftCreationTime
218 FILETIME>timestamp >>created
221 BY_HANDLE_FILE_INFORMATION-ftLastWriteTime
222 FILETIME>timestamp >>modified
225 BY_HANDLE_FILE_INFORMATION-ftLastAccessTime
226 FILETIME>timestamp >>accessed
228 ! [ BY_HANDLE_FILE_INFORMATION-nNumberOfLinks ]
230 ! [ BY_HANDLE_FILE_INFORMATION-nFileIndexLow ]
231 ! [ BY_HANDLE_FILE_INFORMATION-nFileIndexHigh ] bi >64bit
235 : get-file-information ( handle -- BY_HANDLE_FILE_INFORMATION )
237 "BY_HANDLE_FILE_INFORMATION" <c-object>
238 [ GetFileInformationByHandle win32-error=0/f ] keep
239 ] keep CloseHandle win32-error=0/f ;
241 : get-file-information-stat ( path -- BY_HANDLE_FILE_INFORMATION )
243 GENERIC_READ FILE_SHARE_READ f
244 OPEN_EXISTING FILE_FLAG_BACKUP_SEMANTICS f
245 CreateFileW dup INVALID_HANDLE_VALUE = [
246 drop find-first-file-stat WIN32_FIND_DATA>file-info
249 get-file-information BY_HANDLE_FILE_INFORMATION>file-info
252 M: winnt file-info ( path -- info )
253 normalize-path get-file-information-stat ;
255 M: winnt link-info ( path -- info )
258 HOOK: root-directory os ( string -- string' )
260 : volume-information ( normalized-path -- volume-name volume-serial max-component flags type )
261 MAX_PATH 1+ [ <byte-array> ] keep
265 MAX_PATH 1+ [ <byte-array> ] keep
266 [ GetVolumeInformation win32-error=0/f ] 7 nkeep
268 [ utf16n alien>string ] 4 ndip
269 utf16n alien>string ;
271 : file-system-space ( normalized-path -- available-space total-space free-space )
272 "ULARGE_INTEGER" <c-object>
273 "ULARGE_INTEGER" <c-object>
274 "ULARGE_INTEGER" <c-object>
275 [ GetDiskFreeSpaceEx win32-error=0/f ] 3keep ;
277 : calculate-file-system-info ( file-system-info -- file-system-info' )
279 [ dup [ total-space>> ] [ free-space>> ] bi - >>used-space drop ]
283 TUPLE: win32-file-system-info < file-system-info max-component flags device-serial ;
285 M: winnt file-system-info ( path -- file-system-info )
286 normalize-path root-directory
287 dup [ volume-information ] [ file-system-space ] bi
288 \ win32-file-system-info new
289 swap *ulonglong >>free-space
290 swap *ulonglong >>total-space
291 swap *ulonglong >>available-space
294 swap *uint >>max-component
295 swap *uint >>device-serial
298 calculate-file-system-info ;
300 : volume>paths ( string -- array )
301 16384 "ushort" <c-array> tuck dup length
302 0 <uint> dup [ GetVolumePathNamesForVolumeName 0 = ] dip swap [
303 win32-error-string throw
305 *uint "ushort" heap-size * head
306 utf16n alien>string CHAR: \0 split
309 : find-first-volume ( -- string handle )
310 MAX_PATH 1+ [ <byte-array> ] keep
312 FindFirstVolume dup win32-error=0/f
313 [ utf16n alien>string ] dip ;
315 : find-next-volume ( handle -- string/f )
316 MAX_PATH 1+ [ <byte-array> tuck ] keep
318 GetLastError ERROR_NO_MORE_FILES =
319 [ drop f ] [ win32-error-string throw ] if
324 : find-volumes ( -- array )
328 [ _ find-next-volume dup ]
333 ] [ '[ _ FindVolumeClose win32-error=0/f ] ] bi [ ] cleanup ;
335 M: winnt file-systems ( -- array )
336 find-volumes [ volume>paths ] map
339 [ drop \ file-system-info new swap >>mount-point ] recover
342 : file-times ( path -- timestamp timestamp timestamp )
344 normalize-path open-existing &dispose handle>>
345 "FILETIME" <c-object>
346 "FILETIME" <c-object>
347 "FILETIME" <c-object>
348 [ GetFileTime win32-error=0/f ] 3keep
349 [ FILETIME>timestamp >local-time ] tri@
352 : (set-file-times) ( handle timestamp/f timestamp/f timestamp/f -- )
353 [ timestamp>FILETIME ] tri@
354 SetFileTime win32-error=0/f ;
356 : set-file-times ( path timestamp/f timestamp/f timestamp/f -- )
357 #! timestamp order: creation access write
360 normalize-path open-existing &dispose handle>>
361 ] 3dip (set-file-times)
364 : set-file-create-time ( path timestamp -- )
367 : set-file-access-time ( path timestamp -- )
368 [ f ] dip f set-file-times ;
370 : set-file-write-time ( path timestamp -- )
371 [ f f ] dip set-file-times ;
373 M: winnt touch-file ( path -- )
376 maybe-create-file [ &dispose ] dip
377 [ drop ] [ handle>> f now dup (set-file-times) ] if