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 file: 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 file = self.file.borrow_mut();
54 file.body.close(self.is_readable, self.is_writable);
55 }
56}
57
58impl OpenFileDescription {
59 pub(crate) fn new(
61 file: 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 file.borrow_mut().body.open(is_readable, is_writable);
69
70 Self {
71 file,
72 offset,
73 is_readable,
74 is_writable,
75 is_appending,
76 is_nonblocking,
77 }
78 }
79
80 #[must_use]
82 pub(crate) fn file(&self) -> &Rc<RefCell<Inode>> {
83 &self.file
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.file.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.file.borrow().body.is_ready_for_writing()
127 }
128
129 pub(super) fn register_reader_waker(&mut self, waker: Weak<Cell<Option<Waker>>>) {
136 self.file.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.file.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.file.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.file.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.file.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.file.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 #[must_use]
376 pub fn inode(&self) -> &Rc<RefCell<Inode>> {
377 &self.file
378 }
379}
380
381#[derive(Clone, Debug)]
383pub struct FdBody {
384 pub open_file_description: Rc<RefCell<OpenFileDescription>>,
386 pub flags: EnumSet<FdFlag>,
388}
389
390impl PartialEq for FdBody {
391 fn eq(&self, rhs: &Self) -> bool {
392 Rc::ptr_eq(&self.open_file_description, &rhs.open_file_description)
393 && self.flags == rhs.flags
394 }
395}
396
397impl Eq for FdBody {}
398
399#[cfg(test)]
400mod tests {
401 use super::super::{Mode, PIPE_SIZE, WakerSet};
402 use super::*;
403 use assert_matches::assert_matches;
404 use std::collections::VecDeque;
405
406 #[test]
407 fn regular_file_read_unreadable() {
408 let mut open_file = OpenFileDescription {
409 file: Rc::new(RefCell::new(Inode::new([]))),
410 offset: 0,
411 is_readable: false,
412 is_writable: false,
413 is_appending: false,
414 is_nonblocking: false,
415 };
416
417 let mut buffer = [0];
418 let result = open_file.read(&mut buffer);
419 assert_eq!(result, Err(Errno::EBADF));
420 }
421
422 #[test]
423 fn regular_file_read_more_than_content() {
424 let mut open_file = OpenFileDescription {
425 file: Rc::new(RefCell::new(Inode::new([1, 2, 3]))),
426 offset: 1,
427 is_readable: true,
428 is_writable: false,
429 is_appending: false,
430 is_nonblocking: false,
431 };
432
433 let mut buffer = [0; 3];
434 let result = open_file.read(&mut buffer);
435 assert_eq!(result, Ok(2));
436 assert_eq!(open_file.offset, 3);
437 assert_eq!(buffer[..2], [2, 3]);
438 }
439
440 #[test]
441 fn fifo_nonblocking_read_not_ready() {
442 let fifo = Rc::new(RefCell::new(Inode {
443 body: FileBody::Fifo {
444 content: VecDeque::new(),
445 readers: 1,
446 writers: 1,
447 pending_open_wakers: WakerSet::new(),
448 pending_read_wakers: WakerSet::new(),
449 pending_write_wakers: WakerSet::new(),
450 },
451 permissions: Mode::default(),
452 }));
453 let mut open_file = OpenFileDescription::new(
454 fifo, 0, true, false,
455 false, true,
456 );
457
458 let mut buffer = [0; 4];
459 let result = open_file.poll_read(&mut buffer, || unreachable!());
460 assert_eq!(result, Poll::Ready(Err(Errno::EAGAIN)));
461 }
462
463 #[test]
464 fn fifo_nonblocking_read_ready() {
465 let fifo = Rc::new(RefCell::new(Inode {
466 body: FileBody::Fifo {
467 content: VecDeque::from([0, 1, 2, 3]),
468 readers: 1,
469 writers: 1,
470 pending_open_wakers: WakerSet::new(),
471 pending_read_wakers: WakerSet::new(),
472 pending_write_wakers: WakerSet::new(),
473 },
474 permissions: Mode::default(),
475 }));
476 let mut open_file = OpenFileDescription::new(
477 fifo, 0, true, false,
478 false, true,
479 );
480
481 let mut buffer = [0; 4];
482 let result = open_file.poll_read(&mut buffer, || unreachable!());
483 assert_eq!(result, Poll::Ready(Ok(4)));
484 assert_eq!(buffer, [0, 1, 2, 3]);
485 }
486
487 #[test]
488 fn regular_file_write_unwritable() {
489 let mut open_file = OpenFileDescription {
490 file: Rc::new(RefCell::new(Inode::new([]))),
491 offset: 0,
492 is_readable: false,
493 is_writable: false,
494 is_appending: false,
495 is_nonblocking: false,
496 };
497
498 let result = open_file.write(&[0]);
499 assert_eq!(result, Err(Errno::EBADF));
500 }
501
502 #[test]
503 fn regular_file_write_more_than_content() {
504 let mut open_file = OpenFileDescription {
505 file: Rc::new(RefCell::new(Inode::new([1, 2, 3]))),
506 offset: 1,
507 is_readable: false,
508 is_writable: true,
509 is_appending: false,
510 is_nonblocking: false,
511 };
512
513 let result = open_file.write(&[9, 8, 7, 6]);
514 assert_eq!(result, Ok(4));
515 assert_eq!(open_file.offset, 5);
516 assert_matches!(
517 &open_file.file.borrow().body,
518 FileBody::Regular { content, .. } => {
519 assert_eq!(content[..], [1, 9, 8, 7, 6]);
520 }
521 );
522 }
523
524 #[test]
525 fn regular_file_write_appending() {
526 let mut open_file = OpenFileDescription {
527 file: Rc::new(RefCell::new(Inode::new([1, 2, 3]))),
528 offset: 1,
529 is_readable: false,
530 is_writable: true,
531 is_appending: true,
532 is_nonblocking: false,
533 };
534
535 let result = open_file.write(&[4, 5]);
536 assert_eq!(result, Ok(2));
537 assert_eq!(open_file.offset, 5);
538 assert_matches!(
539 &open_file.file.borrow().body,
540 FileBody::Regular { content, .. } => {
541 assert_eq!(content[..], [1, 2, 3, 4, 5]);
542 }
543 );
544 }
545
546 #[test]
547 fn fifo_nonblocking_write_not_ready() {
548 let fifo = Rc::new(RefCell::new(Inode {
549 body: FileBody::Fifo {
550 content: VecDeque::from([0; PIPE_SIZE]),
551 readers: 1,
552 writers: 1,
553 pending_open_wakers: WakerSet::new(),
554 pending_read_wakers: WakerSet::new(),
555 pending_write_wakers: WakerSet::new(),
556 },
557 permissions: Mode::default(),
558 }));
559 let mut open_file = OpenFileDescription::new(
560 fifo, 0, false, true,
561 false, true,
562 );
563
564 let result = open_file.poll_write(&[0; 4], || unreachable!());
565 assert_eq!(result, Poll::Ready(Err(Errno::EAGAIN)));
566 }
567
568 #[test]
569 fn fifo_nonblocking_write_ready() {
570 let fifo = Rc::new(RefCell::new(Inode {
571 body: FileBody::Fifo {
572 content: VecDeque::new(),
573 readers: 1,
574 writers: 1,
575 pending_open_wakers: WakerSet::new(),
576 pending_read_wakers: WakerSet::new(),
577 pending_write_wakers: WakerSet::new(),
578 },
579 permissions: Mode::default(),
580 }));
581 let mut open_file = OpenFileDescription::new(
582 fifo, 0, false, true,
583 false, true,
584 );
585
586 let result = open_file.poll_write(&[9; 4], || unreachable!());
587 assert_eq!(result, Poll::Ready(Ok(4)));
588 }
589
590 #[test]
591 fn poll_write_full_regular_file_returns_after_one_call() {
592 let mut open_file = OpenFileDescription {
596 file: Rc::new(RefCell::new(Inode::new([]))),
597 offset: 0,
598 is_readable: false,
599 is_writable: true,
600 is_appending: false,
601 is_nonblocking: false,
602 };
603 let mut bytes_written = 0usize;
604 let buffer = [1, 2, 3, 4, 5];
605 let result = open_file.poll_write_full(&buffer, &mut bytes_written, || unreachable!());
606 assert_eq!(result, Poll::Ready(Ok(5)));
607 assert_eq!(bytes_written, 5);
608 assert_matches!(
609 &open_file.file.borrow().body,
610 FileBody::Regular { content, .. } => {
611 assert_eq!(content[..], [1, 2, 3, 4, 5]);
612 }
613 );
614 }
615
616 #[test]
617 fn poll_write_full_blocking_fifo_loops_until_full() {
618 let fifo = Rc::new(RefCell::new(Inode {
622 body: FileBody::Fifo {
623 content: VecDeque::new(),
624 readers: 1,
625 writers: 1,
626 pending_open_wakers: WakerSet::new(),
627 pending_read_wakers: WakerSet::new(),
628 pending_write_wakers: WakerSet::new(),
629 },
630 permissions: Mode::default(),
631 }));
632 let mut open_file = OpenFileDescription::new(
633 fifo, 0, false, true,
634 false, false,
635 );
636
637 let buffer = [7u8; PIPE_SIZE + 1];
640 let waker_holder: Rc<Cell<Option<Waker>>> = Rc::new(Cell::new(Some(Waker::noop().clone())));
641 let mut bytes_written = 0usize;
642 let result =
643 open_file.poll_write_full(&buffer, &mut bytes_written, || Rc::downgrade(&waker_holder));
644 assert_eq!(result, Poll::Pending);
645 assert_eq!(bytes_written, PIPE_SIZE);
646 }
647
648 #[test]
649 fn poll_write_full_nonblocking_fifo_returns_after_one_chunk() {
650 let fifo = Rc::new(RefCell::new(Inode {
653 body: FileBody::Fifo {
654 content: VecDeque::new(),
655 readers: 1,
656 writers: 1,
657 pending_open_wakers: WakerSet::new(),
658 pending_read_wakers: WakerSet::new(),
659 pending_write_wakers: WakerSet::new(),
660 },
661 permissions: Mode::default(),
662 }));
663 let mut open_file = OpenFileDescription::new(
664 fifo, 0, false, true,
665 false, true,
666 );
667
668 let buffer = [3u8; PIPE_SIZE * 2];
669 let mut bytes_written = 0usize;
670 let result = open_file.poll_write_full(&buffer, &mut bytes_written, || unreachable!());
671 assert_eq!(result, Poll::Ready(Ok(PIPE_SIZE)));
674 assert_eq!(bytes_written, PIPE_SIZE);
675 }
676
677 #[test]
678 fn regular_file_seek_from_start() {
679 let mut open_file = OpenFileDescription {
680 file: Rc::new(RefCell::new(Inode::new([]))),
681 offset: 3,
682 is_readable: true,
683 is_writable: true,
684 is_appending: false,
685 is_nonblocking: false,
686 };
687
688 let result = open_file.seek(SeekFrom::Start(10));
689 assert_eq!(result, Ok(10));
690 assert_eq!(open_file.offset, 10);
691
692 let result = open_file.seek(SeekFrom::Start(0));
693 assert_eq!(result, Ok(0));
694 assert_eq!(open_file.offset, 0);
695
696 let result = open_file.seek(SeekFrom::Start(3));
697 assert_eq!(result, Ok(3));
698 assert_eq!(open_file.offset, 3);
699 }
700
701 #[test]
702 fn regular_file_seek_from_current() {
703 let mut open_file = OpenFileDescription {
704 file: Rc::new(RefCell::new(Inode::new([]))),
705 offset: 5,
706 is_readable: true,
707 is_writable: true,
708 is_appending: false,
709 is_nonblocking: false,
710 };
711
712 let result = open_file.seek(SeekFrom::Current(10));
713 assert_eq!(result, Ok(15));
714 assert_eq!(open_file.offset, 15);
715
716 let result = open_file.seek(SeekFrom::Current(0));
717 assert_eq!(result, Ok(15));
718 assert_eq!(open_file.offset, 15);
719
720 let result = open_file.seek(SeekFrom::Current(-5));
721 assert_eq!(result, Ok(10));
722 assert_eq!(open_file.offset, 10);
723
724 let result = open_file.seek(SeekFrom::Current(-11));
725 assert_eq!(result, Err(Errno::EINVAL));
726 assert_eq!(open_file.offset, 10);
727 }
728
729 #[test]
730 fn regular_file_seek_from_end() {
731 let mut open_file = OpenFileDescription {
732 file: Rc::new(RefCell::new(Inode::new([1, 2, 3]))),
733 offset: 2,
734 is_readable: true,
735 is_writable: true,
736 is_appending: false,
737 is_nonblocking: false,
738 };
739
740 let result = open_file.seek(SeekFrom::End(7));
741 assert_eq!(result, Ok(10));
742 assert_eq!(open_file.offset, 10);
743
744 let result = open_file.seek(SeekFrom::End(0));
745 assert_eq!(result, Ok(3));
746 assert_eq!(open_file.offset, 3);
747
748 let result = open_file.seek(SeekFrom::End(-3));
749 assert_eq!(result, Ok(0));
750 assert_eq!(open_file.offset, 0);
751
752 let result = open_file.seek(SeekFrom::End(-4));
753 assert_eq!(result, Err(Errno::EINVAL));
754 assert_eq!(open_file.offset, 0);
755 }
756
757 #[test]
758 fn fifo_reader_drop() {
759 let file = Rc::new(RefCell::new(Inode {
760 body: FileBody::Fifo {
761 content: VecDeque::new(),
762 readers: 1,
763 writers: 1,
764 pending_open_wakers: WakerSet::new(),
765 pending_read_wakers: WakerSet::new(),
766 pending_write_wakers: WakerSet::new(),
767 },
768 permissions: Mode::default(),
769 }));
770 let open_file = OpenFileDescription {
771 file: Rc::clone(&file),
772 offset: 0,
773 is_readable: true,
774 is_writable: false,
775 is_appending: false,
776 is_nonblocking: false,
777 };
778 drop(open_file);
779
780 assert_matches!(&file.borrow().body, FileBody::Fifo { readers, writers, .. } => {
781 assert_eq!(*readers, 0);
782 assert_eq!(*writers, 1);
783 });
784 }
785
786 #[test]
787 fn fifo_writer_drop() {
788 let file = Rc::new(RefCell::new(Inode {
789 body: FileBody::Fifo {
790 content: VecDeque::new(),
791 readers: 1,
792 writers: 1,
793 pending_open_wakers: WakerSet::new(),
794 pending_read_wakers: WakerSet::new(),
795 pending_write_wakers: WakerSet::new(),
796 },
797 permissions: Mode::default(),
798 }));
799 let open_file = OpenFileDescription {
800 file: Rc::clone(&file),
801 offset: 0,
802 is_readable: false,
803 is_writable: true,
804 is_appending: false,
805 is_nonblocking: false,
806 };
807 drop(open_file);
808
809 assert_matches!(&file.borrow().body, FileBody::Fifo { readers, writers, .. } => {
810 assert_eq!(*readers, 1);
811 assert_eq!(*writers, 0);
812 });
813 }
814}