@@ -242,6 +242,118 @@ pub fn openat<P: ?Sized + NixPath>(
242
242
Errno :: result( fd)
243
243
}
244
244
245
+ #[ cfg( target_os = "linux" ) ]
246
+ libc_bitflags! {
247
+ /// Path resolution flags.
248
+ ///
249
+ /// See [path resolution(7)](https://man7.org/linux/man-pages/man7/path_resolution.7.html)
250
+ /// for details of the resolution process.
251
+ pub struct ResolveFlag : libc:: c_ulonglong {
252
+ /// Do not permit the path resolution to succeed if any component of
253
+ /// the resolution is not a descendant of the directory indicated by
254
+ /// dirfd. This causes absolute symbolic links (and absolute values of
255
+ /// pathname) to be rejected.
256
+ RESOLVE_BENEATH ;
257
+
258
+ /// Treat the directory referred to by dirfd as the root directory
259
+ /// while resolving pathname.
260
+ RESOLVE_IN_ROOT ;
261
+
262
+ /// Disallow all magic-link resolution during path resolution. Magic
263
+ /// links are symbolic link-like objects that are most notably found
264
+ /// in proc(5); examples include `/proc/[pid]/exe` and `/proc/[pid]/fd/*`.
265
+ ///
266
+ /// See symlink(7) for more details.
267
+ RESOLVE_NO_MAGICLINKS ;
268
+
269
+ /// Disallow resolution of symbolic links during path resolution. This
270
+ /// option implies RESOLVE_NO_MAGICLINKS.
271
+ RESOLVE_NO_SYMLINKS ;
272
+
273
+ /// Disallow traversal of mount points during path resolution (including
274
+ /// all bind mounts).
275
+ RESOLVE_NO_XDEV ;
276
+ }
277
+ }
278
+
279
+
280
+ /// Specifies how [openat2] should open a pathname.
281
+ ///
282
+ /// See <https://man7.org/linux/man-pages/man2/open_how.2type.html>
283
+ #[ cfg( target_os = "linux" ) ]
284
+ #[ repr( transparent) ]
285
+ #[ derive( Clone , Copy , Debug ) ]
286
+ pub struct OpenHow ( libc:: open_how) ;
287
+
288
+ #[ cfg( target_os = "linux" ) ]
289
+ impl OpenHow {
290
+ /// Create a new zero-filled `open_how`.
291
+ pub fn new( ) -> Self {
292
+ // safety: according to the man page, open_how MUST be zero-initialized
293
+ // on init so that unknown fields are also zeroed.
294
+ Self ( unsafe {
295
+ std:: mem:: MaybeUninit :: zeroed( ) . assume_init( )
296
+ } )
297
+ }
298
+
299
+ /// Set the open flags used to open a file, completely overwriting any
300
+ /// existing flags.
301
+ pub fn flags( mut self , flags: OFlag ) -> Self {
302
+ let flags = flags. bits( ) as libc:: c_ulonglong;
303
+ self . 0 . flags = flags;
304
+ self
305
+ }
306
+
307
+ /// Set the file mode new files will be created with, overwriting any
308
+ /// existing flags.
309
+ pub fn mode( mut self , mode: Mode ) -> Self {
310
+ let mode = mode. bits( ) as libc:: c_ulonglong;
311
+ self . 0 . mode = mode;
312
+ self
313
+ }
314
+
315
+ /// Set resolve flags, completely overwriting any existing flags.
316
+ ///
317
+ /// See [ResolveFlag] for more detail.
318
+ pub fn resolve( mut self , resolve: ResolveFlag ) -> Self {
319
+ let resolve = resolve. bits( ) ;
320
+ self . 0 . resolve = resolve;
321
+ self
322
+ }
323
+ }
324
+
325
+
326
+ /// Open or create a file for reading, writing or executing.
327
+ ///
328
+ /// `openat2` is an extension of the [`openat`] function that allows the caller
329
+ /// to control how path resolution happens.
330
+ ///
331
+ /// # See also
332
+ ///
333
+ /// [openat2](https://man7.org/linux/man-pages/man2/openat2.2.html)
334
+ #[ cfg( target_os = "linux" ) ]
335
+ pub fn openat2<P : ?Sized + NixPath >(
336
+ dirfd: RawFd ,
337
+ path: & P ,
338
+ mut how: OpenHow ,
339
+ ) -> Result <RawFd > {
340
+ let fd = path. with_nix_path( |cstr| unsafe {
341
+ libc:: syscall(
342
+ libc:: SYS_openat2 ,
343
+ dirfd,
344
+ cstr. as_ptr( ) ,
345
+ & mut how as * mut OpenHow ,
346
+ std:: mem:: size_of:: <libc:: open_how>( ) ,
347
+ )
348
+ } ) ?;
349
+
350
+ // convert the result of syscall into the right size for an fd in a sort of
351
+ // portable way. if the conversion fails somehow, EBADF is reasonable - the
352
+ // return value of syscall can't be converted into an fd.
353
+ let fd: libc:: c_int = fd. try_into( ) . map_err( |_| Errno :: EBADF ) ?;
354
+ Errno :: result( fd)
355
+ }
356
+
245
357
/// Change the name of a file.
246
358
///
247
359
/// The `renameat` function is equivalent to `rename` except in the case where either `old_path`
0 commit comments