• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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