1use super::super::Errno;
20use super::super::FileType;
21use super::FdFlag;
22use super::FileBody;
23use super::Inode;
24use enumset::EnumSet;
25use std::cell::Cell;
26use std::cell::RefCell;
27use std::fmt::Debug;
28use std::io::SeekFrom;
29use std::rc::Rc;
30use std::rc::Weak;
31use std::task::Poll;
32use std::task::Waker;
33
34#[derive(Clone, Debug)]
36pub struct OpenFileDescription {
37 inode: Rc<RefCell<Inode>>,
39 offset: usize,
41 is_readable: bool,
43 is_writable: bool,
45 is_appending: bool,
47 is_nonblocking: bool,
49}
50
51impl Drop for OpenFileDescription {
52 fn drop(&mut self) {
53 let mut inode = self.inode.borrow_mut();
54 inode.body.close(self.is_readable, self.is_writable);
55 }
56}
57
58impl OpenFileDescription {
59 pub(crate) fn new(
61 inode: Rc<RefCell<Inode>>,
62 offset: usize,
63 is_readable: bool,
64 is_writable: bool,
65 is_appending: bool,
66 is_nonblocking: bool,
67 ) -> Self {
68 inode.borrow_mut().body.open(is_readable, is_writable);
69
70 Self {
71 inode,
72 offset,
73 is_readable,
74 is_writable,
75 is_appending,
76 is_nonblocking,
77 }
78 }
79
80 #[must_use]
82 pub fn inode(&self) -> &Rc<RefCell<Inode>> {
83 &self.inode
84 }
85
86 #[must_use]
88 pub fn is_readable(&self) -> bool {
89 self.is_readable
90 }
91
92 #[must_use]
94 pub fn is_writable(&self) -> bool {
95 self.is_writable
96 }
97
98 #[inline]
100 #[must_use]
101 pub fn is_nonblocking(&self) -> bool {
102 self.is_nonblocking
103 }
104
105 #[inline]
107 pub fn set_nonblocking(&mut self, is_nonblocking: bool) {
108 self.is_nonblocking = is_nonblocking
109 }
110
111 #[must_use]
114 pub fn is_ready_for_reading(&self) -> bool {
115 !self.is_readable || self.inode.borrow().body.is_ready_for_reading()
118 }
119
120 #[must_use]
123 pub fn is_ready_for_writing(&self) -> bool {
124 !self.is_writable || self.inode.borrow().body.is_ready_for_writing()
127 }
128
129 pub(super) fn register_reader_waker(&mut self, waker: Weak<Cell<Option<Waker>>>) {
136 self.inode.borrow_mut().body.register_reader_waker(waker);
137 }
138
139 pub(super) fn register_writer_waker(&mut self, waker: Weak<Cell<Option<Waker>>>) {
146 self.inode.borrow_mut().body.register_writer_waker(waker);
147 }
148
149 pub fn read(&mut self, buffer: &mut [u8]) -> Result<usize, Errno> {
157 match self.poll_read(buffer, Weak::new) {
158 Poll::Ready(result) => result,
159 Poll::Pending => Err(Errno::EAGAIN),
160 }
161 }
162
163 pub fn poll_read<F>(
185 &mut self,
186 buffer: &mut [u8],
187 mut get_waker: F,
188 ) -> Poll<Result<usize, Errno>>
189 where
190 F: FnMut() -> Weak<Cell<Option<Waker>>>,
191 {
192 if !self.is_readable {
193 return Poll::Ready(Err(Errno::EBADF));
194 }
195
196 let file = self.inode.borrow_mut();
197 let is_nonblocking = self.is_nonblocking;
198 let maybe_get_waker = move || {
199 if is_nonblocking {
200 Weak::new()
201 } else {
202 get_waker()
203 }
204 };
205
206 let poll = { file }
207 .body
208 .poll_read(buffer, self.offset, maybe_get_waker);
209
210 if is_nonblocking && poll.is_pending() {
211 return Poll::Ready(Err(Errno::EAGAIN));
212 }
213 if let Poll::Ready(Ok(count)) = poll {
214 self.offset += count;
215 }
216
217 poll
218 }
219
220 pub fn write(&mut self, buffer: &[u8]) -> Result<usize, Errno> {
224 match self.poll_write(buffer, Weak::new) {
225 Poll::Ready(result) => result,
226 Poll::Pending => Err(Errno::EAGAIN),
227 }
228 }
229
230 pub fn poll_write<F>(&mut self, buffer: &[u8], mut get_waker: F) -> Poll<Result<usize, Errno>>
252 where
253 F: FnMut() -> Weak<Cell<Option<Waker>>>,
254 {
255 if !self.is_writable {
256 return Poll::Ready(Err(Errno::EBADF));
257 }
258
259 let file = self.inode.borrow_mut();
260 let offset = if self.is_appending {
261 file.body.size()
262 } else {
263 self.offset
264 };
265 let is_nonblocking = self.is_nonblocking;
266 let maybe_get_waker = move || {
267 if is_nonblocking {
268 Weak::new()
269 } else {
270 get_waker()
271 }
272 };
273
274 let poll = { file }.body.poll_write(buffer, offset, maybe_get_waker);
275
276 if is_nonblocking && poll.is_pending() {
277 return Poll::Ready(Err(Errno::EAGAIN));
278 }
279 if let Poll::Ready(Ok(count)) = poll {
280 self.offset = offset + count;
281 }
282
283 poll
284 }
285
286 pub fn poll_write_full<F>(
310 &mut self,
311 buffer: &[u8],
312 bytes_written: &mut usize,
313 mut get_waker: F,
314 ) -> Poll<Result<usize, Errno>>
315 where
316 F: FnMut() -> Weak<Cell<Option<Waker>>>,
317 {
318 let loop_on_success =
322 !self.is_nonblocking && self.inode.borrow().body.r#type() == FileType::Fifo;
323 loop {
324 let remaining = &buffer[*bytes_written..];
325 if remaining.is_empty() {
326 return Poll::Ready(Ok(*bytes_written));
327 }
328 match self.poll_write(remaining, &mut get_waker) {
329 Poll::Ready(Ok(n)) => {
330 *bytes_written += n;
331 if !loop_on_success || n == 0 {
332 return Poll::Ready(Ok(*bytes_written));
333 }
334 }
336 Poll::Ready(Err(e)) => {
337 return Poll::Ready(if *bytes_written > 0 {
338 Ok(*bytes_written)
339 } else {
340 Err(e)
341 });
342 }
343 Poll::Pending => return Poll::Pending,
344 }
345 }
346 }
347
348 pub fn seek(&mut self, position: SeekFrom) -> Result<usize, Errno> {
350 let len = match &self.inode.borrow().body {
351 FileBody::Regular { content, .. } => content.len(),
352 FileBody::Directory { files, .. } => files.len(),
353 FileBody::Fifo { .. } => return Err(Errno::ESPIPE),
354 FileBody::Symlink { .. } | FileBody::Terminal { .. } => return Err(Errno::ENOTSUP),
355 };
356
357 let new_offset = match position {
358 SeekFrom::Start(offset) => offset.try_into().ok(),
359 SeekFrom::Current(offset) => offset
360 .try_into()
361 .ok()
362 .and_then(|offset| self.offset.checked_add_signed(offset)),
363 SeekFrom::End(offset) => offset
364 .try_into()
365 .ok()
366 .and_then(|offset| len.checked_add_signed(offset)),
367 };
368
369 let new_offset = new_offset.ok_or(Errno::EINVAL)?;
370 self.offset = new_offset;
371 Ok(new_offset)
372 }
373}
374
375#[derive(Clone, Debug)]
377pub struct FdBody {
378 pub open_file_description: Rc<RefCell<OpenFileDescription>>,
380 pub flags: EnumSet<FdFlag>,
382}
383
384impl PartialEq for FdBody {
385 fn eq(&self, rhs: &Self) -> bool {
386 Rc::ptr_eq(&self.open_file_description, &rhs.open_file_description)
387 && self.flags == rhs.flags
388 }
389}
390
391impl Eq for FdBody {}
392
393#[cfg(test)]
394mod tests {
395 use super::super::{Mode, PIPE_SIZE, WakerSet};
396 use super::*;
397 use assert_matches::assert_matches;
398 use std::collections::VecDeque;
399
400 #[test]
401 fn regular_file_read_unreadable() {
402 let mut open_file = OpenFileDescription {
403 inode: Rc::new(RefCell::new(Inode::new([]))),
404 offset: 0,
405 is_readable: false,
406 is_writable: false,
407 is_appending: false,
408 is_nonblocking: false,
409 };
410
411 let mut buffer = [0];
412 let result = open_file.read(&mut buffer);
413 assert_eq!(result, Err(Errno::EBADF));
414 }
415
416 #[test]
417 fn regular_file_read_more_than_content() {
418 let mut open_file = OpenFileDescription {
419 inode: Rc::new(RefCell::new(Inode::new([1, 2, 3]))),
420 offset: 1,
421 is_readable: true,
422 is_writable: false,
423 is_appending: false,
424 is_nonblocking: false,
425 };
426
427 let mut buffer = [0; 3];
428 let result = open_file.read(&mut buffer);
429 assert_eq!(result, Ok(2));
430 assert_eq!(open_file.offset, 3);
431 assert_eq!(buffer[..2], [2, 3]);
432 }
433
434 #[test]
435 fn fifo_nonblocking_read_not_ready() {
436 let fifo = Rc::new(RefCell::new(Inode {
437 body: FileBody::Fifo {
438 content: VecDeque::new(),
439 readers: 1,
440 writers: 1,
441 pending_open_wakers: WakerSet::new(),
442 pending_read_wakers: WakerSet::new(),
443 pending_write_wakers: WakerSet::new(),
444 },
445 permissions: Mode::default(),
446 }));
447 let mut open_file = OpenFileDescription::new(
448 fifo, 0, true, false,
449 false, true,
450 );
451
452 let mut buffer = [0; 4];
453 let result = open_file.poll_read(&mut buffer, || unreachable!());
454 assert_eq!(result, Poll::Ready(Err(Errno::EAGAIN)));
455 }
456
457 #[test]
458 fn fifo_nonblocking_read_ready() {
459 let fifo = Rc::new(RefCell::new(Inode {
460 body: FileBody::Fifo {
461 content: VecDeque::from([0, 1, 2, 3]),
462 readers: 1,
463 writers: 1,
464 pending_open_wakers: WakerSet::new(),
465 pending_read_wakers: WakerSet::new(),
466 pending_write_wakers: WakerSet::new(),
467 },
468 permissions: Mode::default(),
469 }));
470 let mut open_file = OpenFileDescription::new(
471 fifo, 0, true, false,
472 false, true,
473 );
474
475 let mut buffer = [0; 4];
476 let result = open_file.poll_read(&mut buffer, || unreachable!());
477 assert_eq!(result, Poll::Ready(Ok(4)));
478 assert_eq!(buffer, [0, 1, 2, 3]);
479 }
480
481 #[test]
482 fn regular_file_write_unwritable() {
483 let mut open_file = OpenFileDescription {
484 inode: Rc::new(RefCell::new(Inode::new([]))),
485 offset: 0,
486 is_readable: false,
487 is_writable: false,
488 is_appending: false,
489 is_nonblocking: false,
490 };
491
492 let result = open_file.write(&[0]);
493 assert_eq!(result, Err(Errno::EBADF));
494 }
495
496 #[test]
497 fn regular_file_write_more_than_content() {
498 let mut open_file = OpenFileDescription {
499 inode: Rc::new(RefCell::new(Inode::new([1, 2, 3]))),
500 offset: 1,
501 is_readable: false,
502 is_writable: true,
503 is_appending: false,
504 is_nonblocking: false,
505 };
506
507 let result = open_file.write(&[9, 8, 7, 6]);
508 assert_eq!(result, Ok(4));
509 assert_eq!(open_file.offset, 5);
510 assert_matches!(
511 &open_file.inode.borrow().body,
512 FileBody::Regular { content, .. } => {
513 assert_eq!(content[..], [1, 9, 8, 7, 6]);
514 }
515 );
516 }
517
518 #[test]
519 fn regular_file_write_appending() {
520 let mut open_file = OpenFileDescription {
521 inode: Rc::new(RefCell::new(Inode::new([1, 2, 3]))),
522 offset: 1,
523 is_readable: false,
524 is_writable: true,
525 is_appending: true,
526 is_nonblocking: false,
527 };
528
529 let result = open_file.write(&[4, 5]);
530 assert_eq!(result, Ok(2));
531 assert_eq!(open_file.offset, 5);
532 assert_matches!(
533 &open_file.inode.borrow().body,
534 FileBody::Regular { content, .. } => {
535 assert_eq!(content[..], [1, 2, 3, 4, 5]);
536 }
537 );
538 }
539
540 #[test]
541 fn fifo_nonblocking_write_not_ready() {
542 let fifo = Rc::new(RefCell::new(Inode {
543 body: FileBody::Fifo {
544 content: VecDeque::from([0; PIPE_SIZE]),
545 readers: 1,
546 writers: 1,
547 pending_open_wakers: WakerSet::new(),
548 pending_read_wakers: WakerSet::new(),
549 pending_write_wakers: WakerSet::new(),
550 },
551 permissions: Mode::default(),
552 }));
553 let mut open_file = OpenFileDescription::new(
554 fifo, 0, false, true,
555 false, true,
556 );
557
558 let result = open_file.poll_write(&[0; 4], || unreachable!());
559 assert_eq!(result, Poll::Ready(Err(Errno::EAGAIN)));
560 }
561
562 #[test]
563 fn fifo_nonblocking_write_ready() {
564 let fifo = Rc::new(RefCell::new(Inode {
565 body: FileBody::Fifo {
566 content: VecDeque::new(),
567 readers: 1,
568 writers: 1,
569 pending_open_wakers: WakerSet::new(),
570 pending_read_wakers: WakerSet::new(),
571 pending_write_wakers: WakerSet::new(),
572 },
573 permissions: Mode::default(),
574 }));
575 let mut open_file = OpenFileDescription::new(
576 fifo, 0, false, true,
577 false, true,
578 );
579
580 let result = open_file.poll_write(&[9; 4], || unreachable!());
581 assert_eq!(result, Poll::Ready(Ok(4)));
582 }
583
584 #[test]
585 fn poll_write_full_regular_file_returns_after_one_call() {
586 let mut open_file = OpenFileDescription {
590 inode: Rc::new(RefCell::new(Inode::new([]))),
591 offset: 0,
592 is_readable: false,
593 is_writable: true,
594 is_appending: false,
595 is_nonblocking: false,
596 };
597 let mut bytes_written = 0usize;
598 let buffer = [1, 2, 3, 4, 5];
599 let result = open_file.poll_write_full(&buffer, &mut bytes_written, || unreachable!());
600 assert_eq!(result, Poll::Ready(Ok(5)));
601 assert_eq!(bytes_written, 5);
602 assert_matches!(
603 &open_file.inode.borrow().body,
604 FileBody::Regular { content, .. } => {
605 assert_eq!(content[..], [1, 2, 3, 4, 5]);
606 }
607 );
608 }
609
610 #[test]
611 fn poll_write_full_blocking_fifo_loops_until_full() {
612 let fifo = Rc::new(RefCell::new(Inode {
616 body: FileBody::Fifo {
617 content: VecDeque::new(),
618 readers: 1,
619 writers: 1,
620 pending_open_wakers: WakerSet::new(),
621 pending_read_wakers: WakerSet::new(),
622 pending_write_wakers: WakerSet::new(),
623 },
624 permissions: Mode::default(),
625 }));
626 let mut open_file = OpenFileDescription::new(
627 fifo, 0, false, true,
628 false, false,
629 );
630
631 let buffer = [7u8; PIPE_SIZE + 1];
634 let waker_holder: Rc<Cell<Option<Waker>>> = Rc::new(Cell::new(Some(Waker::noop().clone())));
635 let mut bytes_written = 0usize;
636 let result =
637 open_file.poll_write_full(&buffer, &mut bytes_written, || Rc::downgrade(&waker_holder));
638 assert_eq!(result, Poll::Pending);
639 assert_eq!(bytes_written, PIPE_SIZE);
640 }
641
642 #[test]
643 fn poll_write_full_nonblocking_fifo_returns_after_one_chunk() {
644 let fifo = Rc::new(RefCell::new(Inode {
647 body: FileBody::Fifo {
648 content: VecDeque::new(),
649 readers: 1,
650 writers: 1,
651 pending_open_wakers: WakerSet::new(),
652 pending_read_wakers: WakerSet::new(),
653 pending_write_wakers: WakerSet::new(),
654 },
655 permissions: Mode::default(),
656 }));
657 let mut open_file = OpenFileDescription::new(
658 fifo, 0, false, true,
659 false, true,
660 );
661
662 let buffer = [3u8; PIPE_SIZE * 2];
663 let mut bytes_written = 0usize;
664 let result = open_file.poll_write_full(&buffer, &mut bytes_written, || unreachable!());
665 assert_eq!(result, Poll::Ready(Ok(PIPE_SIZE)));
668 assert_eq!(bytes_written, PIPE_SIZE);
669 }
670
671 #[test]
672 fn regular_file_seek_from_start() {
673 let mut open_file = OpenFileDescription {
674 inode: Rc::new(RefCell::new(Inode::new([]))),
675 offset: 3,
676 is_readable: true,
677 is_writable: true,
678 is_appending: false,
679 is_nonblocking: false,
680 };
681
682 let result = open_file.seek(SeekFrom::Start(10));
683 assert_eq!(result, Ok(10));
684 assert_eq!(open_file.offset, 10);
685
686 let result = open_file.seek(SeekFrom::Start(0));
687 assert_eq!(result, Ok(0));
688 assert_eq!(open_file.offset, 0);
689
690 let result = open_file.seek(SeekFrom::Start(3));
691 assert_eq!(result, Ok(3));
692 assert_eq!(open_file.offset, 3);
693 }
694
695 #[test]
696 fn regular_file_seek_from_current() {
697 let mut open_file = OpenFileDescription {
698 inode: Rc::new(RefCell::new(Inode::new([]))),
699 offset: 5,
700 is_readable: true,
701 is_writable: true,
702 is_appending: false,
703 is_nonblocking: false,
704 };
705
706 let result = open_file.seek(SeekFrom::Current(10));
707 assert_eq!(result, Ok(15));
708 assert_eq!(open_file.offset, 15);
709
710 let result = open_file.seek(SeekFrom::Current(0));
711 assert_eq!(result, Ok(15));
712 assert_eq!(open_file.offset, 15);
713
714 let result = open_file.seek(SeekFrom::Current(-5));
715 assert_eq!(result, Ok(10));
716 assert_eq!(open_file.offset, 10);
717
718 let result = open_file.seek(SeekFrom::Current(-11));
719 assert_eq!(result, Err(Errno::EINVAL));
720 assert_eq!(open_file.offset, 10);
721 }
722
723 #[test]
724 fn regular_file_seek_from_end() {
725 let mut open_file = OpenFileDescription {
726 inode: Rc::new(RefCell::new(Inode::new([1, 2, 3]))),
727 offset: 2,
728 is_readable: true,
729 is_writable: true,
730 is_appending: false,
731 is_nonblocking: false,
732 };
733
734 let result = open_file.seek(SeekFrom::End(7));
735 assert_eq!(result, Ok(10));
736 assert_eq!(open_file.offset, 10);
737
738 let result = open_file.seek(SeekFrom::End(0));
739 assert_eq!(result, Ok(3));
740 assert_eq!(open_file.offset, 3);
741
742 let result = open_file.seek(SeekFrom::End(-3));
743 assert_eq!(result, Ok(0));
744 assert_eq!(open_file.offset, 0);
745
746 let result = open_file.seek(SeekFrom::End(-4));
747 assert_eq!(result, Err(Errno::EINVAL));
748 assert_eq!(open_file.offset, 0);
749 }
750
751 #[test]
752 fn fifo_reader_drop() {
753 let file = Rc::new(RefCell::new(Inode {
754 body: FileBody::Fifo {
755 content: VecDeque::new(),
756 readers: 1,
757 writers: 1,
758 pending_open_wakers: WakerSet::new(),
759 pending_read_wakers: WakerSet::new(),
760 pending_write_wakers: WakerSet::new(),
761 },
762 permissions: Mode::default(),
763 }));
764 let open_file = OpenFileDescription {
765 inode: Rc::clone(&file),
766 offset: 0,
767 is_readable: true,
768 is_writable: false,
769 is_appending: false,
770 is_nonblocking: false,
771 };
772 drop(open_file);
773
774 assert_matches!(&file.borrow().body, FileBody::Fifo { readers, writers, .. } => {
775 assert_eq!(*readers, 0);
776 assert_eq!(*writers, 1);
777 });
778 }
779
780 #[test]
781 fn fifo_writer_drop() {
782 let file = Rc::new(RefCell::new(Inode {
783 body: FileBody::Fifo {
784 content: VecDeque::new(),
785 readers: 1,
786 writers: 1,
787 pending_open_wakers: WakerSet::new(),
788 pending_read_wakers: WakerSet::new(),
789 pending_write_wakers: WakerSet::new(),
790 },
791 permissions: Mode::default(),
792 }));
793 let open_file = OpenFileDescription {
794 inode: Rc::clone(&file),
795 offset: 0,
796 is_readable: false,
797 is_writable: true,
798 is_appending: false,
799 is_nonblocking: false,
800 };
801 drop(open_file);
802
803 assert_matches!(&file.borrow().body, FileBody::Fifo { readers, writers, .. } => {
804 assert_eq!(*readers, 1);
805 assert_eq!(*writers, 0);
806 });
807 }
808}