6363# NOTE: THIS MUST BE USED BEFORE THE map() OR map_at() MODIFIERS!
6464# - "resolve_final_symlink" is the opposite of "dont_resolve_final_symlink"
6565# (and it is on by default)
66+ # - "allow_nonexistent" is used to prefix "map" modifiers where the
67+ # whole pathname (not just the last component) is allowed to refer
68+ # to nonexistent file in nonexistent directory.
69+ # NOTE: THIS MUST BE USED BEFORE THE map() OR map_at() MODIFIERS!
70+ # - "allow_nonexistent_if(condition)" conditionally
71+ # allows the pathname to refer to nonexistent file in nonexistent directory
72+ # (see "allow_nonexistent")
73+ # NOTE: THIS MUST BE USED BEFORE THE map() OR map_at() MODIFIERS!
6674# - "postprocess(varname)" can be used to call postprocessor functions for
6775# mapped variables.
6876# - "return(expr)" can be used to alter the return value.
@@ -493,6 +501,22 @@ sub expr_to_flagexpr {
493501 return " $expr ? $flag : 0" ;
494502}
495503
504+ sub flagexpr_join {
505+ my $result = " 0" ;
506+ foreach my $flagexpr (@_ ) {
507+ if ($flagexpr eq " 0" ) {
508+ # zero flag, leave result as is
509+ } elsif ($result eq " 0" ) {
510+ # zero result, replace with flag
511+ $result = $flagexpr ;
512+ } else {
513+ # non-zero result and flag, join with |
514+ $result .= " | $flagexpr " ;
515+ }
516+ }
517+ return $result ;
518+ }
519+
496520# Process the modifier section coming from the original input line.
497521# This returns undef if failed, or a structure containing code fragments
498522# and other information for the actual code generation phase.
@@ -521,6 +545,7 @@ sub process_wrap_or_gate_modifiers {
521545 ' mapped_params_by_orig_name' => {},
522546 ' mapping_results_by_orig_name' => {},
523547 ' dont_resolve_final_symlink' => 0,
548+ ' allow_nonexistent' => 0,
524549
525550 ' postprocess_vars' => [],
526551 ' return_expr' => undef ,
@@ -573,6 +598,9 @@ sub process_wrap_or_gate_modifiers {
573598 my $new_name = " mapped__" .$param_to_be_mapped ;
574599 my $no_symlink_resolve =
575600 expr_to_flagexpr($mods -> {' dont_resolve_final_symlink' }, " SBOX_MAP_PATH_DONT_RESOLVE_FINAL_SYMLINK" );
601+ my $allow_nonexistent =
602+ expr_to_flagexpr($mods -> {' allow_nonexistent' }, " SBOX_MAP_PATH_ALLOW_NONEXISTENT" );
603+ my $flags = flagexpr_join($no_symlink_resolve , $allow_nonexistent );
576604
577605 $mods -> {' mapped_params_by_orig_name' }-> {$param_to_be_mapped } = " res_$new_name .mres_result_path" ;
578606 $mods -> {' mapping_results_by_orig_name' }-> {$param_to_be_mapped } = " res_$new_name " ;
@@ -583,7 +611,7 @@ sub process_wrap_or_gate_modifiers {
583611 " \t clear_mapping_results_struct(&res_$new_name );\n " .
584612 " \t sbox_map_path(__func__, " .
585613 " $param_to_be_mapped , " .
586- " $no_symlink_resolve , " .
614+ " $flags , " .
587615 " &res_$new_name , classmask);\n " .
588616 " \t if (res_$new_name .mres_errno) {\n " .
589617 " \t\t SB_LOG(SB_LOGLEVEL_DEBUG, \" mapping failed, errno %d \" ," .
@@ -626,6 +654,9 @@ sub process_wrap_or_gate_modifiers {
626654 my $ro_flag = $param_to_be_mapped ." _is_readonly" ;
627655 my $no_symlink_resolve =
628656 expr_to_flagexpr($mods -> {' dont_resolve_final_symlink' }, " SBOX_MAP_PATH_DONT_RESOLVE_FINAL_SYMLINK" );
657+ my $allow_nonexistent =
658+ expr_to_flagexpr($mods -> {' allow_nonexistent' }, " SBOX_MAP_PATH_ALLOW_NONEXISTENT" );
659+ my $flags = flagexpr_join($no_symlink_resolve , $allow_nonexistent );
629660
630661 $mods -> {' mapped_params_by_orig_name' }-> {$param_to_be_mapped } = " res_$new_name .mres_result_path" ;
631662 $mods -> {' mapping_results_by_orig_name' }-> {$param_to_be_mapped } = " res_$new_name " ;
@@ -636,7 +667,7 @@ sub process_wrap_or_gate_modifiers {
636667 " \t sbox_map_path_at(__func__, " .
637668 " $fd_param , " .
638669 " $param_to_be_mapped , " .
639- " $no_symlink_resolve , " .
670+ " $flags , " .
640671 " &res_$new_name , classmask);\n " .
641672 " \t if (res_$new_name .mres_errno) {\n " .
642673 " \t\t errno = res_$new_name .mres_errno;\n " .
@@ -692,6 +723,11 @@ sub process_wrap_or_gate_modifiers {
692723 } elsif ($modifiers [$i ] =~ m / ^dont_resolve_final_symlink_if\( (.*)\) $ / ) {
693724 my $condition = $1 ;
694725 $mods -> {' dont_resolve_final_symlink' } = " ($condition )" ;
726+ } elsif ($modifiers [$i ] eq ' allow_nonexistent' ) {
727+ $mods -> {' allow_nonexistent' } = 1;
728+ } elsif ($modifiers [$i ] =~ m / ^allow_nonexistent_if\( (.*)\) $ / ) {
729+ my $condition = $1 ;
730+ $mods -> {' allow_nonexistent' } = " ($condition )" ;
695731 } elsif (($modifiers [$i ] =~ m / ^optional_arg_is_create_mode\( (.*)\) $ / ) &&
696732 ($fn -> {' has_varargs' })) {
697733 my $va_list_condition = $1 ;
0 commit comments