3
3
// For the full copyright and license information, please view the LICENSE
4
4
// file that was distributed with this source code.
5
5
6
- //! Set of functions to manage files and symlinks
6
+ //! Set of functions to manage regular files, special files, and links.
7
7
8
8
// spell-checker:ignore backport
9
9
10
10
#[ cfg( unix) ]
11
11
use libc:: {
12
12
S_IFBLK , S_IFCHR , S_IFDIR , S_IFIFO , S_IFLNK , S_IFMT , S_IFREG , S_IFSOCK , S_IRGRP , S_IROTH ,
13
13
S_IRUSR , S_ISGID , S_ISUID , S_ISVTX , S_IWGRP , S_IWOTH , S_IWUSR , S_IXGRP , S_IXOTH , S_IXUSR ,
14
- mode_t,
14
+ mkfifo , mode_t,
15
15
} ;
16
16
use std:: collections:: HashSet ;
17
17
use std:: collections:: VecDeque ;
18
18
use std:: env;
19
+ #[ cfg( unix) ]
20
+ use std:: ffi:: CString ;
19
21
use std:: ffi:: { OsStr , OsString } ;
20
22
use std:: fs;
21
23
use std:: fs:: read_dir;
@@ -798,6 +800,37 @@ pub fn get_filename(file: &Path) -> Option<&str> {
798
800
file. file_name ( ) . and_then ( |filename| filename. to_str ( ) )
799
801
}
800
802
803
+ /// Make a FIFO, also known as a named pipe.
804
+ ///
805
+ /// This is a safe wrapper for the unsafe [`libc::mkfifo`] function,
806
+ /// which makes a [named
807
+ /// pipe](https://en.wikipedia.org/wiki/Named_pipe) on Unix systems.
808
+ ///
809
+ /// # Errors
810
+ ///
811
+ /// If the named pipe cannot be created.
812
+ ///
813
+ /// # Examples
814
+ ///
815
+ /// ```ignore
816
+ /// use uucore::fs::make_fifo;
817
+ ///
818
+ /// make_fifo("my-pipe").expect("failed to create the named pipe");
819
+ ///
820
+ /// std::thread::spawn(|| { std::fs::write("my-pipe", b"hello").unwrap(); });
821
+ /// assert_eq!(std::fs::read("my-pipe").unwrap(), b"hello");
822
+ /// ```
823
+ #[ cfg( unix) ]
824
+ pub fn make_fifo ( path : & Path ) -> std:: io:: Result < ( ) > {
825
+ let name = CString :: new ( path. to_str ( ) . unwrap ( ) ) . unwrap ( ) ;
826
+ let err = unsafe { mkfifo ( name. as_ptr ( ) , 0o666 ) } ;
827
+ if err == -1 {
828
+ Err ( std:: io:: Error :: from_raw_os_error ( err) )
829
+ } else {
830
+ Ok ( ( ) )
831
+ }
832
+ }
833
+
801
834
#[ cfg( test) ]
802
835
mod tests {
803
836
// Note this useful idiom: importing names from outer (for mod tests) scope.
@@ -807,6 +840,8 @@ mod tests {
807
840
#[ cfg( unix) ]
808
841
use std:: os:: unix;
809
842
#[ cfg( unix) ]
843
+ use std:: os:: unix:: fs:: FileTypeExt ;
844
+ #[ cfg( unix) ]
810
845
use tempfile:: { NamedTempFile , tempdir} ;
811
846
812
847
struct NormalizePathTestCase < ' a > {
@@ -1039,4 +1074,25 @@ mod tests {
1039
1074
let file_path = PathBuf :: from ( "~/foo.txt" ) ;
1040
1075
assert ! ( matches!( get_filename( & file_path) , Some ( "foo.txt" ) ) ) ;
1041
1076
}
1077
+
1078
+ #[ cfg( unix) ]
1079
+ #[ test]
1080
+ fn test_make_fifo ( ) {
1081
+ // Create the FIFO in a temporary directory.
1082
+ let tempdir = tempdir ( ) . unwrap ( ) ;
1083
+ let path = tempdir. path ( ) . join ( "f" ) ;
1084
+ assert ! ( make_fifo( & path) . is_ok( ) ) ;
1085
+
1086
+ // Check that it is indeed a FIFO.
1087
+ assert ! ( std:: fs:: metadata( & path) . unwrap( ) . file_type( ) . is_fifo( ) ) ;
1088
+
1089
+ // Check that we can write to it and read from it.
1090
+ //
1091
+ // Write and read need to happen in different threads,
1092
+ // otherwise `write` would block indefinitely while waiting
1093
+ // for the `read`.
1094
+ let path2 = path. clone ( ) ;
1095
+ std:: thread:: spawn ( move || assert ! ( std:: fs:: write( & path2, b"foo" ) . is_ok( ) ) ) ;
1096
+ assert_eq ! ( std:: fs:: read( & path) . unwrap( ) , b"foo" ) ;
1097
+ }
1042
1098
}
0 commit comments