| 1 | //! Extended attribute functions. |
| 2 | |
| 3 | #![allow (unsafe_code)] |
| 4 | |
| 5 | use crate::buffer::Buffer; |
| 6 | use crate::{backend, ffi, io, path}; |
| 7 | use backend::c; |
| 8 | use backend::fd::AsFd; |
| 9 | use bitflags::bitflags; |
| 10 | |
| 11 | bitflags! { |
| 12 | /// `XATTR_*` constants for use with [`setxattr`], and other `*setxattr` |
| 13 | /// functions. |
| 14 | #[repr (transparent)] |
| 15 | #[derive (Copy, Clone, Eq, PartialEq, Hash, Debug)] |
| 16 | pub struct XattrFlags: ffi::c_uint { |
| 17 | /// `XATTR_CREATE` |
| 18 | const CREATE = c::XATTR_CREATE as c::c_uint; |
| 19 | |
| 20 | /// `XATTR_REPLACE` |
| 21 | const REPLACE = c::XATTR_REPLACE as c::c_uint; |
| 22 | |
| 23 | /// <https://docs.rs/bitflags/*/bitflags/#externally-defined-flags> |
| 24 | const _ = !0; |
| 25 | } |
| 26 | } |
| 27 | |
| 28 | /// `getxattr(path, name, value)`—Get extended filesystem attributes. |
| 29 | /// |
| 30 | /// For a higher-level API to xattr functionality, see the [xattr] crate. |
| 31 | /// |
| 32 | /// [xattr]: https://crates.io/crates/xattr |
| 33 | /// |
| 34 | /// # References |
| 35 | /// - [Linux] |
| 36 | /// - [Apple] |
| 37 | /// |
| 38 | /// [Linux]: https://man7.org/linux/man-pages/man2/getxattr.2.html |
| 39 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getxattr.2.html |
| 40 | #[inline ] |
| 41 | pub fn getxattr<P: path::Arg, Name: path::Arg, Buf: Buffer<u8>>( |
| 42 | path: P, |
| 43 | name: Name, |
| 44 | mut value: Buf, |
| 45 | ) -> io::Result<Buf::Output> { |
| 46 | path.into_with_c_str(|path: &CStr| { |
| 47 | name.into_with_c_str(|name: &CStr| { |
| 48 | // SAFETY: `getxattr` behaves. |
| 49 | let len: usize = unsafe { backend::fs::syscalls::getxattr(path, name, value.parts_mut())? }; |
| 50 | // SAFETY: `getxattr` behaves. |
| 51 | unsafe { Ok(value.assume_init(len)) } |
| 52 | }) |
| 53 | }) |
| 54 | } |
| 55 | |
| 56 | /// `lgetxattr(path, name, value.as_ptr(), value.len())`—Get extended |
| 57 | /// filesystem attributes, without following symlinks in the last path |
| 58 | /// component. |
| 59 | /// |
| 60 | /// # References |
| 61 | /// - [Linux] |
| 62 | /// |
| 63 | /// [Linux]: https://man7.org/linux/man-pages/man2/lgetxattr.2.html |
| 64 | #[inline ] |
| 65 | pub fn lgetxattr<P: path::Arg, Name: path::Arg, Buf: Buffer<u8>>( |
| 66 | path: P, |
| 67 | name: Name, |
| 68 | mut value: Buf, |
| 69 | ) -> io::Result<Buf::Output> { |
| 70 | path.into_with_c_str(|path: &CStr| { |
| 71 | name.into_with_c_str(|name: &CStr| { |
| 72 | // SAFETY: `lgetxattr` behaves. |
| 73 | let len: usize = unsafe { backend::fs::syscalls::lgetxattr(path, name, value.parts_mut())? }; |
| 74 | // SAFETY: `lgetxattr` behaves. |
| 75 | unsafe { Ok(value.assume_init(len)) } |
| 76 | }) |
| 77 | }) |
| 78 | } |
| 79 | |
| 80 | /// `fgetxattr(fd, name, value.as_ptr(), value.len())`—Get extended |
| 81 | /// filesystem attributes on an open file descriptor. |
| 82 | /// |
| 83 | /// # References |
| 84 | /// - [Linux] |
| 85 | /// - [Apple] |
| 86 | /// |
| 87 | /// [Linux]: https://man7.org/linux/man-pages/man2/fgetxattr.2.html |
| 88 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fgetxattr.2.html |
| 89 | #[inline ] |
| 90 | pub fn fgetxattr<Fd: AsFd, Name: path::Arg, Buf: Buffer<u8>>( |
| 91 | fd: Fd, |
| 92 | name: Name, |
| 93 | mut value: Buf, |
| 94 | ) -> io::Result<Buf::Output> { |
| 95 | name.into_with_c_str(|name: &CStr| { |
| 96 | // SAFETY: `fgetxattr` behaves. |
| 97 | let len: usize = unsafe { backend::fs::syscalls::fgetxattr(fd.as_fd(), name, value.parts_mut())? }; |
| 98 | // SAFETY: `fgetxattr` behaves. |
| 99 | unsafe { Ok(value.assume_init(len)) } |
| 100 | }) |
| 101 | } |
| 102 | |
| 103 | /// `setxattr(path, name, value.as_ptr(), value.len(), flags)`—Set extended |
| 104 | /// filesystem attributes. |
| 105 | /// |
| 106 | /// # References |
| 107 | /// - [Linux] |
| 108 | /// - [Apple] |
| 109 | /// |
| 110 | /// [Linux]: https://man7.org/linux/man-pages/man2/setxattr.2.html |
| 111 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/setxattr.2.html |
| 112 | #[inline ] |
| 113 | pub fn setxattr<P: path::Arg, Name: path::Arg>( |
| 114 | path: P, |
| 115 | name: Name, |
| 116 | value: &[u8], |
| 117 | flags: XattrFlags, |
| 118 | ) -> io::Result<()> { |
| 119 | path.into_with_c_str(|path: &CStr| { |
| 120 | name.into_with_c_str(|name: &CStr| backend::fs::syscalls::setxattr(path, name, value, flags)) |
| 121 | }) |
| 122 | } |
| 123 | |
| 124 | /// `setxattr(path, name, value.as_ptr(), value.len(), flags)`—Set extended |
| 125 | /// filesystem attributes, without following symlinks in the last path |
| 126 | /// component. |
| 127 | /// |
| 128 | /// # References |
| 129 | /// - [Linux] |
| 130 | /// |
| 131 | /// [Linux]: https://man7.org/linux/man-pages/man2/lsetxattr.2.html |
| 132 | #[inline ] |
| 133 | pub fn lsetxattr<P: path::Arg, Name: path::Arg>( |
| 134 | path: P, |
| 135 | name: Name, |
| 136 | value: &[u8], |
| 137 | flags: XattrFlags, |
| 138 | ) -> io::Result<()> { |
| 139 | path.into_with_c_str(|path: &CStr| { |
| 140 | name.into_with_c_str(|name: &CStr| backend::fs::syscalls::lsetxattr(path, name, value, flags)) |
| 141 | }) |
| 142 | } |
| 143 | |
| 144 | /// `fsetxattr(fd, name, value.as_ptr(), value.len(), flags)`—Set extended |
| 145 | /// filesystem attributes on an open file descriptor. |
| 146 | /// |
| 147 | /// # References |
| 148 | /// - [Linux] |
| 149 | /// - [Apple] |
| 150 | /// |
| 151 | /// [Linux]: https://man7.org/linux/man-pages/man2/fsetxattr.2.html |
| 152 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fsetxattr.2.html |
| 153 | #[inline ] |
| 154 | pub fn fsetxattr<Fd: AsFd, Name: path::Arg>( |
| 155 | fd: Fd, |
| 156 | name: Name, |
| 157 | value: &[u8], |
| 158 | flags: XattrFlags, |
| 159 | ) -> io::Result<()> { |
| 160 | name.into_with_c_str(|name: &CStr| backend::fs::syscalls::fsetxattr(fd.as_fd(), name, value, flags)) |
| 161 | } |
| 162 | |
| 163 | /// `listxattr(path, list.as_ptr(), list.len())`—List extended filesystem |
| 164 | /// attributes. |
| 165 | /// |
| 166 | /// # References |
| 167 | /// - [Linux] |
| 168 | /// |
| 169 | /// [Linux]: https://man7.org/linux/man-pages/man2/listxattr.2.html |
| 170 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/listxattr.2.html |
| 171 | #[inline ] |
| 172 | pub fn listxattr<P: path::Arg, Buf: Buffer<u8>>(path: P, mut list: Buf) -> io::Result<Buf::Output> { |
| 173 | path.into_with_c_str(|path: &CStr| { |
| 174 | // SAFETY: `listxattr` behaves. |
| 175 | let len: usize = unsafe { backend::fs::syscalls::listxattr(path, list.parts_mut())? }; |
| 176 | // SAFETY: `listxattr` behaves. |
| 177 | unsafe { Ok(list.assume_init(len)) } |
| 178 | }) |
| 179 | } |
| 180 | |
| 181 | /// `llistxattr(path, list.as_ptr(), list.len())`—List extended filesystem |
| 182 | /// attributes, without following symlinks in the last path component. |
| 183 | /// |
| 184 | /// # References |
| 185 | /// - [Linux] |
| 186 | /// |
| 187 | /// [Linux]: https://man7.org/linux/man-pages/man2/llistxattr.2.html |
| 188 | #[inline ] |
| 189 | pub fn llistxattr<P: path::Arg, Buf: Buffer<u8>>( |
| 190 | path: P, |
| 191 | mut list: Buf, |
| 192 | ) -> io::Result<Buf::Output> { |
| 193 | path.into_with_c_str(|path: &CStr| { |
| 194 | // SAFETY: `flistxattr` behaves. |
| 195 | let len: usize = unsafe { backend::fs::syscalls::llistxattr(path, list.parts_mut())? }; |
| 196 | // SAFETY: `flistxattr` behaves. |
| 197 | unsafe { Ok(list.assume_init(len)) } |
| 198 | }) |
| 199 | } |
| 200 | |
| 201 | /// `flistxattr(fd, list.as_ptr(), list.len())`—List extended filesystem |
| 202 | /// attributes on an open file descriptor. |
| 203 | /// |
| 204 | /// # References |
| 205 | /// - [Linux] |
| 206 | /// - [Apple] |
| 207 | /// |
| 208 | /// [Linux]: https://man7.org/linux/man-pages/man2/flistxattr.2.html |
| 209 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/flistxattr.2.html |
| 210 | #[inline ] |
| 211 | pub fn flistxattr<Fd: AsFd, Buf: Buffer<u8>>(fd: Fd, mut list: Buf) -> io::Result<Buf::Output> { |
| 212 | // SAFETY: `flistxattr` behaves. |
| 213 | let len: usize = unsafe { backend::fs::syscalls::flistxattr(fd.as_fd(), list.parts_mut())? }; |
| 214 | // SAFETY: `flistxattr` behaves. |
| 215 | unsafe { Ok(list.assume_init(len)) } |
| 216 | } |
| 217 | |
| 218 | /// `removexattr(path, name)`—Remove an extended filesystem attribute. |
| 219 | /// |
| 220 | /// # References |
| 221 | /// - [Linux] |
| 222 | /// - [Apple] |
| 223 | /// |
| 224 | /// [Linux]: https://man7.org/linux/man-pages/man2/removexattr.2.html |
| 225 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/removexattr.2.html |
| 226 | pub fn removexattr<P: path::Arg, Name: path::Arg>(path: P, name: Name) -> io::Result<()> { |
| 227 | path.into_with_c_str(|path: &CStr| { |
| 228 | name.into_with_c_str(|name: &CStr| backend::fs::syscalls::removexattr(path, name)) |
| 229 | }) |
| 230 | } |
| 231 | |
| 232 | /// `lremovexattr(path, name)`—Remove an extended filesystem attribute, |
| 233 | /// without following symlinks in the last path component. |
| 234 | /// |
| 235 | /// # References |
| 236 | /// - [Linux] |
| 237 | /// |
| 238 | /// [Linux]: https://man7.org/linux/man-pages/man2/lremovexattr.2.html |
| 239 | pub fn lremovexattr<P: path::Arg, Name: path::Arg>(path: P, name: Name) -> io::Result<()> { |
| 240 | path.into_with_c_str(|path: &CStr| { |
| 241 | name.into_with_c_str(|name: &CStr| backend::fs::syscalls::lremovexattr(path, name)) |
| 242 | }) |
| 243 | } |
| 244 | |
| 245 | /// `fremovexattr(fd, name)`—Remove an extended filesystem attribute on an |
| 246 | /// open file descriptor. |
| 247 | /// |
| 248 | /// # References |
| 249 | /// - [Linux] |
| 250 | /// - [Apple] |
| 251 | /// |
| 252 | /// [Linux]: https://man7.org/linux/man-pages/man2/fremovexattr.2.html |
| 253 | /// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fremovexattr.2.html |
| 254 | pub fn fremovexattr<Fd: AsFd, Name: path::Arg>(fd: Fd, name: Name) -> io::Result<()> { |
| 255 | name.into_with_c_str(|name: &CStr| backend::fs::syscalls::fremovexattr(fd.as_fd(), name)) |
| 256 | } |
| 257 | |