1use super::super::Errno;
20use super::FdFlag;
21use super::FileBody;
22use super::Inode;
23use enumset::EnumSet;
24use std::cell::RefCell;
25use std::fmt::Debug;
26use std::io::SeekFrom;
27use std::rc::Rc;
28
29pub const PIPE_BUF: usize = 512;
34
35pub const PIPE_SIZE: usize = PIPE_BUF * 2;
40
41#[derive(Clone, Debug)]
43#[non_exhaustive]
44pub struct OpenFileDescription {
45 pub(crate) file: Rc<RefCell<Inode>>,
47 pub(crate) offset: usize,
49 pub(crate) is_readable: bool,
51 pub(crate) is_writable: bool,
53 pub(crate) is_appending: bool,
55 }
58
59impl Drop for OpenFileDescription {
60 fn drop(&mut self) {
61 if let FileBody::Fifo {
62 readers, writers, ..
63 } = &mut self.file.borrow_mut().body
64 {
65 if self.is_readable {
66 *readers -= 1;
67 }
68 if self.is_writable {
69 *writers -= 1;
70 }
71 }
72 }
73}
74
75impl OpenFileDescription {
76 #[must_use]
78 pub fn is_readable(&self) -> bool {
79 self.is_readable
80 }
81
82 #[must_use]
84 pub fn is_writable(&self) -> bool {
85 self.is_writable
86 }
87
88 #[must_use]
91 pub fn is_ready_for_reading(&self) -> bool {
92 match &self.file.borrow().body {
93 FileBody::Regular { .. } | FileBody::Directory { .. } | FileBody::Terminal { .. } => {
94 true
95 }
96 FileBody::Fifo {
97 content, writers, ..
98 } => !self.is_readable || !content.is_empty() || *writers == 0,
99 FileBody::Symlink { target: _ } => false,
100 }
101 }
102
103 #[must_use]
106 pub fn is_ready_for_writing(&self) -> bool {
107 match &self.file.borrow().body {
108 FileBody::Regular { .. } | FileBody::Directory { .. } | FileBody::Terminal { .. } => {
109 true
110 }
111 FileBody::Fifo {
112 content, readers, ..
113 } => *readers == 0 || PIPE_SIZE - content.len() >= PIPE_BUF,
114 FileBody::Symlink { target: _ } => false,
115 }
116 }
117
118 pub fn read(&mut self, mut buffer: &mut [u8]) -> Result<usize, Errno> {
122 if !self.is_readable {
123 return Err(Errno::EBADF);
124 }
125 match &mut self.file.borrow_mut().body {
126 FileBody::Regular { content, .. } | FileBody::Terminal { content } => {
127 let len = content.len();
128 if self.offset >= len {
129 return Ok(0);
130 }
131 let limit = len - self.offset;
132 if buffer.len() > limit {
133 buffer = &mut buffer[..limit];
134 }
135 let count = buffer.len();
136 let src = &content[self.offset..][..count];
137 buffer.copy_from_slice(src);
138 self.offset += count;
139 Ok(count)
140 }
141 FileBody::Fifo {
142 content, writers, ..
143 } => {
144 let limit = content.len();
145 if limit == 0 && *writers > 0 {
146 return Err(Errno::EAGAIN);
147 }
148 let mut count = 0;
149 for to in buffer {
150 if let Some(from) = content.pop_front() {
151 *to = from;
152 count += 1;
153 } else {
154 break;
155 }
156 }
157 Ok(count)
158 }
159 FileBody::Directory { .. } => Err(Errno::EISDIR),
160 FileBody::Symlink { target: _ } => Err(Errno::ENOTSUP),
161 }
162 }
163
164 pub fn write(&mut self, mut buffer: &[u8]) -> Result<usize, Errno> {
168 if !self.is_writable {
169 return Err(Errno::EBADF);
170 }
171 match &mut self.file.borrow_mut().body {
172 FileBody::Regular { content, .. } | FileBody::Terminal { content } => {
173 let len = content.len();
174 let count = buffer.len();
175 if self.is_appending {
176 self.offset = len;
177 }
178 if self.offset > len {
179 let zeroes = self.offset - len;
180 content.reserve(zeroes + count);
181 content.resize_with(self.offset, u8::default);
182 }
183 let limit = count.min(content.len() - self.offset);
184 let dst = &mut content[self.offset..][..limit];
185 dst.copy_from_slice(&buffer[..limit]);
186 content.reserve(count - limit);
187 content.extend(&buffer[limit..]);
188 self.offset += count;
189 Ok(count)
190 }
191 FileBody::Fifo {
192 content, readers, ..
193 } => {
194 if *readers == 0 {
195 return Err(Errno::EPIPE);
197 }
198 let room = PIPE_SIZE - content.len();
199 if room < buffer.len() {
200 if room == 0 || buffer.len() <= PIPE_BUF {
201 return Err(Errno::EAGAIN);
202 }
203 buffer = &buffer[..room];
204 }
205 content.extend(buffer);
206 debug_assert!(content.len() <= PIPE_SIZE);
207 Ok(buffer.len())
208 }
209 FileBody::Directory { .. } => Err(Errno::EISDIR),
210 FileBody::Symlink { target: _ } => Err(Errno::ENOTSUP),
211 }
212 }
213
214 pub fn seek(&mut self, position: SeekFrom) -> Result<usize, Errno> {
216 let len = match &self.file.borrow().body {
217 FileBody::Regular { content, .. } => content.len(),
218 FileBody::Directory { files, .. } => files.len(),
219 FileBody::Fifo { .. } => return Err(Errno::ESPIPE),
220 FileBody::Symlink { .. } | FileBody::Terminal { .. } => return Err(Errno::ENOTSUP),
221 };
222
223 let new_offset = match position {
224 SeekFrom::Start(offset) => offset.try_into().ok(),
225 SeekFrom::Current(offset) => offset
226 .try_into()
227 .ok()
228 .and_then(|offset| self.offset.checked_add_signed(offset)),
229 SeekFrom::End(offset) => offset
230 .try_into()
231 .ok()
232 .and_then(|offset| len.checked_add_signed(offset)),
233 };
234
235 let new_offset = new_offset.ok_or(Errno::EINVAL)?;
236 self.offset = new_offset;
237 Ok(new_offset)
238 }
239
240 #[must_use]
242 pub fn inode(&self) -> &Rc<RefCell<Inode>> {
243 &self.file
244 }
245}
246
247#[derive(Clone, Debug)]
249pub struct FdBody {
250 pub open_file_description: Rc<RefCell<OpenFileDescription>>,
252 pub flags: EnumSet<FdFlag>,
254}
255
256impl PartialEq for FdBody {
257 fn eq(&self, rhs: &Self) -> bool {
258 Rc::ptr_eq(&self.open_file_description, &rhs.open_file_description)
259 && self.flags == rhs.flags
260 }
261}
262
263impl Eq for FdBody {}
264
265#[cfg(test)]
266mod tests {
267 use super::super::Mode;
268 use super::*;
269 use assert_matches::assert_matches;
270 use std::collections::VecDeque;
271
272 #[test]
273 fn regular_file_read_unreadable() {
274 let mut open_file = OpenFileDescription {
275 file: Rc::new(RefCell::new(Inode::new([]))),
276 offset: 0,
277 is_readable: false,
278 is_writable: false,
279 is_appending: false,
280 };
281
282 let mut buffer = [0];
283 let result = open_file.read(&mut buffer);
284 assert_eq!(result, Err(Errno::EBADF));
285 }
286
287 #[test]
288 fn regular_file_read_beyond_file_length() {
289 let mut open_file = OpenFileDescription {
290 file: Rc::new(RefCell::new(Inode::new([1]))),
291 offset: 1,
292 is_readable: true,
293 is_writable: false,
294 is_appending: false,
295 };
296
297 let mut buffer = [0];
298 let result = open_file.read(&mut buffer);
299 assert_eq!(result, Ok(0));
300 assert_eq!(open_file.offset, 1);
301
302 open_file.offset = 2;
303 let result = open_file.read(&mut buffer);
304 assert_eq!(result, Ok(0));
305 assert_eq!(open_file.offset, 2);
306 }
307
308 #[test]
309 fn regular_file_read_more_than_content() {
310 let mut open_file = OpenFileDescription {
311 file: Rc::new(RefCell::new(Inode::new([1, 2, 3]))),
312 offset: 1,
313 is_readable: true,
314 is_writable: false,
315 is_appending: false,
316 };
317
318 let mut buffer = [0; 3];
319 let result = open_file.read(&mut buffer);
320 assert_eq!(result, Ok(2));
321 assert_eq!(open_file.offset, 3);
322 assert_eq!(buffer[..2], [2, 3]);
323 }
324
325 #[test]
326 fn regular_file_read_less_than_content() {
327 let mut open_file = OpenFileDescription {
328 file: Rc::new(RefCell::new(Inode::new([1, 2, 3, 4, 5]))),
329 offset: 1,
330 is_readable: true,
331 is_writable: false,
332 is_appending: false,
333 };
334
335 let mut buffer = [0; 3];
336 let result = open_file.read(&mut buffer);
337 assert_eq!(result, Ok(3));
338 assert_eq!(open_file.offset, 4);
339 assert_eq!(buffer, [2, 3, 4]);
340 }
341
342 #[test]
343 fn regular_file_write_unwritable() {
344 let mut open_file = OpenFileDescription {
345 file: Rc::new(RefCell::new(Inode::new([]))),
346 offset: 0,
347 is_readable: false,
348 is_writable: false,
349 is_appending: false,
350 };
351
352 let result = open_file.write(&[0]);
353 assert_eq!(result, Err(Errno::EBADF));
354 }
355
356 #[test]
357 fn regular_file_write_less_than_content() {
358 let mut open_file = OpenFileDescription {
359 file: Rc::new(RefCell::new(Inode::new([1, 2, 3, 4, 5]))),
360 offset: 1,
361 is_readable: false,
362 is_writable: true,
363 is_appending: false,
364 };
365
366 let result = open_file.write(&[9, 8, 7]);
367 assert_eq!(result, Ok(3));
368 assert_eq!(open_file.offset, 4);
369 assert_matches!(
370 &open_file.file.borrow().body,
371 FileBody::Regular { content, .. } => {
372 assert_eq!(content[..], [1, 9, 8, 7, 5]);
373 }
374 );
375 }
376
377 #[test]
378 fn regular_file_write_more_than_content() {
379 let mut open_file = OpenFileDescription {
380 file: Rc::new(RefCell::new(Inode::new([1, 2, 3]))),
381 offset: 1,
382 is_readable: false,
383 is_writable: true,
384 is_appending: false,
385 };
386
387 let result = open_file.write(&[9, 8, 7, 6]);
388 assert_eq!(result, Ok(4));
389 assert_eq!(open_file.offset, 5);
390 assert_matches!(
391 &open_file.file.borrow().body,
392 FileBody::Regular { content, .. } => {
393 assert_eq!(content[..], [1, 9, 8, 7, 6]);
394 }
395 );
396 }
397
398 #[test]
399 fn regular_file_write_beyond_file_length() {
400 let mut open_file = OpenFileDescription {
401 file: Rc::new(RefCell::new(Inode::new([1]))),
402 offset: 3,
403 is_readable: false,
404 is_writable: true,
405 is_appending: false,
406 };
407
408 let result = open_file.write(&[2, 3]);
409 assert_eq!(result, Ok(2));
410 assert_eq!(open_file.offset, 5);
411 assert_matches!(
412 &open_file.file.borrow().body,
413 FileBody::Regular { content, .. } => {
414 assert_eq!(content[..], [1, 0, 0, 2, 3]);
415 }
416 );
417 }
418
419 #[test]
420 fn regular_file_write_appending() {
421 let mut open_file = OpenFileDescription {
422 file: Rc::new(RefCell::new(Inode::new([1, 2, 3]))),
423 offset: 1,
424 is_readable: false,
425 is_writable: true,
426 is_appending: true,
427 };
428
429 let result = open_file.write(&[4, 5]);
430 assert_eq!(result, Ok(2));
431 assert_eq!(open_file.offset, 5);
432 assert_matches!(
433 &open_file.file.borrow().body,
434 FileBody::Regular { content, .. } => {
435 assert_eq!(content[..], [1, 2, 3, 4, 5]);
436 }
437 );
438 }
439
440 #[test]
441 fn regular_file_seek_from_start() {
442 let mut open_file = OpenFileDescription {
443 file: Rc::new(RefCell::new(Inode::new([]))),
444 offset: 3,
445 is_readable: true,
446 is_writable: true,
447 is_appending: false,
448 };
449
450 let result = open_file.seek(SeekFrom::Start(10));
451 assert_eq!(result, Ok(10));
452 assert_eq!(open_file.offset, 10);
453
454 let result = open_file.seek(SeekFrom::Start(0));
455 assert_eq!(result, Ok(0));
456 assert_eq!(open_file.offset, 0);
457
458 let result = open_file.seek(SeekFrom::Start(3));
459 assert_eq!(result, Ok(3));
460 assert_eq!(open_file.offset, 3);
461 }
462
463 #[test]
464 fn regular_file_seek_from_current() {
465 let mut open_file = OpenFileDescription {
466 file: Rc::new(RefCell::new(Inode::new([]))),
467 offset: 5,
468 is_readable: true,
469 is_writable: true,
470 is_appending: false,
471 };
472
473 let result = open_file.seek(SeekFrom::Current(10));
474 assert_eq!(result, Ok(15));
475 assert_eq!(open_file.offset, 15);
476
477 let result = open_file.seek(SeekFrom::Current(0));
478 assert_eq!(result, Ok(15));
479 assert_eq!(open_file.offset, 15);
480
481 let result = open_file.seek(SeekFrom::Current(-5));
482 assert_eq!(result, Ok(10));
483 assert_eq!(open_file.offset, 10);
484
485 let result = open_file.seek(SeekFrom::Current(-11));
486 assert_eq!(result, Err(Errno::EINVAL));
487 assert_eq!(open_file.offset, 10);
488 }
489
490 #[test]
491 fn regular_file_seek_from_end() {
492 let mut open_file = OpenFileDescription {
493 file: Rc::new(RefCell::new(Inode::new([1, 2, 3]))),
494 offset: 2,
495 is_readable: true,
496 is_writable: true,
497 is_appending: false,
498 };
499
500 let result = open_file.seek(SeekFrom::End(7));
501 assert_eq!(result, Ok(10));
502 assert_eq!(open_file.offset, 10);
503
504 let result = open_file.seek(SeekFrom::End(0));
505 assert_eq!(result, Ok(3));
506 assert_eq!(open_file.offset, 3);
507
508 let result = open_file.seek(SeekFrom::End(-3));
509 assert_eq!(result, Ok(0));
510 assert_eq!(open_file.offset, 0);
511
512 let result = open_file.seek(SeekFrom::End(-4));
513 assert_eq!(result, Err(Errno::EINVAL));
514 assert_eq!(open_file.offset, 0);
515 }
516
517 #[test]
518 fn fifo_reader_drop() {
519 let file = Rc::new(RefCell::new(Inode {
520 body: FileBody::Fifo {
521 content: VecDeque::new(),
522 readers: 1,
523 writers: 1,
524 },
525 permissions: Mode::default(),
526 }));
527 let open_file = OpenFileDescription {
528 file: Rc::clone(&file),
529 offset: 0,
530 is_readable: true,
531 is_writable: false,
532 is_appending: false,
533 };
534 drop(open_file);
535
536 assert_matches!(&file.borrow().body, FileBody::Fifo { readers, writers, .. } => {
537 assert_eq!(*readers, 0);
538 assert_eq!(*writers, 1);
539 });
540 }
541
542 #[test]
543 fn fifo_writer_drop() {
544 let file = Rc::new(RefCell::new(Inode {
545 body: FileBody::Fifo {
546 content: VecDeque::new(),
547 readers: 1,
548 writers: 1,
549 },
550 permissions: Mode::default(),
551 }));
552 let open_file = OpenFileDescription {
553 file: Rc::clone(&file),
554 offset: 0,
555 is_readable: false,
556 is_writable: true,
557 is_appending: false,
558 };
559 drop(open_file);
560
561 assert_matches!(&file.borrow().body, FileBody::Fifo { readers, writers, .. } => {
562 assert_eq!(*readers, 1);
563 assert_eq!(*writers, 0);
564 });
565 }
566
567 #[test]
568 fn fifo_is_ready_for_writing() {
569 let file = Rc::new(RefCell::new(Inode {
570 body: FileBody::Fifo {
571 content: VecDeque::new(),
572 readers: 1,
573 writers: 1,
574 },
575 permissions: Mode::default(),
576 }));
577 let mut open_file = OpenFileDescription {
578 file: Rc::clone(&file),
579 offset: 0,
580 is_readable: false,
581 is_writable: true,
582 is_appending: false,
583 };
584
585 assert!(open_file.is_ready_for_writing());
586
587 let buffer = [42; PIPE_SIZE - PIPE_BUF];
588 let result = open_file.write(&buffer);
589 assert_eq!(result, Ok(PIPE_SIZE - PIPE_BUF));
590 assert!(open_file.is_ready_for_writing());
591
592 let result = open_file.write(&[123]);
593 assert_eq!(result, Ok(1));
594 assert!(!open_file.is_ready_for_writing());
595
596 assert_matches!(&mut file.borrow_mut().body, FileBody::Fifo { readers, .. } => {
597 *readers = 0;
598 });
599 assert!(open_file.is_ready_for_writing());
600 }
601
602 #[test]
603 fn fifo_read_empty() {
604 let mut open_file = OpenFileDescription {
605 file: Rc::new(RefCell::new(Inode {
606 body: FileBody::Fifo {
607 content: VecDeque::new(),
608 readers: 1,
609 writers: 0,
610 },
611 permissions: Mode::default(),
612 })),
613 offset: 0,
614 is_readable: true,
615 is_writable: false,
616 is_appending: false,
617 };
618
619 let mut buffer = [100; 5];
620 let result = open_file.read(&mut buffer);
621 assert_eq!(result, Ok(0));
622 }
623
624 #[test]
625 fn fifo_read_non_empty() {
626 let mut open_file = OpenFileDescription {
627 file: Rc::new(RefCell::new(Inode {
628 body: FileBody::Fifo {
629 content: VecDeque::from([1, 5, 7, 3, 42, 7, 6]),
630 readers: 1,
631 writers: 0,
632 },
633 permissions: Mode::default(),
634 })),
635 offset: 0,
636 is_readable: true,
637 is_writable: false,
638 is_appending: false,
639 };
640
641 let mut buffer = [100; 4];
642 let result = open_file.read(&mut buffer);
643 assert_eq!(result, Ok(4));
644 assert_eq!(buffer, [1, 5, 7, 3]);
645
646 let result = open_file.read(&mut buffer);
647 assert_eq!(result, Ok(3));
648 assert_eq!(buffer[..3], [42, 7, 6]);
649
650 let result = open_file.read(&mut buffer);
651 assert_eq!(result, Ok(0));
652 }
653
654 #[test]
655 fn fifo_read_not_ready() {
656 let mut open_file = OpenFileDescription {
657 file: Rc::new(RefCell::new(Inode {
658 body: FileBody::Fifo {
659 content: VecDeque::new(),
660 readers: 1,
661 writers: 1,
662 },
663 permissions: Mode::default(),
664 })),
665 offset: 0,
666 is_readable: true,
667 is_writable: false,
668 is_appending: false,
669 };
670
671 let mut buffer = [100; 5];
672 let result = open_file.read(&mut buffer);
673 assert_eq!(result, Err(Errno::EAGAIN));
674 }
675
676 #[test]
677 fn fifo_write_vacant() {
678 let file = Rc::new(RefCell::new(Inode {
679 body: FileBody::Fifo {
680 content: VecDeque::new(),
681 readers: 1,
682 writers: 1,
683 },
684 permissions: Mode::default(),
685 }));
686 let mut open_file = OpenFileDescription {
687 file: Rc::clone(&file),
688 offset: 0,
689 is_readable: false,
690 is_writable: true,
691 is_appending: false,
692 };
693
694 let result = open_file.write(&[1, 1, 2, 3]);
695 assert_eq!(result, Ok(4));
696
697 let result = open_file.write(&[5, 8, 13]);
698 assert_eq!(result, Ok(3));
699
700 assert_matches!(&mut file.borrow_mut().body, FileBody::Fifo { content, .. } => {
701 assert_eq!(content.make_contiguous(), [1, 1, 2, 3, 5, 8, 13]);
702 });
703 }
704
705 #[test]
706 fn fifo_write_full() {
707 let mut open_file = OpenFileDescription {
708 file: Rc::new(RefCell::new(Inode {
709 body: FileBody::Fifo {
710 content: VecDeque::new(),
711 readers: 1,
712 writers: 1,
713 },
714 permissions: Mode::default(),
715 })),
716 offset: 0,
717 is_readable: false,
718 is_writable: true,
719 is_appending: false,
720 };
721
722 open_file.write(&[0; PIPE_SIZE]).unwrap();
723
724 let result = open_file.write(&[1; 1]);
726 assert_eq!(result, Err(Errno::EAGAIN));
727 let result = open_file.write(&[1; PIPE_BUF + 1]);
728 assert_eq!(result, Err(Errno::EAGAIN));
729
730 let result = open_file.write(&[1; 0]);
732 assert_eq!(result, Ok(0));
733 }
734
735 #[test]
736 fn fifo_write_atomic_full() {
737 let file = Rc::new(RefCell::new(Inode {
738 body: FileBody::Fifo {
739 content: VecDeque::new(),
740 readers: 1,
741 writers: 1,
742 },
743 permissions: Mode::default(),
744 }));
745 let mut open_file = OpenFileDescription {
746 file: Rc::clone(&file),
747 offset: 0,
748 is_readable: false,
749 is_writable: true,
750 is_appending: false,
751 };
752
753 const LEN: usize = PIPE_SIZE - PIPE_BUF + 1;
754 open_file.write(&[0; LEN]).unwrap();
755
756 let result = open_file.write(&[1; PIPE_BUF]);
759 assert_eq!(result, Err(Errno::EAGAIN));
760
761 assert_matches!(&file.borrow().body, FileBody::Fifo { content, .. } => {
762 assert_eq!(content.len(), LEN);
763 });
764 }
765
766 #[test]
767 fn fifo_write_non_atomic_full() {
768 let mut open_file = OpenFileDescription {
769 file: Rc::new(RefCell::new(Inode {
770 body: FileBody::Fifo {
771 content: VecDeque::new(),
772 readers: 1,
773 writers: 1,
774 },
775 permissions: Mode::default(),
776 })),
777 offset: 0,
778 is_readable: false,
779 is_writable: true,
780 is_appending: false,
781 };
782
783 const LEN: usize = PIPE_SIZE - PIPE_BUF;
784 open_file.write(&[0; LEN]).unwrap();
785
786 let result = open_file.write(&[1; PIPE_BUF + 1]);
790 assert_eq!(result, Ok(PIPE_BUF));
791 }
792
793 #[test]
794 fn fifo_write_orphan() {
795 let mut open_file = OpenFileDescription {
796 file: Rc::new(RefCell::new(Inode {
797 body: FileBody::Fifo {
798 content: VecDeque::new(),
799 readers: 0,
800 writers: 1,
801 },
802 permissions: Mode::default(),
803 })),
804 offset: 0,
805 is_readable: false,
806 is_writable: true,
807 is_appending: false,
808 };
809
810 let result = open_file.write(&[1; 1]);
811 assert_eq!(result, Err(Errno::EPIPE));
812 }
813}