fts/ffi.rs
1//! Bindings for libc fts.
2
3use libc::*;
4
5/// struct FTS in fts.h ( opaque struct )
6pub enum FTS {}
7
8/// struct FTSENT in fts.h
9#[repr(C)]
10#[derive(Debug)]
11pub struct FTSENT {
12 /// cycle node
13 pub fts_cycle: *const FTSENT,
14 /// parent directory
15 pub fts_parent: *const FTSENT,
16 /// next file in directory
17 pub fts_link: *const FTSENT,
18 /// local numeric value
19 pub fts_number: c_long,
20 /// local address value
21 pub fts_pointer: *const c_void,
22 /// access path
23 pub fts_accpath: *const c_char,
24 /// root path
25 pub fts_path: *const c_char,
26 /// errno for this node
27 pub fts_errno: c_int,
28 /// fd for symlink
29 pub fts_symfd: c_int,
30 /// strlen(fts_path)
31 pub fts_pathlen: c_ushort,
32 /// strlen(fts_name)
33 pub fts_namelen: c_ushort,
34 /// inode
35 pub fts_ino: ino_t,
36 /// device
37 pub fts_dev: dev_t,
38 /// link count
39 pub fts_nlink: nlink_t,
40 /// depth (-1 to N)
41 pub fts_level: c_short,
42 /// user flags for FTSENT structure
43 pub fts_info: c_ushort,
44 /// private flags for FTSENT structure
45 pub fts_flags: c_ushort,
46 /// fts_set() instructions
47 pub fts_instr: c_ushort,
48 /// stat(2) information
49 pub fts_statp: *const stat,
50 /// file name
51 pub fts_name: [u8; 0],
52}
53
54/// fts_level: level of root parent
55pub const FTS_ROOTPARENTLEVEL: c_short = -1;
56/// fts_level: level of root
57pub const FTS_ROOTLEVEL: c_short = 0;
58/// fts_info: preorder directory
59pub const FTS_D: c_ushort = 1;
60/// fts_info: directory that causes cycles
61pub const FTS_DC: c_ushort = 2;
62/// fts_info: none of the above
63pub const FTS_DEFAULT: c_ushort = 3;
64/// fts_info: unreadable directory
65pub const FTS_DNR: c_ushort = 4;
66/// fts_info: dot or dot-dot
67pub const FTS_DOT: c_ushort = 5;
68/// fts_info: postorder directory
69pub const FTS_DP: c_ushort = 6;
70/// fts_info: error; errno is set
71pub const FTS_ERR: c_ushort = 7;
72/// fts_info: regular file
73pub const FTS_F: c_ushort = 8;
74/// fts_info: initialized only
75pub const FTS_INIT: c_ushort = 9;
76/// fts_info: stat(2) failed
77pub const FTS_NS: c_ushort = 10;
78/// fts_info: no stat(2) requested
79pub const FTS_NSOK: c_ushort = 11;
80/// fts_info: symbolic link
81pub const FTS_SL: c_ushort = 12;
82/// fts_info: symbolic link without target
83pub const FTS_SLNONE: c_ushort = 13;
84/// fts_info: whiteout object
85pub const FTS_W: c_ushort = 14;
86/// fts_flags: don't chdir .. to the parent
87pub const FTS_DONTCHDIR: c_ushort = 0x01;
88/// fts_flags: followed a symlink to get here
89pub const FTS_SYMFOLLOW: c_ushort = 0x02;
90/// fts_instr: read node again
91pub const FTS_AGAIN: c_int = 1;
92/// fts_instr: follow symbolic link
93pub const FTS_FOLLOW: c_int = 2;
94/// fts_instr: no instructions
95pub const FTS_NOINSTR: c_int = 3;
96/// fts_instr: discard node
97pub const FTS_SKIP: c_int = 4;
98/// fts_open options: follow command line symlinks
99pub const FTS_COMFOLLOW: c_int = 0x0001;
100/// fts_open options: logical walk
101pub const FTS_LOGICAL: c_int = 0x0002;
102/// fts_open options: don't change directories
103pub const FTS_NOCHDIR: c_int = 0x0004;
104/// fts_open options: don't get stat info
105pub const FTS_NOSTAT: c_int = 0x0008;
106/// fts_open options: physical walk
107pub const FTS_PHYSICAL: c_int = 0x0010;
108/// fts_open options: return dot and dot-dot
109pub const FTS_SEEDOT: c_int = 0x0020;
110/// fts_open options: don't cross devices
111pub const FTS_XDEV: c_int = 0x0040;
112/// fts_open options: return whiteout information
113pub const FTS_WHITEOUT: c_int = 0x0080;
114/// fts_open options: valid user option mask
115pub const FTS_OPTIONMASK: c_int = 0x00ff;
116/// fts_open options: (private) child names only
117pub const FTS_NAMEONLY: c_int = 0x0100;
118/// fts_open options: (private) unrecoverable error
119pub const FTS_STOP: c_int = 0x0200;
120
121extern "C" {
122 /// fts_open() in fts.h
123 ///
124 /// # C function
125 /// ```c
126 /// FTS *fts_open(char * const *path_argv, int options,
127 /// int (*compar)(const FTSENT **, const FTSENT **));
128 /// ```
129 ///
130 /// # Safety
131 /// `path_argv` must be a pointer of a null-terminated array of C strings( null-terminated ).
132 ///
133 /// `options` must contain either `FTS_LOGICAL` or `FTS_PHYSICAL`.
134 ///
135 /// # Examples
136 /// ```
137 /// let path = std::ffi::CString::new( "." ).unwrap();
138 /// let paths = vec![path.as_ptr(), std::ptr::null()];
139 /// let _fts = unsafe { fts::ffi::fts_open( paths.as_ptr(), fts::ffi::FTS_LOGICAL, None ) };
140 /// ```
141 #[cfg_attr(target_os = "macos", link_name = "fts_open$INODE64")]
142 pub fn fts_open(
143 path_argv: *const *const c_char,
144 options: c_int,
145 compar: Option<extern "C" fn(*const *const FTSENT, *const *const FTSENT) -> c_int>,
146 ) -> *mut FTS;
147
148 /// fts_read() in fts.h
149 ///
150 /// # C function
151 /// ```c
152 /// FTSENT *fts_read(FTS *ftsp);
153 /// ```
154 ///
155 /// # Safety
156 /// `ftsp` must be a valid pointer of struct FTS.
157 ///
158 /// # Examples
159 /// ```
160 /// let path = std::ffi::CString::new( "." ).unwrap();
161 /// let paths = vec![path.as_ptr(), std::ptr::null()];
162 /// let fts = unsafe { fts::ffi::fts_open( paths.as_ptr(), fts::ffi::FTS_LOGICAL, None ) };
163 /// let _ftsent = unsafe { fts::ffi::fts_read( fts ) };
164 /// ```
165 #[cfg_attr(target_os = "macos", link_name = "fts_read$INODE64")]
166 pub fn fts_read(ftsp: *mut FTS) -> *const FTSENT;
167
168 /// fts_children() in fts.h
169 ///
170 /// # C function
171 /// ```c
172 /// FTSENT *fts_children(FTS *ftsp, int options);
173 /// ```
174 ///
175 /// # Safety
176 /// `ftsp` must be a valid pointer of struct FTS.
177 ///
178 /// `options` must be either 0 or `FTS_NAMEONLY`.
179 ///
180 /// # Examples
181 /// ```
182 /// let path = std::ffi::CString::new( "." ).unwrap();
183 /// let paths = vec![path.as_ptr(), std::ptr::null()];
184 /// let fts = unsafe { fts::ffi::fts_open( paths.as_ptr(), fts::ffi::FTS_LOGICAL, None ) };
185 /// let _ftsent = unsafe { fts::ffi::fts_children( fts, 0 ) };
186 /// ```
187 #[cfg_attr(target_os = "macos", link_name = "fts_children$INODE64")]
188 pub fn fts_children(ftsp: *mut FTS, options: c_int) -> *const FTSENT;
189
190 /// fts_set() in fts.h
191 ///
192 /// # C function
193 /// ```c
194 /// int fts_set(FTS *ftsp, FTSENT *f, int options);
195 /// ```
196 ///
197 /// # Safety
198 /// `ftsp` must be a valid pointer of struct FTS.
199 ///
200 /// `f` must be a valid pointer of struct FTSENT.
201 ///
202 /// `options` must be `FTS_AGAIN`, `FTS_FOLLOW` or `FTS_SKIP`.
203 ///
204 /// # Examples
205 /// ```
206 /// let path = std::ffi::CString::new( "." ).unwrap();
207 /// let paths = vec![path.as_ptr(), std::ptr::null()];
208 /// let fts = unsafe { fts::ffi::fts_open( paths.as_ptr(), fts::ffi::FTS_LOGICAL, None ) };
209 /// let ftsent = unsafe { fts::ffi::fts_read( fts ) };
210 /// let _ = unsafe { fts::ffi::fts_set( fts, ftsent, fts::ffi::FTS_AGAIN ) };
211 /// ```
212 #[cfg_attr(target_os = "macos", link_name = "fts_set$INODE64")]
213 pub fn fts_set(ftsp: *mut FTS, f: *const FTSENT, options: c_int) -> c_int;
214
215 /// fts_close() in fts.h
216 ///
217 /// # C function
218 /// ```c
219 /// int fts_close(FTS *ftsp);
220 /// ```
221 ///
222 /// # Safety
223 /// `ftsp` must be a valid pointer of struct FTS.
224 ///
225 /// # Examples
226 /// ```
227 /// let path = std::ffi::CString::new( "." ).unwrap();
228 /// let paths = vec![path.as_ptr(), std::ptr::null()];
229 /// let fts = unsafe { fts::ffi::fts_open( paths.as_ptr(), fts::ffi::FTS_LOGICAL, None ) };
230 /// let _ = unsafe { fts::ffi::fts_close( fts ) };
231 /// ```
232 #[cfg_attr(target_os = "macos", link_name = "fts_close$INODE64")]
233 pub fn fts_close(ftsp: *mut FTS) -> c_int;
234}
235
236#[cfg(test)]
237mod test {
238 use super::*;
239 use std::ffi::CString;
240 use std::ptr;
241
242 fn ftsent_valid(ftsent: *const FTSENT) {
243 unsafe {
244 assert!(!ftsent.is_null());
245 assert!(!(*ftsent).fts_accpath.is_null());
246 assert!(!(*ftsent).fts_path.is_null());
247 assert!((*ftsent).fts_pathlen != 0);
248 assert!((*ftsent).fts_namelen != 0);
249 assert!((*ftsent).fts_level >= -1);
250 assert!((*ftsent).fts_number == 0);
251 assert!((*ftsent).fts_pointer.is_null());
252 assert!(!(*ftsent).fts_parent.is_null());
253 assert!(!(*ftsent).fts_statp.is_null());
254 }
255 }
256
257 #[test]
258 fn normal() {
259 unsafe {
260 let path = CString::new(".").unwrap();
261 let paths = vec![path.as_ptr(), ptr::null()];
262 let fts = fts_open(paths.as_ptr(), 0, None);
263 assert!(!fts.is_null());
264
265 let mut ftsent = fts_read(fts);
266 while !ftsent.is_null() {
267 ftsent_valid(ftsent);
268 ftsent = fts_read(fts);
269 }
270
271 let ret = fts_close(fts);
272 assert!(ret == 0);
273 }
274 }
275
276 #[test]
277 fn children() {
278 unsafe {
279 let path = CString::new(".").unwrap();
280 let paths = vec![path.as_ptr(), ptr::null()];
281 let fts = fts_open(paths.as_ptr(), FTS_LOGICAL, None);
282 assert!(!fts.is_null());
283
284 let _ = fts_read(fts);
285 let mut ftsent = fts_children(fts, 0);
286 while !ftsent.is_null() {
287 ftsent_valid(ftsent);
288 ftsent = (*ftsent).fts_link;
289 }
290
291 let ret = fts_close(fts);
292 assert!(ret == 0);
293 }
294 }
295}