| 184 | } |
| 185 | |
| 186 | fn ftruncate(&mut self, _tx_offset: u64, size: u64) -> io::Result<()> { |
| 187 | let mut storage = self.storage.write().unwrap(); |
| 188 | let mut avail = self.space.lock().unwrap(); |
| 189 | |
| 190 | // NOTE: We don't modify `self.pos`, which is how `ftruncate(2)` behaves. |
| 191 | // This means the position can be invalid after calling this. |
| 192 | if size > storage.alloc { |
| 193 | if *avail == 0 { |
| 194 | return Err(enospc()); |
| 195 | } |
| 196 | |
| 197 | let want = size.next_multiple_of(PAGE_SIZE as u64) - storage.alloc; |
| 198 | let have = want.min(*avail); |
| 199 | |
| 200 | storage.alloc += have; |
| 201 | *avail -= have; |
| 202 | storage.buf.resize(size as usize, 0); |
| 203 | |
| 204 | // NOTE: `ftruncate(2)` is a bit ambiguous as to what should happen |
| 205 | // if the requested size exceeds the available space. |
| 206 | // |
| 207 | // [std::fs::File::set_len] will succeed, but all subsequent |
| 208 | // operations return EBADF. |
| 209 | // |
| 210 | // That's not super helpful, so instead we zero out as much space as |
| 211 | // possible, and return ENOSPC if more than that was requested. |
| 212 | if want > have { |
| 213 | return Err(enospc()); |
| 214 | } |
| 215 | } else { |
| 216 | let alloc = size.next_multiple_of(PAGE_SIZE as u64); |
| 217 | *avail += storage.alloc - alloc; |
| 218 | storage.alloc = alloc; |
| 219 | storage.buf.resize(size as usize, 0); |
| 220 | } |
| 221 | |
| 222 | Ok(()) |
| 223 | } |
| 224 | |
| 225 | #[cfg(feature = "fallocate")] |
| 226 | fn fallocate(&mut self, size: u64) -> io::Result<()> { |