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 io.files.windows.nt kernel windows.kernel32
5 windows.time windows.types windows accessors alien.c-types
6 combinators generalizations system alien.strings
7 io.encodings.utf16n sequences splitting windows.errors fry
8 continuations destructors calendar ascii
9 combinators.short-circuit literals locals classes.struct
10 specialized-arrays alien.data ;
11 SPECIALIZED-ARRAY: ushort
12 IN: io.files.info.windows
14 :: round-up-to ( n multiple -- n' )
21 TUPLE: windows-file-info < file-info attributes ;
23 : get-compressed-file-size ( path -- n )
24 { DWORD } [ GetCompressedFileSize ] with-out-parameters
25 over INVALID_FILE_SIZE = [ win32-error-string throw ] [ >64bit ] if ;
27 : set-windows-size-on-disk ( file-info path -- file-info )
28 over attributes>> +compressed+ swap member? [
29 get-compressed-file-size
31 drop dup size>> 4096 round-up-to
34 : WIN32_FIND_DATA>file-info ( WIN32_FIND_DATA -- file-info )
35 [ \ windows-file-info new ] dip
37 [ dwFileAttributes>> win32-file-type >>type ]
38 [ dwFileAttributes>> win32-file-attributes >>attributes ]
39 [ [ nFileSizeLow>> ] [ nFileSizeHigh>> ] bi >64bit >>size ]
40 [ dwFileAttributes>> >>permissions ]
41 [ ftCreationTime>> FILETIME>timestamp >>created ]
42 [ ftLastWriteTime>> FILETIME>timestamp >>modified ]
43 [ ftLastAccessTime>> FILETIME>timestamp >>accessed ]
46 : find-first-file-stat ( path -- WIN32_FIND_DATA )
47 WIN32_FIND_DATA <struct> [
49 [ INVALID_HANDLE_VALUE = [ win32-error ] when ] keep
50 FindClose win32-error=0/f
53 : BY_HANDLE_FILE_INFORMATION>file-info ( HANDLE_FILE_INFORMATION -- file-info )
54 [ \ windows-file-info new ] dip
56 [ dwFileAttributes>> win32-file-type >>type ]
57 [ dwFileAttributes>> win32-file-attributes >>attributes ]
60 [ nFileSizeHigh>> ] bi >64bit >>size
62 [ dwFileAttributes>> >>permissions ]
63 [ ftCreationTime>> FILETIME>timestamp >>created ]
64 [ ftLastWriteTime>> FILETIME>timestamp >>modified ]
65 [ ftLastAccessTime>> FILETIME>timestamp >>accessed ]
66 ! [ nNumberOfLinks>> ]
69 ! [ nFileIndexHigh>> ] bi >64bit
73 : get-file-information ( handle -- BY_HANDLE_FILE_INFORMATION )
75 BY_HANDLE_FILE_INFORMATION <struct>
76 [ GetFileInformationByHandle win32-error=0/f ] keep
77 ] keep CloseHandle win32-error=0/f ;
79 : get-file-information-stat ( path -- BY_HANDLE_FILE_INFORMATION )
81 GENERIC_READ FILE_SHARE_READ f
82 OPEN_EXISTING FILE_FLAG_BACKUP_SEMANTICS f
83 CreateFileW dup INVALID_HANDLE_VALUE = [
84 drop find-first-file-stat WIN32_FIND_DATA>file-info
87 get-file-information BY_HANDLE_FILE_INFORMATION>file-info
90 M: windows file-info ( path -- info )
92 [ get-file-information-stat ]
93 [ set-windows-size-on-disk ] bi ;
95 M: windows link-info ( path -- info )
98 CONSTANT: path-length $[ MAX_PATH 1 + ]
100 : volume-information ( normalized-path -- volume-name volume-serial max-component flags type )
101 { { ushort path-length } DWORD DWORD DWORD { ushort path-length } }
102 [ [ path-length ] 4dip path-length GetVolumeInformation win32-error=0/f ]
104 [ utf16n alien>string ] 4dip utf16n alien>string ;
106 : file-system-space ( normalized-path -- available-space total-space free-space )
107 { ULARGE_INTEGER ULARGE_INTEGER ULARGE_INTEGER }
108 [ GetDiskFreeSpaceEx win32-error=0/f ]
109 with-out-parameters ;
111 : calculate-file-system-info ( file-system-info -- file-system-info' )
112 [ dup [ total-space>> ] [ free-space>> ] bi - >>used-space drop ] keep ;
114 TUPLE: win32-file-system-info < file-system-info max-component flags device-serial ;
116 ERROR: not-absolute-path ;
118 : root-directory ( string -- string' )
119 unicode-prefix ?head drop
124 } 1&& [ 2 head "\\" append ] [ not-absolute-path ] if ;
128 : (file-system-info) ( path -- file-system-info )
129 dup [ volume-information ] [ file-system-space ] bi
130 \ win32-file-system-info new
133 swap >>available-space
140 calculate-file-system-info ;
144 M: winnt file-system-info ( path -- file-system-info )
145 normalize-path root-directory (file-system-info) ;
147 CONSTANT: names-buf-length 16384
149 : volume>paths ( string -- array )
150 { { ushort names-buf-length } uint }
151 [ [ names-buf-length ] dip GetVolumePathNamesForVolumeName win32-error=0/f ]
153 head utf16n alien>string { CHAR: \0 } split ;
155 : find-first-volume ( -- string handle )
156 { { ushort path-length } }
157 [ path-length FindFirstVolume dup win32-error=0/f ]
158 with-out-parameters utf16n alien>string swap ;
160 : find-next-volume ( handle -- string/f )
161 { { ushort path-length } }
162 [ path-length FindNextVolume ] with-out-parameters
164 GetLastError ERROR_NO_MORE_FILES =
165 [ drop f ] [ win32-error-string throw ] if
166 ] [ utf16n alien>string ] if ;
168 : find-volumes ( -- array )
172 [ _ find-next-volume dup ] [ ] produce nip
175 ] [ '[ _ FindVolumeClose win32-error=0/f ] ] bi [ ] cleanup ;
177 M: winnt file-systems ( -- array )
178 find-volumes [ volume>paths ] map
180 [ (file-system-info) ]
181 [ drop \ file-system-info new swap >>mount-point ] recover
184 : file-times ( path -- timestamp timestamp timestamp )
186 normalize-path open-read &dispose handle>>
187 { FILETIME FILETIME FILETIME }
188 [ GetFileTime win32-error=0/f ]
190 [ FILETIME>timestamp >local-time ] tri@
193 : set-file-times ( path timestamp/f timestamp/f timestamp/f -- )
194 #! timestamp order: creation access write
197 normalize-path open-existing &dispose handle>>
198 ] 3dip (set-file-times)
201 : set-file-create-time ( path timestamp -- )
204 : set-file-access-time ( path timestamp -- )
205 [ f ] dip f set-file-times ;
207 : set-file-write-time ( path timestamp -- )
208 [ f f ] dip set-file-times ;