]> gitweb.factorcode.org Git - factor.git/blob - basis/io/files/info/windows/windows.factor
9bf987c93bc2aad44514ebfb4ff99cd23d6bf026
[factor.git] / basis / io / files / info / windows / windows.factor
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
12 QUALIFIED: sequences
13 IN: io.files.info.windows
14
15 :: round-up-to ( n multiple -- n' )
16     n multiple rem [
17         n
18     ] [
19         multiple swap - n +
20     ] if-zero ;
21
22 TUPLE: windows-file-info < file-info attributes ;
23
24 : get-compressed-file-size ( path -- n )
25     { DWORD } [ GetCompressedFileSize ] with-out-parameters
26     over INVALID_FILE_SIZE = [ win32-error-string throw ] [ >64bit ] if ;
27
28 : set-windows-size-on-disk ( file-info path -- file-info )
29     over attributes>> +compressed+ swap member? [
30         get-compressed-file-size
31     ] [
32         drop dup size>> 4096 round-up-to
33     ] if >>size-on-disk ;
34
35 : WIN32_FIND_DATA>file-info ( WIN32_FIND_DATA -- file-info )
36     [ \ windows-file-info new ] dip
37     {
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 ]
45     } cleave ;
46
47 : find-first-file-stat ( path -- WIN32_FIND_DATA )
48     WIN32_FIND_DATA <struct> [
49         FindFirstFile
50         [ INVALID_HANDLE_VALUE = [ win32-error ] when ] keep
51         FindClose win32-error=0/f
52     ] keep ;
53
54 : BY_HANDLE_FILE_INFORMATION>file-info ( HANDLE_FILE_INFORMATION -- file-info )
55     [ \ windows-file-info new ] dip
56     {
57         [ dwFileAttributes>> win32-file-type >>type ]
58         [ dwFileAttributes>> win32-file-attributes >>attributes ]
59         [
60             [ nFileSizeLow>> ]
61             [ nFileSizeHigh>> ] bi >64bit >>size
62         ]
63         [ dwFileAttributes>> >>permissions ]
64         [ ftCreationTime>> FILETIME>timestamp >>created ]
65         [ ftLastWriteTime>> FILETIME>timestamp >>modified ]
66         [ ftLastAccessTime>> FILETIME>timestamp >>accessed ]
67         ! [ nNumberOfLinks>> ]
68         ! [
69           ! [ nFileIndexLow>> ]
70           ! [ nFileIndexHigh>> ] bi >64bit
71         ! ]
72     } cleave ;
73
74 : get-file-information ( handle -- BY_HANDLE_FILE_INFORMATION )
75     [
76         BY_HANDLE_FILE_INFORMATION <struct>
77         [ GetFileInformationByHandle win32-error=0/f ] keep
78     ] keep CloseHandle win32-error=0/f ;
79
80 : get-file-information-stat ( path -- BY_HANDLE_FILE_INFORMATION )
81     dup
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
86     ] [
87         nip
88         get-file-information BY_HANDLE_FILE_INFORMATION>file-info
89     ] if ;
90
91 M: windows file-info ( path -- info )
92     normalize-path
93     [ get-file-information-stat ]
94     [ set-windows-size-on-disk ] bi ;
95
96 M: windows link-info ( path -- info )
97     file-info ;
98
99 CONSTANT: path-length $[ MAX_PATH 1 + ]
100
101 : volume-information ( normalized-path -- volume-name volume-serial max-component flags type )
102     { { ushort path-length } DWORD DWORD DWORD { ushort path-length } }
103     [ [ path-length ] 4dip path-length GetVolumeInformation win32-error=0/f ]
104     with-out-parameters
105     [ alien>native-string ] 4dip alien>native-string ;
106
107 : file-system-space ( normalized-path -- available-space total-space free-space )
108     { ULARGE_INTEGER ULARGE_INTEGER ULARGE_INTEGER }
109     [ GetDiskFreeSpaceEx win32-error=0/f ]
110     with-out-parameters ;
111
112 : calculate-file-system-info ( file-system-info -- file-system-info' )
113     [ dup [ total-space>> ] [ free-space>> ] bi - >>used-space drop ] keep ;
114
115 TUPLE: win32-file-system-info < file-system-info max-component flags device-serial ;
116
117 ERROR: not-absolute-path ;
118
119 : root-directory ( string -- string' )
120     unicode-prefix ?head drop
121     dup {
122         [ length 2 >= ]
123         [ second CHAR: : = ]
124         [ first Letter? ]
125     } 1&& [ 2 head "\\" append ] [ not-absolute-path ] if ;
126
127 <PRIVATE
128
129 : (file-system-info) ( path -- file-system-info )
130     dup [ volume-information ] [ file-system-space ] bi
131     \ win32-file-system-info new
132         swap >>free-space
133         swap >>total-space
134         swap >>available-space
135         swap >>type
136         swap >>flags
137         swap >>max-component
138         swap >>device-serial
139         swap >>device-name
140         swap >>mount-point
141     calculate-file-system-info ;
142
143 PRIVATE>
144
145 M: windows file-system-info ( path -- file-system-info )
146     normalize-path root-directory (file-system-info) ;
147
148 CONSTANT: names-buf-length 16384
149
150 : find-first-volume ( -- string handle )
151     { { ushort path-length } }
152     [ path-length FindFirstVolume dup win32-error=0/f ]
153     with-out-parameters alien>native-string swap ;
154
155 : find-next-volume ( handle -- string/f )
156     { { ushort path-length } }
157     [ path-length FindNextVolume ] with-out-parameters
158     swap 0 = [
159         GetLastError ERROR_NO_MORE_FILES =
160         [ drop f ] [ win32-error-string throw ] if
161     ] [ alien>native-string ] if ;
162
163 : find-volumes ( -- array )
164     find-first-volume
165     [
166         '[
167             [ _ find-next-volume dup ] [ ] produce nip
168             swap prefix
169         ]
170     ] [ '[ _ FindVolumeClose win32-error=0/f ] ] bi [ ] cleanup ;
171
172 ! Windows may return a volume which looks up to path ""
173 ! For now, treat it like there is not a volume here
174 : volume>paths ( string -- array )
175     [
176         names-buf-length
177         [ ushort malloc-array &free ] keep
178         0 uint <ref>
179         [ GetVolumePathNamesForVolumeName win32-error=0/f ] 3keep nip
180         uint deref head but-last-slice
181         { 0 } split* 
182         [ { } ] [ [ alien>native-string ] map ] if-empty
183     ] with-destructors ;
184
185 ! Can error with T{ windows-error f 21 "The device is not ready." }
186 ! if there is a D: that is not ready, for instance. Ignore these drives.
187 M: windows file-systems ( -- array )
188     find-volumes [ volume>paths ] map concat [
189         [ (file-system-info) ] [ 2drop f ] recover
190     ] map sift ;
191
192 : file-times ( path -- timestamp timestamp timestamp )
193     [
194         normalize-path open-read &dispose handle>>
195         { FILETIME FILETIME FILETIME }
196         [ GetFileTime win32-error=0/f ]
197         with-out-parameters
198         [ FILETIME>timestamp >local-time ] tri@
199     ] with-destructors ;
200
201 : set-file-times ( path timestamp/f timestamp/f timestamp/f -- )
202     #! timestamp order: creation access write
203     [
204         [
205             normalize-path open-existing &dispose handle>>
206         ] 3dip (set-file-times)
207     ] with-destructors ;
208
209 : set-file-create-time ( path timestamp -- )
210     f f set-file-times ;
211
212 : set-file-access-time ( path timestamp -- )
213     [ f ] dip f set-file-times ;
214
215 : set-file-write-time ( path timestamp -- )
216     [ f f ] dip set-file-times ;
217
218 M: windows file-readable? file-info >boolean ;
219 M: windows file-writable? file-info attributes>> +read-only+ swap member? not ;
220 M: windows file-executable? file-executable-type windows-executable? ;