1 //! Compare libc's makedev, major, minor functions against the actual C macros, for various
2 //! inputs.
3 
4 #![cfg(any(
5     target_os = "android",
6     target_os = "dragonfly",
7     target_os = "emscripten",
8     target_os = "freebsd",
9     target_os = "fuchsia",
10     target_os = "linux",
11     target_os = "netbsd",
12     target_os = "openbsd",
13     target_os = "cygwin",
14 ))]
15 
16 use libc::{self, c_uint, dev_t};
17 
18 cfg_if::cfg_if! {
19     if #[cfg(any(target_os = "solaris", target_os = "illumos"))] {
20         pub type MajorRetType = libc::major_t;
21         pub type MinorRetType = libc::minor_t;
22     } else if #[cfg(any(
23         target_os = "linux",
24         target_os = "l4re",
25         target_os = "emscripten",
26         target_os = "fuchsia",
27         target_os = "nto",
28         target_os = "hurd",
29         target_os = "openbsd",
30         target_os = "cygwin",
31     ))] {
32         pub type MajorRetType = c_uint;
33         pub type MinorRetType = c_uint;
34     } else if #[cfg(any(
35         target_os = "android",
36         target_os = "dragonfly",
37         target_os = "netbsd",
38         target_os = "freebsd",
39     ))] {
40         pub type MajorRetType = libc::c_int;
41         pub type MinorRetType = libc::c_int;
42     } else if #[cfg(any(
43         target_os = "macos",
44         target_os = "ios",
45         target_os = "tvos",
46         target_os = "watchos",
47         target_os = "visionos"
48     ))] {
49         pub type MajorRetType = i32;
50         pub type MinorRetType = i32;
51     }
52 }
53 
54 extern "C" {
makedev_ffi(major: c_uint, minor: c_uint) -> dev_t55     pub fn makedev_ffi(major: c_uint, minor: c_uint) -> dev_t;
major_ffi(dev: dev_t) -> c_uint56     pub fn major_ffi(dev: dev_t) -> c_uint;
minor_ffi(dev: dev_t) -> c_uint57     pub fn minor_ffi(dev: dev_t) -> c_uint;
58 }
59 
compare(major: c_uint, minor: c_uint)60 fn compare(major: c_uint, minor: c_uint) {
61     let dev = unsafe { makedev_ffi(major, minor) };
62     assert_eq!(libc::makedev(major, minor), dev);
63     let major = unsafe { major_ffi(dev) };
64     assert_eq!(libc::major(dev), major as MajorRetType);
65     let minor = unsafe { minor_ffi(dev) };
66     assert_eq!(libc::minor(dev), minor as MinorRetType);
67 }
68 
69 // Every OS should be able to handle 8 bit major and minor numbers
70 #[test]
test_8bits()71 fn test_8bits() {
72     for major in 0..256 {
73         for minor in 0..256 {
74             compare(major, minor);
75         }
76     }
77 }
78 
79 // Android allows 12 bits for major and 20 for minor
80 #[test]
81 #[cfg(target_os = "android")]
test_android_like()82 fn test_android_like() {
83     for major in [0, 1, 255, 256, 4095] {
84         for minor_exp in [1, 8, 16] {
85             for minor in [(1 << minor_exp) - 1, (1 << minor_exp)] {
86                 compare(major, minor);
87             }
88         }
89         compare(major, (1 << 20) - 1);
90     }
91 }
92 
93 // These OSes allow 32 bits for minor, but only 8 for major
94 #[test]
95 #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd",))]
test_fbsd11_like()96 fn test_fbsd11_like() {
97     for major in [0, 1, 255] {
98         for minor_exp in [1, 8, 16, 24, 31] {
99             for minor in [(1 << minor_exp) - 1, (1 << minor_exp)] {
100                 compare(major, minor);
101             }
102         }
103         compare(major, c_uint::MAX);
104     }
105 }
106 
107 // OpenBSD allows 8 bits for major and 24 for minor
108 #[test]
109 #[cfg(target_os = "openbsd")]
test_openbsd_like()110 fn test_openbsd_like() {
111     for major in [0, 1, 255] {
112         for minor_exp in [1, 8, 16] {
113             for minor in [(1 << minor_exp) - 1, (1 << minor_exp)] {
114                 compare(major, minor);
115             }
116         }
117         compare(major, (1 << 24) - 1);
118     }
119 }
120 
121 // These OSes allow 32 bits for both minor and major
122 #[cfg(any(
123     target_os = "emscripten",
124     target_os = "freebsd",
125     target_os = "fuchsia",
126     target_os = "linux",
127     target_os = "cygwin",
128 ))]
129 #[test]
test_fbsd12_like()130 fn test_fbsd12_like() {
131     if size_of::<dev_t>() >= 8 {
132         for major_exp in [0, 16, 24, 31] {
133             for major in [(1 << major_exp) - 1, (1 << major_exp)] {
134                 for minor_exp in [1, 8, 16, 24, 31] {
135                     for minor in [(1 << minor_exp) - 1, (1 << minor_exp)] {
136                         compare(major, minor);
137                     }
138                 }
139                 compare(major, c_uint::MAX);
140             }
141             compare(c_uint::MAX, c_uint::MAX);
142         }
143     }
144 }
145