(dirfd: BorrowedFd<'_>, path: &CStr, mut buffer: Vec<u8>)
| 110 | #[cfg(all(feature = "alloc", not(target_os = "redox")))] |
| 111 | #[allow(unsafe_code)] |
| 112 | fn _readlinkat(dirfd: BorrowedFd<'_>, path: &CStr, mut buffer: Vec<u8>) -> io::Result<CString> { |
| 113 | buffer.clear(); |
| 114 | buffer.reserve(SMALL_PATH_BUFFER_SIZE); |
| 115 | |
| 116 | loop { |
| 117 | let buf = buffer.spare_capacity_mut(); |
| 118 | |
| 119 | // SAFETY: `readlinkat` behaves. |
| 120 | let nread = unsafe { |
| 121 | backend::fs::syscalls::readlinkat( |
| 122 | dirfd.as_fd(), |
| 123 | path, |
| 124 | (buf.as_mut_ptr().cast(), buf.len()), |
| 125 | )? |
| 126 | }; |
| 127 | |
| 128 | debug_assert!(nread <= buffer.capacity()); |
| 129 | if nread < buffer.capacity() { |
| 130 | // SAFETY: From the [documentation]: “On success, these calls |
| 131 | // return the number of bytes placed in buf.” |
| 132 | // |
| 133 | // [documentation]: https://man7.org/linux/man-pages/man2/readlinkat.2.html |
| 134 | unsafe { |
| 135 | buffer.set_len(nread); |
| 136 | } |
| 137 | |
| 138 | // SAFETY: |
| 139 | // - “readlink places the contents of the symbolic link pathname |
| 140 | // in the buffer buf” |
| 141 | // - [POSIX definition 3.271: Pathname]: “A string that is used |
| 142 | // to identify a file.” |
| 143 | // - [POSIX definition 3.375: String]: “A contiguous sequence of |
| 144 | // bytes terminated by and including the first null byte.” |
| 145 | // - “readlink does not append a terminating null byte to buf.” |
| 146 | // |
| 147 | // Thus, there will be no NUL bytes in the string. |
| 148 | // |
| 149 | // [POSIX definition 3.271: Pathname]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap03.html#tag_03_271 |
| 150 | // [POSIX definition 3.375: String]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap03.html#tag_03_375 |
| 151 | unsafe { |
| 152 | return Ok(CString::from_vec_unchecked(buffer)); |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | // Use `Vec` reallocation strategy to grow capacity exponentially. |
| 157 | buffer.reserve(buffer.capacity() + 1); |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | /// `readlinkat(fd, path)`—Reads the contents of a symlink, without |
| 162 | /// allocating. |
no test coverage detected