Skip to main content

yash_env/system/virtual/
file_body.rs

1// This file is part of yash, an extended POSIX shell.
2// Copyright (C) 2021 WATANABE Yuki
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17//! Operations on file contents
18
19use super::super::FileType;
20use super::Inode;
21use super::WakerSet;
22use crate::path::PathBuf;
23use crate::str::UnixStr;
24use crate::system::Errno;
25use std::cell::{Cell, RefCell};
26use std::collections::HashMap;
27use std::collections::VecDeque;
28use std::rc::Rc;
29use std::rc::Weak;
30use std::task::Poll::{Pending, Ready};
31use std::task::{Poll, Waker};
32
33/// Maximum number of bytes guaranteed to be atomic when writing to a pipe.
34///
35/// This value is for the virtual system implementation.
36/// The real system may have a different configuration.
37pub const PIPE_BUF: usize = 512;
38
39/// Maximum number of bytes a pipe can hold at a time.
40///
41/// This value is for the virtual system implementation.
42/// The real system may have a different configuration.
43pub const PIPE_SIZE: usize = PIPE_BUF * 2;
44
45/// Filetype-specific content of a file
46#[derive(Clone, derive_more::Debug, derive_more::Eq, derive_more::PartialEq)]
47#[non_exhaustive]
48pub enum FileBody {
49    /// Regular file
50    Regular {
51        /// File content
52        content: Vec<u8>,
53        /// Whether this file is a native binary that can be exec'ed
54        is_native_executable: bool,
55    },
56    /// Directory
57    Directory {
58        /// Files contained in this directory
59        ///
60        /// The keys of the hashmap are filenames without any parent directory
61        /// components. The hashmap does not contain "." or "..".
62        files: HashMap<Rc<UnixStr>, Rc<RefCell<Inode>>>,
63        // The hash map contents are reference-counted to allow making cheap
64        // copies of them, which is especially handy when traversing entries.
65    },
66    /// Named pipe
67    Fifo {
68        /// Content of the pipe
69        content: VecDeque<u8>,
70        /// Number of open file descriptions reading from this pipe
71        readers: usize,
72        /// Number of open file descriptions writing to this pipe
73        writers: usize,
74        /// Wakers of tasks waiting to open the pipe for reading or writing
75        ///
76        /// A reader and a writer of a pipe are opened synchronously: when a
77        /// task attempts to open the pipe for reading, it will wait until
78        /// another task opens the pipe for writing, and vice versa. This field
79        /// is used to store the wakers of tasks waiting to open the pipe, so
80        /// that they can be notified when a new reader or writer is opened.
81        #[eq(ignore)]
82        #[partial_eq(ignore)]
83        pending_open_wakers: WakerSet,
84        /// Wakers of tasks waiting to read from the pipe
85        ///
86        /// When a task attempts to read from an empty pipe, it will wait until
87        /// another task writes to the pipe. This field is used to store the
88        /// wakers of such tasks, so that they can be notified when new content
89        /// is written.
90        pending_read_wakers: WakerSet,
91        /// Wakers of tasks waiting to write to the pipe
92        ///
93        /// When a task attempts to write to a full pipe, it will wait until
94        /// another task reads from the pipe. This field is used to store the
95        /// wakers of such tasks, so that they can be notified when content is
96        /// read and space is available for writing.
97        pending_write_wakers: WakerSet,
98    },
99    /// Symbolic link
100    Symlink {
101        /// Path to the file referenced by this symlink
102        target: PathBuf,
103    },
104    /// Terminal device
105    ///
106    /// This is a dummy device that works like a regular file.
107    Terminal {
108        /// Virtual file content
109        content: Vec<u8>,
110    },
111    // TODO Other filetypes
112}
113
114/// The default file body is an empty regular file.
115impl Default for FileBody {
116    fn default() -> Self {
117        FileBody::Regular {
118            content: Vec::default(),
119            is_native_executable: bool::default(),
120        }
121    }
122}
123
124impl FileBody {
125    /// Creates a regular file body with the given content.
126    #[must_use]
127    pub fn new<T: Into<Vec<u8>>>(bytes: T) -> Self {
128        FileBody::Regular {
129            content: bytes.into(),
130            is_native_executable: false,
131        }
132    }
133
134    /// Returns the type of the file.
135    #[must_use]
136    pub const fn r#type(&self) -> FileType {
137        match self {
138            Self::Regular { .. } => FileType::Regular,
139            Self::Directory { .. } => FileType::Directory,
140            Self::Fifo { .. } => FileType::Fifo,
141            Self::Symlink { .. } => FileType::Symlink,
142            Self::Terminal { .. } => FileType::CharacterDevice,
143        }
144    }
145
146    /// Returns the size of the file.
147    #[must_use]
148    pub fn size(&self) -> usize {
149        match self {
150            Self::Regular { content, .. } => content.len(),
151            Self::Directory { files } => files.len(),
152            Self::Fifo { content, .. } => content.len(),
153            Self::Symlink { target } => target.as_unix_str().len(),
154            Self::Terminal { .. } => 0,
155        }
156    }
157
158    /// Notifies the file body that a new open file description has been opened
159    /// for this file, with the given access mode.
160    pub(super) fn open(&mut self, is_readable: bool, is_writable: bool) {
161        if let Self::Fifo {
162            readers,
163            writers,
164            pending_open_wakers,
165            ..
166        } = self
167        {
168            if is_readable {
169                *readers += 1;
170            }
171            if is_writable {
172                *writers += 1;
173            }
174            pending_open_wakers.wake_all();
175        }
176    }
177
178    /// Notifies the file body that an open file description has been closed for
179    /// this file, with the given access mode.
180    pub(super) fn close(&mut self, is_readable: bool, is_writable: bool) {
181        if let Self::Fifo {
182            readers,
183            writers,
184            pending_read_wakers,
185            pending_write_wakers,
186            ..
187        } = self
188        {
189            if is_readable {
190                *readers -= 1;
191            }
192            if is_writable {
193                *writers -= 1;
194            }
195            if *readers == 0 || *writers == 0 {
196                // If there are no readers or no writers, all pending read and
197                // write wakers should be woken up, since the read and write
198                // operations no longer block (either EOF or error).
199                pending_read_wakers.wake_all();
200                pending_write_wakers.wake_all();
201            }
202        }
203    }
204
205    /// Returns whether the file supports seeking.
206    #[must_use]
207    pub fn is_seekable(&self) -> bool {
208        match self {
209            Self::Regular { .. } => true,
210            Self::Directory { .. } => false,
211            Self::Fifo { .. } => false,
212            Self::Symlink { .. } => false,
213            Self::Terminal { .. } => false,
214        }
215    }
216
217    /// Returns true if a read operation on this file would not block.
218    #[must_use]
219    pub(super) fn is_ready_for_reading(&self) -> bool {
220        match self {
221            Self::Regular { .. }
222            | Self::Directory { .. }
223            | Self::Terminal { .. }
224            | Self::Symlink { .. } => true,
225            Self::Fifo {
226                content, writers, ..
227            } => *writers == 0 || !content.is_empty(),
228        }
229    }
230
231    /// Returns true if a write operation on this file would not block.
232    #[must_use]
233    pub(super) fn is_ready_for_writing(&self) -> bool {
234        match self {
235            Self::Regular { .. }
236            | Self::Directory { .. }
237            | Self::Terminal { .. }
238            | Self::Symlink { .. } => true,
239
240            // For FIFOs, we consider the file to be ready for writing if it has
241            // enough space for a write request of any size to succeed without
242            // blocking. This matches the behavior of Linux, but I don't know
243            // what about other systems.
244            Self::Fifo {
245                content, readers, ..
246            } => *readers == 0 || PIPE_SIZE - content.len() >= PIPE_BUF,
247        }
248    }
249
250    /// Registers a waker to be woken up when this file becomes ready for reading.
251    pub(super) fn register_reader_waker(&mut self, waker: Weak<Cell<Option<Waker>>>) {
252        if let Self::Fifo {
253            pending_read_wakers,
254            ..
255        } = self
256        {
257            pending_read_wakers.insert(waker);
258        }
259    }
260
261    /// Registers a waker to be woken up when this file becomes ready for writing.
262    pub(super) fn register_writer_waker(&mut self, waker: Weak<Cell<Option<Waker>>>) {
263        if let Self::Fifo {
264            pending_write_wakers,
265            ..
266        } = self
267        {
268            pending_write_wakers.insert(waker);
269        }
270    }
271
272    /// Polls for the result of a read operation on this file.
273    ///
274    /// The `offset` parameter is the offset from which to read, and is only
275    /// relevant for seekable files. For non-seekable files, it can be ignored
276    /// or set to any value.
277    ///
278    /// The `get_waker` parameter is a function that returns a weak reference to
279    /// the waker of the current task. It is used to register the waker for
280    /// pending read operations on files like FIFOs. The function is called only
281    /// when the read operation would block, so it can be used to avoid
282    /// unnecessary allocations of wakers when the operation can complete
283    /// immediately. Since the waker is passed as a weak reference, the caller
284    /// must ensure that there is a strong reference to the waker that lives at
285    /// least until the file body wakes it up, otherwise the weak reference may
286    /// become invalid and the task may not be woken up correctly. The waker is
287    /// wrapped in `Cell<Option<Waker>>` to allow it to be shared among multiple
288    /// wake conditions and to allow it to be taken by the first condition that
289    /// wakes the task.
290    ///
291    /// The returned `Poll` indicates whether the read operation has completed
292    /// or is still pending. If it is `Poll::Ready`, the contained `Result`
293    /// indicates whether the read was successful and how many bytes were read,
294    /// or if it failed with an error. If it is `Poll::Pending`, it means a
295    /// waker has been registered and the caller should wait until it is woken
296    /// up, when this method should be called again.
297    pub(super) fn poll_read<F>(
298        &mut self,
299        mut buffer: &mut [u8],
300        offset: usize,
301        mut get_waker: F,
302    ) -> Poll<Result<usize, Errno>>
303    where
304        F: FnMut() -> Weak<Cell<Option<Waker>>>,
305    {
306        match self {
307            FileBody::Regular { content, .. } | FileBody::Terminal { content } => {
308                let len = content.len();
309                if offset >= len {
310                    return Ready(Ok(0));
311                }
312                let limit = len - offset;
313                if buffer.len() > limit {
314                    buffer = &mut buffer[..limit];
315                }
316                let count = buffer.len();
317                let src = &content[offset..][..count];
318                buffer.copy_from_slice(src);
319                Ready(Ok(count))
320            }
321
322            FileBody::Fifo {
323                content,
324                writers,
325                pending_read_wakers,
326                pending_write_wakers,
327                ..
328            } => {
329                if buffer.is_empty() {
330                    return Ready(Ok(0));
331                }
332
333                let limit = content.len();
334                if limit == 0 && *writers > 0 {
335                    // Block until any writer writes to the pipe or all writers are closed.
336                    pending_read_wakers.insert(get_waker());
337                    return Pending;
338                }
339
340                let mut count = 0;
341                for to in buffer {
342                    if let Some(from) = content.pop_front() {
343                        *to = from;
344                        count += 1;
345                    } else {
346                        break;
347                    }
348                }
349                pending_write_wakers.wake_all();
350                Ready(Ok(count))
351            }
352
353            FileBody::Directory { .. } => Ready(Err(Errno::EISDIR)),
354
355            FileBody::Symlink { target: _ } => Ready(Err(Errno::ENOTSUP)),
356        }
357    }
358
359    /// Polls for the result of a write operation on this file.
360    ///
361    /// The `offset` parameter is the offset to which to write, and is only
362    /// relevant for seekable files. For non-seekable files, it can be ignored
363    /// or set to any value.
364    ///
365    /// The `get_waker` parameter is a function that returns a weak reference to
366    /// the waker of the current task. It is used to register the waker for
367    /// pending write operations on files like FIFOs. The function is called
368    /// only when the write operation would block, so it can be used to avoid
369    /// unnecessary allocations of wakers when the operation can complete
370    /// immediately. Since the waker is passed as a weak reference, the caller
371    /// must ensure that there is a strong reference to the waker that lives at
372    /// least until the file body wakes it up, otherwise the weak reference may
373    /// become invalid and the task may not be woken up correctly. The waker is
374    /// wrapped in `Cell<Option<Waker>>` to allow it to be shared among multiple
375    /// wake conditions and to allow it to be taken by the first condition that
376    /// wakes the task.
377    ///
378    /// For FIFO writes of at most [`PIPE_BUF`] bytes, the write is atomic:
379    /// either all bytes are written at once or the method blocks until enough
380    /// room is available. For larger writes, the method writes as many bytes as
381    /// fit in the pipe buffer and returns immediately; if no bytes fit (the
382    /// pipe is full), it blocks until at least one byte can be written.
383    ///
384    /// The returned `Poll` indicates whether the write operation has completed
385    /// or is still pending. If it is `Poll::Ready`, the contained `Result`
386    /// indicates whether the write was successful and how many bytes were
387    /// written, or if it failed with an error. If it is `Poll::Pending`, it
388    /// means a waker has been registered and the caller should wait until it is
389    /// woken up, when this method should be called again.
390    pub(super) fn poll_write<F>(
391        &mut self,
392        mut buffer: &[u8],
393        offset: usize,
394        mut get_waker: F,
395    ) -> Poll<Result<usize, Errno>>
396    where
397        F: FnMut() -> Weak<Cell<Option<Waker>>>,
398    {
399        match self {
400            FileBody::Regular { content, .. } | FileBody::Terminal { content } => {
401                let len = content.len();
402                let count = buffer.len();
403                if offset > len {
404                    let zeroes = offset - len;
405                    content.reserve(zeroes + count);
406                    content.resize_with(offset, u8::default);
407                }
408                let limit = count.min(content.len() - offset);
409                let dst = &mut content[offset..][..limit];
410                dst.copy_from_slice(&buffer[..limit]);
411                content.reserve(count - limit);
412                content.extend(&buffer[limit..]);
413                Ready(Ok(count))
414            }
415
416            FileBody::Fifo {
417                content,
418                readers,
419                pending_read_wakers,
420                pending_write_wakers,
421                ..
422            } => {
423                if *readers == 0 {
424                    // TODO SIGPIPE
425                    return Ready(Err(Errno::EPIPE));
426                }
427                let room = PIPE_SIZE - content.len();
428                if room < buffer.len() {
429                    if room == 0 || buffer.len() <= PIPE_BUF {
430                        // Block until any reader reads from the pipe or all readers are closed.
431                        pending_write_wakers.insert(get_waker());
432                        return Pending;
433                    }
434                    buffer = &buffer[..room];
435                }
436                content.reserve_exact(room);
437                content.extend(buffer);
438                debug_assert!(content.len() <= PIPE_SIZE);
439                pending_read_wakers.wake_all();
440                Ready(Ok(buffer.len()))
441            }
442
443            FileBody::Directory { .. } => Ready(Err(Errno::EISDIR)),
444
445            FileBody::Symlink { target: _ } => Ready(Err(Errno::ENOTSUP)),
446        }
447    }
448}
449
450#[cfg(test)]
451mod tests {
452    use super::*;
453    use crate::test_helper::WakeFlag;
454    use assert_matches::assert_matches;
455    use std::sync::Arc;
456
457    #[test]
458    fn fifo_file_body_open_increments_readers_and_writers() {
459        let mut body = FileBody::Fifo {
460            content: VecDeque::new(),
461            readers: 0,
462            writers: 0,
463            pending_open_wakers: WakerSet::new(),
464            pending_read_wakers: WakerSet::new(),
465            pending_write_wakers: WakerSet::new(),
466        };
467
468        body.open(true, false);
469        assert_matches!(
470            &body,
471            FileBody::Fifo { readers, writers, .. } if *readers == 1 && *writers == 0
472        );
473
474        body.open(false, true);
475        assert_matches!(
476            &body,
477            FileBody::Fifo { readers, writers, .. } if *readers == 1 && *writers == 1
478        );
479
480        body.open(true, true);
481        assert_matches!(
482            &body,
483            FileBody::Fifo { readers, writers, .. } if *readers == 2 && *writers == 2
484        );
485    }
486
487    #[test]
488    fn fifo_file_body_open_wakes_pending_open_wakers() {
489        let wake_flag_1 = Arc::new(WakeFlag::new());
490        let wake_flag_2 = Arc::new(WakeFlag::new());
491        let waker_1 = Rc::new(Cell::new(Some(Waker::from(wake_flag_1.clone()))));
492        let waker_2 = Rc::new(Cell::new(Some(Waker::from(wake_flag_2.clone()))));
493        let mut body = FileBody::Fifo {
494            content: VecDeque::new(),
495            readers: 0,
496            writers: 0,
497            pending_open_wakers: WakerSet::from_iter([
498                Rc::downgrade(&waker_1),
499                Rc::downgrade(&waker_2),
500            ]),
501            pending_read_wakers: WakerSet::new(),
502            pending_write_wakers: WakerSet::new(),
503        };
504        body.open(true, false);
505        assert!(wake_flag_1.is_woken());
506        assert!(wake_flag_2.is_woken());
507        assert_matches!(
508            &body,
509            FileBody::Fifo { pending_open_wakers, .. } if pending_open_wakers.is_empty()
510        );
511    }
512
513    #[test]
514    fn fifo_file_body_close_decrements_readers_and_writers() {
515        let mut body = FileBody::Fifo {
516            content: VecDeque::new(),
517            readers: 2,
518            writers: 2,
519            pending_open_wakers: WakerSet::new(),
520            pending_read_wakers: WakerSet::new(),
521            pending_write_wakers: WakerSet::new(),
522        };
523
524        body.close(true, false);
525        assert_matches!(
526            &body,
527            FileBody::Fifo { readers, writers, .. } if *readers == 1 && *writers == 2
528        );
529
530        body.close(false, true);
531        assert_matches!(
532            &body,
533            FileBody::Fifo { readers, writers, .. } if *readers == 1 && *writers == 1
534        );
535
536        body.close(true, true);
537        assert_matches!(
538            &body,
539            FileBody::Fifo { readers, writers, .. } if *readers == 0 && *writers == 0
540        );
541    }
542
543    #[test]
544    fn fifo_file_body_wakes_pending_wakers_if_no_writers_remain() {
545        let wake_flag_1 = Arc::new(WakeFlag::new());
546        let wake_flag_2 = Arc::new(WakeFlag::new());
547        let waker_1 = Rc::new(Cell::new(Some(Waker::from(wake_flag_1.clone()))));
548        let waker_2 = Rc::new(Cell::new(Some(Waker::from(wake_flag_2.clone()))));
549        let mut body = FileBody::Fifo {
550            content: VecDeque::new(),
551            readers: 1,
552            writers: 2,
553            pending_open_wakers: WakerSet::new(),
554            pending_read_wakers: WakerSet::from_iter([Rc::downgrade(&waker_1)]),
555            pending_write_wakers: WakerSet::from_iter([Rc::downgrade(&waker_2)]),
556        };
557
558        // One writer is closed, but there is still another writer,
559        // so the pending wakers should not be woken up.
560        body.close(false, true);
561        assert!(!wake_flag_1.is_woken());
562        assert!(!wake_flag_2.is_woken());
563
564        // The other writer is closed, so the pending wakers should be woken up.
565        body.close(false, true);
566        assert!(wake_flag_1.is_woken());
567        assert!(wake_flag_2.is_woken());
568    }
569
570    #[test]
571    fn fifo_file_body_wakes_pending_wakers_if_no_readers_remain() {
572        let wake_flag_1 = Arc::new(WakeFlag::new());
573        let wake_flag_2 = Arc::new(WakeFlag::new());
574        let waker_1 = Rc::new(Cell::new(Some(Waker::from(wake_flag_1.clone()))));
575        let waker_2 = Rc::new(Cell::new(Some(Waker::from(wake_flag_2.clone()))));
576        let mut body = FileBody::Fifo {
577            content: VecDeque::new(),
578            readers: 2,
579            writers: 1,
580            pending_open_wakers: WakerSet::new(),
581            pending_read_wakers: WakerSet::from_iter([Rc::downgrade(&waker_1)]),
582            pending_write_wakers: WakerSet::from_iter([Rc::downgrade(&waker_2)]),
583        };
584
585        // One reader is closed, but there is still another reader,
586        // so the pending wakers should not be woken up.
587        body.close(true, false);
588        assert!(!wake_flag_1.is_woken());
589        assert!(!wake_flag_2.is_woken());
590
591        // The other reader is closed, so the pending wakers should be woken up.
592        body.close(true, false);
593        assert!(wake_flag_1.is_woken());
594        assert!(wake_flag_2.is_woken());
595    }
596
597    #[test]
598    fn fifo_file_body_is_ready_for_reading() {
599        // When there are no writers, the FIFO is always ready for reading
600        // since it will return EOF.
601        let body = FileBody::Fifo {
602            content: VecDeque::new(),
603            readers: 0,
604            writers: 0,
605            pending_open_wakers: WakerSet::new(),
606            pending_read_wakers: WakerSet::new(),
607            pending_write_wakers: WakerSet::new(),
608        };
609        assert!(body.is_ready_for_reading());
610
611        // When there are writers, the FIFO is ready for reading if and only if
612        // it has content.
613        let body = FileBody::Fifo {
614            content: VecDeque::new(),
615            readers: 0,
616            writers: 1,
617            pending_open_wakers: WakerSet::new(),
618            pending_read_wakers: WakerSet::new(),
619            pending_write_wakers: WakerSet::new(),
620        };
621        assert!(!body.is_ready_for_reading());
622        let body = FileBody::Fifo {
623            content: VecDeque::from([0]),
624            readers: 0,
625            writers: 1,
626            pending_open_wakers: WakerSet::new(),
627            pending_read_wakers: WakerSet::new(),
628            pending_write_wakers: WakerSet::new(),
629        };
630        assert!(body.is_ready_for_reading());
631    }
632
633    #[test]
634    fn fifo_file_body_is_ready_for_writing() {
635        // When there are no readers, the FIFO is always ready for writing
636        // since it will return EPIPE.
637        let body = FileBody::Fifo {
638            content: VecDeque::new(),
639            readers: 0,
640            writers: 0,
641            pending_open_wakers: WakerSet::new(),
642            pending_read_wakers: WakerSet::new(),
643            pending_write_wakers: WakerSet::new(),
644        };
645        assert!(body.is_ready_for_writing());
646
647        // When there are readers, the FIFO is ready for writing if and only if
648        // it has enough space for at least one atomic write.
649        let body = FileBody::Fifo {
650            content: VecDeque::from([0; PIPE_SIZE - PIPE_BUF]),
651            readers: 1,
652            writers: 0,
653            pending_open_wakers: WakerSet::new(),
654            pending_read_wakers: WakerSet::new(),
655            pending_write_wakers: WakerSet::new(),
656        };
657        assert!(body.is_ready_for_writing());
658        let body = FileBody::Fifo {
659            content: VecDeque::from([0; PIPE_SIZE - PIPE_BUF + 1]),
660            readers: 1,
661            writers: 0,
662            pending_open_wakers: WakerSet::new(),
663            pending_read_wakers: WakerSet::new(),
664            pending_write_wakers: WakerSet::new(),
665        };
666        assert!(!body.is_ready_for_writing());
667    }
668
669    #[test]
670    fn regular_file_body_read_beyond_file_length() {
671        let mut body = FileBody::new(b"hello");
672        let mut buffer = [0; 10];
673        assert_eq!(body.poll_read(&mut buffer, 5, Weak::new), Ready(Ok(0)));
674        assert_eq!(body.poll_read(&mut buffer, 10, Weak::new), Ready(Ok(0)));
675    }
676
677    #[test]
678    fn regular_file_body_read_more_than_content() {
679        let mut body = FileBody::new(b"hello");
680        let mut buffer = [0; 10];
681        assert_eq!(body.poll_read(&mut buffer, 2, Weak::new), Ready(Ok(3)));
682        assert_eq!(&buffer[..3], b"llo");
683    }
684
685    #[test]
686    fn regular_file_body_read_less_than_content() {
687        let mut body = FileBody::new(b"hello");
688        let mut buffer = [0; 3];
689        assert_eq!(body.poll_read(&mut buffer, 1, Weak::new), Ready(Ok(3)));
690        assert_eq!(&buffer, b"ell");
691    }
692
693    #[test]
694    fn fifo_file_body_read_eof() {
695        // With no writers, the FIFO returns EOF.
696        let mut body = FileBody::Fifo {
697            content: VecDeque::new(),
698            readers: 0,
699            writers: 0,
700            pending_open_wakers: WakerSet::new(),
701            pending_read_wakers: WakerSet::new(),
702            pending_write_wakers: WakerSet::new(),
703        };
704        let mut buffer = [0; 10];
705        assert_eq!(body.poll_read(&mut buffer, 0, Weak::new), Ready(Ok(0)));
706    }
707
708    #[test]
709    fn fifo_file_body_read_empty() {
710        // The FIFO content is empty but there are writers that may write to it,
711        // so the read operation would block.
712        let mut body = FileBody::Fifo {
713            content: VecDeque::new(),
714            readers: 1,
715            writers: 1,
716            pending_open_wakers: WakerSet::new(),
717            pending_read_wakers: WakerSet::new(),
718            pending_write_wakers: WakerSet::new(),
719        };
720        let mut buffer = [0; 10];
721
722        let wake_flag = Arc::new(WakeFlag::new());
723        let waker = Rc::new(Cell::new(Some(Waker::from(wake_flag.clone()))));
724        let get_waker = || Rc::downgrade(&waker);
725        let poll = body.poll_read(&mut buffer, 0, get_waker);
726        assert_eq!(poll, Pending);
727        assert!(!wake_flag.is_woken());
728
729        // When another task writes to the FIFO, the read operation should be woken up.
730        let poll = body.poll_write(b"hello", 0, Weak::new);
731        assert_eq!(poll, Ready(Ok(5)));
732        assert!(wake_flag.is_woken());
733
734        // After being woken up, the read operation should succeed and read the new content.
735        let poll = body.poll_read(&mut buffer, 0, Weak::new);
736        assert_eq!(poll, Ready(Ok(5)));
737        assert_eq!(&buffer[..5], b"hello");
738    }
739
740    #[test]
741    fn fifo_file_body_read_empty_to_empty() {
742        // The FIFO content is empty but the read buffer is also empty,
743        // so the read operation should read 0 bytes without blocking.
744        let mut body = FileBody::Fifo {
745            content: VecDeque::new(),
746            readers: 1,
747            writers: 1,
748            pending_open_wakers: WakerSet::new(),
749            pending_read_wakers: WakerSet::new(),
750            pending_write_wakers: WakerSet::new(),
751        };
752
753        let wake_flag = Arc::new(WakeFlag::new());
754        let waker = Rc::new(Cell::new(Some(Waker::from(wake_flag.clone()))));
755        let get_waker = || Rc::downgrade(&waker);
756        let poll = body.poll_read(&mut [], 0, get_waker);
757        assert_eq!(poll, Ready(Ok(0)));
758        assert!(!wake_flag.is_woken());
759    }
760
761    #[test]
762    fn fifo_file_body_read_non_empty() {
763        let mut body = FileBody::Fifo {
764            content: VecDeque::from(*b"hello"),
765            readers: 0,
766            writers: 0,
767            pending_open_wakers: WakerSet::new(),
768            pending_read_wakers: WakerSet::new(),
769            pending_write_wakers: WakerSet::new(),
770        };
771        let mut buffer = [0; 10];
772        assert_eq!(body.poll_read(&mut buffer, 0, Weak::new), Ready(Ok(5)));
773        assert_eq!(&buffer[..5], b"hello");
774    }
775
776    #[test]
777    fn regular_file_body_write_less_than_content() {
778        let mut body = FileBody::new(b"hello");
779        let buffer = b"ipp";
780        assert_eq!(body.poll_write(buffer, 1, Weak::new), Ready(Ok(3)));
781        assert_eq!(body, FileBody::new(b"hippo"));
782    }
783
784    #[test]
785    fn regular_file_body_write_more_than_content() {
786        let mut body = FileBody::new(b"hello");
787        let buffer = b"icopter";
788        assert_eq!(body.poll_write(buffer, 3, Weak::new), Ready(Ok(7)));
789        assert_eq!(body, FileBody::new(b"helicopter"));
790    }
791
792    #[test]
793    fn regular_file_body_write_beyond_file_length() {
794        let mut body = FileBody::new(b"hello");
795        let buffer = b"world";
796        assert_eq!(body.poll_write(buffer, 7, Weak::new), Ready(Ok(5)));
797        assert_eq!(body, FileBody::new(b"hello\0\0world"));
798    }
799
800    #[test]
801    fn fifo_file_body_write_closed() {
802        // When there are no readers, the FIFO returns EPIPE error.
803        let mut body = FileBody::Fifo {
804            content: VecDeque::new(),
805            readers: 0,
806            writers: 0,
807            pending_open_wakers: WakerSet::new(),
808            pending_read_wakers: WakerSet::new(),
809            pending_write_wakers: WakerSet::new(),
810        };
811        let buffer = b"hello";
812        assert_eq!(
813            body.poll_write(buffer, 0, Weak::new),
814            Ready(Err(Errno::EPIPE))
815        );
816    }
817
818    #[test]
819    fn fifo_file_body_write_atomic_empty() {
820        // When the FIFO has enough space for an atomic write and there are
821        // readers that may read from it, the write operation should succeed.
822        let mut body = FileBody::Fifo {
823            content: VecDeque::from([0; PIPE_SIZE - PIPE_BUF]),
824            readers: 1,
825            writers: 0,
826            pending_open_wakers: WakerSet::new(),
827            pending_read_wakers: WakerSet::new(),
828            pending_write_wakers: WakerSet::new(),
829        };
830        let buffer = [0; PIPE_BUF];
831        assert_eq!(body.poll_write(&buffer, 0, Weak::new), Ready(Ok(PIPE_BUF)));
832    }
833
834    #[test]
835    fn fifo_file_body_write_atomic_full() {
836        // When the FIFO does not have enough space for an atomic write but
837        // there are readers that may read from it, the write operation would
838        // block.
839        let mut body = FileBody::Fifo {
840            content: VecDeque::from([0; PIPE_SIZE - PIPE_BUF + 1]),
841            readers: 1,
842            writers: 0,
843            pending_open_wakers: WakerSet::new(),
844            pending_read_wakers: WakerSet::new(),
845            pending_write_wakers: WakerSet::new(),
846        };
847        let buffer = [0; PIPE_BUF];
848
849        let wake_flag = Arc::new(WakeFlag::new());
850        let waker = Rc::new(Cell::new(Some(Waker::from(wake_flag.clone()))));
851        let get_waker = || Rc::downgrade(&waker);
852        let poll = body.poll_write(&buffer, 0, get_waker);
853        assert_eq!(poll, Pending);
854        assert!(!wake_flag.is_woken());
855
856        // When another task reads from the FIFO, the write operation should be woken up.
857        let mut read_buffer = [0; 1];
858        let poll = body.poll_read(&mut read_buffer, 0, Weak::new);
859        assert_eq!(poll, Ready(Ok(1)));
860        assert!(wake_flag.is_woken());
861
862        // After being woken up, the write operation successfully writes the content to the FIFO.
863        let wake_flag = Arc::new(WakeFlag::new());
864        let waker = Rc::new(Cell::new(Some(Waker::from(wake_flag.clone()))));
865        let get_waker = || Rc::downgrade(&waker);
866        let poll = body.poll_write(&buffer, 0, get_waker);
867        assert_eq!(poll, Ready(Ok(PIPE_BUF)));
868        assert!(!wake_flag.is_woken());
869    }
870
871    #[test]
872    fn fifo_file_body_write_non_atomic_empty() {
873        // When the write size exceeds PIPE_BUF, the FIFO has space for at least
874        // one byte, and there are readers that may read from the FIFO, the
875        // write operation should succeed and write as much as possible.
876        let mut body = FileBody::Fifo {
877            content: VecDeque::from([0; PIPE_SIZE - 1]),
878            readers: 1,
879            writers: 0,
880            pending_open_wakers: WakerSet::new(),
881            pending_read_wakers: WakerSet::new(),
882            pending_write_wakers: WakerSet::new(),
883        };
884        let buffer = [0; PIPE_BUF + 1];
885        assert_eq!(body.poll_write(&buffer, 0, Weak::new), Ready(Ok(1)));
886    }
887
888    #[test]
889    fn fifo_file_body_write_non_atomic_full() {
890        // When the write size exceeds PIPE_BUF, the FIFO is full, and there are
891        // readers that may read from it, the write operation should block until
892        // there is space for at least one byte to be written.
893        let mut body = FileBody::Fifo {
894            content: VecDeque::from([0; PIPE_SIZE]),
895            readers: 1,
896            writers: 0,
897            pending_open_wakers: WakerSet::new(),
898            pending_read_wakers: WakerSet::new(),
899            pending_write_wakers: WakerSet::new(),
900        };
901        let buffer = [0; PIPE_BUF + 1];
902
903        let wake_flag = Arc::new(WakeFlag::new());
904        let waker = Rc::new(Cell::new(Some(Waker::from(wake_flag.clone()))));
905        let get_waker = || Rc::downgrade(&waker);
906        let poll = body.poll_write(&buffer, 0, get_waker);
907        assert_eq!(poll, Pending);
908        assert!(!wake_flag.is_woken());
909
910        // When another task reads from the FIFO, the write operation should be woken up.
911        let mut read_buffer = [0; 1];
912        let poll = body.poll_read(&mut read_buffer, 0, Weak::new);
913        assert_eq!(poll, Ready(Ok(1)));
914        assert!(wake_flag.is_woken());
915
916        // After being woken up, the write operation successfully writes one byte to the FIFO.
917        let wake_flag = Arc::new(WakeFlag::new());
918        let waker = Rc::new(Cell::new(Some(Waker::from(wake_flag.clone()))));
919        let get_waker = || Rc::downgrade(&waker);
920        let poll = body.poll_write(&buffer, 0, get_waker);
921        assert_eq!(poll, Ready(Ok(1)));
922        assert!(!wake_flag.is_woken());
923    }
924}