1 // Copyright (c) 2023 Huawei Device Co., Ltd. 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 use std::fs::{File as SyncFile, Metadata, Permissions}; 15 use std::future::Future; 16 use std::io; 17 use std::io::{Seek, SeekFrom}; 18 use std::path::Path; 19 use std::pin::Pin; 20 use std::sync::Arc; 21 use std::task::{Context, Poll}; 22 23 use crate::fs::file_buf::FileBuf; 24 use crate::fs::{async_op, poll_ready}; 25 use crate::futures::poll_fn; 26 use crate::io::{AsyncRead, AsyncSeek, AsyncWrite, ReadBuf}; 27 use crate::spawn::spawn_blocking; 28 use crate::sync::Mutex; 29 use crate::task::{JoinHandle, TaskBuilder}; 30 31 /// An asynchronous wrapping of [`std::fs::File`]. Provides async read/write 32 /// methods. 33 pub struct File { 34 file: Arc<SyncFile>, 35 inner: Mutex<FileInner>, 36 // controls how many bytes the buffer could reserve during read 37 // and how many bytes the buffer could extend per time during write 38 buf_size_limit: usize, 39 } 40 41 struct FileInner { 42 state: FileState, 43 write_err: Option<io::ErrorKind>, 44 idx: u64, 45 } 46 47 type RWJoinHandle = JoinHandle<(FileBuf, io::Result<()>)>; 48 49 type SeekJoinHandle = JoinHandle<(FileBuf, io::Result<u64>)>; 50 51 enum FileState { 52 Idle(Option<FileBuf>), 53 Reading(RWJoinHandle), 54 Writing(RWJoinHandle), 55 Seeking(SeekJoinHandle), 56 } 57 58 enum FileOp { 59 Reading, 60 Writing, 61 Seeking, 62 } 63 64 impl Future for FileState { 65 type Output = io::Result<u64>; 66 poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>67 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 68 let state = self.get_mut(); 69 match state { 70 FileState::Idle(_) => unreachable!(), 71 FileState::Reading(x) | FileState::Writing(x) => { 72 let (file_buf, res) = poll_ready!(Pin::new(x).poll(cx))?; 73 *state = FileState::Idle(Some(file_buf)); 74 // For read and write, we dont care about the output 75 Poll::Ready(res.map(|_| 0_u64)) 76 } 77 FileState::Seeking(x) => { 78 let (file_buf, res) = poll_ready!(Pin::new(x).poll(cx))?; 79 *state = FileState::Idle(Some(file_buf)); 80 Poll::Ready(res) 81 } 82 } 83 } 84 } 85 86 impl FileState { 87 #[inline] get_op(&self) -> FileOp88 fn get_op(&self) -> FileOp { 89 match self { 90 FileState::Idle(_) => unreachable!(), 91 FileState::Reading(_) => FileOp::Reading, 92 FileState::Writing(_) => FileOp::Writing, 93 FileState::Seeking(_) => FileOp::Seeking, 94 } 95 } 96 } 97 98 const DEFAULT_BUF_LIMIT: usize = 2 * 1024 * 1024; 99 100 impl File { 101 /// Creates a new [`File`] struct. new(file: SyncFile) -> File102 pub fn new(file: SyncFile) -> File { 103 File { 104 file: Arc::new(file), 105 inner: Mutex::new(FileInner { 106 state: FileState::Idle(Some(FileBuf::with_capacity(0))), 107 write_err: None, 108 idx: 0, 109 }), 110 buf_size_limit: DEFAULT_BUF_LIMIT, 111 } 112 } 113 114 /// Attempts to open a file in read-only mode asynchronously. 115 /// 116 /// See the [`super::OpenOptions::open`] method for more details. 117 /// 118 /// # Errors 119 /// 120 /// This function will return an error if `path` does not already exist. 121 /// 122 /// # Examples 123 /// 124 /// ```no_run 125 /// use ylong_runtime::fs::File; 126 /// 127 /// async fn open() -> std::io::Result<()> { 128 /// let mut f = File::open("foo.txt").await?; 129 /// Ok(()) 130 /// } 131 /// ``` open<P: AsRef<Path>>(path: P) -> io::Result<File>132 pub async fn open<P: AsRef<Path>>(path: P) -> io::Result<File> { 133 let path = path.as_ref().to_owned(); 134 let file = async_op(|| SyncFile::open(path)).await?; 135 Ok(File::new(file)) 136 } 137 138 /// Opens a file in write-only mode asynchronously. 139 /// 140 /// This function will create a file if it does not exist 141 /// and truncate it if it does. 142 /// 143 /// 144 /// # Examples 145 /// 146 /// ```no_run 147 /// use ylong_runtime::fs::File; 148 /// 149 /// async fn create() -> std::io::Result<()> { 150 /// let mut f = File::create("foo.txt").await?; 151 /// Ok(()) 152 /// } 153 /// ``` create<P: AsRef<Path>>(path: P) -> io::Result<File>154 pub async fn create<P: AsRef<Path>>(path: P) -> io::Result<File> { 155 let path = path.as_ref().to_owned(); 156 let file = async_op(|| SyncFile::create(path)).await?; 157 Ok(File::new(file)) 158 } 159 160 /// Changes the permissions on the underlying file asynchronously. 161 /// 162 /// # Errors 163 /// This function will return an error if the user lacks permission change 164 /// attributes on the underlying file. It may also return an error in other 165 /// os-specific unspecified cases. 166 /// 167 /// # Examples 168 /// 169 /// ```no_run 170 /// use ylong_runtime::fs::File; 171 /// 172 /// async fn set_permissions() -> std::io::Result<()> { 173 /// let file = File::open("foo.txt").await?; 174 /// let mut perms = file.metadata().await?.permissions(); 175 /// perms.set_readonly(true); 176 /// file.set_permissions(perms).await?; 177 /// Ok(()) 178 /// } 179 /// ``` 180 /// 181 /// Note that this method alters the permissions of the underlying file, 182 /// even though it takes `&self` rather than `&mut self`. set_permissions(&self, perm: Permissions) -> io::Result<()>183 pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> { 184 let file = self.file.clone(); 185 async_op(move || file.set_permissions(perm)).await 186 } 187 188 /// Attempts to sync all OS-internal metadata to disk asynchronously. 189 /// 190 /// This function will attempt to ensure that all in-memory data reaches the 191 /// filesystem before returning. 192 /// 193 /// This can be used to handle errors that would otherwise only be caught 194 /// when the `File` is closed. Dropping a file will ignore errors in 195 /// synchronizing this in-memory data. 196 /// 197 /// # Examples 198 /// 199 /// ```no_run 200 /// use ylong_runtime::fs::File; 201 /// use ylong_runtime::io::AsyncWriteExt; 202 /// 203 /// async fn sync_all() -> std::io::Result<()> { 204 /// let mut f = File::create("foo.txt").await?; 205 /// f.write_all(b"Hello, world!").await?; 206 /// 207 /// f.sync_all().await?; 208 /// Ok(()) 209 /// } 210 /// ``` sync_all(&self) -> io::Result<()>211 pub async fn sync_all(&self) -> io::Result<()> { 212 let mut file = self.inner.lock().await; 213 if let Err(e) = poll_fn(|cx| Pin::new(&mut *file).poll_flush(cx)).await { 214 file.write_err = Some(e.kind()); 215 } 216 let file = self.file.clone(); 217 async_op(move || file.sync_all()).await 218 } 219 220 /// This function is similar to [`File::sync_all`], except that it might not 221 /// synchronize file metadata to the filesystem. 222 /// 223 /// This is intended for use cases that must synchronize content, but don't 224 /// need the metadata on disk. The goal of this method is to reduce disk 225 /// operations. 226 /// 227 /// # Examples 228 /// 229 /// ```no_run 230 /// use ylong_runtime::fs::File; 231 /// use ylong_runtime::io::AsyncWriteExt; 232 /// 233 /// async fn sync_data() -> std::io::Result<()> { 234 /// let mut f = File::create("foo.txt").await?; 235 /// f.write_all(b"Hello, world!").await?; 236 /// 237 /// f.sync_data().await?; 238 /// Ok(()) 239 /// } 240 /// ``` sync_data(&self) -> io::Result<()>241 pub async fn sync_data(&self) -> io::Result<()> { 242 let mut file = self.inner.lock().await; 243 if let Err(e) = poll_fn(|cx| Pin::new(&mut *file).poll_flush(cx)).await { 244 file.write_err = Some(e.kind()); 245 } 246 let file = self.file.clone(); 247 async_op(move || file.sync_data()).await 248 } 249 250 /// Truncates or extends the underlying file, updating the size of this file 251 /// to become size. If the size is less than the current file's size, 252 /// then the file will be shrunk. If it is greater than the current file's 253 /// size, then the file will be extended to size and have all of the 254 /// intermediate data filled in with 0s. The file's cursor isn't 255 /// changed. In particular, if the cursor was at the end and the file is 256 /// shrunk using this operation, the cursor will now be past the end. 257 /// 258 /// # Errors 259 /// 260 /// This function will return an error if the file is not opened for 261 /// writing. 262 /// 263 /// # Example 264 /// 265 /// ```no_run 266 /// use ylong_runtime::fs::File; 267 /// 268 /// async fn set_len() -> std::io::Result<()> { 269 /// let mut f = File::create("foo.txt").await?; 270 /// f.set_len(10).await?; 271 /// 272 /// Ok(()) 273 /// } 274 /// ``` set_len(&self, size: u64) -> io::Result<()>275 pub async fn set_len(&self, size: u64) -> io::Result<()> { 276 let mut file = self.inner.lock().await; 277 if let Err(e) = poll_fn(|cx| Pin::new(&mut *file).poll_flush(cx)).await { 278 file.write_err = Some(e.kind()); 279 } 280 281 let mut buf = match file.state { 282 // after each take, buf will be set right back 283 FileState::Idle(ref mut buf) => buf.take().unwrap(), 284 _ => unreachable!(), 285 }; 286 287 let arc_file = self.file.clone(); 288 289 let (buf, res) = spawn_blocking(&TaskBuilder::new(), move || { 290 let res = if buf.remaining() == 0 { 291 (&*arc_file) 292 .seek(SeekFrom::Current(buf.drop_unread())) 293 .and_then(|_| arc_file.set_len(size)) 294 } else { 295 arc_file.set_len(size) 296 } 297 .map(|_| 0); 298 299 (buf, res) 300 }) 301 .await?; 302 303 file.state = FileState::Idle(Some(buf)); 304 305 res.map(|u| file.idx = u) 306 } 307 308 /// Queries metadata about the underlying file asynchronously. 309 /// 310 /// # Examples 311 /// 312 /// ```no_run 313 /// use ylong_runtime::fs::File; 314 /// 315 /// async fn metadata() -> std::io::Result<()> { 316 /// let mut f = File::open("foo.txt").await?; 317 /// let metadata = f.metadata().await?; 318 /// Ok(()) 319 /// } 320 /// ``` metadata(&self) -> io::Result<Metadata>321 pub async fn metadata(&self) -> io::Result<Metadata> { 322 let file = self.file.clone(); 323 async_op(move || file.metadata()).await 324 } 325 326 /// Creates a new File instance that shares the same underlying file handle 327 /// as the existing File instance. Reads, writes, and seeks will affect both 328 /// File instances simultaneously. 329 /// 330 /// # Example 331 /// 332 /// ```no_run 333 /// use ylong_runtime::fs::File; 334 /// 335 /// async fn try_clone() -> std::io::Result<()> { 336 /// let mut f = File::open("foo.txt").await?; 337 /// let file_copy = f.try_clone().await?; 338 /// Ok(()) 339 /// } 340 /// ``` try_clone(&self) -> io::Result<File>341 pub async fn try_clone(&self) -> io::Result<File> { 342 let file = self.file.clone(); 343 let file = async_op(move || file.try_clone()).await?; 344 Ok(Self::new(file)) 345 } 346 347 /// Sets the buffer size limit for [`AsyncRead`] and [`AsyncWrite`] 348 /// operation of this file. 349 /// 350 /// # Examples 351 /// 352 /// ```no_run 353 /// # async fn set_file_buffer_limit() { 354 /// use ylong_runtime::fs::File; 355 /// use ylong_runtime::io::{AsyncReadExt, AsyncWriteExt}; 356 /// let mut file = File::open("foo.txt").await.unwrap(); 357 /// file.set_buffer_size_limit(1024 * 1024 * 2); 358 /// let mut buf = vec![0; 1024 * 1024 * 16]; 359 /// // write the buffer in chunks up to 2MB each 360 /// let _ = file.write_all(&mut buf).await; 361 /// let _ = file.sync_all().await; 362 /// 363 /// let mut file = File::open("foo.txt").await.unwrap(); 364 /// file.set_buffer_size_limit(1024 * 1024 * 2); 365 /// let mut read_buf = vec![]; 366 /// // read the file in chunks up to 2MB each 367 /// let _ = file.read_to_end(&mut read_buf); 368 /// # } 369 /// ``` set_buffer_size_limit(&mut self, buf_size_limit: usize)370 pub fn set_buffer_size_limit(&mut self, buf_size_limit: usize) { 371 self.buf_size_limit = buf_size_limit; 372 } 373 } 374 375 impl AsyncSeek for File { poll_seek( self: Pin<&mut Self>, cx: &mut Context<'_>, mut pos: SeekFrom, ) -> Poll<io::Result<u64>>376 fn poll_seek( 377 self: Pin<&mut Self>, 378 cx: &mut Context<'_>, 379 mut pos: SeekFrom, 380 ) -> Poll<io::Result<u64>> { 381 let file = self.get_mut(); 382 let inner = file.inner.get_mut(); 383 loop { 384 match inner.state { 385 FileState::Idle(ref mut buf) => { 386 // after each take, buf will be set right back 387 let mut r_buf = buf.take().unwrap(); 388 389 // move the cursor back since there's unread data in the buf 390 let unread = r_buf.drop_unread(); 391 if unread != 0 { 392 if let SeekFrom::Current(ref mut idx) = pos { 393 *idx -= unread 394 } 395 } 396 397 let file = file.file.clone(); 398 inner.state = 399 FileState::Seeking(spawn_blocking(&TaskBuilder::new(), move || { 400 let ret = (&*file).seek(pos); 401 (r_buf, ret) 402 })); 403 } 404 ref mut state => { 405 let op = state.get_op(); 406 let res = poll_ready!(Pin::new(state).poll(cx)); 407 match op { 408 FileOp::Reading => {} 409 FileOp::Writing => { 410 if let Err(e) = res { 411 // Save the error for the next write. 412 inner.write_err = Some(e.kind()); 413 } 414 } 415 FileOp::Seeking => { 416 if let Ok(idx) = res { 417 inner.idx = idx; 418 } 419 return Poll::Ready(res); 420 } 421 } 422 } 423 } 424 } 425 } 426 } 427 428 impl AsyncRead for File { poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<io::Result<()>>429 fn poll_read( 430 self: Pin<&mut Self>, 431 cx: &mut Context<'_>, 432 buf: &mut ReadBuf<'_>, 433 ) -> Poll<io::Result<()>> { 434 let file = self.get_mut(); 435 let inner = file.inner.get_mut(); 436 437 loop { 438 match inner.state { 439 FileState::Idle(ref mut file_buf) => { 440 // after each take, buf will be set right back 441 let mut r_buf = file_buf.take().unwrap(); 442 // There is still remaining data from the last read, append it to read buf 443 // directly 444 if r_buf.remaining() != 0 { 445 r_buf.append_to(buf); 446 *file_buf = Some(r_buf); 447 return Poll::Ready(Ok(())); 448 } 449 450 // Make sure there is enough space to read. File_buf's size might be bigger than 451 // the read_buf's size since other thread might also read into the read_buf. 452 r_buf.reserve(buf.remaining(), file.buf_size_limit); 453 454 // State transition 455 let file = file.file.clone(); 456 inner.state = 457 FileState::Reading(spawn_blocking(&TaskBuilder::new(), move || { 458 let ret = r_buf.read(&mut &*file).map(|_| ()); 459 (r_buf, ret) 460 })); 461 } 462 FileState::Reading(ref mut x) => { 463 let (mut file_buf, res) = poll_ready!(Pin::new(x).poll(cx))?; 464 // Append the data inside the file to the read buffer 465 if res.is_ok() { 466 file_buf.append_to(buf); 467 } 468 inner.state = FileState::Idle(Some(file_buf)); 469 return Poll::Ready(res); 470 } 471 FileState::Writing(ref mut x) => { 472 let (file_buf, res) = poll_ready!(Pin::new(x).poll(cx))?; 473 474 // Save the error for the next write 475 if let Err(e) = res { 476 inner.write_err = Some(e.kind()); 477 } 478 inner.state = FileState::Idle(Some(file_buf)) 479 } 480 FileState::Seeking(ref mut x) => { 481 let (file_buf, res) = poll_ready!(Pin::new(x).poll(cx))?; 482 inner.state = FileState::Idle(Some(file_buf)); 483 if let Ok(idx) = res { 484 inner.idx = idx; 485 } 486 } 487 } 488 } 489 } 490 } 491 492 impl AsyncWrite for File { poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll<io::Result<usize>>493 fn poll_write( 494 self: Pin<&mut Self>, 495 cx: &mut Context<'_>, 496 buf: &[u8], 497 ) -> Poll<io::Result<usize>> { 498 let file = self.get_mut(); 499 let inner = file.inner.get_mut(); 500 501 if let Some(e) = inner.write_err { 502 return Poll::Ready(Err(e.into())); 503 } 504 505 loop { 506 match inner.state { 507 FileState::Idle(ref mut file_buf) => { 508 // after each take, buf will be set right back 509 let mut w_buf = file_buf.take().unwrap(); 510 511 let unread = w_buf.drop_unread(); 512 let n = w_buf.append(buf, file.buf_size_limit); 513 let file = file.file.clone(); 514 515 inner.state = 516 FileState::Writing(spawn_blocking(&TaskBuilder::new(), move || { 517 // Move the cursor back since there's unread data in the buf. 518 if unread != 0 { 519 if let Err(e) = (&*file).seek(SeekFrom::Current(-unread)) { 520 return (w_buf, Err(e)); 521 } 522 } 523 let res = w_buf.write(&mut &*file); 524 (w_buf, res) 525 })); 526 return Poll::Ready(Ok(n)); 527 } 528 ref mut state => { 529 let op = state.get_op(); 530 if let Poll::Ready(Err(e)) = Pin::new(state).poll(cx) { 531 if let FileOp::Writing = op { 532 return Poll::Ready(Err(e)); 533 } 534 } 535 } 536 } 537 } 538 } 539 poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>540 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { 541 self.inner.get_mut().poll_flush(cx) 542 } 543 poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>>544 fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> { 545 self.poll_flush(cx) 546 } 547 } 548 549 impl FileInner { poll_flush(&mut self, cx: &mut Context) -> Poll<io::Result<()>>550 fn poll_flush(&mut self, cx: &mut Context) -> Poll<io::Result<()>> { 551 if let Some(e) = self.write_err { 552 return Poll::Ready(Err(e.into())); 553 } 554 555 match self.state { 556 FileState::Idle(_) => Poll::Ready(Ok(())), 557 ref mut state => { 558 let op = state.get_op(); 559 let res = poll_ready!(Pin::new(state).poll(cx)); 560 561 match op { 562 FileOp::Writing => Poll::Ready(res.map(|_| ())), 563 _ => Poll::Ready(Ok(())), 564 } 565 } 566 } 567 } 568 } 569 570 #[cfg(test)] 571 mod test { 572 use std::io; 573 use std::io::SeekFrom; 574 575 use crate::fs::async_file::DEFAULT_BUF_LIMIT; 576 use crate::fs::{remove_file, File}; 577 use crate::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt}; 578 579 /// UT test for `set_len` 580 /// 581 /// # Brief 582 /// 583 /// 1. Creates a new file. 584 /// 2. Removes the file with `set_len()`, check result is Ok(()). 585 /// 3. Deletes the file. 586 #[test] ut_fs_file_set_len()587 fn ut_fs_file_set_len() { 588 crate::block_on(async { 589 let file_path = "file11.txt"; 590 591 let file = File::create(file_path).await.unwrap(); 592 let res = file.set_len(10).await; 593 assert!(res.is_ok()); 594 595 let res = remove_file(file_path).await; 596 assert!(res.is_ok()); 597 }); 598 } 599 600 /// UT test for `try_clone` 601 /// 602 /// # Brief 603 /// 604 /// 1. Creates a new file. 605 /// 2. Creates a new File instance with `try_clone()`, check result is 606 /// Ok(()). 607 /// 3. Deletes the file. 608 #[test] ut_fs_file_try_clone()609 fn ut_fs_file_try_clone() { 610 crate::block_on(async { 611 let file_path = "file12.txt"; 612 613 let file = File::create(file_path).await.unwrap(); 614 let res = file.try_clone().await; 615 assert!(res.is_ok()); 616 617 let res = remove_file(file_path).await; 618 assert!(res.is_ok()); 619 }); 620 } 621 622 /// UT test cases for asynchronous file Seek 623 /// 624 /// # Brief 625 /// 1. Generate an asynchronous file IO with create. 626 /// 2. Start a task to perform a write operation. 627 /// 3. Start another task for seek and read operations. 628 #[test] ut_fs_file_seek()629 fn ut_fs_file_seek() { 630 let file_path = "file13.txt"; 631 let handle = crate::spawn(async move { 632 let mut file = File::create(file_path).await.unwrap(); 633 let buf = vec![65, 66, 67, 68, 69, 70, 71, 72, 73]; 634 let res = file.write(&buf).await.unwrap(); 635 assert_eq!(res, 9); 636 file.sync_all().await.unwrap(); 637 }); 638 crate::block_on(handle).unwrap(); 639 640 let handle2 = crate::spawn(async move { 641 let mut file = File::open(file_path).await.unwrap(); 642 let ret = file.seek(SeekFrom::Current(3)).await.unwrap(); 643 assert_eq!(ret, 3); 644 645 let mut buf = [0; 1]; 646 let ret = file.read(&mut buf).await.unwrap(); 647 assert_eq!(ret, 1); 648 assert_eq!(buf, [68]); 649 650 let ret = file.seek(SeekFrom::Current(1)).await.unwrap(); 651 assert_eq!(ret, 5); 652 653 let mut buf = [0; 1]; 654 let ret = file.read(&mut buf).await.unwrap(); 655 assert_eq!(ret, 1); 656 assert_eq!(buf, [70]); 657 658 let ret = file.seek(SeekFrom::Current(2)).await.unwrap(); 659 assert_eq!(ret, 8); 660 661 let mut buf = [0; 2]; 662 let ret = file.read(&mut buf).await.unwrap(); 663 assert_eq!(ret, 1); 664 assert_eq!(buf, [73, 0]); 665 666 let ret = file.seek(SeekFrom::Start(0)).await.unwrap(); 667 assert_eq!(ret, 0); 668 let mut buf = [0; 9]; 669 let ret = file.read(&mut buf).await.unwrap(); 670 assert_eq!(ret, 9); 671 assert_eq!(buf, [65, 66, 67, 68, 69, 70, 71, 72, 73]); 672 673 let ret = file.seek(SeekFrom::End(-1)).await.unwrap(); 674 assert_eq!(ret, 8); 675 let mut buf = [0; 2]; 676 let ret = file.read(&mut buf).await.unwrap(); 677 assert_eq!(ret, 1); 678 assert_eq!(buf, [73, 0]); 679 }); 680 681 crate::block_on(handle2).unwrap(); 682 std::fs::remove_file(file_path).unwrap(); 683 } 684 685 /// UT test cases for Asynchronous file set permission 686 /// 687 /// # Brief 688 /// 1. Generate an asynchronous file IO with create. 689 /// 2. Asynchronously get the permissions of the file. 690 /// 3. Change the permission to read only, set it to this file. 691 #[test] ut_fs_file_set_permission()692 fn ut_fs_file_set_permission() { 693 let file_path = "file14.txt"; 694 let handle = crate::spawn(async move { 695 let file = File::create(file_path).await.unwrap(); 696 let mut perms = file.metadata().await.unwrap().permissions(); 697 perms.set_readonly(true); 698 let ret = file.set_permissions(perms).await; 699 assert!(ret.is_ok()); 700 let mut perms = file.metadata().await.unwrap().permissions(); 701 #[allow(clippy::permissions_set_readonly_false)] 702 perms.set_readonly(false); 703 let ret = file.set_permissions(perms).await; 704 assert!(ret.is_ok()); 705 }); 706 crate::block_on(handle).unwrap(); 707 std::fs::remove_file(file_path).unwrap(); 708 } 709 710 /// UT test cases for asynchronous file sync 711 /// 712 /// # Brief 713 /// 1. Generate an asynchronous file IO with create. 714 /// 2. Call sync_all and sync_data after asynchronous write. 715 #[test] ut_fs_file_sync_all()716 fn ut_fs_file_sync_all() { 717 let file_path = "file15.txt"; 718 let handle = crate::spawn(async move { 719 let mut file = File::create(file_path).await.unwrap(); 720 let buf = [2; 20000]; 721 let ret = file.write_all(&buf).await; 722 assert!(ret.is_ok()); 723 let ret = file.sync_all().await; 724 assert!(ret.is_ok()); 725 726 let buf = [2; 20000]; 727 let ret = file.write_all(&buf).await; 728 assert!(ret.is_ok()); 729 let ret = file.sync_data().await; 730 assert!(ret.is_ok()); 731 }); 732 crate::block_on(handle).unwrap(); 733 std::fs::remove_file(file_path).unwrap(); 734 } 735 736 /// UT for setting the buffer's size limit 737 /// 738 /// # Brief 739 /// 1. Creates a new file, checks if its buffer size limit equals to 740 /// DEFAULT_BUF_LIMIT 2. Sets a new limit for file buffer 741 /// 3. Writes the entire buffer into the file 742 #[test] ut_fs_set_buf_size_limit()743 fn ut_fs_set_buf_size_limit() { 744 let file_path = "file16.txt"; 745 let handle = crate::spawn(async move { 746 let mut file = File::create(file_path).await.unwrap(); 747 assert_eq!(file.buf_size_limit, DEFAULT_BUF_LIMIT); 748 749 file.set_buffer_size_limit(1024 * 1024 * 4); 750 assert_eq!(file.buf_size_limit, 1024 * 1024 * 4); 751 752 let buf = [2; 20000]; 753 let ret = file.write_all(&buf).await; 754 assert!(ret.is_ok()); 755 let ret = file.sync_all().await; 756 assert!(ret.is_ok()); 757 }); 758 crate::block_on(handle).unwrap(); 759 std::fs::remove_file(file_path).unwrap(); 760 } 761 762 use std::fmt::{Debug, Formatter}; 763 764 impl Debug for File { fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result765 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 766 self.file.fmt(f) 767 } 768 } 769 770 /// UT for opening an non-existed file 771 /// 772 /// # Brief 773 /// 1. Open a file that does not exist 774 /// 2. Check if the returned error is NotFound 775 #[test] ut_fs_open_fail()776 fn ut_fs_open_fail() { 777 let handle = crate::spawn(async move { 778 let file = File::open("file_not_exist").await; 779 assert_eq!(file.unwrap_err().kind(), io::ErrorKind::NotFound); 780 }); 781 crate::block_on(handle).unwrap(); 782 } 783 } 784