44// file that was distributed with this source code.
55use std:: fs;
66use std:: path:: Path ;
7- #[ cfg( not( windows) ) ]
8- use uucore:: mode;
97use uucore:: translate;
108
11- /// Takes a user-supplied string and tries to parse to u16 mode bitmask.
12- /// Supports comma-separated mode strings like "ug+rwX,o+rX" (same as chmod).
13- pub fn parse ( mode_string : & str , considering_dir : bool , umask : u32 ) -> Result < u32 , String > {
14- // Split by commas and process each mode part sequentially
15- let mut current_mode: u32 = 0 ;
16-
17- for mode_part in mode_string. split ( ',' ) {
18- let mode_part = mode_part. trim ( ) ;
19- if mode_part. is_empty ( ) {
20- continue ;
21- }
22-
23- current_mode = if mode_part. chars ( ) . any ( |c| c. is_ascii_digit ( ) ) {
24- mode:: parse_numeric ( current_mode, mode_part, considering_dir) ?
25- } else {
26- mode:: parse_symbolic ( current_mode, mode_part, umask, considering_dir) ?
27- } ;
28- }
29-
30- Ok ( current_mode)
31- }
32-
339/// chmod a file or directory on UNIX.
3410///
3511/// Adapted from mkdir.rs. Handles own error printing.
@@ -55,128 +31,3 @@ pub fn chmod(path: &Path, mode: u32) -> Result<(), ()> {
5531 // chmod on Windows only sets the readonly flag, which isn't even honored on directories
5632 Ok ( ( ) )
5733}
58-
59- #[ cfg( test) ]
60- #[ cfg( not( windows) ) ]
61- mod tests {
62- use super :: parse;
63-
64- #[ test]
65- fn test_parse_numeric_mode ( ) {
66- // Simple numeric mode
67- assert_eq ! ( parse( "644" , false , 0 ) . unwrap( ) , 0o644 ) ;
68- assert_eq ! ( parse( "755" , false , 0 ) . unwrap( ) , 0o755 ) ;
69- assert_eq ! ( parse( "777" , false , 0 ) . unwrap( ) , 0o777 ) ;
70- assert_eq ! ( parse( "600" , false , 0 ) . unwrap( ) , 0o600 ) ;
71- }
72-
73- #[ test]
74- fn test_parse_numeric_mode_with_operator ( ) {
75- // Numeric mode with + operator
76- assert_eq ! ( parse( "+100" , false , 0 ) . unwrap( ) , 0o100 ) ;
77- assert_eq ! ( parse( "+644" , false , 0 ) . unwrap( ) , 0o644 ) ;
78-
79- // Numeric mode with - operator (starting from 0, so nothing to remove)
80- assert_eq ! ( parse( "-4" , false , 0 ) . unwrap( ) , 0 ) ;
81- // But if we first set a mode, then remove bits
82- assert_eq ! ( parse( "644,-4" , false , 0 ) . unwrap( ) , 0o640 ) ;
83- }
84-
85- #[ test]
86- fn test_parse_symbolic_mode ( ) {
87- // Simple symbolic modes
88- assert_eq ! ( parse( "u+x" , false , 0 ) . unwrap( ) , 0o100 ) ;
89- assert_eq ! ( parse( "g+w" , false , 0 ) . unwrap( ) , 0o020 ) ;
90- assert_eq ! ( parse( "o+r" , false , 0 ) . unwrap( ) , 0o004 ) ;
91- assert_eq ! ( parse( "a+x" , false , 0 ) . unwrap( ) , 0o111 ) ;
92- }
93-
94- #[ test]
95- fn test_parse_symbolic_mode_multiple_permissions ( ) {
96- // Multiple permissions in one mode
97- assert_eq ! ( parse( "u+rw" , false , 0 ) . unwrap( ) , 0o600 ) ;
98- assert_eq ! ( parse( "ug+rwx" , false , 0 ) . unwrap( ) , 0o770 ) ;
99- assert_eq ! ( parse( "a+rwx" , false , 0 ) . unwrap( ) , 0o777 ) ;
100- }
101-
102- #[ test]
103- fn test_parse_comma_separated_modes ( ) {
104- // Comma-separated mode strings (as mentioned in the doc comment)
105- assert_eq ! ( parse( "ug+rwX,o+rX" , false , 0 ) . unwrap( ) , 0o664 ) ;
106- assert_eq ! ( parse( "u+rwx,g+rx,o+r" , false , 0 ) . unwrap( ) , 0o754 ) ;
107- assert_eq ! ( parse( "u+w,g+w,o+w" , false , 0 ) . unwrap( ) , 0o222 ) ;
108- }
109-
110- #[ test]
111- fn test_parse_comma_separated_with_spaces ( ) {
112- // Comma-separated with spaces (should be trimmed)
113- assert_eq ! ( parse( "u+rw, g+rw, o+r" , false , 0 ) . unwrap( ) , 0o664 ) ;
114- assert_eq ! ( parse( " u+x , g+x " , false , 0 ) . unwrap( ) , 0o110 ) ;
115- }
116-
117- #[ test]
118- fn test_parse_mixed_numeric_and_symbolic ( ) {
119- // Mix of numeric and symbolic modes
120- assert_eq ! ( parse( "644,u+x" , false , 0 ) . unwrap( ) , 0o744 ) ;
121- assert_eq ! ( parse( "u+rw,755" , false , 0 ) . unwrap( ) , 0o755 ) ;
122- }
123-
124- #[ test]
125- fn test_parse_empty_string ( ) {
126- // Empty string should return 0
127- assert_eq ! ( parse( "" , false , 0 ) . unwrap( ) , 0 ) ;
128- assert_eq ! ( parse( " " , false , 0 ) . unwrap( ) , 0 ) ;
129- assert_eq ! ( parse( ",," , false , 0 ) . unwrap( ) , 0 ) ;
130- }
131-
132- #[ test]
133- fn test_parse_with_umask ( ) {
134- // Test with umask (affects symbolic modes when no level is specified)
135- let umask = 0o022 ;
136- assert_eq ! ( parse( "+w" , false , umask) . unwrap( ) , 0o200 ) ;
137- // The umask should be respected for symbolic modes without explicit level
138- }
139-
140- #[ test]
141- fn test_parse_considering_dir ( ) {
142- // Test directory vs file mode differences
143- // For directories, X (capital X) should add execute permission
144- assert_eq ! ( parse( "a+X" , true , 0 ) . unwrap( ) , 0o111 ) ;
145- // For files without execute, X should not add execute
146- assert_eq ! ( parse( "a+X" , false , 0 ) . unwrap( ) , 0o000 ) ;
147-
148- // Numeric modes for directories preserve setuid/setgid bits
149- assert_eq ! ( parse( "755" , true , 0 ) . unwrap( ) , 0o755 ) ;
150- }
151-
152- #[ test]
153- fn test_parse_invalid_modes ( ) {
154- // Invalid numeric mode (too large)
155- assert ! ( parse( "10000" , false , 0 ) . is_err( ) ) ;
156-
157- // Invalid operator
158- assert ! ( parse( "u*rw" , false , 0 ) . is_err( ) ) ;
159-
160- // Invalid symbolic mode
161- assert ! ( parse( "invalid" , false , 0 ) . is_err( ) ) ;
162- }
163-
164- #[ test]
165- fn test_parse_complex_combinations ( ) {
166- // Complex real-world examples
167- assert_eq ! ( parse( "u=rwx,g=rx,o=r" , false , 0 ) . unwrap( ) , 0o754 ) ;
168- // To test removal, we need to first set permissions, then remove them
169- assert_eq ! ( parse( "644,a-w" , false , 0 ) . unwrap( ) , 0o444 ) ;
170- assert_eq ! ( parse( "644,g-r" , false , 0 ) . unwrap( ) , 0o604 ) ;
171- }
172-
173- #[ test]
174- fn test_parse_sequential_application ( ) {
175- // Test that comma-separated modes are applied sequentially
176- // First set to 644, then add execute for user
177- assert_eq ! ( parse( "644,u+x" , false , 0 ) . unwrap( ) , 0o744 ) ;
178-
179- // First add user write, then set to 755 (should override)
180- assert_eq ! ( parse( "u+w,755" , false , 0 ) . unwrap( ) , 0o755 ) ;
181- }
182- }
0 commit comments