@@ -137,39 +137,42 @@ fn parse_change(mode: &str, fperm: u32, considering_dir: bool) -> (u32, usize) {
137137 ( srwx, pos)
138138}
139139
140- /// Takes a user-supplied string and tries to parse to u16 mode bitmask .
140+ /// Modify a file mode based on a user-supplied string .
141141/// Supports comma-separated mode strings like "ug+rwX,o+rX" (same as chmod).
142- pub fn parse ( mode_string : & str , considering_dir : bool , umask : u32 ) -> Result < u32 , String > {
143- // Split by commas and process each mode part sequentially
144- let mut current_mode: u32 = 0 ;
142+ pub fn parse_chmod (
143+ current_mode : u32 ,
144+ mode_string : & str ,
145+ considering_dir : bool ,
146+ umask : u32 ,
147+ ) -> Result < u32 , String > {
148+ let mut new_mode: u32 = current_mode;
145149
150+ // Split by commas and process each mode part sequentially
146151 for mode_part in mode_string. split ( ',' ) {
147152 let mode_part = mode_part. trim ( ) ;
148153 if mode_part. is_empty ( ) {
149154 continue ;
150155 }
151156
152- current_mode = if mode_part. chars ( ) . any ( |c| c. is_ascii_digit ( ) ) {
153- parse_numeric ( current_mode , mode_part, considering_dir) ?
157+ new_mode = if mode_part. chars ( ) . any ( |c| c. is_ascii_digit ( ) ) {
158+ parse_numeric ( new_mode , mode_part, considering_dir) ?
154159 } else {
155- parse_symbolic ( current_mode , mode_part, umask, considering_dir) ?
160+ parse_symbolic ( new_mode , mode_part, umask, considering_dir) ?
156161 } ;
157162 }
158163
159- Ok ( current_mode)
164+ Ok ( new_mode)
165+ }
166+
167+ /// Takes a user-supplied string and tries to parse to u32 mode bitmask.
168+ pub fn parse ( mode_string : & str , considering_dir : bool , umask : u32 ) -> Result < u32 , String > {
169+ parse_chmod ( 0 , mode_string, considering_dir, umask)
160170}
161171
162172#[ allow( clippy:: unnecessary_cast) ]
163173pub fn parse_mode ( mode : & str ) -> Result < mode_t , String > {
164174 let mut new_mode = ( S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ) as u32 ;
165-
166- for mode_chunk in mode. split ( ',' ) {
167- new_mode = if mode_chunk. chars ( ) . any ( |c| c. is_ascii_digit ( ) ) {
168- parse_numeric ( new_mode, mode_chunk, true ) ?
169- } else {
170- parse_symbolic ( new_mode, mode_chunk, get_umask ( ) , true ) ?
171- } ;
172- }
175+ new_mode = parse_chmod ( new_mode, mode, true , get_umask ( ) ) ?;
173176 Ok ( new_mode as mode_t )
174177}
175178
@@ -203,23 +206,25 @@ pub fn get_umask() -> u32 {
203206mod tests {
204207
205208 use super :: parse;
209+ use super :: parse_chmod;
210+ use super :: parse_mode;
206211
207212 #[ test]
208- fn symbolic_modes ( ) {
209- assert_eq ! ( super :: parse_mode( "u+x" ) . unwrap( ) , 0o766 ) ;
213+ fn test_symbolic_modes ( ) {
214+ assert_eq ! ( parse_mode( "u+x" ) . unwrap( ) , 0o766 ) ;
210215 assert_eq ! (
211- super :: parse_mode( "+x" ) . unwrap( ) ,
216+ parse_mode( "+x" ) . unwrap( ) ,
212217 if crate :: os:: is_wsl_1( ) { 0o776 } else { 0o777 }
213218 ) ;
214- assert_eq ! ( super :: parse_mode( "a-w" ) . unwrap( ) , 0o444 ) ;
215- assert_eq ! ( super :: parse_mode( "g-r" ) . unwrap( ) , 0o626 ) ;
219+ assert_eq ! ( parse_mode( "a-w" ) . unwrap( ) , 0o444 ) ;
220+ assert_eq ! ( parse_mode( "g-r" ) . unwrap( ) , 0o626 ) ;
216221 }
217222
218223 #[ test]
219- fn numeric_modes ( ) {
220- assert_eq ! ( super :: parse_mode( "644" ) . unwrap( ) , 0o644 ) ;
221- assert_eq ! ( super :: parse_mode( "+100" ) . unwrap( ) , 0o766 ) ;
222- assert_eq ! ( super :: parse_mode( "-4" ) . unwrap( ) , 0o662 ) ;
224+ fn test_numeric_modes ( ) {
225+ assert_eq ! ( parse_mode( "644" ) . unwrap( ) , 0o644 ) ;
226+ assert_eq ! ( parse_mode( "+100" ) . unwrap( ) , 0o766 ) ;
227+ assert_eq ! ( parse_mode( "-4" ) . unwrap( ) , 0o662 ) ;
223228 }
224229
225230 #[ test]
@@ -340,4 +345,19 @@ mod tests {
340345 // First add user write, then set to 755 (should override)
341346 assert_eq ! ( parse( "u+w,755" , false , 0 ) . unwrap( ) , 0o755 ) ;
342347 }
348+
349+ #[ test]
350+ fn test_chmod_symbolic_modes ( ) {
351+ assert_eq ! ( parse_chmod( 0o666 , "u+x" , false , 0 ) . unwrap( ) , 0o766 ) ;
352+ assert_eq ! ( parse_chmod( 0o666 , "+x" , false , 0 ) . unwrap( ) , 0o777 ) ;
353+ assert_eq ! ( parse_chmod( 0o666 , "a-w" , false , 0 ) . unwrap( ) , 0o444 ) ;
354+ assert_eq ! ( parse_chmod( 0o666 , "g-r" , false , 0 ) . unwrap( ) , 0o626 ) ;
355+ }
356+
357+ #[ test]
358+ fn test_chmod_numeric_modes ( ) {
359+ assert_eq ! ( parse_chmod( 0o666 , "644" , false , 0 ) . unwrap( ) , 0o644 ) ;
360+ assert_eq ! ( parse_chmod( 0o666 , "+100" , false , 0 ) . unwrap( ) , 0o766 ) ;
361+ assert_eq ! ( parse_chmod( 0o666 , "-4" , false , 0 ) . unwrap( ) , 0o662 ) ;
362+ }
343363}
0 commit comments