confz_fileset_init (7016B)
1 # vim: ft=zsh noet ts=4 sts=4 sw=4 2 3 # 4 # confz functions for file hierarchies and fileset miniformat 5 # 6 7 zmodload -F zsh/stat b:zstat 8 zmodload -m -F zsh/files b:zf_\* 9 10 typeset -g -A fileset_stat_cache fileset_stat_cur fileset_ftypes fileset_typenames 11 typeset -g fileset_stat_cur fileset_stat_next_id fileset_stat_cur_type fileset_stat_cur_perm fileset_stat_cur_major fileset_stat_cur_minor 12 13 fileset_ftypes=( # convert hex type to a word 14 C S # unix socket 15 c S 16 A L # symlink, could also be 'h' 17 a L 18 8 f # plain file 19 6 b # block device file 20 4 d # directory 21 2 c # character device file 22 1 p # FIFO pipe 23 ) 24 25 fileset_typenames=( 26 S "unix socket" 27 L "symbolic link" 28 f "plain file" 29 b "block device" 30 c "character device" 31 p "named pipe" 32 ) 33 34 fileset_reset_cache(){ 35 # omit unsetting used variables for now 36 # probably no particular gain in freeing them 37 fileset_stat_cache=() 38 fileset_stat_cur=() 39 fileset_stat_next_id=1 40 } 41 fileset_reset_cache 42 43 # runs zstat on $1 if not already in cache 44 # the result is available as $fileset_stat_cur associative array 45 fileset_stat() { 46 local id ret ftype fperm 47 id=${fileset_stat_cache[$1]:-missing} 48 if [[ $id == missing ]]; then 49 typeset -gA fileset_stat_$fileset_stat_next_id 50 zstat -L -H fileset_stat_$fileset_stat_next_id $1 &>/dev/null 51 ret=$? 52 if (($ret == 0)); then 53 fileset_stat_cache[$1]=$fileset_stat_next_id 54 fileset_stat_set_cur $fileset_stat_next_id 55 fileset_stat_next_id=$[ $fileset_stat_next_id + 1 ] 56 else 57 fileset_stat_cache[$1]=-$ret 58 fi 59 return $ret 60 elif (( $id >= 0 )); then 61 fileset_stat_set_cur $id 62 return 0 63 else 64 return $[ -($id) ] 65 fi 66 } 67 68 fileset_stat_set_cur(){ 69 local param ftype 70 param=fileset_stat_$1 71 fileset_stat_cur=( "${(@kvP)param}" ) 72 ftype=$[ [##16] $fileset_stat_cur[mode] >> 12 ] 73 fileset_stat_cur_type=$fileset_ftypes[$ftype] 74 fileset_stat_cur_perm=$[ [##8] $fileset_stat_cur[mode] & 4095 ] 75 fileset_stat_cur_major=$[ $fileset_stat_cur[rdev] >> 8 ] 76 fileset_stat_cur_minor=$[ $fileset_stat_cur[rdev] & 255 ] 77 } 78 79 fileset_resetcmd() { 80 fileset_reset_cache 81 "$@" 82 } 83 84 confz_fs_p_check() { 85 checkvars filename 86 local parent 87 parent=${${vars[filename]}:h} 88 do_command=( fileset_resetcmd mkdir -p $parent ) 89 fileset_stat $parent && [[ $fileset_stat_cur_type == d ]] 90 } 91 92 93 confz_fs_type_or_missing_check() { 94 checkvars filename flags filetype 95 if fileset_stat $vars[filename]; then 96 if [[ $fileset_stat_cur_type == $vars[filetype] ]]; then 97 return 0 98 elif [[ $vars[flags] == *'!'* ]]; then 99 fail_reason="expected ${fileset_typenames[${vars[filetype]}]}, got ${fileset_typenames[$fileset_stat_cur_type]}: ${(qqq)vars[filename]}" 100 return 1 101 else 102 die "$0: expected ${fileset_typenames[${vars[filetype]}]}, got ${fileset_typenames[$fileset_stat_cur_type]}: ${(qqq)vars[filename]}" 103 fi 104 else 105 return 0 106 fi 107 } 108 109 confz_fs_type_or_missing_do() { 110 local is_dir 111 if fileset_stat $vars[filename] && [[ $fileset_stat_cur_type == d ]]; then 112 is_dir=1 113 else 114 is_dir=0 115 fi 116 117 fileset_reset_cache 118 if [[ $vars[flags] == *r* ]]; then 119 if [[ $vars[flags] == *f* ]]; then 120 zf_rm -rf $vars[filename] 121 else 122 zf_rm -r $vars[filename] 123 fi 124 elif (($is_dir)); then 125 zf_rmdir $vars[filename] 126 else 127 if [[ $vars[flags] == *f* ]]; then 128 zf_rm -f $vars[filename] 129 else 130 zf_rm $vars[filename] 131 fi 132 fi 133 } 134 135 136 confz_fs_l_check() { 137 checkvars filename destination 138 defvar flags '' 139 140 if [[ $vars[flags] == *p* ]]; then 141 require fs_p :filename 142 fi 143 144 require fs_type_or_missing :filename :flags filetype=L 145 146 fileset_stat $vars[filename] && \ 147 [[ $fileset_stat_cur_type == L ]] && \ 148 [[ $fileset_stat_cur[link] == $vars[destination] ]] 149 } 150 151 confz_fs_l_do() { 152 local missing 153 fileset_stat $vars[filename] 154 missing=$? 155 fileset_reset_cache 156 if ! (($missing)); then 157 rm $vars[filename] || return $? 158 fi 159 zf_ln -sh $vars[destination] $vars[filename] 160 } 161 162 163 confz_fs_device_check() { 164 checkvars filename device_type major minor 165 defvar flags '' 166 167 if [[ $vars[flags] == *p* ]]; then 168 require fs_p :filename 169 fi 170 171 case $vars[device_type] in 172 (c) require fs_type_or_missing :filename :flags filetype=c ;; 173 (b) require fs_type_or_missing :filename :flags filetype=b ;; 174 (*) die "Incorrect device type: ${(qqq)vars[device_type]}" ;; 175 esac 176 177 fileset_stat $vars[filename] && \ 178 [[ $fileset_stat_cur_type == $vars[device_type] ]] && \ 179 [[ $fileset_stat_cur_major == $vars[major] ]] && \ 180 [[ $fileset_stat_cur_minor == $vars[minor] ]] 181 } 182 183 confz_fs_device_do() { 184 local missing 185 fileset_stat $vars[filename] 186 missing=$? 187 fileset_reset_cache 188 if ! (($missing)); then 189 rm $vars[filename] || return $? 190 fi 191 mknod $vars[filename] $vars[device_type] $vars[major] $vars[minor] 192 } 193 194 195 confz_fs_pipe_check() { 196 checkvars filename 197 defvar flags '' 198 199 if [[ $vars[flags] == *p* ]]; then 200 require fs_p :filename 201 fi 202 203 require fs_type_or_missing :filename :flags filetype=p 204 205 do_command=( fileset_resetcmd mkfifo $vars[filename] ) 206 fileset_stat $vars[filename] && [[ $fileset_stat_cur_type == p ]] 207 } 208 209 210 confz_fs_r_check() { 211 checkvars filename 212 defvar flags '' 213 do_command=( confz_fs_type_or_missing_do ) 214 ! fileset_stat $vars[filename] 215 } 216 217 218 confz_fs_m_check() { 219 checkvars filename mode 220 do_command=( fileset_resetcmd chmod $vars[mode] $vars[filename] ) 221 fileset_stat $vars[filename] && (( $fileset_stat_cur_perm == $vars[mode] )) 222 } 223 224 225 confz_fs_o_check() { 226 checkvars filename owner 227 do_command=( fileset_resetcmd zf_chown -h $vars[owner] $vars[filename] ) 228 fileset_stat $vars[filename] || \ 229 die "fs_o: could not access file ${(qqq)vars[filename]}" 230 231 if [[ $vars[owner] =~ '^[0-9]+:[0-9]+$' ]]; then 232 (( $fileset_stat_cur[uid] == ${${vars[owner]}%:*} && \ 233 $fileset_stat_cur[gid] == ${${vars[owner]}#*:} )) 234 elif [[ $vars[owner] =~ '^[0-9]+$' ]]; then 235 (( $fileset_stat_cur[uid] == ${${vars[owner]}%:*} )) 236 else 237 die "fs_o does not support non-numeric user/group: ${(qqq)vars[owner]}" 238 fi 239 } 240 241 242 confz_fs_f_check() { 243 checkvars filename 244 defvar flags '' 245 246 if [[ $vars[flags] == *p* ]]; then 247 require fs_p :filename 248 fi 249 250 require fs_type_or_missing :filename :flags filetype=f 251 252 fileset_stat $vars[filename] && [[ $fileset_stat_cur_type == f ]] 253 } 254 255 confz_fs_f_do() { 256 fileset_reset_cache 257 printf '' >> $vars[filename] 258 } 259 260 261 confz_fs_d_check() { 262 checkvars filename 263 defvar flags '' 264 265 require fs_type_or_missing :filename :flags filetype=d 266 267 if [[ $vars[flags] == *p* ]]; then 268 do_command=( fileset_resetcmd mkdir -p $vars[filename] ) 269 else 270 do_command=( fileset_resetcmd mkdir $vars[filename] ) 271 fi 272 273 fileset_stat $vars[filename] && [[ $fileset_stat_cur_type == d ]] 274 } 275 276 277 confz_fs_c_check() { 278 checkvars filename content_call 279 defvar flags '' 280 require fs_f :filename :flags 281 "${(Q@)${(z)vars[content_call]}}" | cmp -s - $vars[filename] 282 } 283 284 confz_fs_c_do() { 285 "${(Q@)${(z)vars[content_call]}}" > $vars[filename] 286 } 287 288 confz_fs_contentnl_check() { 289 checkvars filename content 290 defvar flags '' 291 require fs_f :filename :flags 292 printf '%s\n' "$vars[content]" | cmp -s - $vars[filename] 293 } 294 confz_fs_contentnl_do() { 295 printf '%s\n' "$vars[content]" > $vars[filename] 296 } 297