1 // Copyright 2023 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 //! Testing virtio-fs.
6
7 use fixture::vm::Config;
8 use fixture::vm::TestVm;
9
10 /// Tests file copy on virtiofs
11 ///
12 /// 1. Create `original.txt` on a temporal directory.
13 /// 2. Start a VM with a virtiofs device for the temporal directory.
14 /// 3. Copy `original.txt` to `new.txt` in the guest.
15 /// 4. Check that `new.txt` is created in the host.
16 #[test]
copy_file()17 fn copy_file() {
18 const ORIGINAL_FILE_NAME: &str = "original.txt";
19 const NEW_FILE_NAME: &str = "new.txt";
20 const TEST_DATA: &str = "virtiofs works!";
21
22 let temp_dir = tempfile::tempdir().unwrap();
23 let orig_file = temp_dir.path().join(ORIGINAL_FILE_NAME);
24
25 std::fs::write(orig_file, TEST_DATA).unwrap();
26
27 let tag = "mtdtest";
28
29 let config = Config::new().extra_args(vec![
30 "--shared-dir".to_string(),
31 format!(
32 "{}:{tag}:type=fs:cache=auto",
33 temp_dir.path().to_str().unwrap()
34 ),
35 ]);
36
37 let mut vm = TestVm::new(config).unwrap();
38 // TODO(b/269137600): Split this into multiple lines instead of connecting commands with `&&`.
39 vm.exec_in_guest(&format!(
40 "mount -t virtiofs {tag} /mnt && cp /mnt/{} /mnt/{} && sync",
41 ORIGINAL_FILE_NAME, NEW_FILE_NAME,
42 ))
43 .unwrap();
44
45 let new_file = temp_dir.path().join(NEW_FILE_NAME);
46 let contents = std::fs::read(new_file).unwrap();
47 assert_eq!(TEST_DATA.as_bytes(), &contents);
48 }
49
50 /// Tests file ownership seen by the VM.
51 ///
52 /// 1. Create `user_file.txt` owned by the current user of the host on a temporal directory.
53 /// 2. Set virtiofs options: uidmap=<mapped-uid> <current-uid> 1, uid=<mapped-uid>.
54 /// 3. Start a VM with a virtiofs device for the temporal directory.
55 /// 4. Check that `user_file.txt`'s uid is <mapped-uid> in the VM.
56 /// 5. Verify gid similarly.
57 #[cfg(any(target_os = "android", target_os = "linux"))]
58 #[test]
file_ugid()59 fn file_ugid() {
60 const FILE_NAME: &str = "user_file.txt";
61 let uid = base::geteuid();
62 let gid = base::getegid();
63 let mapped_uid: u32 = rand::random();
64 let mapped_gid: u32 = rand::random();
65 let uid_map = format!("{} {} 1", mapped_uid, uid);
66 let gid_map = format!("{} {} 1", mapped_gid, gid);
67
68 let temp_dir = tempfile::tempdir().unwrap();
69 let orig_file = temp_dir.path().join(FILE_NAME);
70
71 std::fs::write(orig_file, "").unwrap();
72
73 let tag = "mtdtest";
74
75 let config = Config::new().extra_args(vec![
76 "--shared-dir".to_string(),
77 format!(
78 "{}:{tag}:type=fs:uidmap={}:gidmap={}:uid={}:gid={}",
79 temp_dir.path().to_str().unwrap(),
80 uid_map,
81 gid_map,
82 mapped_uid,
83 mapped_gid
84 ),
85 ]);
86
87 let mut vm = TestVm::new(config).unwrap();
88 vm.exec_in_guest(&format!("mount -t virtiofs {tag} /mnt"))
89 .unwrap();
90 let output = vm
91 .exec_in_guest(&format!("stat /mnt/{}", FILE_NAME,))
92 .unwrap();
93 // stat output example:
94 // File: /mnt/user_file.txt
95 // Size: 0 Blocks: 0 IO Block: 4096 regular empty file
96 // Device: 0,11 Inode: 11666031 Links: 1
97 // Access: (0640/-rw-r-----) Uid: (2350626183/ UNKNOWN) Gid: (949179291/ UNKNOWN)
98 // Access: 2023-04-05 03:06:27.110144457 +0000
99 // Modify: 2023-04-05 03:06:27.110144457 +0000
100 // Change: 2023-04-05 03:06:27.110144457 +0000
101 assert!(output.stdout.contains(&format!("Uid: ({}/", mapped_uid)));
102 assert!(output.stdout.contains(&format!("Gid: ({}/", mapped_gid)));
103 }
104