1 ! Copyright (C) 2008 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: byte-arrays math io.backend io.files.info
4 io.files.windows kernel windows.kernel32
5 windows.time windows.types windows accessors alien.c-types
6 combinators generalizations system alien.strings
7 sequences splitting windows.errors fry
8 continuations destructors calendar ascii
9 combinators.short-circuit literals locals classes.struct
10 specialized-arrays alien.data libc windows.shell32 ;
11 SPECIALIZED-ARRAY: ushort
13 IN: io.files.info.windows
15 :: round-up-to ( n multiple -- n' )
22 TUPLE: windows-file-info < file-info-tuple attributes ;
24 : get-compressed-file-size ( path -- n )
25 { DWORD } [ GetCompressedFileSize ] with-out-parameters
26 over INVALID_FILE_SIZE = [ win32-error-string throw ] [ >64bit ] if ;
28 : set-windows-size-on-disk ( file-info path -- file-info )
29 over attributes>> +compressed+ swap member? [
30 get-compressed-file-size
32 drop dup size>> 4096 round-up-to
35 : WIN32_FIND_DATA>file-info ( WIN32_FIND_DATA -- file-info )
36 [ \ windows-file-info new ] dip
38 [ dwFileAttributes>> win32-file-type >>type ]
39 [ dwFileAttributes>> win32-file-attributes >>attributes ]
40 [ [ nFileSizeLow>> ] [ nFileSizeHigh>> ] bi >64bit >>size ]
41 [ dwFileAttributes>> >>permissions ]
42 [ ftCreationTime>> FILETIME>timestamp >>created ]
43 [ ftLastWriteTime>> FILETIME>timestamp >>modified ]
44 [ ftLastAccessTime>> FILETIME>timestamp >>accessed ]
47 : find-first-file-stat ( path -- WIN32_FIND_DATA )
48 WIN32_FIND_DATA <struct> [
50 [ INVALID_HANDLE_VALUE = [ win32-error ] when ] keep
51 FindClose win32-error=0/f
54 : BY_HANDLE_FILE_INFORMATION>file-info ( HANDLE_FILE_INFORMATION -- file-info )
55 [ \ windows-file-info new ] dip
57 [ dwFileAttributes>> win32-file-type >>type ]
58 [ dwFileAttributes>> win32-file-attributes >>attributes ]
61 [ nFileSizeHigh>> ] bi >64bit >>size
63 [ dwFileAttributes>> >>permissions ]
64 [ ftCreationTime>> FILETIME>timestamp >>created ]
65 [ ftLastWriteTime>> FILETIME>timestamp >>modified ]
66 [ ftLastAccessTime>> FILETIME>timestamp >>accessed ]
67 ! [ nNumberOfLinks>> ]
70 ! [ nFileIndexHigh>> ] bi >64bit
74 : get-file-information ( handle -- BY_HANDLE_FILE_INFORMATION )
76 BY_HANDLE_FILE_INFORMATION <struct>
77 [ GetFileInformationByHandle win32-error=0/f ] keep
78 ] keep CloseHandle win32-error=0/f ;
80 : get-file-information-stat ( path -- BY_HANDLE_FILE_INFORMATION )
82 GENERIC_READ FILE_SHARE_READ f
83 OPEN_EXISTING FILE_FLAG_BACKUP_SEMANTICS f
84 CreateFileW dup INVALID_HANDLE_VALUE = [
85 drop find-first-file-stat WIN32_FIND_DATA>file-info
88 get-file-information BY_HANDLE_FILE_INFORMATION>file-info
91 M: windows file-info ( path -- info )
93 [ get-file-information-stat ]
94 [ set-windows-size-on-disk ] bi ;
96 M: windows link-info ( path -- info )
99 : file-executable-type ( path -- executable/f )
103 ! hi is zero means old style executable
104 0 SHGFI_EXETYPE SHGetFileInfoW
108 nip >lo-hi first2 zero? [
110 { 0x5A4D [ +dos-executable+ ] }
111 { 0x4550 [ +win32-console-executable+ ] }
116 { 0x454C [ +win32-vxd-executable+ ] }
117 { 0x454E [ +win32-os2-executable+ ] }
118 { 0x4550 [ +win32-nt-executable+ ] }
124 CONSTANT: path-length $[ MAX_PATH 1 + ]
126 : volume-information ( normalized-path -- volume-name volume-serial max-component flags type )
127 { { ushort path-length } DWORD DWORD DWORD { ushort path-length } }
128 [ [ path-length ] 4dip path-length GetVolumeInformation win32-error=0/f ]
130 [ alien>native-string ] 4dip alien>native-string ;
132 : file-system-space ( normalized-path -- available-space total-space free-space )
133 { ULARGE_INTEGER ULARGE_INTEGER ULARGE_INTEGER }
134 [ GetDiskFreeSpaceEx win32-error=0/f ]
135 with-out-parameters ;
137 : calculate-file-system-info ( file-system-info -- file-system-info' )
138 [ dup [ total-space>> ] [ free-space>> ] bi - >>used-space drop ] keep ;
140 TUPLE: win32-file-system-info < file-system-info-tuple max-component flags device-serial ;
142 ERROR: not-absolute-path ;
144 : root-directory ( string -- string' )
145 unicode-prefix ?head drop
150 } 1&& [ 2 head "\\" append ] [ not-absolute-path ] if ;
154 : (file-system-info) ( path -- file-system-info )
155 dup [ volume-information ] [ file-system-space ] bi
156 \ win32-file-system-info new
159 swap >>available-space
166 calculate-file-system-info ;
170 M: windows file-system-info ( path -- file-system-info )
171 normalize-path root-directory (file-system-info) ;
173 CONSTANT: names-buf-length 16384
175 : find-first-volume ( -- string handle )
176 { { ushort path-length } }
177 [ path-length FindFirstVolume dup win32-error=0/f ]
178 with-out-parameters alien>native-string swap ;
180 : find-next-volume ( handle -- string/f )
181 { { ushort path-length } }
182 [ path-length FindNextVolume ] with-out-parameters
184 GetLastError ERROR_NO_MORE_FILES =
185 [ drop f ] [ win32-error-string throw ] if
186 ] [ alien>native-string ] if ;
188 : find-volumes ( -- array )
192 [ _ find-next-volume dup ] [ ] produce nip
195 ] [ '[ _ FindVolumeClose win32-error=0/f ] ] bi [ ] cleanup ;
197 ! Windows may return a volume which looks up to path ""
198 ! For now, treat it like there is not a volume here
199 : volume>paths ( string -- array )
202 [ ushort malloc-array &free ] keep
204 [ GetVolumePathNamesForVolumeName win32-error=0/f ] 3keep nip
205 uint deref head but-last-slice
206 { 0 } split-slice harvest
207 [ { } ] [ [ { 0 } append alien>native-string ] map ] if-empty
210 ! Can error with T{ windows-error f 21 "The device is not ready." }
211 ! if there is a D: that is not ready, for instance. Ignore these drives.
212 M: windows file-systems ( -- array )
213 find-volumes [ volume>paths ] map concat [
214 [ (file-system-info) ] [ 2drop f ] recover
217 : file-times ( path -- timestamp timestamp timestamp )
219 normalize-path open-read &dispose handle>>
220 { FILETIME FILETIME FILETIME }
221 [ GetFileTime win32-error=0/f ]
223 [ FILETIME>timestamp >local-time ] tri@
226 : set-file-times ( path timestamp/f timestamp/f timestamp/f -- )
227 ! timestamp order: creation access write
230 normalize-path open-existing &dispose handle>>
231 ] 3dip (set-file-times)
234 : set-file-create-time ( path timestamp -- )
237 : set-file-access-time ( path timestamp -- )
238 [ f ] dip f set-file-times ;
240 : set-file-write-time ( path timestamp -- )
241 [ f f ] dip set-file-times ;
243 M: windows file-readable? file-info >boolean ;
244 M: windows file-writable? file-info attributes>> +read-only+ swap member? not ;
245 M: windows file-executable? file-executable-type windows-executable? ;