Hex Artifact Content

Artifact 171439581efda1a4baba0f0c2fa5fd0a1e954092:


0000: 23 21 20 2f 75 73 72 2f 62 69 6e 2f 65 6e 76 20  #! /usr/bin/env 
0010: 74 63 6c 73 68 0a 0a 70 61 63 6b 61 67 65 20 72  tclsh..package r
0020: 65 71 75 69 72 65 20 68 74 74 70 20 32 2e 37 0a  equire http 2.7.
0030: 70 61 63 6b 61 67 65 20 72 65 71 75 69 72 65 20  package require 
0040: 73 71 6c 69 74 65 33 0a 70 61 63 6b 61 67 65 20  sqlite3.package 
0050: 72 65 71 75 69 72 65 20 73 68 61 31 0a 70 61 63  require sha1.pac
0060: 6b 61 67 65 20 72 65 71 75 69 72 65 20 61 70 70  kage require app
0070: 66 73 64 0a 70 61 63 6b 61 67 65 20 72 65 71 75  fsd.package requ
0080: 69 72 65 20 70 6c 61 74 66 6f 72 6d 0a 70 61 63  ire platform.pac
0090: 6b 61 67 65 20 72 65 71 75 69 72 65 20 70 6b 69  kage require pki
00a0: 0a 0a 23 20 46 75 6e 63 74 69 6f 6e 73 20 73 70  ..# Functions sp
00b0: 65 63 69 66 69 63 61 6c 6c 79 20 6d 65 61 6e 74  ecifically meant
00c0: 20 66 6f 72 20 75 73 65 72 73 20 74 6f 20 72 65   for users to re
00d0: 70 6c 61 63 65 20 61 73 20 61 20 70 61 72 74 20  place as a part 
00e0: 6f 66 20 63 6f 6e 66 69 67 75 72 61 74 69 6f 6e  of configuration
00f0: 0a 6e 61 6d 65 73 70 61 63 65 20 65 76 61 6c 20  .namespace eval 
0100: 3a 3a 61 70 70 66 73 3a 3a 75 73 65 72 20 7b 0a  ::appfs::user {.
0110: 09 23 20 55 73 65 72 2d 72 65 70 6c 61 63 61 62  .# User-replacab
0120: 6c 65 20 66 75 6e 63 74 69 6f 6e 20 74 6f 20 63  le function to c
0130: 6f 6e 76 65 72 74 20 61 20 68 6f 73 74 6e 61 6d  onvert a hostnam
0140: 65 2f 68 61 73 68 2f 6d 65 74 68 6f 64 20 74 6f  e/hash/method to
0150: 20 61 6e 20 55 52 4c 0a 09 70 72 6f 63 20 63 6f   an URL..proc co
0160: 6e 73 74 72 75 63 74 5f 75 72 6c 20 7b 68 6f 73  nstruct_url {hos
0170: 74 6e 61 6d 65 20 68 61 73 68 20 6d 65 74 68 6f  tname hash metho
0180: 64 7d 20 7b 0a 09 09 72 65 74 75 72 6e 20 22 68  d} {...return "h
0190: 74 74 70 3a 2f 2f 24 68 6f 73 74 6e 61 6d 65 2f  ttp://$hostname/
01a0: 61 70 70 66 73 2f 24 6d 65 74 68 6f 64 2f 24 68  appfs/$method/$h
01b0: 61 73 68 22 0a 09 7d 0a 0a 09 23 20 55 73 65 72  ash"..}...# User
01c0: 2d 72 65 70 6c 61 63 65 61 62 6c 65 20 66 75 6e  -replaceable fun
01d0: 63 74 69 6f 6e 20 67 65 74 20 74 68 65 20 68 6f  ction get the ho
01e0: 6d 65 20 64 69 72 65 63 74 6f 72 79 20 6f 66 20  me directory of 
01f0: 74 68 65 20 63 75 72 72 65 6e 74 20 75 73 65 72  the current user
0200: 0a 09 70 72 6f 63 20 67 65 74 5f 68 6f 6d 65 64  ..proc get_homed
0210: 69 72 20 7b 7d 20 7b 0a 09 09 72 65 74 75 72 6e  ir {} {...return
0220: 20 5b 3a 3a 61 70 70 66 73 64 3a 3a 67 65 74 5f   [::appfsd::get_
0230: 68 6f 6d 65 64 69 72 5d 0a 09 7d 0a 7d 0a 0a 6e  homedir]..}.}..n
0240: 61 6d 65 73 70 61 63 65 20 65 76 61 6c 20 3a 3a  amespace eval ::
0250: 61 70 70 66 73 20 7b 0a 09 76 61 72 69 61 62 6c  appfs {..variabl
0260: 65 20 63 61 63 68 65 64 69 72 20 22 2f 74 6d 70  e cachedir "/tmp
0270: 2f 61 70 70 66 73 2d 63 61 63 68 65 22 0a 09 76  /appfs-cache"..v
0280: 61 72 69 61 62 6c 65 20 74 74 6c 20 33 36 30 30  ariable ttl 3600
0290: 0a 09 76 61 72 69 61 62 6c 65 20 6e 74 74 6c 20  ..variable nttl 
02a0: 36 30 0a 0a 0a 09 70 72 6f 63 20 5f 68 61 73 68  60....proc _hash
02b0: 5f 73 65 70 20 7b 68 61 73 68 20 7b 73 65 70 73  _sep {hash {seps
02c0: 20 34 7d 7d 20 7b 0a 09 09 66 6f 72 20 7b 73 65   4}} {...for {se
02d0: 74 20 69 64 78 20 30 7d 20 7b 24 69 64 78 20 3c  t idx 0} {$idx <
02e0: 20 24 73 65 70 73 7d 20 7b 69 6e 63 72 20 69 64   $seps} {incr id
02f0: 78 7d 20 7b 0a 09 09 09 61 70 70 65 6e 64 20 72  x} {....append r
0300: 65 74 76 61 6c 20 22 5b 73 74 72 69 6e 67 20 72  etval "[string r
0310: 61 6e 67 65 20 24 68 61 73 68 20 5b 65 78 70 72  ange $hash [expr
0320: 20 7b 24 69 64 78 20 2a 20 32 7d 5d 20 5b 65 78   {$idx * 2}] [ex
0330: 70 72 20 7b 28 24 69 64 78 20 2a 20 32 29 20 2b  pr {($idx * 2) +
0340: 20 31 7d 5d 5d 2f 22 0a 09 09 7d 0a 09 09 61 70   1}]]/"...}...ap
0350: 70 65 6e 64 20 72 65 74 76 61 6c 20 22 5b 73 74  pend retval "[st
0360: 72 69 6e 67 20 72 61 6e 67 65 20 24 68 61 73 68  ring range $hash
0370: 20 5b 65 78 70 72 20 7b 24 69 64 78 20 2a 20 32   [expr {$idx * 2
0380: 7d 5d 20 65 6e 64 5d 22 0a 0a 09 09 72 65 74 75  }] end]"....retu
0390: 72 6e 20 24 72 65 74 76 61 6c 0a 09 7d 0a 0a 09  rn $retval..}...
03a0: 70 72 6f 63 20 5f 63 61 63 68 65 66 69 6c 65 20  proc _cachefile 
03b0: 7b 75 72 6c 20 6b 65 79 20 7b 6b 65 79 49 73 48  {url key {keyIsH
03c0: 61 73 68 20 31 7d 7d 20 7b 0a 09 09 73 65 74 20  ash 1}} {...set 
03d0: 66 69 6c 65 6b 65 79 20 24 6b 65 79 0a 09 09 69  filekey $key...i
03e0: 66 20 7b 24 6b 65 79 49 73 48 61 73 68 7d 20 7b  f {$keyIsHash} {
03f0: 0a 09 09 09 73 65 74 20 66 69 6c 65 6b 65 79 20  ....set filekey 
0400: 5b 5f 68 61 73 68 5f 73 65 70 20 24 66 69 6c 65  [_hash_sep $file
0410: 6b 65 79 5d 0a 09 09 7d 0a 0a 09 09 73 65 74 20  key]...}....set 
0420: 66 69 6c 65 20 5b 66 69 6c 65 20 6a 6f 69 6e 20  file [file join 
0430: 24 3a 3a 61 70 70 66 73 3a 3a 63 61 63 68 65 64  $::appfs::cached
0440: 69 72 20 24 66 69 6c 65 6b 65 79 5d 0a 0a 09 09  ir $filekey]....
0450: 66 69 6c 65 20 6d 6b 64 69 72 20 5b 66 69 6c 65  file mkdir [file
0460: 20 64 69 72 6e 61 6d 65 20 24 66 69 6c 65 5d 0a   dirname $file].
0470: 0a 09 09 69 66 20 7b 5b 66 69 6c 65 20 65 78 69  ...if {[file exi
0480: 73 74 73 20 24 66 69 6c 65 5d 7d 20 7b 0a 09 09  sts $file]} {...
0490: 09 72 65 74 75 72 6e 20 24 66 69 6c 65 0a 09 09  .return $file...
04a0: 7d 0a 0a 09 09 73 65 74 20 74 6d 70 66 69 6c 65  }....set tmpfile
04b0: 20 22 24 7b 66 69 6c 65 7d 2e 5b 65 78 70 72 20   "${file}.[expr 
04c0: 7b 72 61 6e 64 28 29 7d 5d 5b 63 6c 6f 63 6b 20  {rand()}][clock 
04d0: 63 6c 69 63 6b 73 5d 22 0a 0a 09 09 73 65 74 20  clicks]"....set 
04e0: 66 64 20 5b 6f 70 65 6e 20 24 74 6d 70 66 69 6c  fd [open $tmpfil
04f0: 65 20 22 77 22 5d 0a 09 09 66 63 6f 6e 66 69 67  e "w"]...fconfig
0500: 75 72 65 20 24 66 64 20 2d 74 72 61 6e 73 6c 61  ure $fd -transla
0510: 74 69 6f 6e 20 62 69 6e 61 72 79 0a 0a 09 09 63  tion binary....c
0520: 61 74 63 68 20 7b 0a 09 09 09 73 65 74 20 74 6f  atch {....set to
0530: 6b 65 6e 20 5b 3a 3a 68 74 74 70 3a 3a 67 65 74  ken [::http::get
0540: 75 72 6c 20 24 75 72 6c 20 2d 63 68 61 6e 6e 65  url $url -channe
0550: 6c 20 24 66 64 20 2d 62 69 6e 61 72 79 20 74 72  l $fd -binary tr
0560: 75 65 5d 0a 09 09 7d 0a 0a 09 09 69 66 20 7b 5b  ue]...}....if {[
0570: 69 6e 66 6f 20 65 78 69 73 74 73 20 74 6f 6b 65  info exists toke
0580: 6e 5d 7d 20 7b 0a 09 09 09 73 65 74 20 6e 63 6f  n]} {....set nco
0590: 64 65 20 5b 3a 3a 68 74 74 70 3a 3a 6e 63 6f 64  de [::http::ncod
05a0: 65 20 24 74 6f 6b 65 6e 5d 0a 09 09 09 3a 3a 68  e $token]....::h
05b0: 74 74 70 3a 3a 72 65 73 65 74 20 24 74 6f 6b 65  ttp::reset $toke
05c0: 6e 0a 09 09 7d 20 65 6c 73 65 20 7b 0a 09 09 09  n...} else {....
05d0: 73 65 74 20 6e 63 6f 64 65 20 22 39 30 30 22 0a  set ncode "900".
05e0: 09 09 7d 0a 0a 09 09 63 6c 6f 73 65 20 24 66 64  ..}....close $fd
05f0: 0a 0a 09 09 69 66 20 7b 24 6b 65 79 49 73 48 61  ....if {$keyIsHa
0600: 73 68 7d 20 7b 0a 09 09 09 73 65 74 20 68 61 73  sh} {....set has
0610: 68 20 5b 73 74 72 69 6e 67 20 74 6f 6c 6f 77 65  h [string tolowe
0620: 72 20 5b 73 68 61 31 3a 3a 73 68 61 31 20 2d 68  r [sha1::sha1 -h
0630: 65 78 20 2d 66 69 6c 65 20 24 74 6d 70 66 69 6c  ex -file $tmpfil
0640: 65 5d 5d 0a 09 09 7d 20 65 6c 73 65 20 7b 0a 09  e]]...} else {..
0650: 09 09 73 65 74 20 68 61 73 68 20 24 6b 65 79 0a  ..set hash $key.
0660: 09 09 7d 0a 0a 09 09 69 66 20 7b 24 6e 63 6f 64  ..}....if {$ncod
0670: 65 20 3d 3d 20 22 32 30 30 22 20 26 26 20 24 68  e == "200" && $h
0680: 61 73 68 20 3d 3d 20 24 6b 65 79 7d 20 7b 0a 09  ash == $key} {..
0690: 09 09 66 69 6c 65 20 72 65 6e 61 6d 65 20 2d 66  ..file rename -f
06a0: 6f 72 63 65 20 2d 2d 20 24 74 6d 70 66 69 6c 65  orce -- $tmpfile
06b0: 20 24 66 69 6c 65 0a 09 09 7d 20 65 6c 73 65 20   $file...} else 
06c0: 7b 0a 09 09 09 66 69 6c 65 20 64 65 6c 65 74 65  {....file delete
06d0: 20 2d 66 6f 72 63 65 20 2d 2d 20 24 74 6d 70 66   -force -- $tmpf
06e0: 69 6c 65 0a 09 09 7d 0a 0a 09 09 72 65 74 75 72  ile...}....retur
06f0: 6e 20 24 66 69 6c 65 0a 09 7d 0a 0a 0a 09 70 72  n $file..}....pr
0700: 6f 63 20 5f 69 73 48 61 73 68 20 7b 76 61 6c 75  oc _isHash {valu
0710: 65 7d 20 7b 0a 09 09 73 65 74 20 76 61 6c 75 65  e} {...set value
0720: 20 5b 73 74 72 69 6e 67 20 74 6f 6c 6f 77 65 72   [string tolower
0730: 20 24 76 61 6c 75 65 5d 0a 0a 09 09 69 66 20 7b   $value]....if {
0740: 5b 73 74 72 69 6e 67 20 6c 65 6e 67 74 68 20 24  [string length $
0750: 76 61 6c 75 65 5d 20 21 3d 20 34 30 7d 20 7b 0a  value] != 40} {.
0760: 09 09 09 72 65 74 75 72 6e 20 66 61 6c 73 65 0a  ...return false.
0770: 09 09 7d 0a 0a 09 09 69 66 20 7b 21 5b 72 65 67  ..}....if {![reg
0780: 65 78 70 20 7b 5e 5b 30 2d 39 61 2d 66 5d 2a 24  exp {^[0-9a-f]*$
0790: 7d 20 24 76 61 6c 75 65 5d 7d 20 7b 0a 09 09 09  } $value]} {....
07a0: 72 65 74 75 72 6e 20 66 61 6c 73 65 0a 09 09 7d  return false...}
07b0: 0a 0a 09 09 72 65 74 75 72 6e 20 74 72 75 65 0a  ....return true.
07c0: 09 7d 0a 0a 09 70 72 6f 63 20 5f 6e 6f 72 6d 61  .}...proc _norma
07d0: 6c 69 7a 65 4f 53 20 7b 6f 73 7d 20 7b 0a 09 09  lizeOS {os} {...
07e0: 73 65 74 20 6f 73 20 5b 73 74 72 69 6e 67 20 74  set os [string t
07f0: 6f 6c 6f 77 65 72 20 5b 73 74 72 69 6e 67 20 74  olower [string t
0800: 72 69 6d 20 24 6f 73 5d 5d 0a 0a 09 09 73 77 69  rim $os]]....swi
0810: 74 63 68 20 2d 2d 20 24 6f 73 20 7b 0a 09 09 09  tch -- $os {....
0820: 22 6c 69 6e 75 78 22 20 2d 20 22 66 72 65 65 62  "linux" - "freeb
0830: 73 64 22 20 2d 20 22 6f 70 65 6e 62 73 64 22 20  sd" - "openbsd" 
0840: 2d 20 22 6e 65 74 62 73 64 22 20 7b 0a 09 09 09  - "netbsd" {....
0850: 09 72 65 74 75 72 6e 20 24 6f 73 0a 09 09 09 7d  .return $os....}
0860: 0a 09 09 09 22 73 75 6e 6f 73 22 20 7b 0a 09 09  ...."sunos" {...
0870: 09 09 72 65 74 75 72 6e 20 22 73 6f 6c 61 72 69  ..return "solari
0880: 73 22 0a 09 09 09 7d 0a 09 09 09 22 6e 6f 61 72  s"....}...."noar
0890: 63 68 22 20 2d 20 22 6e 6f 6e 65 22 20 2d 20 22  ch" - "none" - "
08a0: 61 6e 79 22 20 2d 20 22 61 6c 6c 22 20 7b 0a 09  any" - "all" {..
08b0: 09 09 09 72 65 74 75 72 6e 20 22 6e 6f 61 72 63  ...return "noarc
08c0: 68 22 0a 09 09 09 7d 0a 09 09 7d 0a 0a 09 09 72  h"....}...}....r
08d0: 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f  eturn -code erro
08e0: 72 20 22 55 6e 61 62 6c 65 20 74 6f 20 6e 6f 72  r "Unable to nor
08f0: 6d 61 6c 69 7a 65 20 4f 53 3a 20 24 6f 73 22 0a  malize OS: $os".
0900: 09 7d 0a 0a 09 70 72 6f 63 20 5f 6e 6f 72 6d 61  .}...proc _norma
0910: 6c 69 7a 65 43 50 55 20 7b 63 70 75 7d 20 7b 0a  lizeCPU {cpu} {.
0920: 09 09 73 65 74 20 63 70 75 20 5b 73 74 72 69 6e  ..set cpu [strin
0930: 67 20 74 6f 6c 6f 77 65 72 20 5b 73 74 72 69 6e  g tolower [strin
0940: 67 20 74 72 69 6d 20 24 63 70 75 5d 5d 0a 0a 09  g trim $cpu]]...
0950: 09 73 77 69 74 63 68 20 2d 67 6c 6f 62 20 2d 2d  .switch -glob --
0960: 20 24 63 70 75 20 7b 0a 09 09 09 22 69 3f 38 36   $cpu {...."i?86
0970: 22 20 7b 0a 09 09 09 09 72 65 74 75 72 6e 20 22  " {.....return "
0980: 69 78 38 36 22 0a 09 09 09 7d 0a 09 09 09 22 78  ix86"....}...."x
0990: 38 36 5f 36 34 22 20 7b 0a 09 09 09 09 72 65 74  86_64" {.....ret
09a0: 75 72 6e 20 24 63 70 75 0a 09 09 09 7d 0a 09 09  urn $cpu....}...
09b0: 09 22 6e 6f 61 72 63 68 22 20 2d 20 22 6e 6f 6e  ."noarch" - "non
09c0: 65 22 20 2d 20 22 61 6e 79 22 20 2d 20 22 61 6c  e" - "any" - "al
09d0: 6c 22 20 7b 0a 09 09 09 09 72 65 74 75 72 6e 20  l" {.....return 
09e0: 22 6e 6f 61 72 63 68 22 0a 09 09 09 7d 0a 09 09  "noarch"....}...
09f0: 7d 0a 0a 09 09 72 65 74 75 72 6e 20 2d 63 6f 64  }....return -cod
0a00: 65 20 65 72 72 6f 72 20 22 55 6e 61 62 6c 65 20  e error "Unable 
0a10: 74 6f 20 6e 6f 72 6d 61 6c 69 7a 65 20 43 50 55  to normalize CPU
0a20: 3a 20 24 63 70 75 22 0a 09 7d 0a 0a 09 70 72 6f  : $cpu"..}...pro
0a30: 63 20 5f 61 73 5f 75 73 65 72 20 7b 63 6f 64 65  c _as_user {code
0a40: 7d 20 7b 0a 09 09 3a 3a 61 70 70 66 73 64 3a 3a  } {...::appfsd::
0a50: 73 69 6d 75 6c 61 74 65 5f 75 73 65 72 5f 66 73  simulate_user_fs
0a60: 5f 65 6e 74 65 72 0a 0a 09 09 73 65 74 20 72 65  _enter....set re
0a70: 74 63 6f 64 65 20 5b 63 61 74 63 68 20 5b 6c 69  tcode [catch [li
0a80: 73 74 20 75 70 6c 65 76 65 6c 20 24 63 6f 64 65  st uplevel $code
0a90: 5d 20 72 65 74 73 74 72 5d 0a 0a 09 09 3a 3a 61  ] retstr]....::a
0aa0: 70 70 66 73 64 3a 3a 73 69 6d 75 6c 61 74 65 5f  ppfsd::simulate_
0ab0: 75 73 65 72 5f 66 73 5f 6c 65 61 76 65 0a 0a 09  user_fs_leave...
0ac0: 09 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 24 72  .return -code $r
0ad0: 65 74 63 6f 64 65 20 24 72 65 74 73 74 72 0a 09  etcode $retstr..
0ae0: 7d 0a 0a 09 70 72 6f 63 20 69 6e 69 74 20 7b 7d  }...proc init {}
0af0: 20 7b 0a 09 09 69 66 20 7b 5b 69 6e 66 6f 20 65   {...if {[info e
0b00: 78 69 73 74 73 20 3a 3a 61 70 70 66 73 3a 3a 69  xists ::appfs::i
0b10: 6e 69 74 5f 63 61 6c 6c 65 64 5d 7d 20 7b 0a 09  nit_called]} {..
0b20: 09 09 72 65 74 75 72 6e 0a 09 09 7d 0a 0a 09 09  ..return...}....
0b30: 23 20 46 6f 72 63 65 20 5b 70 61 72 72 61 79 5d  # Force [parray]
0b40: 20 74 6f 20 62 65 20 6c 6f 61 64 65 64 0a 09 09   to be loaded...
0b50: 63 61 74 63 68 20 7b 0a 09 09 09 70 61 72 72 61  catch {....parra
0b60: 79 20 64 6f 65 73 5f 6e 6f 74 5f 65 78 69 73 74  y does_not_exist
0b70: 0a 09 09 7d 0a 0a 09 09 73 65 74 20 3a 3a 61 70  ...}....set ::ap
0b80: 70 66 73 3a 3a 69 6e 69 74 5f 63 61 6c 6c 65 64  pfs::init_called
0b90: 20 31 0a 0a 09 09 23 20 4c 6f 61 64 20 63 6f 6e   1....# Load con
0ba0: 66 69 67 75 72 61 74 69 6f 6e 20 66 69 6c 65 0a  figuration file.
0bb0: 09 09 73 65 74 20 63 6f 6e 66 69 67 5f 66 69 6c  ..set config_fil
0bc0: 65 20 5b 66 69 6c 65 20 6a 6f 69 6e 20 24 3a 3a  e [file join $::
0bd0: 61 70 70 66 73 3a 3a 63 61 63 68 65 64 69 72 20  appfs::cachedir 
0be0: 63 6f 6e 66 69 67 5d 0a 09 09 69 66 20 7b 5b 66  config]...if {[f
0bf0: 69 6c 65 20 65 78 69 73 74 73 20 24 63 6f 6e 66  ile exists $conf
0c00: 69 67 5f 66 69 6c 65 5d 7d 20 7b 0a 09 09 09 73  ig_file]} {....s
0c10: 6f 75 72 63 65 20 24 63 6f 6e 66 69 67 5f 66 69  ource $config_fi
0c20: 6c 65 0a 09 09 7d 0a 0a 09 09 69 66 20 7b 21 5b  le...}....if {![
0c30: 69 6e 66 6f 20 65 78 69 73 74 73 20 3a 3a 61 70  info exists ::ap
0c40: 70 66 73 3a 3a 64 62 5d 7d 20 7b 0a 09 09 09 66  pfs::db]} {....f
0c50: 69 6c 65 20 6d 6b 64 69 72 20 24 3a 3a 61 70 70  ile mkdir $::app
0c60: 66 73 3a 3a 63 61 63 68 65 64 69 72 0a 0a 09 09  fs::cachedir....
0c70: 09 73 71 6c 69 74 65 33 20 3a 3a 61 70 70 66 73  .sqlite3 ::appfs
0c80: 3a 3a 64 62 20 5b 66 69 6c 65 20 6a 6f 69 6e 20  ::db [file join 
0c90: 24 3a 3a 61 70 70 66 73 3a 3a 63 61 63 68 65 64  $::appfs::cached
0ca0: 69 72 20 63 61 63 68 65 2e 64 62 5d 0a 0a 09 09  ir cache.db]....
0cb0: 09 3a 3a 61 70 70 66 73 3a 3a 64 62 20 74 69 6d  .::appfs::db tim
0cc0: 65 6f 75 74 20 33 30 30 30 30 0a 09 09 7d 0a 0a  eout 30000...}..
0cd0: 09 09 23 20 43 72 65 61 74 65 20 74 61 62 6c 65  ..# Create table
0ce0: 73 0a 09 09 64 62 20 65 76 61 6c 20 7b 43 52 45  s...db eval {CRE
0cf0: 41 54 45 20 54 41 42 4c 45 20 49 46 20 4e 4f 54  ATE TABLE IF NOT
0d00: 20 45 58 49 53 54 53 20 73 69 74 65 73 28 68 6f   EXISTS sites(ho
0d10: 73 74 6e 61 6d 65 20 50 52 49 4d 41 52 59 20 4b  stname PRIMARY K
0d20: 45 59 2c 20 6c 61 73 74 55 70 64 61 74 65 2c 20  EY, lastUpdate, 
0d30: 74 74 6c 29 3b 7d 0a 09 09 64 62 20 65 76 61 6c  ttl);}...db eval
0d40: 20 7b 43 52 45 41 54 45 20 54 41 42 4c 45 20 49   {CREATE TABLE I
0d50: 46 20 4e 4f 54 20 45 58 49 53 54 53 20 70 61 63  F NOT EXISTS pac
0d60: 6b 61 67 65 73 28 68 6f 73 74 6e 61 6d 65 2c 20  kages(hostname, 
0d70: 73 68 61 31 2c 20 70 61 63 6b 61 67 65 2c 20 76  sha1, package, v
0d80: 65 72 73 69 6f 6e 2c 20 6f 73 2c 20 63 70 75 41  ersion, os, cpuA
0d90: 72 63 68 2c 20 69 73 4c 61 74 65 73 74 2c 20 68  rch, isLatest, h
0da0: 61 76 65 4d 61 6e 69 66 65 73 74 29 3b 7d 0a 09  aveManifest);}..
0db0: 09 64 62 20 65 76 61 6c 20 7b 43 52 45 41 54 45  .db eval {CREATE
0dc0: 20 54 41 42 4c 45 20 49 46 20 4e 4f 54 20 45 58   TABLE IF NOT EX
0dd0: 49 53 54 53 20 66 69 6c 65 73 28 70 61 63 6b 61  ISTS files(packa
0de0: 67 65 5f 73 68 61 31 2c 20 74 79 70 65 2c 20 74  ge_sha1, type, t
0df0: 69 6d 65 2c 20 73 6f 75 72 63 65 2c 20 73 69 7a  ime, source, siz
0e00: 65 2c 20 70 65 72 6d 73 2c 20 66 69 6c 65 5f 73  e, perms, file_s
0e10: 68 61 31 2c 20 66 69 6c 65 5f 6e 61 6d 65 2c 20  ha1, file_name, 
0e20: 66 69 6c 65 5f 64 69 72 65 63 74 6f 72 79 29 3b  file_directory);
0e30: 7d 0a 0a 09 09 23 20 43 72 65 61 74 65 20 69 6e  }....# Create in
0e40: 64 65 78 65 73 0a 09 09 64 62 20 65 76 61 6c 20  dexes...db eval 
0e50: 7b 43 52 45 41 54 45 20 49 4e 44 45 58 20 49 46  {CREATE INDEX IF
0e60: 20 4e 4f 54 20 45 58 49 53 54 53 20 73 69 74 65   NOT EXISTS site
0e70: 73 5f 69 6e 64 65 78 20 4f 4e 20 73 69 74 65 73  s_index ON sites
0e80: 20 28 68 6f 73 74 6e 61 6d 65 29 3b 7d 0a 09 09   (hostname);}...
0e90: 64 62 20 65 76 61 6c 20 7b 43 52 45 41 54 45 20  db eval {CREATE 
0ea0: 49 4e 44 45 58 20 49 46 20 4e 4f 54 20 45 58 49  INDEX IF NOT EXI
0eb0: 53 54 53 20 70 61 63 6b 61 67 65 73 5f 69 6e 64  STS packages_ind
0ec0: 65 78 20 4f 4e 20 70 61 63 6b 61 67 65 73 20 28  ex ON packages (
0ed0: 68 6f 73 74 6e 61 6d 65 2c 20 73 68 61 31 2c 20  hostname, sha1, 
0ee0: 70 61 63 6b 61 67 65 2c 20 76 65 72 73 69 6f 6e  package, version
0ef0: 2c 20 6f 73 2c 20 63 70 75 41 72 63 68 29 3b 7d  , os, cpuArch);}
0f00: 0a 09 09 64 62 20 65 76 61 6c 20 7b 43 52 45 41  ...db eval {CREA
0f10: 54 45 20 49 4e 44 45 58 20 49 46 20 4e 4f 54 20  TE INDEX IF NOT 
0f20: 45 58 49 53 54 53 20 66 69 6c 65 73 5f 69 6e 64  EXISTS files_ind
0f30: 65 78 20 4f 4e 20 66 69 6c 65 73 20 28 70 61 63  ex ON files (pac
0f40: 6b 61 67 65 5f 73 68 61 31 2c 20 66 69 6c 65 5f  kage_sha1, file_
0f50: 6e 61 6d 65 2c 20 66 69 6c 65 5f 64 69 72 65 63  name, file_direc
0f60: 74 6f 72 79 29 3b 7d 0a 09 7d 0a 0a 09 70 72 6f  tory);}..}...pro
0f70: 63 20 64 6f 77 6e 6c 6f 61 64 20 7b 68 6f 73 74  c download {host
0f80: 6e 61 6d 65 20 68 61 73 68 20 7b 6d 65 74 68 6f  name hash {metho
0f90: 64 20 73 68 61 31 7d 7d 20 7b 0a 09 09 73 65 74  d sha1}} {...set
0fa0: 20 75 72 6c 20 5b 3a 3a 61 70 70 66 73 3a 3a 75   url [::appfs::u
0fb0: 73 65 72 3a 3a 63 6f 6e 73 74 72 75 63 74 5f 75  ser::construct_u
0fc0: 72 6c 20 24 68 6f 73 74 6e 61 6d 65 20 24 68 61  rl $hostname $ha
0fd0: 73 68 20 24 6d 65 74 68 6f 64 5d 0a 09 09 73 65  sh $method]...se
0fe0: 74 20 66 69 6c 65 20 5b 5f 63 61 63 68 65 66 69  t file [_cachefi
0ff0: 6c 65 20 24 75 72 6c 20 24 68 61 73 68 5d 0a 0a  le $url $hash]..
1000: 09 09 69 66 20 7b 21 5b 66 69 6c 65 20 65 78 69  ..if {![file exi
1010: 73 74 73 20 24 66 69 6c 65 5d 7d 20 7b 0a 09 09  sts $file]} {...
1020: 09 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72  .return -code er
1030: 72 6f 72 20 22 55 6e 61 62 6c 65 20 74 6f 20 66  ror "Unable to f
1040: 65 74 63 68 20 28 66 69 6c 65 20 64 6f 65 73 20  etch (file does 
1050: 6e 6f 74 20 65 78 69 73 74 3a 20 24 66 69 6c 65  not exist: $file
1060: 29 22 0a 09 09 7d 0a 0a 09 09 72 65 74 75 72 6e  )"...}....return
1070: 20 24 66 69 6c 65 0a 09 7d 0a 0a 09 70 72 6f 63   $file..}...proc
1080: 20 67 65 74 69 6e 64 65 78 20 7b 68 6f 73 74 6e   getindex {hostn
1090: 61 6d 65 7d 20 7b 0a 09 09 73 65 74 20 6e 6f 77  ame} {...set now
10a0: 20 5b 63 6c 6f 63 6b 20 73 65 63 6f 6e 64 73 5d   [clock seconds]
10b0: 0a 0a 09 09 73 65 74 20 6c 61 73 74 55 70 64 61  ....set lastUpda
10c0: 74 65 73 20 5b 64 62 20 65 76 61 6c 20 7b 53 45  tes [db eval {SE
10d0: 4c 45 43 54 20 6c 61 73 74 55 70 64 61 74 65 2c  LECT lastUpdate,
10e0: 20 74 74 6c 20 46 52 4f 4d 20 73 69 74 65 73 20   ttl FROM sites 
10f0: 57 48 45 52 45 20 68 6f 73 74 6e 61 6d 65 20 3d  WHERE hostname =
1100: 20 24 68 6f 73 74 6e 61 6d 65 20 4c 49 4d 49 54   $hostname LIMIT
1110: 20 31 3b 7d 5d 0a 09 09 69 66 20 7b 5b 6c 6c 65   1;}]...if {[lle
1120: 6e 67 74 68 20 24 6c 61 73 74 55 70 64 61 74 65  ngth $lastUpdate
1130: 73 5d 20 3d 3d 20 30 7d 20 7b 0a 09 09 09 73 65  s] == 0} {....se
1140: 74 20 6c 61 73 74 55 70 64 61 74 65 20 30 0a 09  t lastUpdate 0..
1150: 09 09 73 65 74 20 74 74 6c 20 30 0a 09 09 7d 20  ..set ttl 0...} 
1160: 65 6c 73 65 20 7b 0a 09 09 09 73 65 74 20 6c 61  else {....set la
1170: 73 74 55 70 64 61 74 65 20 5b 6c 69 6e 64 65 78  stUpdate [lindex
1180: 20 24 6c 61 73 74 55 70 64 61 74 65 73 20 30 5d   $lastUpdates 0]
1190: 0a 09 09 09 73 65 74 20 74 74 6c 20 5b 6c 69 6e  ....set ttl [lin
11a0: 64 65 78 20 24 6c 61 73 74 55 70 64 61 74 65 73  dex $lastUpdates
11b0: 20 31 5d 0a 09 09 7d 0a 0a 09 09 69 66 20 7b 24   1]...}....if {$
11c0: 6e 6f 77 20 3c 20 28 24 6c 61 73 74 55 70 64 61  now < ($lastUpda
11d0: 74 65 20 2b 20 24 74 74 6c 29 7d 20 7b 0a 09 09  te + $ttl)} {...
11e0: 09 72 65 74 75 72 6e 20 43 4f 4d 50 4c 45 54 45  .return COMPLETE
11f0: 0a 09 09 7d 0a 0a 09 09 69 66 20 7b 5b 73 74 72  ...}....if {[str
1200: 69 6e 67 20 6d 61 74 63 68 20 22 2a 5c 5b 2f 7e  ing match "*\[/~
1210: 5c 5d 2a 22 20 24 68 6f 73 74 6e 61 6d 65 5d 7d  \]*" $hostname]}
1220: 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 2d 63 6f   {....return -co
1230: 64 65 20 65 72 72 6f 72 20 22 49 6e 76 61 6c 69  de error "Invali
1240: 64 20 68 6f 73 74 6e 61 6d 65 22 0a 09 09 7d 0a  d hostname"...}.
1250: 0a 09 09 73 65 74 20 75 72 6c 20 22 68 74 74 70  ...set url "http
1260: 3a 2f 2f 24 68 6f 73 74 6e 61 6d 65 2f 61 70 70  ://$hostname/app
1270: 66 73 2f 69 6e 64 65 78 22 0a 0a 09 09 63 61 74  fs/index"....cat
1280: 63 68 20 7b 0a 09 09 09 73 65 74 20 74 6f 6b 65  ch {....set toke
1290: 6e 20 5b 3a 3a 68 74 74 70 3a 3a 67 65 74 75 72  n [::http::getur
12a0: 6c 20 24 75 72 6c 5d 0a 09 09 09 69 66 20 7b 5b  l $url]....if {[
12b0: 3a 3a 68 74 74 70 3a 3a 6e 63 6f 64 65 20 24 74  ::http::ncode $t
12c0: 6f 6b 65 6e 5d 20 3d 3d 20 22 32 30 30 22 7d 20  oken] == "200"} 
12d0: 7b 0a 09 09 09 09 73 65 74 20 69 6e 64 65 78 68  {.....set indexh
12e0: 61 73 68 5f 64 61 74 61 20 5b 3a 3a 68 74 74 70  ash_data [::http
12f0: 3a 3a 64 61 74 61 20 24 74 6f 6b 65 6e 5d 0a 09  ::data $token]..
1300: 09 09 7d 0a 09 09 09 3a 3a 68 74 74 70 3a 3a 72  ..}....::http::r
1310: 65 73 65 74 20 24 74 6f 6b 65 6e 0a 09 09 09 3a  eset $token....:
1320: 3a 68 74 74 70 3a 3a 63 6c 65 61 6e 75 70 20 24  :http::cleanup $
1330: 74 6f 6b 65 6e 0a 09 09 7d 0a 0a 09 09 69 66 20  token...}....if 
1340: 7b 21 5b 69 6e 66 6f 20 65 78 69 73 74 73 20 69  {![info exists i
1350: 6e 64 65 78 68 61 73 68 5f 64 61 74 61 5d 7d 20  ndexhash_data]} 
1360: 7b 0a 09 09 09 23 20 43 61 63 68 65 20 74 68 69  {....# Cache thi
1370: 73 20 72 65 73 75 6c 74 20 66 6f 72 20 36 30 20  s result for 60 
1380: 73 65 63 6f 6e 64 73 0a 09 09 09 64 62 20 65 76  seconds....db ev
1390: 61 6c 20 7b 49 4e 53 45 52 54 20 4f 52 20 52 45  al {INSERT OR RE
13a0: 50 4c 41 43 45 20 49 4e 54 4f 20 73 69 74 65 73  PLACE INTO sites
13b0: 20 28 68 6f 73 74 6e 61 6d 65 2c 20 6c 61 73 74   (hostname, last
13c0: 55 70 64 61 74 65 2c 20 74 74 6c 29 20 56 41 4c  Update, ttl) VAL
13d0: 55 45 53 20 28 24 68 6f 73 74 6e 61 6d 65 2c 20  UES ($hostname, 
13e0: 24 6e 6f 77 2c 20 24 3a 3a 61 70 70 66 73 3a 3a  $now, $::appfs::
13f0: 6e 74 74 6c 29 3b 7d 0a 0a 09 09 09 72 65 74 75  nttl);}.....retu
1400: 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22  rn -code error "
1410: 55 6e 61 62 6c 65 20 74 6f 20 66 65 74 63 68 20  Unable to fetch 
1420: 24 75 72 6c 22 0a 09 09 7d 0a 0a 09 09 73 65 74  $url"...}....set
1430: 20 69 6e 64 65 78 68 61 73 68 20 5b 6c 69 6e 64   indexhash [lind
1440: 65 78 20 5b 73 70 6c 69 74 20 24 69 6e 64 65 78  ex [split $index
1450: 68 61 73 68 5f 64 61 74 61 20 22 2c 22 5d 20 30  hash_data ","] 0
1460: 5d 0a 0a 09 09 69 66 20 7b 21 5b 5f 69 73 48 61  ]....if {![_isHa
1470: 73 68 20 24 69 6e 64 65 78 68 61 73 68 5d 7d 20  sh $indexhash]} 
1480: 7b 0a 09 09 09 72 65 74 75 72 6e 20 2d 63 6f 64  {....return -cod
1490: 65 20 65 72 72 6f 72 20 22 49 6e 76 61 6c 69 64  e error "Invalid
14a0: 20 68 61 73 68 3a 20 24 69 6e 64 65 78 68 61 73   hash: $indexhas
14b0: 68 22 0a 09 09 7d 0a 0a 09 09 73 65 74 20 66 69  h"...}....set fi
14c0: 6c 65 20 5b 64 6f 77 6e 6c 6f 61 64 20 24 68 6f  le [download $ho
14d0: 73 74 6e 61 6d 65 20 24 69 6e 64 65 78 68 61 73  stname $indexhas
14e0: 68 5d 0a 09 09 73 65 74 20 66 64 20 5b 6f 70 65  h]...set fd [ope
14f0: 6e 20 24 66 69 6c 65 5d 0a 09 09 73 65 74 20 64  n $file]...set d
1500: 61 74 61 20 5b 72 65 61 64 20 24 66 64 5d 0a 09  ata [read $fd]..
1510: 09 63 6c 6f 73 65 20 24 66 64 0a 0a 09 09 73 65  .close $fd....se
1520: 74 20 63 75 72 72 5f 70 61 63 6b 61 67 65 73 20  t curr_packages 
1530: 5b 6c 69 73 74 5d 0a 09 09 66 6f 72 65 61 63 68  [list]...foreach
1540: 20 6c 69 6e 65 20 5b 73 70 6c 69 74 20 24 64 61   line [split $da
1550: 74 61 20 22 5c 6e 22 5d 20 7b 0a 09 09 09 73 65  ta "\n"] {....se
1560: 74 20 6c 69 6e 65 20 5b 73 74 72 69 6e 67 20 74  t line [string t
1570: 72 69 6d 20 24 6c 69 6e 65 5d 0a 0a 09 09 09 69  rim $line].....i
1580: 66 20 7b 5b 73 74 72 69 6e 67 20 6d 61 74 63 68  f {[string match
1590: 20 22 2a 2f 2a 22 20 24 6c 69 6e 65 5d 7d 20 7b   "*/*" $line]} {
15a0: 0a 09 09 09 09 63 6f 6e 74 69 6e 75 65 0a 09 09  .....continue...
15b0: 09 7d 0a 0a 09 09 09 69 66 20 7b 24 6c 69 6e 65  .}.....if {$line
15c0: 20 3d 3d 20 22 22 7d 20 7b 0a 09 09 09 09 63 6f   == ""} {.....co
15d0: 6e 74 69 6e 75 65 0a 09 09 09 7d 0a 0a 09 09 09  ntinue....}.....
15e0: 73 65 74 20 77 6f 72 6b 20 5b 73 70 6c 69 74 20  set work [split 
15f0: 24 6c 69 6e 65 20 22 2c 22 5d 0a 0a 09 09 09 75  $line ","].....u
1600: 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e  nset -nocomplain
1610: 20 70 6b 67 49 6e 66 6f 0a 09 09 09 69 66 20 7b   pkgInfo....if {
1620: 5b 63 61 74 63 68 20 7b 0a 09 09 09 09 73 65 74  [catch {.....set
1630: 20 70 6b 67 49 6e 66 6f 28 70 61 63 6b 61 67 65   pkgInfo(package
1640: 29 20 20 5b 6c 69 6e 64 65 78 20 24 77 6f 72 6b  )  [lindex $work
1650: 20 30 5d 0a 09 09 09 09 73 65 74 20 70 6b 67 49   0].....set pkgI
1660: 6e 66 6f 28 76 65 72 73 69 6f 6e 29 20 20 5b 6c  nfo(version)  [l
1670: 69 6e 64 65 78 20 24 77 6f 72 6b 20 31 5d 0a 09  index $work 1]..
1680: 09 09 09 73 65 74 20 70 6b 67 49 6e 66 6f 28 6f  ...set pkgInfo(o
1690: 73 29 20 20 20 20 20 20 20 5b 5f 6e 6f 72 6d 61  s)       [_norma
16a0: 6c 69 7a 65 4f 53 20 5b 6c 69 6e 64 65 78 20 24  lizeOS [lindex $
16b0: 77 6f 72 6b 20 32 5d 5d 0a 09 09 09 09 73 65 74  work 2]].....set
16c0: 20 70 6b 67 49 6e 66 6f 28 63 70 75 41 72 63 68   pkgInfo(cpuArch
16d0: 29 20 20 5b 5f 6e 6f 72 6d 61 6c 69 7a 65 43 50  )  [_normalizeCP
16e0: 55 20 5b 6c 69 6e 64 65 78 20 24 77 6f 72 6b 20  U [lindex $work 
16f0: 33 5d 5d 0a 09 09 09 09 73 65 74 20 70 6b 67 49  3]].....set pkgI
1700: 6e 66 6f 28 68 61 73 68 29 20 20 20 20 20 5b 73  nfo(hash)     [s
1710: 74 72 69 6e 67 20 74 6f 6c 6f 77 65 72 20 5b 6c  tring tolower [l
1720: 69 6e 64 65 78 20 24 77 6f 72 6b 20 34 5d 5d 0a  index $work 4]].
1730: 09 09 09 09 73 65 74 20 70 6b 67 49 6e 66 6f 28  ....set pkgInfo(
1740: 68 61 73 68 5f 74 79 70 65 29 20 22 73 68 61 31  hash_type) "sha1
1750: 22 0a 09 09 09 09 73 65 74 20 70 6b 67 49 6e 66  ".....set pkgInf
1760: 6f 28 69 73 4c 61 74 65 73 74 29 20 5b 65 78 70  o(isLatest) [exp
1770: 72 20 7b 21 21 5b 6c 69 6e 64 65 78 20 24 77 6f  r {!![lindex $wo
1780: 72 6b 20 35 5d 7d 5d 0a 09 09 09 7d 5d 7d 20 7b  rk 5]}]....}]} {
1790: 0a 09 09 09 09 63 6f 6e 74 69 6e 75 65 0a 09 09  .....continue...
17a0: 09 7d 0a 0a 09 09 09 69 66 20 7b 21 5b 5f 69 73  .}.....if {![_is
17b0: 48 61 73 68 20 24 70 6b 67 49 6e 66 6f 28 68 61  Hash $pkgInfo(ha
17c0: 73 68 29 5d 7d 20 7b 0a 09 09 09 09 63 6f 6e 74  sh)]} {.....cont
17d0: 69 6e 75 65 0a 09 09 09 7d 0a 0a 09 09 09 6c 61  inue....}.....la
17e0: 70 70 65 6e 64 20 63 75 72 72 5f 70 61 63 6b 61  ppend curr_packa
17f0: 67 65 73 20 24 70 6b 67 49 6e 66 6f 28 68 61 73  ges $pkgInfo(has
1800: 68 29 0a 0a 09 09 09 23 20 44 6f 20 6e 6f 74 20  h).....# Do not 
1810: 64 6f 20 61 6e 79 20 61 64 64 69 74 69 6f 6e 61  do any additiona
1820: 6c 20 77 6f 72 6b 20 69 66 20 77 65 20 61 6c 72  l work if we alr
1830: 65 61 64 79 20 68 61 76 65 20 74 68 69 73 20 70  eady have this p
1840: 61 63 6b 61 67 65 0a 09 09 09 73 65 74 20 65 78  ackage....set ex
1850: 69 73 74 69 6e 67 5f 70 61 63 6b 61 67 65 73 20  isting_packages 
1860: 5b 64 62 20 65 76 61 6c 20 7b 53 45 4c 45 43 54  [db eval {SELECT
1870: 20 70 61 63 6b 61 67 65 20 46 52 4f 4d 20 70 61   package FROM pa
1880: 63 6b 61 67 65 73 20 57 48 45 52 45 20 68 6f 73  ckages WHERE hos
1890: 74 6e 61 6d 65 20 3d 20 24 68 6f 73 74 6e 61 6d  tname = $hostnam
18a0: 65 20 41 4e 44 20 73 68 61 31 20 3d 20 24 70 6b  e AND sha1 = $pk
18b0: 67 49 6e 66 6f 28 68 61 73 68 29 3b 7d 5d 0a 09  gInfo(hash);}]..
18c0: 09 09 69 66 20 7b 5b 6c 73 65 61 72 63 68 20 2d  ..if {[lsearch -
18d0: 65 78 61 63 74 20 24 65 78 69 73 74 69 6e 67 5f  exact $existing_
18e0: 70 61 63 6b 61 67 65 73 20 24 70 6b 67 49 6e 66  packages $pkgInf
18f0: 6f 28 70 61 63 6b 61 67 65 29 5d 20 21 3d 20 2d  o(package)] != -
1900: 31 7d 20 7b 0a 09 09 09 09 63 6f 6e 74 69 6e 75  1} {.....continu
1910: 65 0a 09 09 09 7d 0a 0a 09 09 09 69 66 20 7b 24  e....}.....if {$
1920: 70 6b 67 49 6e 66 6f 28 69 73 4c 61 74 65 73 74  pkgInfo(isLatest
1930: 29 7d 20 7b 0a 09 09 09 09 64 62 20 65 76 61 6c  )} {.....db eval
1940: 20 7b 55 50 44 41 54 45 20 70 61 63 6b 61 67 65   {UPDATE package
1950: 73 20 53 45 54 20 69 73 4c 61 74 65 73 74 20 3d  s SET isLatest =
1960: 20 30 20 57 48 45 52 45 20 68 6f 73 74 6e 61 6d   0 WHERE hostnam
1970: 65 20 3d 20 24 68 6f 73 74 6e 61 6d 65 20 41 4e  e = $hostname AN
1980: 44 20 70 61 63 6b 61 67 65 20 3d 20 24 70 6b 67  D package = $pkg
1990: 49 6e 66 6f 28 24 70 61 63 6b 61 67 65 29 20 41  Info($package) A
19a0: 4e 44 20 6f 73 20 3d 20 24 70 6b 67 49 6e 66 6f  ND os = $pkgInfo
19b0: 28 24 70 61 63 6b 61 67 65 29 20 41 4e 44 20 63  ($package) AND c
19c0: 70 75 41 72 63 68 20 3d 20 24 70 6b 67 49 6e 66  puArch = $pkgInf
19d0: 6f 28 63 70 75 41 72 63 68 29 3b 7d 0a 09 09 09  o(cpuArch);}....
19e0: 7d 0a 0a 09 09 09 64 62 20 65 76 61 6c 20 7b 49  }.....db eval {I
19f0: 4e 53 45 52 54 20 49 4e 54 4f 20 70 61 63 6b 61  NSERT INTO packa
1a00: 67 65 73 20 28 68 6f 73 74 6e 61 6d 65 2c 20 73  ges (hostname, s
1a10: 68 61 31 2c 20 70 61 63 6b 61 67 65 2c 20 76 65  ha1, package, ve
1a20: 72 73 69 6f 6e 2c 20 6f 73 2c 20 63 70 75 41 72  rsion, os, cpuAr
1a30: 63 68 2c 20 69 73 4c 61 74 65 73 74 2c 20 68 61  ch, isLatest, ha
1a40: 76 65 4d 61 6e 69 66 65 73 74 29 20 56 41 4c 55  veManifest) VALU
1a50: 45 53 20 28 24 68 6f 73 74 6e 61 6d 65 2c 20 24  ES ($hostname, $
1a60: 70 6b 67 49 6e 66 6f 28 68 61 73 68 29 2c 20 24  pkgInfo(hash), $
1a70: 70 6b 67 49 6e 66 6f 28 70 61 63 6b 61 67 65 29  pkgInfo(package)
1a80: 2c 20 24 70 6b 67 49 6e 66 6f 28 76 65 72 73 69  , $pkgInfo(versi
1a90: 6f 6e 29 2c 20 24 70 6b 67 49 6e 66 6f 28 6f 73  on), $pkgInfo(os
1aa0: 29 2c 20 24 70 6b 67 49 6e 66 6f 28 63 70 75 41  ), $pkgInfo(cpuA
1ab0: 72 63 68 29 2c 20 24 70 6b 67 49 6e 66 6f 28 69  rch), $pkgInfo(i
1ac0: 73 4c 61 74 65 73 74 29 2c 20 30 29 3b 7d 0a 0a  sLatest), 0);}..
1ad0: 09 09 7d 0a 0a 09 09 23 20 4c 6f 6f 6b 20 66 6f  ..}....# Look fo
1ae0: 72 20 70 61 63 6b 61 67 65 73 20 74 68 61 74 20  r packages that 
1af0: 68 61 76 65 20 62 65 65 6e 20 64 65 6c 65 74 65  have been delete
1b00: 64 0a 09 09 73 65 74 20 66 6f 75 6e 64 5f 70 61  d...set found_pa
1b10: 63 6b 61 67 65 73 20 5b 64 62 20 65 76 61 6c 20  ckages [db eval 
1b20: 7b 53 45 4c 45 43 54 20 73 68 61 31 20 46 52 4f  {SELECT sha1 FRO
1b30: 4d 20 70 61 63 6b 61 67 65 73 20 57 48 45 52 45  M packages WHERE
1b40: 20 68 6f 73 74 6e 61 6d 65 20 3d 20 24 68 6f 73   hostname = $hos
1b50: 74 6e 61 6d 65 3b 7d 5d 0a 09 09 66 6f 72 65 61  tname;}]...forea
1b60: 63 68 20 70 61 63 6b 61 67 65 20 24 66 6f 75 6e  ch package $foun
1b70: 64 5f 70 61 63 6b 61 67 65 73 20 7b 0a 09 09 09  d_packages {....
1b80: 73 65 74 20 66 6f 75 6e 64 5f 70 61 63 6b 61 67  set found_packag
1b90: 65 73 5f 61 72 72 28 24 70 61 63 6b 61 67 65 29  es_arr($package)
1ba0: 20 31 0a 09 09 7d 0a 0a 09 09 66 6f 72 65 61 63   1...}....foreac
1bb0: 68 20 70 61 63 6b 61 67 65 20 24 63 75 72 72 5f  h package $curr_
1bc0: 70 61 63 6b 61 67 65 73 20 7b 0a 09 09 09 75 6e  packages {....un
1bd0: 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e 20  set -nocomplain 
1be0: 66 6f 75 6e 64 5f 70 61 63 6b 61 67 65 73 5f 61  found_packages_a
1bf0: 72 72 28 24 70 61 63 6b 61 67 65 29 0a 09 09 7d  rr($package)...}
1c00: 0a 0a 09 09 66 6f 72 65 61 63 68 20 70 61 63 6b  ....foreach pack
1c10: 61 67 65 20 5b 61 72 72 61 79 20 6e 61 6d 65 73  age [array names
1c20: 20 66 6f 75 6e 64 5f 70 61 63 6b 61 67 65 73 5f   found_packages_
1c30: 61 72 72 5d 20 7b 0a 09 09 09 64 62 20 65 76 61  arr] {....db eva
1c40: 6c 20 7b 44 45 4c 45 54 45 20 46 52 4f 4d 20 70  l {DELETE FROM p
1c50: 61 63 6b 61 67 65 73 20 57 48 45 52 45 20 68 6f  ackages WHERE ho
1c60: 73 74 6e 61 6d 65 20 3d 20 24 68 6f 73 74 6e 61  stname = $hostna
1c70: 6d 65 20 41 4e 44 20 73 68 61 31 20 3d 20 24 70  me AND sha1 = $p
1c80: 61 63 6b 61 67 65 3b 7d 0a 09 09 7d 0a 0a 09 09  ackage;}...}....
1c90: 64 62 20 65 76 61 6c 20 7b 49 4e 53 45 52 54 20  db eval {INSERT 
1ca0: 4f 52 20 52 45 50 4c 41 43 45 20 49 4e 54 4f 20  OR REPLACE INTO 
1cb0: 73 69 74 65 73 20 28 68 6f 73 74 6e 61 6d 65 2c  sites (hostname,
1cc0: 20 6c 61 73 74 55 70 64 61 74 65 2c 20 74 74 6c   lastUpdate, ttl
1cd0: 29 20 56 41 4c 55 45 53 20 28 24 68 6f 73 74 6e  ) VALUES ($hostn
1ce0: 61 6d 65 2c 20 24 6e 6f 77 2c 20 24 3a 3a 61 70  ame, $now, $::ap
1cf0: 70 66 73 3a 3a 74 74 6c 29 3b 7d 0a 0a 09 09 61  pfs::ttl);}....a
1d00: 70 70 66 73 64 3a 3a 67 65 74 5f 70 61 74 68 5f  ppfsd::get_path_
1d10: 69 6e 66 6f 5f 63 61 63 68 65 5f 66 6c 75 73 68  info_cache_flush
1d20: 0a 0a 09 09 72 65 74 75 72 6e 20 43 4f 4d 50 4c  ....return COMPL
1d30: 45 54 45 0a 09 7d 0a 0a 09 70 72 6f 63 20 67 65  ETE..}...proc ge
1d40: 74 70 6b 67 6d 61 6e 69 66 65 73 74 20 7b 68 6f  tpkgmanifest {ho
1d50: 73 74 6e 61 6d 65 20 70 61 63 6b 61 67 65 5f 73  stname package_s
1d60: 68 61 31 7d 20 7b 0a 09 09 73 65 74 20 68 61 76  ha1} {...set hav
1d70: 65 4d 61 6e 69 66 65 73 74 20 5b 64 62 20 6f 6e  eManifest [db on
1d80: 65 63 6f 6c 75 6d 6e 20 7b 53 45 4c 45 43 54 20  ecolumn {SELECT 
1d90: 68 61 76 65 4d 61 6e 69 66 65 73 74 20 46 52 4f  haveManifest FRO
1da0: 4d 20 70 61 63 6b 61 67 65 73 20 57 48 45 52 45  M packages WHERE
1db0: 20 73 68 61 31 20 3d 20 24 70 61 63 6b 61 67 65   sha1 = $package
1dc0: 5f 73 68 61 31 20 4c 49 4d 49 54 20 31 3b 7d 5d  _sha1 LIMIT 1;}]
1dd0: 0a 0a 09 09 69 66 20 7b 24 68 61 76 65 4d 61 6e  ....if {$haveMan
1de0: 69 66 65 73 74 20 3d 3d 20 22 31 22 7d 20 7b 0a  ifest == "1"} {.
1df0: 09 09 09 72 65 74 75 72 6e 20 43 4f 4d 50 4c 45  ...return COMPLE
1e00: 54 45 0a 09 09 7d 0a 0a 09 09 69 66 20 7b 21 5b  TE...}....if {![
1e10: 5f 69 73 48 61 73 68 20 24 70 61 63 6b 61 67 65  _isHash $package
1e20: 5f 73 68 61 31 5d 7d 20 7b 0a 09 09 09 72 65 74  _sha1]} {....ret
1e30: 75 72 6e 20 46 41 49 4c 0a 09 09 7d 0a 0a 09 09  urn FAIL...}....
1e40: 73 65 74 20 66 69 6c 65 20 5b 64 6f 77 6e 6c 6f  set file [downlo
1e50: 61 64 20 24 68 6f 73 74 6e 61 6d 65 20 24 70 61  ad $hostname $pa
1e60: 63 6b 61 67 65 5f 73 68 61 31 5d 0a 09 09 73 65  ckage_sha1]...se
1e70: 74 20 66 64 20 5b 6f 70 65 6e 20 24 66 69 6c 65  t fd [open $file
1e80: 5d 0a 09 09 73 65 74 20 70 6b 67 64 61 74 61 20  ]...set pkgdata 
1e90: 5b 72 65 61 64 20 24 66 64 5d 0a 09 09 63 6c 6f  [read $fd]...clo
1ea0: 73 65 20 24 66 64 0a 0a 09 09 64 62 20 74 72 61  se $fd....db tra
1eb0: 6e 73 61 63 74 69 6f 6e 20 7b 0a 09 09 09 66 6f  nsaction {....fo
1ec0: 72 65 61 63 68 20 6c 69 6e 65 20 5b 73 70 6c 69  reach line [spli
1ed0: 74 20 24 70 6b 67 64 61 74 61 20 22 5c 6e 22 5d  t $pkgdata "\n"]
1ee0: 20 7b 0a 09 09 09 09 73 65 74 20 6c 69 6e 65 20   {.....set line 
1ef0: 5b 73 74 72 69 6e 67 20 74 72 69 6d 20 24 6c 69  [string trim $li
1f00: 6e 65 5d 0a 0a 09 09 09 09 69 66 20 7b 24 6c 69  ne]......if {$li
1f10: 6e 65 20 3d 3d 20 22 22 7d 20 7b 0a 09 09 09 09  ne == ""} {.....
1f20: 09 63 6f 6e 74 69 6e 75 65 0a 09 09 09 09 7d 0a  .continue.....}.
1f30: 0a 09 09 09 09 73 65 74 20 77 6f 72 6b 20 5b 73  .....set work [s
1f40: 70 6c 69 74 20 24 6c 69 6e 65 20 22 2c 22 5d 0a  plit $line ","].
1f50: 0a 09 09 09 09 75 6e 73 65 74 20 2d 6e 6f 63 6f  .....unset -noco
1f60: 6d 70 6c 61 69 6e 20 66 69 6c 65 49 6e 66 6f 0a  mplain fileInfo.
1f70: 09 09 09 09 73 65 74 20 66 69 6c 65 49 6e 66 6f  ....set fileInfo
1f80: 28 74 79 70 65 29 20 5b 6c 69 6e 64 65 78 20 24  (type) [lindex $
1f90: 77 6f 72 6b 20 30 5d 0a 09 09 09 09 73 65 74 20  work 0].....set 
1fa0: 66 69 6c 65 49 6e 66 6f 28 74 69 6d 65 29 20 5b  fileInfo(time) [
1fb0: 6c 69 6e 64 65 78 20 24 77 6f 72 6b 20 31 5d 0a  lindex $work 1].
1fc0: 0a 09 09 09 09 73 65 74 20 77 6f 72 6b 20 5b 6c  .....set work [l
1fd0: 72 61 6e 67 65 20 24 77 6f 72 6b 20 32 20 65 6e  range $work 2 en
1fe0: 64 5d 0a 09 09 09 09 73 77 69 74 63 68 20 2d 2d  d].....switch --
1ff0: 20 24 66 69 6c 65 49 6e 66 6f 28 74 79 70 65 29   $fileInfo(type)
2000: 20 7b 0a 09 09 09 09 09 22 23 6d 61 6e 69 66 65   {......"#manife
2010: 73 74 6d 65 74 61 64 61 74 61 22 20 7b 0a 09 09  stmetadata" {...
2020: 09 09 09 09 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d  ....unset -nocom
2030: 70 6c 61 69 6e 20 66 69 6c 65 49 6e 66 6f 0a 09  plain fileInfo..
2040: 09 09 09 09 09 63 6f 6e 74 69 6e 75 65 0a 09 09  .....continue...
2050: 09 09 09 7d 0a 09 09 09 09 09 22 66 69 6c 65 22  ...}......"file"
2060: 20 7b 0a 09 09 09 09 09 09 73 65 74 20 66 69 6c   {.......set fil
2070: 65 49 6e 66 6f 28 73 69 7a 65 29 20 5b 6c 69 6e  eInfo(size) [lin
2080: 64 65 78 20 24 77 6f 72 6b 20 30 5d 0a 09 09 09  dex $work 0]....
2090: 09 09 09 73 65 74 20 66 69 6c 65 49 6e 66 6f 28  ...set fileInfo(
20a0: 70 65 72 6d 73 29 20 5b 6c 69 6e 64 65 78 20 24  perms) [lindex $
20b0: 77 6f 72 6b 20 31 5d 0a 09 09 09 09 09 09 73 65  work 1].......se
20c0: 74 20 66 69 6c 65 49 6e 66 6f 28 73 68 61 31 29  t fileInfo(sha1)
20d0: 20 5b 6c 69 6e 64 65 78 20 24 77 6f 72 6b 20 32   [lindex $work 2
20e0: 5d 0a 0a 09 09 09 09 09 09 73 65 74 20 77 6f 72  ]........set wor
20f0: 6b 20 5b 6c 72 61 6e 67 65 20 24 77 6f 72 6b 20  k [lrange $work 
2100: 33 20 65 6e 64 5d 0a 09 09 09 09 09 7d 0a 09 09  3 end]......}...
2110: 09 09 09 22 73 79 6d 6c 69 6e 6b 22 20 7b 0a 09  ..."symlink" {..
2120: 09 09 09 09 09 73 65 74 20 66 69 6c 65 49 6e 66  .....set fileInf
2130: 6f 28 73 6f 75 72 63 65 29 20 5b 6c 69 6e 64 65  o(source) [linde
2140: 78 20 24 77 6f 72 6b 20 30 5d 0a 09 09 09 09 09  x $work 0]......
2150: 09 73 65 74 20 77 6f 72 6b 20 5b 6c 72 61 6e 67  .set work [lrang
2160: 65 20 24 77 6f 72 6b 20 31 20 65 6e 64 5d 0a 09  e $work 1 end]..
2170: 09 09 09 09 7d 0a 09 09 09 09 09 22 64 69 72 65  ....}......"dire
2180: 63 74 6f 72 79 22 20 7b 0a 09 09 09 09 09 09 23  ctory" {.......#
2190: 20 4e 6f 20 65 78 74 72 61 20 64 61 74 61 20 72   No extra data r
21a0: 65 71 75 69 72 65 64 0a 09 09 09 09 09 7d 0a 09  equired......}..
21b0: 09 09 09 09 64 65 66 61 75 6c 74 20 7b 0a 09 09  ....default {...
21c0: 09 09 09 09 23 20 48 61 6e 64 6c 65 20 75 6e 6b  ....# Handle unk
21d0: 6e 6f 77 6e 20 74 79 70 65 73 0a 09 09 09 09 09  nown types......
21e0: 09 69 66 20 7b 5b 73 74 72 69 6e 67 20 69 6e 64  .if {[string ind
21f0: 65 78 20 24 66 69 6c 65 49 6e 66 6f 28 74 79 70  ex $fileInfo(typ
2200: 65 29 20 30 5d 20 3d 3d 20 22 23 22 7d 20 7b 0a  e) 0] == "#"} {.
2210: 09 09 09 09 09 09 09 23 20 4d 65 74 61 64 61 74  .......# Metadat
2220: 61 20 74 79 70 65 2c 20 69 67 6e 6f 72 65 0a 09  a type, ignore..
2230: 09 09 09 09 09 09 23 20 69 74 20 69 66 20 77 65  ......# it if we
2240: 20 64 6f 6e 27 74 0a 09 09 09 09 09 09 09 23 20   don't........# 
2250: 75 6e 64 65 72 73 74 61 6e 64 20 74 68 69 73 20  understand this 
2260: 74 79 70 65 0a 09 09 09 09 09 09 09 63 6f 6e 74  type........cont
2270: 69 6e 75 65 0a 09 09 09 09 09 09 7d 20 65 6c 73  inue.......} els
2280: 65 20 7b 0a 09 09 09 09 09 09 09 23 20 55 6e 6b  e {........# Unk
2290: 6e 6f 77 6e 20 74 79 70 65 2c 0a 09 09 09 09 09  nown type,......
22a0: 09 09 23 20 67 65 6e 65 72 61 74 65 20 61 6e 20  ..# generate an 
22b0: 65 72 72 6f 72 0a 09 09 09 09 09 09 09 65 72 72  error........err
22c0: 6f 72 20 22 4d 61 6e 69 66 65 73 74 20 63 61 6e  or "Manifest can
22d0: 6e 6f 74 20 62 65 20 70 61 72 73 65 64 22 0a 09  not be parsed"..
22e0: 09 09 09 09 09 7d 0a 09 09 09 09 09 7d 0a 09 09  .....}......}...
22f0: 09 09 7d 0a 0a 09 09 09 09 73 65 74 20 66 69 6c  ..}......set fil
2300: 65 49 6e 66 6f 28 6e 61 6d 65 29 20 5b 6a 6f 69  eInfo(name) [joi
2310: 6e 20 24 77 6f 72 6b 20 22 2c 22 5d 0a 09 09 09  n $work ","]....
2320: 09 73 65 74 20 66 69 6c 65 49 6e 66 6f 28 6e 61  .set fileInfo(na
2330: 6d 65 29 20 5b 73 70 6c 69 74 20 5b 73 74 72 69  me) [split [stri
2340: 6e 67 20 74 72 69 6d 20 24 66 69 6c 65 49 6e 66  ng trim $fileInf
2350: 6f 28 6e 61 6d 65 29 20 22 2f 22 5d 20 22 2f 22  o(name) "/"] "/"
2360: 5d 0a 09 09 09 09 73 65 74 20 66 69 6c 65 49 6e  ].....set fileIn
2370: 66 6f 28 64 69 72 65 63 74 6f 72 79 29 20 5b 6a  fo(directory) [j
2380: 6f 69 6e 20 5b 6c 72 61 6e 67 65 20 24 66 69 6c  oin [lrange $fil
2390: 65 49 6e 66 6f 28 6e 61 6d 65 29 20 30 20 65 6e  eInfo(name) 0 en
23a0: 64 2d 31 5d 20 22 2f 22 5d 0a 09 09 09 09 73 65  d-1] "/"].....se
23b0: 74 20 66 69 6c 65 49 6e 66 6f 28 6e 61 6d 65 29  t fileInfo(name)
23c0: 20 5b 6c 69 6e 64 65 78 20 24 66 69 6c 65 49 6e   [lindex $fileIn
23d0: 66 6f 28 6e 61 6d 65 29 20 65 6e 64 5d 0a 0a 09  fo(name) end]...
23e0: 09 09 09 64 62 20 65 76 61 6c 20 7b 49 4e 53 45  ...db eval {INSE
23f0: 52 54 20 49 4e 54 4f 20 66 69 6c 65 73 20 28 70  RT INTO files (p
2400: 61 63 6b 61 67 65 5f 73 68 61 31 2c 20 74 79 70  ackage_sha1, typ
2410: 65 2c 20 74 69 6d 65 2c 20 73 6f 75 72 63 65 2c  e, time, source,
2420: 20 73 69 7a 65 2c 20 70 65 72 6d 73 2c 20 66 69   size, perms, fi
2430: 6c 65 5f 73 68 61 31 2c 20 66 69 6c 65 5f 6e 61  le_sha1, file_na
2440: 6d 65 2c 20 66 69 6c 65 5f 64 69 72 65 63 74 6f  me, file_directo
2450: 72 79 29 20 56 41 4c 55 45 53 20 28 24 70 61 63  ry) VALUES ($pac
2460: 6b 61 67 65 5f 73 68 61 31 2c 20 24 66 69 6c 65  kage_sha1, $file
2470: 49 6e 66 6f 28 74 79 70 65 29 2c 20 24 66 69 6c  Info(type), $fil
2480: 65 49 6e 66 6f 28 74 69 6d 65 29 2c 20 24 66 69  eInfo(time), $fi
2490: 6c 65 49 6e 66 6f 28 73 6f 75 72 63 65 29 2c 20  leInfo(source), 
24a0: 24 66 69 6c 65 49 6e 66 6f 28 73 69 7a 65 29 2c  $fileInfo(size),
24b0: 20 24 66 69 6c 65 49 6e 66 6f 28 70 65 72 6d 73   $fileInfo(perms
24c0: 29 2c 20 24 66 69 6c 65 49 6e 66 6f 28 73 68 61  ), $fileInfo(sha
24d0: 31 29 2c 20 24 66 69 6c 65 49 6e 66 6f 28 6e 61  1), $fileInfo(na
24e0: 6d 65 29 2c 20 24 66 69 6c 65 49 6e 66 6f 28 64  me), $fileInfo(d
24f0: 69 72 65 63 74 6f 72 79 29 20 29 3b 7d 0a 09 09  irectory) );}...
2500: 09 09 64 62 20 65 76 61 6c 20 7b 55 50 44 41 54  ..db eval {UPDAT
2510: 45 20 70 61 63 6b 61 67 65 73 20 53 45 54 20 68  E packages SET h
2520: 61 76 65 4d 61 6e 69 66 65 73 74 20 3d 20 31 20  aveManifest = 1 
2530: 57 48 45 52 45 20 73 68 61 31 20 3d 20 24 70 61  WHERE sha1 = $pa
2540: 63 6b 61 67 65 5f 73 68 61 31 3b 7d 0a 09 09 09  ckage_sha1;}....
2550: 7d 0a 09 09 7d 0a 0a 09 09 61 70 70 66 73 64 3a  }...}....appfsd:
2560: 3a 67 65 74 5f 70 61 74 68 5f 69 6e 66 6f 5f 63  :get_path_info_c
2570: 61 63 68 65 5f 66 6c 75 73 68 0a 0a 09 09 72 65  ache_flush....re
2580: 74 75 72 6e 20 43 4f 4d 50 4c 45 54 45 0a 09 7d  turn COMPLETE..}
2590: 0a 0a 09 70 72 6f 63 20 5f 6c 6f 63 61 6c 70 61  ...proc _localpa
25a0: 74 68 20 7b 70 61 63 6b 61 67 65 20 68 6f 73 74  th {package host
25b0: 6e 61 6d 65 20 66 69 6c 65 7d 20 7b 0a 09 09 73  name file} {...s
25c0: 65 74 20 64 69 72 20 22 22 0a 09 09 63 61 74 63  et dir ""...catc
25d0: 68 20 7b 0a 09 09 09 73 65 74 20 68 6f 6d 65 64  h {....set homed
25e0: 69 72 20 5b 3a 3a 61 70 70 66 73 3a 3a 75 73 65  ir [::appfs::use
25f0: 72 3a 3a 67 65 74 5f 68 6f 6d 65 64 69 72 5d 0a  r::get_homedir].
2600: 09 09 09 73 65 74 20 64 69 72 20 5b 66 69 6c 65  ...set dir [file
2610: 20 6a 6f 69 6e 20 24 68 6f 6d 65 64 69 72 20 2e   join $homedir .
2620: 61 70 70 66 73 20 22 2e 2f 24 7b 70 61 63 6b 61  appfs "./${packa
2630: 67 65 7d 40 24 7b 68 6f 73 74 6e 61 6d 65 7d 22  ge}@${hostname}"
2640: 20 22 2e 2f 24 7b 66 69 6c 65 7d 22 5d 0a 09 09   "./${file}"]...
2650: 7d 0a 09 09 72 65 74 75 72 6e 20 24 64 69 72 0a  }...return $dir.
2660: 09 7d 0a 0a 09 70 72 6f 63 20 5f 77 68 69 74 65  .}...proc _white
2670: 6f 75 74 70 61 74 68 20 7b 70 61 63 6b 61 67 65  outpath {package
2680: 20 68 6f 73 74 6e 61 6d 65 20 66 69 6c 65 7d 20   hostname file} 
2690: 7b 0a 09 09 73 65 74 20 64 69 72 20 22 22 0a 09  {...set dir ""..
26a0: 09 63 61 74 63 68 20 7b 0a 09 09 09 73 65 74 20  .catch {....set 
26b0: 68 6f 6d 65 64 69 72 20 5b 3a 3a 61 70 70 66 73  homedir [::appfs
26c0: 3a 3a 75 73 65 72 3a 3a 67 65 74 5f 68 6f 6d 65  ::user::get_home
26d0: 64 69 72 5d 0a 09 09 09 73 65 74 20 64 69 72 20  dir]....set dir 
26e0: 5b 66 69 6c 65 20 6a 6f 69 6e 20 24 68 6f 6d 65  [file join $home
26f0: 64 69 72 20 2e 61 70 70 66 73 20 22 2e 2f 24 7b  dir .appfs "./${
2700: 70 61 63 6b 61 67 65 7d 40 24 7b 68 6f 73 74 6e  package}@${hostn
2710: 61 6d 65 7d 22 20 22 2e 41 50 50 46 53 2e 57 48  ame}" ".APPFS.WH
2720: 49 54 45 4f 55 54 22 20 22 2e 2f 24 7b 66 69 6c  ITEOUT" "./${fil
2730: 65 7d 2e 41 50 50 46 53 2e 57 48 49 54 45 4f 55  e}.APPFS.WHITEOU
2740: 54 22 5d 0a 09 09 7d 0a 09 09 72 65 74 75 72 6e  T"]...}...return
2750: 20 24 64 69 72 0a 09 7d 0a 0a 09 70 72 6f 63 20   $dir..}...proc 
2760: 5f 70 61 72 73 65 70 61 74 68 20 7b 70 61 74 68  _parsepath {path
2770: 7d 20 7b 0a 09 09 73 65 74 20 70 61 74 68 20 5b  } {...set path [
2780: 73 74 72 69 6e 67 20 74 72 69 6d 20 24 70 61 74  string trim $pat
2790: 68 20 22 2f 22 5d 0a 09 09 73 65 74 20 70 61 74  h "/"]...set pat
27a0: 68 20 5b 73 70 6c 69 74 20 24 70 61 74 68 20 22  h [split $path "
27b0: 2f 22 5d 0a 09 09 73 65 74 20 70 61 74 68 6c 65  /"]...set pathle
27c0: 6e 20 5b 6c 6c 65 6e 67 74 68 20 24 70 61 74 68  n [llength $path
27d0: 5d 0a 0a 09 09 61 72 72 61 79 20 73 65 74 20 72  ]....array set r
27e0: 65 74 76 61 6c 20 5b 6c 69 73 74 20 5f 63 68 69  etval [list _chi
27f0: 6c 64 72 65 6e 20 73 69 74 65 73 20 5f 74 79 70  ldren sites _typ
2800: 65 20 74 6f 70 6c 65 76 65 6c 5d 0a 0a 09 09 69  e toplevel]....i
2810: 66 20 7b 24 70 61 74 68 6c 65 6e 20 3e 20 30 7d  f {$pathlen > 0}
2820: 20 7b 0a 09 09 09 73 65 74 20 72 65 74 76 61 6c   {....set retval
2830: 28 68 6f 73 74 6e 61 6d 65 29 20 5b 6c 69 6e 64  (hostname) [lind
2840: 65 78 20 24 70 61 74 68 20 30 5d 0a 09 09 09 73  ex $path 0]....s
2850: 65 74 20 72 65 74 76 61 6c 28 5f 63 68 69 6c 64  et retval(_child
2860: 72 65 6e 29 20 70 61 63 6b 61 67 65 73 0a 09 09  ren) packages...
2870: 09 73 65 74 20 72 65 74 76 61 6c 28 5f 74 79 70  .set retval(_typ
2880: 65 29 20 73 69 74 65 73 0a 0a 09 09 09 69 66 20  e) sites.....if 
2890: 7b 24 70 61 74 68 6c 65 6e 20 3e 20 31 7d 20 7b  {$pathlen > 1} {
28a0: 0a 09 09 09 09 73 65 74 20 70 61 63 6b 61 67 65  .....set package
28b0: 20 5b 6c 69 6e 64 65 78 20 24 70 61 74 68 20 31   [lindex $path 1
28c0: 5d 0a 09 09 09 09 69 66 20 7b 5b 73 74 72 69 6e  ].....if {[strin
28d0: 67 20 6c 65 6e 67 74 68 20 24 70 61 63 6b 61 67  g length $packag
28e0: 65 5d 20 3d 3d 20 22 34 30 22 20 26 26 20 5b 72  e] == "40" && [r
28f0: 65 67 65 78 70 20 7b 5e 5b 61 2d 66 41 2d 46 30  egexp {^[a-fA-F0
2900: 2d 39 5d 2a 24 7d 20 24 70 61 63 6b 61 67 65 5d  -9]*$} $package]
2910: 7d 20 7b 0a 09 09 09 09 09 73 65 74 20 72 65 74  } {......set ret
2920: 76 61 6c 28 70 61 63 6b 61 67 65 5f 73 68 61 31  val(package_sha1
2930: 29 20 24 70 61 63 6b 61 67 65 0a 09 09 09 09 09  ) $package......
2940: 73 65 74 20 72 65 74 76 61 6c 28 5f 63 68 69 6c  set retval(_chil
2950: 64 72 65 6e 29 20 66 69 6c 65 73 0a 09 09 09 09  dren) files.....
2960: 09 73 65 74 20 72 65 74 76 61 6c 28 5f 74 79 70  .set retval(_typ
2970: 65 29 20 66 69 6c 65 73 0a 0a 09 09 09 09 09 3a  e) files.......:
2980: 3a 61 70 70 66 73 3a 3a 64 62 20 65 76 61 6c 20  :appfs::db eval 
2990: 7b 53 45 4c 45 43 54 20 70 61 63 6b 61 67 65 2c  {SELECT package,
29a0: 20 6f 73 2c 20 63 70 75 41 72 63 68 2c 20 76 65   os, cpuArch, ve
29b0: 72 73 69 6f 6e 20 46 52 4f 4d 20 70 61 63 6b 61  rsion FROM packa
29c0: 67 65 73 20 57 48 45 52 45 20 73 68 61 31 20 3d  ges WHERE sha1 =
29d0: 20 24 72 65 74 76 61 6c 28 70 61 63 6b 61 67 65   $retval(package
29e0: 5f 73 68 61 31 29 3b 7d 20 70 6b 67 69 6e 66 6f  _sha1);} pkginfo
29f0: 20 7b 7d 0a 09 09 09 09 09 73 65 74 20 72 65 74   {}......set ret
2a00: 76 61 6c 28 70 61 63 6b 61 67 65 29 20 24 70 6b  val(package) $pk
2a10: 67 69 6e 66 6f 28 70 61 63 6b 61 67 65 29 0a 09  ginfo(package)..
2a20: 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 6f  ....set retval(o
2a30: 73 29 20 24 70 6b 67 69 6e 66 6f 28 6f 73 29 0a  s) $pkginfo(os).
2a40: 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28  .....set retval(
2a50: 63 70 75 29 20 24 70 6b 67 69 6e 66 6f 28 63 70  cpu) $pkginfo(cp
2a60: 75 41 72 63 68 29 0a 09 09 09 09 09 73 65 74 20  uArch)......set 
2a70: 72 65 74 76 61 6c 28 76 65 72 73 69 6f 6e 29 20  retval(version) 
2a80: 24 70 6b 67 69 6e 66 6f 28 76 65 72 73 69 6f 6e  $pkginfo(version
2a90: 29 0a 0a 09 09 09 09 09 69 66 20 7b 24 70 61 74  ).......if {$pat
2aa0: 68 6c 65 6e 20 3e 20 32 7d 20 7b 0a 09 09 09 09  hlen > 2} {.....
2ab0: 09 09 73 65 74 20 72 65 74 76 61 6c 28 66 69 6c  ..set retval(fil
2ac0: 65 29 20 5b 6a 6f 69 6e 20 5b 6c 72 61 6e 67 65  e) [join [lrange
2ad0: 20 24 70 61 74 68 20 32 20 65 6e 64 5d 20 22 2f   $path 2 end] "/
2ae0: 22 5d 0a 09 09 09 09 09 7d 20 65 6c 73 65 20 7b  "]......} else {
2af0: 0a 09 09 09 09 09 09 73 65 74 20 72 65 74 76 61  .......set retva
2b00: 6c 28 66 69 6c 65 29 20 22 22 0a 09 09 09 09 09  l(file) ""......
2b10: 7d 0a 09 09 09 09 7d 20 65 6c 73 65 20 7b 0a 09  }.....} else {..
2b20: 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 70  ....set retval(p
2b30: 61 63 6b 61 67 65 29 20 24 70 61 63 6b 61 67 65  ackage) $package
2b40: 0a 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c  ......set retval
2b50: 28 5f 63 68 69 6c 64 72 65 6e 29 20 6f 73 2d 63  (_children) os-c
2b60: 70 75 0a 09 09 09 09 09 73 65 74 20 72 65 74 76  pu......set retv
2b70: 61 6c 28 5f 74 79 70 65 29 20 70 61 63 6b 61 67  al(_type) packag
2b80: 65 73 0a 0a 09 09 09 09 09 69 66 20 7b 24 70 61  es.......if {$pa
2b90: 74 68 6c 65 6e 20 3e 20 32 7d 20 7b 0a 09 09 09  thlen > 2} {....
2ba0: 09 09 09 73 65 74 20 6f 73 5f 63 70 75 20 5b 6c  ...set os_cpu [l
2bb0: 69 6e 64 65 78 20 24 70 61 74 68 20 32 5d 0a 09  index $path 2]..
2bc0: 09 09 09 09 09 73 65 74 20 6f 73 5f 63 70 75 20  .....set os_cpu 
2bd0: 5b 73 70 6c 69 74 20 24 6f 73 5f 63 70 75 20 22  [split $os_cpu "
2be0: 2d 22 5d 0a 0a 09 09 09 09 09 09 73 65 74 20 72  -"]........set r
2bf0: 65 74 76 61 6c 28 6f 73 29 20 5b 6c 69 6e 64 65  etval(os) [linde
2c00: 78 20 24 6f 73 5f 63 70 75 20 30 5d 0a 09 09 09  x $os_cpu 0]....
2c10: 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 63 70  ...set retval(cp
2c20: 75 29 20 5b 6c 69 6e 64 65 78 20 24 6f 73 5f 63  u) [lindex $os_c
2c30: 70 75 20 31 5d 0a 09 09 09 09 09 09 73 65 74 20  pu 1].......set 
2c40: 72 65 74 76 61 6c 28 5f 63 68 69 6c 64 72 65 6e  retval(_children
2c50: 29 20 76 65 72 73 69 6f 6e 73 0a 09 09 09 09 09  ) versions......
2c60: 09 73 65 74 20 72 65 74 76 61 6c 28 5f 74 79 70  .set retval(_typ
2c70: 65 29 20 6f 73 2d 63 70 75 0a 0a 09 09 09 09 09  e) os-cpu.......
2c80: 09 69 66 20 7b 24 70 61 74 68 6c 65 6e 20 3e 20  .if {$pathlen > 
2c90: 33 7d 20 7b 0a 09 09 09 09 09 09 09 73 65 74 20  3} {........set 
2ca0: 72 65 74 76 61 6c 28 76 65 72 73 69 6f 6e 29 20  retval(version) 
2cb0: 5b 6c 69 6e 64 65 78 20 24 70 61 74 68 20 33 5d  [lindex $path 3]
2cc0: 0a 09 09 09 09 09 09 09 73 65 74 20 72 65 74 76  ........set retv
2cd0: 61 6c 28 5f 63 68 69 6c 64 72 65 6e 29 20 66 69  al(_children) fi
2ce0: 6c 65 73 0a 09 09 09 09 09 09 09 73 65 74 20 72  les........set r
2cf0: 65 74 76 61 6c 28 5f 74 79 70 65 29 20 76 65 72  etval(_type) ver
2d00: 73 69 6f 6e 73 0a 0a 09 09 09 09 09 09 09 73 65  sions.........se
2d10: 74 20 72 65 74 76 61 6c 28 70 61 63 6b 61 67 65  t retval(package
2d20: 5f 73 68 61 31 29 20 5b 3a 3a 61 70 70 66 73 3a  _sha1) [::appfs:
2d30: 3a 64 62 20 6f 6e 65 63 6f 6c 75 6d 6e 20 7b 53  :db onecolumn {S
2d40: 45 4c 45 43 54 20 73 68 61 31 20 46 52 4f 4d 20  ELECT sha1 FROM 
2d50: 70 61 63 6b 61 67 65 73 20 57 48 45 52 45 20 68  packages WHERE h
2d60: 6f 73 74 6e 61 6d 65 20 3d 20 24 72 65 74 76 61  ostname = $retva
2d70: 6c 28 68 6f 73 74 6e 61 6d 65 29 20 41 4e 44 20  l(hostname) AND 
2d80: 70 61 63 6b 61 67 65 20 3d 20 24 72 65 74 76 61  package = $retva
2d90: 6c 28 70 61 63 6b 61 67 65 29 20 41 4e 44 20 6f  l(package) AND o
2da0: 73 20 3d 20 24 72 65 74 76 61 6c 28 6f 73 29 20  s = $retval(os) 
2db0: 41 4e 44 20 63 70 75 41 72 63 68 20 3d 20 24 72  AND cpuArch = $r
2dc0: 65 74 76 61 6c 28 63 70 75 29 20 41 4e 44 20 76  etval(cpu) AND v
2dd0: 65 72 73 69 6f 6e 20 3d 20 24 72 65 74 76 61 6c  ersion = $retval
2de0: 28 76 65 72 73 69 6f 6e 29 3b 7d 5d 0a 09 09 09  (version);}]....
2df0: 09 09 09 09 69 66 20 7b 24 72 65 74 76 61 6c 28  ....if {$retval(
2e00: 70 61 63 6b 61 67 65 5f 73 68 61 31 29 20 3d 3d  package_sha1) ==
2e10: 20 22 22 7d 20 7b 0a 09 09 09 09 09 09 09 09 73   ""} {.........s
2e20: 65 74 20 72 65 74 76 61 6c 28 5f 63 68 69 6c 64  et retval(_child
2e30: 72 65 6e 29 20 64 65 61 64 0a 09 09 09 09 09 09  ren) dead.......
2e40: 09 09 72 65 74 75 72 6e 20 5b 61 72 72 61 79 20  ..return [array 
2e50: 67 65 74 20 72 65 74 76 61 6c 5d 0a 09 09 09 09  get retval].....
2e60: 09 09 09 7d 0a 0a 09 09 09 09 09 09 09 69 66 20  ...}.........if 
2e70: 7b 24 70 61 74 68 6c 65 6e 20 3e 20 34 7d 20 7b  {$pathlen > 4} {
2e80: 0a 09 09 09 09 09 09 09 09 73 65 74 20 72 65 74  .........set ret
2e90: 76 61 6c 28 5f 74 79 70 65 29 20 66 69 6c 65 73  val(_type) files
2ea0: 0a 09 09 09 09 09 09 09 09 73 65 74 20 72 65 74  .........set ret
2eb0: 76 61 6c 28 66 69 6c 65 29 20 5b 6a 6f 69 6e 20  val(file) [join 
2ec0: 5b 6c 72 61 6e 67 65 20 24 70 61 74 68 20 34 20  [lrange $path 4 
2ed0: 65 6e 64 5d 20 22 2f 22 5d 0a 09 09 09 09 09 09  end] "/"].......
2ee0: 09 7d 20 65 6c 73 65 20 7b 0a 09 09 09 09 09 09  .} else {.......
2ef0: 09 09 73 65 74 20 72 65 74 76 61 6c 28 5f 74 79  ..set retval(_ty
2f00: 70 65 29 20 66 69 6c 65 73 0a 09 09 09 09 09 09  pe) files.......
2f10: 09 09 73 65 74 20 72 65 74 76 61 6c 28 66 69 6c  ..set retval(fil
2f20: 65 29 20 22 22 0a 09 09 09 09 09 09 09 7d 0a 09  e) ""........}..
2f30: 09 09 09 09 09 7d 0a 09 09 09 09 09 7d 0a 09 09  .....}......}...
2f40: 09 09 7d 0a 09 09 09 7d 0a 09 09 7d 0a 0a 09 09  ..}....}...}....
2f50: 72 65 74 75 72 6e 20 5b 61 72 72 61 79 20 67 65  return [array ge
2f60: 74 20 72 65 74 76 61 6c 5d 0a 09 7d 0a 0a 09 70  t retval]..}...p
2f70: 72 6f 63 20 67 65 74 63 68 69 6c 64 72 65 6e 20  roc getchildren 
2f80: 7b 64 69 72 7d 20 7b 0a 09 09 61 72 72 61 79 20  {dir} {...array 
2f90: 73 65 74 20 70 61 74 68 69 6e 66 6f 20 5b 5f 70  set pathinfo [_p
2fa0: 61 72 73 65 70 61 74 68 20 24 64 69 72 5d 0a 0a  arsepath $dir]..
2fb0: 09 09 73 77 69 74 63 68 20 2d 2d 20 24 70 61 74  ..switch -- $pat
2fc0: 68 69 6e 66 6f 28 5f 63 68 69 6c 64 72 65 6e 29  hinfo(_children)
2fd0: 20 7b 0a 09 09 09 22 73 69 74 65 73 22 20 7b 0a   {...."sites" {.
2fe0: 09 09 09 09 72 65 74 75 72 6e 20 5b 3a 3a 61 70  ....return [::ap
2ff0: 70 66 73 3a 3a 64 62 20 65 76 61 6c 20 7b 53 45  pfs::db eval {SE
3000: 4c 45 43 54 20 44 49 53 54 49 4e 43 54 20 68 6f  LECT DISTINCT ho
3010: 73 74 6e 61 6d 65 20 46 52 4f 4d 20 70 61 63 6b  stname FROM pack
3020: 61 67 65 73 3b 7d 5d 0a 09 09 09 7d 0a 09 09 09  ages;}]....}....
3030: 22 70 61 63 6b 61 67 65 73 22 20 7b 0a 09 09 09  "packages" {....
3040: 09 63 61 74 63 68 20 7b 0a 09 09 09 09 09 3a 3a  .catch {......::
3050: 61 70 70 66 73 3a 3a 67 65 74 69 6e 64 65 78 20  appfs::getindex 
3060: 24 70 61 74 68 69 6e 66 6f 28 68 6f 73 74 6e 61  $pathinfo(hostna
3070: 6d 65 29 0a 09 09 09 09 7d 0a 0a 09 09 09 09 72  me).....}......r
3080: 65 74 75 72 6e 20 5b 3a 3a 61 70 70 66 73 3a 3a  eturn [::appfs::
3090: 64 62 20 65 76 61 6c 20 7b 53 45 4c 45 43 54 20  db eval {SELECT 
30a0: 44 49 53 54 49 4e 43 54 20 70 61 63 6b 61 67 65  DISTINCT package
30b0: 20 46 52 4f 4d 20 70 61 63 6b 61 67 65 73 20 57   FROM packages W
30c0: 48 45 52 45 20 68 6f 73 74 6e 61 6d 65 20 3d 20  HERE hostname = 
30d0: 24 70 61 74 68 69 6e 66 6f 28 68 6f 73 74 6e 61  $pathinfo(hostna
30e0: 6d 65 29 3b 7d 5d 0a 09 09 09 7d 0a 09 09 09 22  me);}]....}...."
30f0: 6f 73 2d 63 70 75 22 20 7b 0a 09 09 09 09 73 65  os-cpu" {.....se
3100: 74 20 72 65 74 76 61 6c 20 5b 3a 3a 61 70 70 66  t retval [::appf
3110: 73 3a 3a 64 62 20 65 76 61 6c 20 7b 53 45 4c 45  s::db eval {SELE
3120: 43 54 20 44 49 53 54 49 4e 43 54 20 6f 73 20 7c  CT DISTINCT os |
3130: 7c 20 22 2d 22 20 7c 7c 20 63 70 75 41 72 63 68  | "-" || cpuArch
3140: 20 46 52 4f 4d 20 70 61 63 6b 61 67 65 73 20 57   FROM packages W
3150: 48 45 52 45 20 68 6f 73 74 6e 61 6d 65 20 3d 20  HERE hostname = 
3160: 24 70 61 74 68 69 6e 66 6f 28 68 6f 73 74 6e 61  $pathinfo(hostna
3170: 6d 65 29 20 41 4e 44 20 70 61 63 6b 61 67 65 20  me) AND package 
3180: 3d 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63 6b  = $pathinfo(pack
3190: 61 67 65 29 3b 7d 5d 0a 0a 09 09 09 09 6c 61 70  age);}]......lap
31a0: 70 65 6e 64 20 72 65 74 76 61 6c 20 22 70 6c 61  pend retval "pla
31b0: 74 66 6f 72 6d 22 0a 0a 09 09 09 09 72 65 74 75  tform"......retu
31c0: 72 6e 20 24 72 65 74 76 61 6c 0a 09 09 09 7d 0a  rn $retval....}.
31d0: 09 09 09 22 76 65 72 73 69 6f 6e 73 22 20 7b 0a  ..."versions" {.
31e0: 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 20 5b  ....set retval [
31f0: 3a 3a 61 70 70 66 73 3a 3a 64 62 20 65 76 61 6c  ::appfs::db eval
3200: 20 7b 0a 09 09 09 09 09 53 45 4c 45 43 54 20 44   {......SELECT D
3210: 49 53 54 49 4e 43 54 20 76 65 72 73 69 6f 6e 20  ISTINCT version 
3220: 46 52 4f 4d 20 70 61 63 6b 61 67 65 73 20 57 48  FROM packages WH
3230: 45 52 45 20 68 6f 73 74 6e 61 6d 65 20 3d 20 24  ERE hostname = $
3240: 70 61 74 68 69 6e 66 6f 28 68 6f 73 74 6e 61 6d  pathinfo(hostnam
3250: 65 29 20 41 4e 44 20 70 61 63 6b 61 67 65 20 3d  e) AND package =
3260: 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63 6b 61   $pathinfo(packa
3270: 67 65 29 20 41 4e 44 20 6f 73 20 3d 20 24 70 61  ge) AND os = $pa
3280: 74 68 69 6e 66 6f 28 6f 73 29 20 41 4e 44 20 63  thinfo(os) AND c
3290: 70 75 41 72 63 68 20 3d 20 24 70 61 74 68 69 6e  puArch = $pathin
32a0: 66 6f 28 63 70 75 29 3b 0a 09 09 09 09 7d 5d 0a  fo(cpu);.....}].
32b0: 0a 09 09 09 09 3a 3a 61 70 70 66 73 3a 3a 64 62  .....::appfs::db
32c0: 20 65 76 61 6c 20 7b 53 45 4c 45 43 54 20 76 65   eval {SELECT ve
32d0: 72 73 69 6f 6e 20 46 52 4f 4d 20 70 61 63 6b 61  rsion FROM packa
32e0: 67 65 73 20 57 48 45 52 45 20 69 73 4c 61 74 65  ges WHERE isLate
32f0: 73 74 20 3d 20 31 20 41 4e 44 20 68 6f 73 74 6e  st = 1 AND hostn
3300: 61 6d 65 20 3d 20 24 70 61 74 68 69 6e 66 6f 28  ame = $pathinfo(
3310: 68 6f 73 74 6e 61 6d 65 29 20 41 4e 44 20 70 61  hostname) AND pa
3320: 63 6b 61 67 65 20 3d 20 24 70 61 74 68 69 6e 66  ckage = $pathinf
3330: 6f 28 70 61 63 6b 61 67 65 29 20 41 4e 44 20 6f  o(package) AND o
3340: 73 20 3d 20 24 70 61 74 68 69 6e 66 6f 28 6f 73  s = $pathinfo(os
3350: 29 20 41 4e 44 20 63 70 75 41 72 63 68 20 3d 20  ) AND cpuArch = 
3360: 24 70 61 74 68 69 6e 66 6f 28 63 70 75 29 20 4c  $pathinfo(cpu) L
3370: 49 4d 49 54 20 31 3b 7d 20 6c 61 74 65 73 74 5f  IMIT 1;} latest_
3380: 69 6e 66 6f 20 7b 7d 0a 0a 09 09 09 09 69 66 20  info {}......if 
3390: 7b 5b 69 6e 66 6f 20 65 78 69 73 74 73 20 6c 61  {[info exists la
33a0: 74 65 73 74 5f 69 6e 66 6f 28 76 65 72 73 69 6f  test_info(versio
33b0: 6e 29 5d 7d 20 7b 0a 09 09 09 09 09 6c 61 70 70  n)]} {......lapp
33c0: 65 6e 64 20 72 65 74 76 61 6c 20 22 6c 61 74 65  end retval "late
33d0: 73 74 22 0a 09 09 09 09 7d 0a 0a 09 09 09 09 72  st".....}......r
33e0: 65 74 75 72 6e 20 24 72 65 74 76 61 6c 0a 09 09  eturn $retval...
33f0: 09 7d 0a 09 09 09 22 66 69 6c 65 73 22 20 7b 0a  .}...."files" {.
3400: 09 09 09 09 63 61 74 63 68 20 7b 0a 09 09 09 09  ....catch {.....
3410: 09 3a 3a 61 70 70 66 73 3a 3a 67 65 74 69 6e 64  .::appfs::getind
3420: 65 78 20 24 70 61 74 68 69 6e 66 6f 28 68 6f 73  ex $pathinfo(hos
3430: 74 6e 61 6d 65 29 0a 09 09 09 09 09 3a 3a 61 70  tname)......::ap
3440: 70 66 73 3a 3a 67 65 74 70 6b 67 6d 61 6e 69 66  pfs::getpkgmanif
3450: 65 73 74 20 24 70 61 74 68 69 6e 66 6f 28 68 6f  est $pathinfo(ho
3460: 73 74 6e 61 6d 65 29 20 24 70 61 74 68 69 6e 66  stname) $pathinf
3470: 6f 28 70 61 63 6b 61 67 65 5f 73 68 61 31 29 0a  o(package_sha1).
3480: 09 09 09 09 7d 0a 0a 09 09 09 09 73 65 74 20 72  ....}......set r
3490: 65 74 76 61 6c 20 5b 3a 3a 61 70 70 66 73 3a 3a  etval [::appfs::
34a0: 64 62 20 65 76 61 6c 20 7b 53 45 4c 45 43 54 20  db eval {SELECT 
34b0: 44 49 53 54 49 4e 43 54 20 66 69 6c 65 5f 6e 61  DISTINCT file_na
34c0: 6d 65 20 46 52 4f 4d 20 66 69 6c 65 73 20 57 48  me FROM files WH
34d0: 45 52 45 20 70 61 63 6b 61 67 65 5f 73 68 61 31  ERE package_sha1
34e0: 20 3d 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63   = $pathinfo(pac
34f0: 6b 61 67 65 5f 73 68 61 31 29 20 41 4e 44 20 66  kage_sha1) AND f
3500: 69 6c 65 5f 64 69 72 65 63 74 6f 72 79 20 3d 20  ile_directory = 
3510: 24 70 61 74 68 69 6e 66 6f 28 66 69 6c 65 29 3b  $pathinfo(file);
3520: 7d 5d 0a 0a 09 09 09 09 69 66 20 7b 5b 69 6e 66  }]......if {[inf
3530: 6f 20 65 78 69 73 74 73 20 70 61 74 68 69 6e 66  o exists pathinf
3540: 6f 28 70 61 63 6b 61 67 65 29 5d 20 26 26 20 5b  o(package)] && [
3550: 69 6e 66 6f 20 65 78 69 73 74 73 20 70 61 74 68  info exists path
3560: 69 6e 66 6f 28 68 6f 73 74 6e 61 6d 65 29 5d 20  info(hostname)] 
3570: 26 26 20 5b 69 6e 66 6f 20 65 78 69 73 74 73 20  && [info exists 
3580: 70 61 74 68 69 6e 66 6f 28 66 69 6c 65 29 5d 7d  pathinfo(file)]}
3590: 20 7b 0a 09 09 09 09 09 5f 61 73 5f 75 73 65 72   {......_as_user
35a0: 20 7b 0a 09 09 09 09 09 09 73 65 74 20 64 69 72   {.......set dir
35b0: 20 5b 5f 6c 6f 63 61 6c 70 61 74 68 20 24 70 61   [_localpath $pa
35c0: 74 68 69 6e 66 6f 28 70 61 63 6b 61 67 65 29 20  thinfo(package) 
35d0: 24 70 61 74 68 69 6e 66 6f 28 68 6f 73 74 6e 61  $pathinfo(hostna
35e0: 6d 65 29 20 24 70 61 74 68 69 6e 66 6f 28 66 69  me) $pathinfo(fi
35f0: 6c 65 29 5d 0a 09 09 09 09 09 09 73 65 74 20 77  le)].......set w
3600: 68 69 74 65 6f 75 74 64 69 72 20 5b 73 74 72 69  hiteoutdir [stri
3610: 6e 67 20 72 61 6e 67 65 20 5b 5f 77 68 69 74 65  ng range [_white
3620: 6f 75 74 70 61 74 68 20 24 70 61 74 68 69 6e 66  outpath $pathinf
3630: 6f 28 70 61 63 6b 61 67 65 29 20 24 70 61 74 68  o(package) $path
3640: 69 6e 66 6f 28 68 6f 73 74 6e 61 6d 65 29 20 24  info(hostname) $
3650: 70 61 74 68 69 6e 66 6f 28 66 69 6c 65 29 5d 20  pathinfo(file)] 
3660: 30 20 65 6e 64 2d 31 35 5d 0a 0a 09 09 09 09 09  0 end-15].......
3670: 09 69 66 20 7b 24 77 68 69 74 65 6f 75 74 64 69  .if {$whiteoutdi
3680: 72 20 21 3d 20 22 22 7d 20 7b 0a 09 09 09 09 09  r != ""} {......
3690: 09 09 66 6f 72 65 61 63 68 20 66 69 6c 65 20 5b  ..foreach file [
36a0: 67 6c 6f 62 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e  glob -nocomplain
36b0: 20 2d 74 61 69 6c 73 20 2d 64 69 72 65 63 74 6f   -tails -directo
36c0: 72 79 20 24 77 68 69 74 65 6f 75 74 64 69 72 20  ry $whiteoutdir 
36d0: 7b 7b 2e 2c 7d 2a 2e 41 50 50 46 53 2e 57 48 49  {{.,}*.APPFS.WHI
36e0: 54 45 4f 55 54 7d 5d 20 7b 0a 09 09 09 09 09 09  TEOUT}] {.......
36f0: 09 09 73 65 74 20 72 65 6d 6f 76 65 20 5b 73 74  ..set remove [st
3700: 72 69 6e 67 20 72 61 6e 67 65 20 24 66 69 6c 65  ring range $file
3710: 20 30 20 65 6e 64 2d 31 35 5d 0a 09 09 09 09 09   0 end-15]......
3720: 09 09 09 73 65 74 20 69 64 78 20 5b 6c 73 65 61  ...set idx [lsea
3730: 72 63 68 20 2d 65 78 61 63 74 20 24 72 65 74 76  rch -exact $retv
3740: 61 6c 20 24 72 65 6d 6f 76 65 5d 0a 09 09 09 09  al $remove].....
3750: 09 09 09 09 69 66 20 7b 24 69 64 78 20 21 3d 20  ....if {$idx != 
3760: 2d 31 7d 20 7b 0a 09 09 09 09 09 09 09 09 09 73  -1} {..........s
3770: 65 74 20 72 65 74 76 61 6c 20 5b 6c 72 65 70 6c  et retval [lrepl
3780: 61 63 65 20 24 72 65 74 76 61 6c 20 24 69 64 78  ace $retval $idx
3790: 20 24 69 64 78 5d 0a 09 09 09 09 09 09 09 09 7d   $idx].........}
37a0: 0a 09 09 09 09 09 09 09 7d 0a 09 09 09 09 09 09  ........}.......
37b0: 7d 0a 0a 09 09 09 09 09 09 69 66 20 7b 24 64 69  }........if {$di
37c0: 72 20 21 3d 20 22 22 7d 20 7b 0a 09 09 09 09 09  r != ""} {......
37d0: 09 09 66 6f 72 65 61 63 68 20 66 69 6c 65 20 5b  ..foreach file [
37e0: 67 6c 6f 62 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e  glob -nocomplain
37f0: 20 2d 74 61 69 6c 73 20 2d 64 69 72 65 63 74 6f   -tails -directo
3800: 72 79 20 24 64 69 72 20 7b 7b 2e 2c 7d 2a 7d 5d  ry $dir {{.,}*}]
3810: 20 7b 0a 09 09 09 09 09 09 09 09 69 66 20 7b 24   {.........if {$
3820: 66 69 6c 65 20 3d 3d 20 22 2e 22 20 7c 7c 20 24  file == "." || $
3830: 66 69 6c 65 20 3d 3d 20 22 2e 2e 22 7d 20 7b 0a  file == ".."} {.
3840: 09 09 09 09 09 09 09 09 09 63 6f 6e 74 69 6e 75  .........continu
3850: 65 0a 09 09 09 09 09 09 09 09 7d 0a 0a 09 09 09  e.........}.....
3860: 09 09 09 09 09 69 66 20 7b 24 66 69 6c 65 20 3d  .....if {$file =
3870: 3d 20 22 2e 41 50 50 46 53 2e 57 48 49 54 45 4f  = ".APPFS.WHITEO
3880: 55 54 22 7d 20 7b 0a 09 09 09 09 09 09 09 09 09  UT"} {..........
3890: 63 6f 6e 74 69 6e 75 65 0a 09 09 09 09 09 09 09  continue........
38a0: 09 7d 0a 0a 09 09 09 09 09 09 09 09 69 66 20 7b  .}..........if {
38b0: 5b 6c 73 65 61 72 63 68 20 2d 65 78 61 63 74 20  [lsearch -exact 
38c0: 24 72 65 74 76 61 6c 20 24 66 69 6c 65 5d 20 21  $retval $file] !
38d0: 3d 20 2d 31 7d 20 7b 0a 09 09 09 09 09 09 09 09  = -1} {.........
38e0: 09 63 6f 6e 74 69 6e 75 65 0a 09 09 09 09 09 09  .continue.......
38f0: 09 09 7d 0a 0a 09 09 09 09 09 09 09 09 6c 61 70  ..}..........lap
3900: 70 65 6e 64 20 72 65 74 76 61 6c 20 24 66 69 6c  pend retval $fil
3910: 65 0a 09 09 09 09 09 09 09 7d 0a 09 09 09 09 09  e........}......
3920: 09 7d 0a 09 09 09 09 09 7d 0a 09 09 09 09 7d 0a  .}......}.....}.
3930: 0a 09 09 09 09 72 65 74 75 72 6e 20 24 72 65 74  .....return $ret
3940: 76 61 6c 0a 09 09 09 7d 0a 09 09 7d 0a 0a 09 09  val....}...}....
3950: 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72 72  return -code err
3960: 6f 72 20 22 49 6e 76 61 6c 69 64 20 6f 72 20 75  or "Invalid or u
3970: 6e 61 63 63 65 70 74 61 62 6c 65 20 70 61 74 68  nacceptable path
3980: 3a 20 24 64 69 72 22 0a 09 7d 0a 0a 09 70 72 6f  : $dir"..}...pro
3990: 63 20 67 65 74 61 74 74 72 20 7b 70 61 74 68 7d  c getattr {path}
39a0: 20 7b 0a 09 09 61 72 72 61 79 20 73 65 74 20 70   {...array set p
39b0: 61 74 68 69 6e 66 6f 20 5b 5f 70 61 72 73 65 70  athinfo [_parsep
39c0: 61 74 68 20 24 70 61 74 68 5d 0a 09 09 61 72 72  ath $path]...arr
39d0: 61 79 20 73 65 74 20 72 65 74 76 61 6c 20 5b 6c  ay set retval [l
39e0: 69 73 74 5d 0a 0a 09 09 63 61 74 63 68 20 7b 0a  ist]....catch {.
39f0: 09 09 09 3a 3a 61 70 70 66 73 3a 3a 67 65 74 69  ...::appfs::geti
3a00: 6e 64 65 78 20 24 70 61 74 68 69 6e 66 6f 28 68  ndex $pathinfo(h
3a10: 6f 73 74 6e 61 6d 65 29 0a 09 09 09 3a 3a 61 70  ostname)....::ap
3a20: 70 66 73 3a 3a 67 65 74 70 6b 67 6d 61 6e 69 66  pfs::getpkgmanif
3a30: 65 73 74 20 24 70 61 74 68 69 6e 66 6f 28 68 6f  est $pathinfo(ho
3a40: 73 74 6e 61 6d 65 29 20 24 70 61 74 68 69 6e 66  stname) $pathinf
3a50: 6f 28 70 61 63 6b 61 67 65 5f 73 68 61 31 29 0a  o(package_sha1).
3a60: 09 09 7d 0a 0a 09 09 73 77 69 74 63 68 20 2d 2d  ..}....switch --
3a70: 20 24 70 61 74 68 69 6e 66 6f 28 5f 74 79 70 65   $pathinfo(_type
3a80: 29 20 7b 0a 09 09 09 22 74 6f 70 6c 65 76 65 6c  ) {...."toplevel
3a90: 22 20 7b 0a 09 09 09 09 73 65 74 20 72 65 74 76  " {.....set retv
3aa0: 61 6c 28 74 79 70 65 29 20 64 69 72 65 63 74 6f  al(type) directo
3ab0: 72 79 0a 09 09 09 09 73 65 74 20 72 65 74 76 61  ry.....set retva
3ac0: 6c 28 63 68 69 6c 64 63 6f 75 6e 74 29 20 5b 6c  l(childcount) [l
3ad0: 6c 65 6e 67 74 68 20 5b 67 65 74 63 68 69 6c 64  length [getchild
3ae0: 72 65 6e 20 24 70 61 74 68 5d 5d 0a 09 09 09 7d  ren $path]]....}
3af0: 0a 09 09 09 22 73 69 74 65 73 22 20 7b 0a 09 09  ...."sites" {...
3b00: 09 09 73 65 74 20 63 68 65 63 6b 20 5b 3a 3a 61  ..set check [::a
3b10: 70 70 66 73 3a 3a 64 62 20 6f 6e 65 63 6f 6c 75  ppfs::db onecolu
3b20: 6d 6e 20 7b 53 45 4c 45 43 54 20 31 20 46 52 4f  mn {SELECT 1 FRO
3b30: 4d 20 70 61 63 6b 61 67 65 73 20 57 48 45 52 45  M packages WHERE
3b40: 20 68 6f 73 74 6e 61 6d 65 20 3d 20 24 70 61 74   hostname = $pat
3b50: 68 69 6e 66 6f 28 68 6f 73 74 6e 61 6d 65 29 3b  hinfo(hostname);
3b60: 7d 5d 0a 09 09 09 09 69 66 20 7b 24 63 68 65 63  }].....if {$chec
3b70: 6b 20 3d 3d 20 22 31 22 7d 20 7b 0a 09 09 09 09  k == "1"} {.....
3b80: 09 73 65 74 20 72 65 74 76 61 6c 28 74 79 70 65  .set retval(type
3b90: 29 20 64 69 72 65 63 74 6f 72 79 0a 09 09 09 09  ) directory.....
3ba0: 09 73 65 74 20 72 65 74 76 61 6c 28 63 68 69 6c  .set retval(chil
3bb0: 64 63 6f 75 6e 74 29 20 5b 6c 6c 65 6e 67 74 68  dcount) [llength
3bc0: 20 5b 67 65 74 63 68 69 6c 64 72 65 6e 20 24 70   [getchildren $p
3bd0: 61 74 68 5d 5d 0a 09 09 09 09 7d 0a 09 09 09 7d  ath]].....}....}
3be0: 0a 09 09 09 22 70 61 63 6b 61 67 65 73 22 20 7b  ...."packages" {
3bf0: 0a 09 09 09 09 73 65 74 20 63 68 65 63 6b 20 5b  .....set check [
3c00: 3a 3a 61 70 70 66 73 3a 3a 64 62 20 6f 6e 65 63  ::appfs::db onec
3c10: 6f 6c 75 6d 6e 20 7b 53 45 4c 45 43 54 20 31 20  olumn {SELECT 1 
3c20: 46 52 4f 4d 20 70 61 63 6b 61 67 65 73 20 57 48  FROM packages WH
3c30: 45 52 45 20 68 6f 73 74 6e 61 6d 65 20 3d 20 24  ERE hostname = $
3c40: 70 61 74 68 69 6e 66 6f 28 68 6f 73 74 6e 61 6d  pathinfo(hostnam
3c50: 65 29 20 41 4e 44 20 70 61 63 6b 61 67 65 20 3d  e) AND package =
3c60: 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63 6b 61   $pathinfo(packa
3c70: 67 65 29 3b 7d 5d 0a 09 09 09 09 69 66 20 7b 24  ge);}].....if {$
3c80: 63 68 65 63 6b 20 3d 3d 20 22 31 22 7d 20 7b 0a  check == "1"} {.
3c90: 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28  .....set retval(
3ca0: 74 79 70 65 29 20 64 69 72 65 63 74 6f 72 79 0a  type) directory.
3cb0: 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28  .....set retval(
3cc0: 63 68 69 6c 64 63 6f 75 6e 74 29 20 5b 6c 6c 65  childcount) [lle
3cd0: 6e 67 74 68 20 5b 67 65 74 63 68 69 6c 64 72 65  ngth [getchildre
3ce0: 6e 20 24 70 61 74 68 5d 5d 0a 09 09 09 09 7d 0a  n $path]].....}.
3cf0: 09 09 09 7d 0a 09 09 09 22 6f 73 2d 63 70 75 22  ...}...."os-cpu"
3d00: 20 7b 0a 09 09 09 09 69 66 20 7b 24 70 61 74 68   {.....if {$path
3d10: 69 6e 66 6f 28 6f 73 29 20 3d 3d 20 22 70 6c 61  info(os) == "pla
3d20: 74 66 6f 72 6d 22 20 26 26 20 24 70 61 74 68 69  tform" && $pathi
3d30: 6e 66 6f 28 63 70 75 29 20 3d 3d 20 22 22 7d 20  nfo(cpu) == ""} 
3d40: 7b 0a 09 09 09 09 09 73 65 74 20 72 65 74 76 61  {......set retva
3d50: 6c 28 74 79 70 65 29 20 73 79 6d 6c 69 6e 6b 0a  l(type) symlink.
3d60: 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28  .....set retval(
3d70: 73 6f 75 72 63 65 29 20 5b 70 6c 61 74 66 6f 72  source) [platfor
3d80: 6d 3a 3a 67 65 6e 65 72 69 63 5d 0a 09 09 09 09  m::generic].....
3d90: 7d 20 65 6c 73 65 20 7b 0a 09 09 09 09 09 73 65  } else {......se
3da0: 74 20 63 68 65 63 6b 20 5b 3a 3a 61 70 70 66 73  t check [::appfs
3db0: 3a 3a 64 62 20 6f 6e 65 63 6f 6c 75 6d 6e 20 7b  ::db onecolumn {
3dc0: 0a 09 09 09 09 09 09 53 45 4c 45 43 54 20 31 20  .......SELECT 1 
3dd0: 46 52 4f 4d 20 70 61 63 6b 61 67 65 73 20 57 48  FROM packages WH
3de0: 45 52 45 20 68 6f 73 74 6e 61 6d 65 20 3d 20 24  ERE hostname = $
3df0: 70 61 74 68 69 6e 66 6f 28 68 6f 73 74 6e 61 6d  pathinfo(hostnam
3e00: 65 29 20 41 4e 44 20 70 61 63 6b 61 67 65 20 3d  e) AND package =
3e10: 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63 6b 61   $pathinfo(packa
3e20: 67 65 29 20 41 4e 44 20 6f 73 20 3d 20 24 70 61  ge) AND os = $pa
3e30: 74 68 69 6e 66 6f 28 6f 73 29 20 41 4e 44 20 63  thinfo(os) AND c
3e40: 70 75 41 72 63 68 20 3d 20 24 70 61 74 68 69 6e  puArch = $pathin
3e50: 66 6f 28 63 70 75 29 3b 0a 09 09 09 09 09 7d 5d  fo(cpu);......}]
3e60: 0a 09 09 09 09 09 69 66 20 7b 24 63 68 65 63 6b  ......if {$check
3e70: 20 3d 3d 20 22 31 22 7d 20 7b 0a 09 09 09 09 09   == "1"} {......
3e80: 09 73 65 74 20 72 65 74 76 61 6c 28 74 79 70 65  .set retval(type
3e90: 29 20 64 69 72 65 63 74 6f 72 79 0a 09 09 09 09  ) directory.....
3ea0: 09 09 73 65 74 20 72 65 74 76 61 6c 28 63 68 69  ..set retval(chi
3eb0: 6c 64 63 6f 75 6e 74 29 20 5b 6c 6c 65 6e 67 74  ldcount) [llengt
3ec0: 68 20 5b 67 65 74 63 68 69 6c 64 72 65 6e 20 24  h [getchildren $
3ed0: 70 61 74 68 5d 5d 0a 09 09 09 09 09 7d 0a 09 09  path]]......}...
3ee0: 09 09 7d 0a 09 09 09 7d 0a 09 09 09 22 76 65 72  ..}....}...."ver
3ef0: 73 69 6f 6e 73 22 20 7b 0a 09 09 09 09 69 66 20  sions" {.....if 
3f00: 7b 24 70 61 74 68 69 6e 66 6f 28 76 65 72 73 69  {$pathinfo(versi
3f10: 6f 6e 29 20 3d 3d 20 22 6c 61 74 65 73 74 22 7d  on) == "latest"}
3f20: 20 7b 0a 09 09 09 09 09 3a 3a 61 70 70 66 73 3a   {......::appfs:
3f30: 3a 64 62 20 65 76 61 6c 20 7b 53 45 4c 45 43 54  :db eval {SELECT
3f40: 20 76 65 72 73 69 6f 6e 20 46 52 4f 4d 20 70 61   version FROM pa
3f50: 63 6b 61 67 65 73 20 57 48 45 52 45 20 69 73 4c  ckages WHERE isL
3f60: 61 74 65 73 74 20 3d 20 31 20 41 4e 44 20 68 6f  atest = 1 AND ho
3f70: 73 74 6e 61 6d 65 20 3d 20 24 70 61 74 68 69 6e  stname = $pathin
3f80: 66 6f 28 68 6f 73 74 6e 61 6d 65 29 20 41 4e 44  fo(hostname) AND
3f90: 20 70 61 63 6b 61 67 65 20 3d 20 24 70 61 74 68   package = $path
3fa0: 69 6e 66 6f 28 70 61 63 6b 61 67 65 29 20 41 4e  info(package) AN
3fb0: 44 20 6f 73 20 3d 20 24 70 61 74 68 69 6e 66 6f  D os = $pathinfo
3fc0: 28 6f 73 29 20 41 4e 44 20 63 70 75 41 72 63 68  (os) AND cpuArch
3fd0: 20 3d 20 24 70 61 74 68 69 6e 66 6f 28 63 70 75   = $pathinfo(cpu
3fe0: 29 20 4c 49 4d 49 54 20 31 3b 7d 20 6c 61 74 65  ) LIMIT 1;} late
3ff0: 73 74 5f 69 6e 66 6f 20 7b 7d 0a 0a 09 09 09 09  st_info {}......
4000: 09 69 66 20 7b 5b 69 6e 66 6f 20 65 78 69 73 74  .if {[info exist
4010: 73 20 6c 61 74 65 73 74 5f 69 6e 66 6f 28 76 65  s latest_info(ve
4020: 72 73 69 6f 6e 29 5d 7d 20 7b 0a 09 09 09 09 09  rsion)]} {......
4030: 09 73 65 74 20 72 65 74 76 61 6c 28 74 79 70 65  .set retval(type
4040: 29 20 73 79 6d 6c 69 6e 6b 0a 09 09 09 09 09 09  ) symlink.......
4050: 73 65 74 20 72 65 74 76 61 6c 28 73 6f 75 72 63  set retval(sourc
4060: 65 29 20 24 6c 61 74 65 73 74 5f 69 6e 66 6f 28  e) $latest_info(
4070: 76 65 72 73 69 6f 6e 29 0a 09 09 09 09 09 7d 0a  version)......}.
4080: 09 09 09 09 7d 20 65 6c 73 65 20 7b 0a 09 09 09  ....} else {....
4090: 09 09 69 66 20 7b 5b 69 6e 66 6f 20 65 78 69 73  ..if {[info exis
40a0: 74 73 20 70 61 74 68 69 6e 66 6f 28 70 61 63 6b  ts pathinfo(pack
40b0: 61 67 65 5f 73 68 61 31 29 5d 20 26 26 20 24 70  age_sha1)] && $p
40c0: 61 74 68 69 6e 66 6f 28 70 61 63 6b 61 67 65 5f  athinfo(package_
40d0: 73 68 61 31 29 20 21 3d 20 22 22 7d 20 7b 0a 09  sha1) != ""} {..
40e0: 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28  .....set retval(
40f0: 74 79 70 65 29 20 64 69 72 65 63 74 6f 72 79 0a  type) directory.
4100: 09 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c  ......set retval
4110: 28 63 68 69 6c 64 63 6f 75 6e 74 29 20 5b 6c 6c  (childcount) [ll
4120: 65 6e 67 74 68 20 5b 67 65 74 63 68 69 6c 64 72  ength [getchildr
4130: 65 6e 20 24 70 61 74 68 5d 5d 0a 09 09 09 09 09  en $path]]......
4140: 7d 0a 09 09 09 09 7d 0a 09 09 09 7d 0a 09 09 09  }.....}....}....
4150: 22 66 69 6c 65 73 22 20 7b 0a 09 09 09 09 73 65  "files" {.....se
4160: 74 20 72 65 74 76 61 6c 28 70 61 63 6b 61 67 65  t retval(package
4170: 64 29 20 31 0a 0a 09 09 09 09 73 65 74 20 6c 6f  d) 1......set lo
4180: 63 61 6c 70 61 74 68 20 5b 5f 6c 6f 63 61 6c 70  calpath [_localp
4190: 61 74 68 20 24 70 61 74 68 69 6e 66 6f 28 70 61  ath $pathinfo(pa
41a0: 63 6b 61 67 65 29 20 24 70 61 74 68 69 6e 66 6f  ckage) $pathinfo
41b0: 28 68 6f 73 74 6e 61 6d 65 29 20 24 70 61 74 68  (hostname) $path
41c0: 69 6e 66 6f 28 66 69 6c 65 29 5d 0a 09 09 09 09  info(file)].....
41d0: 73 65 74 20 77 68 69 74 65 6f 75 74 70 61 74 68  set whiteoutpath
41e0: 20 20 5b 5f 77 68 69 74 65 6f 75 74 70 61 74 68    [_whiteoutpath
41f0: 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63 6b 61   $pathinfo(packa
4200: 67 65 29 20 24 70 61 74 68 69 6e 66 6f 28 68 6f  ge) $pathinfo(ho
4210: 73 74 6e 61 6d 65 29 20 24 70 61 74 68 69 6e 66  stname) $pathinf
4220: 6f 28 66 69 6c 65 29 5d 0a 0a 09 09 09 09 73 65  o(file)]......se
4230: 74 20 72 65 74 76 61 6c 28 6c 6f 63 61 6c 70 61  t retval(localpa
4240: 74 68 29 20 24 6c 6f 63 61 6c 70 61 74 68 0a 09  th) $localpath..
4250: 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 77 68  ...set retval(wh
4260: 69 74 65 6f 75 74 70 61 74 68 29 20 24 77 68 69  iteoutpath) $whi
4270: 74 65 6f 75 74 70 61 74 68 0a 0a 09 09 09 09 75  teoutpath......u
4280: 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e  nset -nocomplain
4290: 20 6c 6f 63 61 6c 70 61 74 68 69 6e 66 6f 0a 09   localpathinfo..
42a0: 09 09 09 69 66 20 7b 24 6c 6f 63 61 6c 70 61 74  ...if {$localpat
42b0: 68 20 21 3d 20 22 22 7d 20 7b 0a 09 09 09 09 09  h != ""} {......
42c0: 5f 61 73 5f 75 73 65 72 20 7b 0a 09 09 09 09 09  _as_user {......
42d0: 09 63 61 74 63 68 20 7b 0a 09 09 09 09 09 09 09  .catch {........
42e0: 66 69 6c 65 20 6c 73 74 61 74 20 24 6c 6f 63 61  file lstat $loca
42f0: 6c 70 61 74 68 20 6c 6f 63 61 6c 70 61 74 68 69  lpath localpathi
4300: 6e 66 6f 0a 09 09 09 09 09 09 7d 0a 09 09 09 09  nfo.......}.....
4310: 09 7d 0a 09 09 09 09 7d 0a 0a 09 09 09 09 69 66  .}.....}......if
4320: 20 7b 24 6c 6f 63 61 6c 70 61 74 68 20 21 3d 20   {$localpath != 
4330: 22 22 20 26 26 20 5b 69 6e 66 6f 20 65 78 69 73  "" && [info exis
4340: 74 73 20 6c 6f 63 61 6c 70 61 74 68 69 6e 66 6f  ts localpathinfo
4350: 5d 7d 20 7b 0a 09 09 09 09 09 73 65 74 20 72 65  ]} {......set re
4360: 74 76 61 6c 28 69 73 5f 6c 6f 63 61 6c 66 69 6c  tval(is_localfil
4370: 65 29 20 31 0a 09 09 09 09 09 63 61 74 63 68 20  e) 1......catch 
4380: 7b 0a 09 09 09 09 09 09 73 65 74 20 72 65 74 76  {.......set retv
4390: 61 6c 28 74 69 6d 65 29 20 24 6c 6f 63 61 6c 70  al(time) $localp
43a0: 61 74 68 69 6e 66 6f 28 6d 74 69 6d 65 29 0a 0a  athinfo(mtime)..
43b0: 09 09 09 09 09 09 73 77 69 74 63 68 20 2d 2d 20  ......switch -- 
43c0: 24 6c 6f 63 61 6c 70 61 74 68 69 6e 66 6f 28 74  $localpathinfo(t
43d0: 79 70 65 29 20 7b 0a 09 09 09 09 09 09 09 22 64  ype) {........"d
43e0: 69 72 65 63 74 6f 72 79 22 20 7b 0a 09 09 09 09  irectory" {.....
43f0: 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 74  ....set retval(t
4400: 79 70 65 29 20 22 64 69 72 65 63 74 6f 72 79 22  ype) "directory"
4410: 0a 09 09 09 09 09 09 09 09 73 65 74 20 72 65 74  .........set ret
4420: 76 61 6c 28 63 68 69 6c 64 63 6f 75 6e 74 29 20  val(childcount) 
4430: 5b 6c 6c 65 6e 67 74 68 20 5b 67 65 74 63 68 69  [llength [getchi
4440: 6c 64 72 65 6e 20 24 70 61 74 68 5d 5d 0a 09 09  ldren $path]]...
4450: 09 09 09 09 09 7d 0a 09 09 09 09 09 09 09 22 66  .....}........"f
4460: 69 6c 65 22 20 7b 0a 09 09 09 09 09 09 09 09 73  ile" {.........s
4470: 65 74 20 72 65 74 76 61 6c 28 74 79 70 65 29 20  et retval(type) 
4480: 22 66 69 6c 65 22 0a 09 09 09 09 09 09 09 09 73  "file".........s
4490: 65 74 20 72 65 74 76 61 6c 28 73 69 7a 65 29 20  et retval(size) 
44a0: 24 6c 6f 63 61 6c 70 61 74 68 69 6e 66 6f 28 73  $localpathinfo(s
44b0: 69 7a 65 29 0a 09 09 09 09 09 09 09 09 5f 61 73  ize)........._as
44c0: 5f 75 73 65 72 20 7b 0a 09 09 09 09 09 09 09 09  _user {.........
44d0: 09 69 66 20 7b 5b 66 69 6c 65 20 65 78 65 63 75  .if {[file execu
44e0: 74 61 62 6c 65 20 24 6c 6f 63 61 6c 70 61 74 68  table $localpath
44f0: 5d 7d 20 7b 0a 09 09 09 09 09 09 09 09 09 09 73  ]} {...........s
4500: 65 74 20 72 65 74 76 61 6c 28 70 65 72 6d 73 29  et retval(perms)
4510: 20 22 78 22 0a 09 09 09 09 09 09 09 09 09 7d 20   "x"..........} 
4520: 65 6c 73 65 20 7b 0a 09 09 09 09 09 09 09 09 09  else {..........
4530: 09 73 65 74 20 72 65 74 76 61 6c 28 70 65 72 6d  .set retval(perm
4540: 73 29 20 22 22 0a 09 09 09 09 09 09 09 09 09 7d  s) ""..........}
4550: 0a 09 09 09 09 09 09 09 09 7d 0a 09 09 09 09 09  .........}......
4560: 09 09 7d 0a 09 09 09 09 09 09 09 22 6c 69 6e 6b  ..}........"link
4570: 22 20 7b 0a 09 09 09 09 09 09 09 09 73 65 74 20  " {.........set 
4580: 72 65 74 76 61 6c 28 74 79 70 65 29 20 22 73 79  retval(type) "sy
4590: 6d 6c 69 6e 6b 22 0a 0a 09 09 09 09 09 09 09 09  mlink"..........
45a0: 5f 61 73 5f 75 73 65 72 20 7b 0a 09 09 09 09 09  _as_user {......
45b0: 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 73  ....set retval(s
45c0: 6f 75 72 63 65 29 20 5b 66 69 6c 65 20 72 65 61  ource) [file rea
45d0: 64 6c 69 6e 6b 20 24 6c 6f 63 61 6c 70 61 74 68  dlink $localpath
45e0: 5d 0a 09 09 09 09 09 09 09 09 7d 0a 09 09 09 09  ].........}.....
45f0: 09 09 09 7d 0a 09 09 09 09 09 09 09 22 66 69 66  ...}........"fif
4600: 6f 22 20 7b 0a 09 09 09 09 09 09 09 09 23 20 43  o" {.........# C
4610: 61 70 69 74 61 6c 69 7a 65 64 20 73 6f 20 74 68  apitalized so th
4620: 61 74 20 74 68 65 20 66 69 72 73 74 20 63 68 61  at the first cha
4630: 72 20 69 73 20 75 6e 69 71 75 65 0a 09 09 09 09  r is unique.....
4640: 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 74  ....set retval(t
4650: 79 70 65 29 20 22 46 69 66 6f 22 0a 09 09 09 09  ype) "Fifo".....
4660: 09 09 09 7d 0a 09 09 09 09 09 09 09 22 73 6f 63  ...}........"soc
4670: 6b 65 74 22 20 7b 0a 09 09 09 09 09 09 09 09 23  ket" {.........#
4680: 20 43 61 70 69 74 61 6c 69 7a 65 64 20 73 6f 20   Capitalized so 
4690: 74 68 61 74 20 74 68 65 20 66 69 72 73 74 20 63  that the first c
46a0: 68 61 72 20 69 73 20 75 6e 69 71 75 65 0a 09 09  har is unique...
46b0: 09 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c  ......set retval
46c0: 28 74 79 70 65 29 20 22 53 6f 63 6b 65 74 22 0a  (type) "Socket".
46d0: 09 09 09 09 09 09 09 7d 0a 09 09 09 09 09 09 7d  .......}.......}
46e0: 0a 09 09 09 09 09 7d 20 65 72 72 0a 09 09 09 09  ......} err.....
46f0: 7d 20 65 6c 73 65 20 7b 0a 09 09 09 09 09 69 66  } else {......if
4700: 20 7b 24 77 68 69 74 65 6f 75 74 70 61 74 68 20   {$whiteoutpath 
4710: 3d 3d 20 22 22 20 7c 7c 20 21 5b 66 69 6c 65 20  == "" || ![file 
4720: 65 78 69 73 74 73 20 24 77 68 69 74 65 6f 75 74  exists $whiteout
4730: 70 61 74 68 5d 7d 20 7b 0a 09 09 09 09 09 09 73  path]} {.......s
4740: 65 74 20 72 65 74 76 61 6c 28 69 73 5f 72 65 6d  et retval(is_rem
4750: 6f 74 65 66 69 6c 65 29 20 31 0a 0a 09 09 09 09  otefile) 1......
4760: 09 09 73 65 74 20 77 6f 72 6b 20 5b 73 70 6c 69  ..set work [spli
4770: 74 20 24 70 61 74 68 69 6e 66 6f 28 66 69 6c 65  t $pathinfo(file
4780: 29 20 22 2f 22 5d 0a 09 09 09 09 09 09 73 65 74  ) "/"].......set
4790: 20 64 69 72 65 63 74 6f 72 79 20 5b 6a 6f 69 6e   directory [join
47a0: 20 5b 6c 72 61 6e 67 65 20 24 77 6f 72 6b 20 30   [lrange $work 0
47b0: 20 65 6e 64 2d 31 5d 20 22 2f 22 5d 0a 09 09 09   end-1] "/"]....
47c0: 09 09 09 73 65 74 20 66 69 6c 65 20 5b 6c 69 6e  ...set file [lin
47d0: 64 65 78 20 24 77 6f 72 6b 20 65 6e 64 5d 0a 0a  dex $work end]..
47e0: 09 09 09 09 09 09 69 66 20 7b 24 64 69 72 65 63  ......if {$direc
47f0: 74 6f 72 79 20 3d 3d 20 22 22 20 26 26 20 24 66  tory == "" && $f
4800: 69 6c 65 20 3d 3d 20 22 22 7d 20 7b 0a 09 09 09  ile == ""} {....
4810: 09 09 09 09 61 72 72 61 79 20 73 65 74 20 72 65  ....array set re
4820: 74 76 61 6c 20 5b 6c 69 73 74 20 74 79 70 65 20  tval [list type 
4830: 64 69 72 65 63 74 6f 72 79 5d 0a 09 09 09 09 09  directory]......
4840: 09 7d 0a 0a 09 09 09 09 09 09 3a 3a 61 70 70 66  .}........::appf
4850: 73 3a 3a 64 62 20 65 76 61 6c 20 7b 53 45 4c 45  s::db eval {SELE
4860: 43 54 20 74 79 70 65 2c 20 74 69 6d 65 2c 20 73  CT type, time, s
4870: 6f 75 72 63 65 2c 20 73 69 7a 65 2c 20 70 65 72  ource, size, per
4880: 6d 73 20 46 52 4f 4d 20 66 69 6c 65 73 20 57 48  ms FROM files WH
4890: 45 52 45 20 70 61 63 6b 61 67 65 5f 73 68 61 31  ERE package_sha1
48a0: 20 3d 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63   = $pathinfo(pac
48b0: 6b 61 67 65 5f 73 68 61 31 29 20 41 4e 44 20 66  kage_sha1) AND f
48c0: 69 6c 65 5f 64 69 72 65 63 74 6f 72 79 20 3d 20  ile_directory = 
48d0: 24 64 69 72 65 63 74 6f 72 79 20 41 4e 44 20 66  $directory AND f
48e0: 69 6c 65 5f 6e 61 6d 65 20 3d 20 24 66 69 6c 65  ile_name = $file
48f0: 3b 7d 20 72 65 74 76 61 6c 20 7b 7d 0a 0a 09 09  ;} retval {}....
4900: 09 09 09 09 69 66 20 7b 5b 69 6e 66 6f 20 65 78  ....if {[info ex
4910: 69 73 74 73 20 72 65 74 76 61 6c 28 74 79 70 65  ists retval(type
4920: 29 5d 20 26 26 20 24 72 65 74 76 61 6c 28 74 79  )] && $retval(ty
4930: 70 65 29 20 3d 3d 20 22 64 69 72 65 63 74 6f 72  pe) == "director
4940: 79 22 7d 20 7b 0a 09 09 09 09 09 09 09 73 65 74  y"} {........set
4950: 20 72 65 74 76 61 6c 28 63 68 69 6c 64 63 6f 75   retval(childcou
4960: 6e 74 29 20 5b 6c 6c 65 6e 67 74 68 20 5b 67 65  nt) [llength [ge
4970: 74 63 68 69 6c 64 72 65 6e 20 24 70 61 74 68 5d  tchildren $path]
4980: 5d 0a 09 09 09 09 09 09 7d 0a 0a 09 09 09 09 09  ].......}.......
4990: 09 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61  .unset -nocompla
49a0: 69 6e 20 72 65 74 76 61 6c 28 2a 29 0a 09 09 09  in retval(*)....
49b0: 09 09 7d 0a 09 09 09 09 7d 0a 0a 09 09 09 7d 0a  ..}.....}.....}.
49c0: 09 09 7d 0a 0a 09 09 69 66 20 7b 21 5b 69 6e 66  ..}....if {![inf
49d0: 6f 20 65 78 69 73 74 73 20 72 65 74 76 61 6c 28  o exists retval(
49e0: 74 79 70 65 29 5d 7d 20 7b 0a 09 09 09 72 65 74  type)]} {....ret
49f0: 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20  urn -code error 
4a00: 22 4e 6f 20 73 75 63 68 20 66 69 6c 65 20 6f 72  "No such file or
4a10: 20 64 69 72 65 63 74 6f 72 79 22 0a 09 09 7d 0a   directory"...}.
4a20: 0a 09 09 72 65 74 75 72 6e 20 5b 61 72 72 61 79  ...return [array
4a30: 20 67 65 74 20 72 65 74 76 61 6c 5d 0a 09 7d 0a   get retval]..}.
4a40: 0a 09 70 72 6f 63 20 6f 70 65 6e 70 61 74 68 20  ..proc openpath 
4a50: 7b 70 61 74 68 20 6d 6f 64 65 7d 20 7b 0a 09 09  {path mode} {...
4a60: 61 72 72 61 79 20 73 65 74 20 70 61 74 68 69 6e  array set pathin
4a70: 66 6f 20 5b 5f 70 61 72 73 65 70 61 74 68 20 24  fo [_parsepath $
4a80: 70 61 74 68 5d 0a 0a 09 09 69 66 20 7b 24 70 61  path]....if {$pa
4a90: 74 68 69 6e 66 6f 28 5f 74 79 70 65 29 20 21 3d  thinfo(_type) !=
4aa0: 20 22 66 69 6c 65 73 22 7d 20 7b 0a 09 09 09 72   "files"} {....r
4ab0: 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f  eturn -code erro
4ac0: 72 20 22 69 6e 76 61 6c 69 64 20 74 79 70 65 22  r "invalid type"
4ad0: 0a 09 09 7d 0a 0a 09 09 73 65 74 20 6c 6f 63 61  ...}....set loca
4ae0: 6c 70 61 74 68 20 5b 5f 6c 6f 63 61 6c 70 61 74  lpath [_localpat
4af0: 68 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63 6b  h $pathinfo(pack
4b00: 61 67 65 29 20 24 70 61 74 68 69 6e 66 6f 28 68  age) $pathinfo(h
4b10: 6f 73 74 6e 61 6d 65 29 20 24 70 61 74 68 69 6e  ostname) $pathin
4b20: 66 6f 28 66 69 6c 65 29 5d 0a 0a 09 09 69 66 20  fo(file)]....if 
4b30: 7b 24 6d 6f 64 65 20 3d 3d 20 22 63 72 65 61 74  {$mode == "creat
4b40: 65 22 7d 20 7b 0a 09 09 09 69 66 20 7b 24 6c 6f  e"} {....if {$lo
4b50: 63 61 6c 70 61 74 68 20 3d 3d 20 22 22 7d 20 7b  calpath == ""} {
4b60: 0a 09 09 09 09 72 65 74 75 72 6e 20 2d 63 6f 64  .....return -cod
4b70: 65 20 65 72 72 6f 72 20 22 41 73 6b 65 64 20 74  e error "Asked t
4b80: 6f 20 63 72 65 61 74 65 2c 20 62 75 74 20 6e 6f  o create, but no
4b90: 20 68 6f 6d 65 20 64 69 72 65 63 74 6f 72 79 2e   home directory.
4ba0: 22 0a 09 09 09 7d 0a 0a 09 09 09 72 65 74 75 72  "....}.....retur
4bb0: 6e 20 24 6c 6f 63 61 6c 70 61 74 68 0a 09 09 7d  n $localpath...}
4bc0: 0a 0a 09 09 69 66 20 7b 24 6c 6f 63 61 6c 70 61  ....if {$localpa
4bd0: 74 68 20 21 3d 20 22 22 20 26 26 20 5b 66 69 6c  th != "" && [fil
4be0: 65 20 65 78 69 73 74 73 20 24 6c 6f 63 61 6c 70  e exists $localp
4bf0: 61 74 68 5d 7d 20 7b 0a 09 09 09 72 65 74 75 72  ath]} {....retur
4c00: 6e 20 24 6c 6f 63 61 6c 70 61 74 68 0a 09 09 7d  n $localpath...}
4c10: 0a 0a 09 09 73 65 74 20 77 6f 72 6b 20 5b 73 70  ....set work [sp
4c20: 6c 69 74 20 24 70 61 74 68 69 6e 66 6f 28 66 69  lit $pathinfo(fi
4c30: 6c 65 29 20 22 2f 22 5d 0a 09 09 73 65 74 20 64  le) "/"]...set d
4c40: 69 72 65 63 74 6f 72 79 20 5b 6a 6f 69 6e 20 5b  irectory [join [
4c50: 6c 72 61 6e 67 65 20 24 77 6f 72 6b 20 30 20 65  lrange $work 0 e
4c60: 6e 64 2d 31 5d 20 22 2f 22 5d 0a 09 09 73 65 74  nd-1] "/"]...set
4c70: 20 66 69 6c 65 20 5b 6c 69 6e 64 65 78 20 24 77   file [lindex $w
4c80: 6f 72 6b 20 65 6e 64 5d 0a 09 09 3a 3a 61 70 70  ork end]...::app
4c90: 66 73 3a 3a 64 62 20 65 76 61 6c 20 7b 53 45 4c  fs::db eval {SEL
4ca0: 45 43 54 20 66 69 6c 65 5f 73 68 61 31 2c 20 70  ECT file_sha1, p
4cb0: 65 72 6d 73 20 46 52 4f 4d 20 66 69 6c 65 73 20  erms FROM files 
4cc0: 57 48 45 52 45 20 70 61 63 6b 61 67 65 5f 73 68  WHERE package_sh
4cd0: 61 31 20 3d 20 24 70 61 74 68 69 6e 66 6f 28 70  a1 = $pathinfo(p
4ce0: 61 63 6b 61 67 65 5f 73 68 61 31 29 20 41 4e 44  ackage_sha1) AND
4cf0: 20 66 69 6c 65 5f 6e 61 6d 65 20 3d 20 24 66 69   file_name = $fi
4d00: 6c 65 20 41 4e 44 20 66 69 6c 65 5f 64 69 72 65  le AND file_dire
4d10: 63 74 6f 72 79 20 3d 20 24 64 69 72 65 63 74 6f  ctory = $directo
4d20: 72 79 3b 7d 20 70 6b 67 70 61 74 68 69 6e 66 6f  ry;} pkgpathinfo
4d30: 20 7b 7d 0a 0a 09 09 69 66 20 7b 24 70 6b 67 70   {}....if {$pkgp
4d40: 61 74 68 69 6e 66 6f 28 66 69 6c 65 5f 73 68 61  athinfo(file_sha
4d50: 31 29 20 3d 3d 20 22 22 7d 20 7b 0a 09 09 09 72  1) == ""} {....r
4d60: 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f  eturn -code erro
4d70: 72 20 22 4e 6f 20 73 75 63 68 20 66 69 6c 65 20  r "No such file 
4d80: 6f 72 20 64 69 72 65 63 74 6f 72 79 22 0a 09 09  or directory"...
4d90: 7d 0a 0a 09 09 73 65 74 20 6c 6f 63 61 6c 63 61  }....set localca
4da0: 63 68 65 66 69 6c 65 20 5b 64 6f 77 6e 6c 6f 61  chefile [downloa
4db0: 64 20 24 70 61 74 68 69 6e 66 6f 28 68 6f 73 74  d $pathinfo(host
4dc0: 6e 61 6d 65 29 20 24 70 6b 67 70 61 74 68 69 6e  name) $pkgpathin
4dd0: 66 6f 28 66 69 6c 65 5f 73 68 61 31 29 5d 0a 0a  fo(file_sha1)]..
4de0: 09 09 69 66 20 7b 24 6d 6f 64 65 20 3d 3d 20 22  ..if {$mode == "
4df0: 77 72 69 74 65 22 7d 20 7b 0a 09 09 09 5f 61 73  write"} {...._as
4e00: 5f 75 73 65 72 20 7b 0a 09 09 09 09 73 65 74 20  _user {.....set 
4e10: 74 6d 70 6c 6f 63 61 6c 70 61 74 68 20 22 24 7b  tmplocalpath "${
4e20: 6c 6f 63 61 6c 70 61 74 68 7d 2e 5b 65 78 70 72  localpath}.[expr
4e30: 20 72 61 6e 64 28 29 5d 5b 63 6c 6f 63 6b 20 63   rand()][clock c
4e40: 6c 69 63 6b 73 5d 22 0a 0a 09 09 09 09 73 65 74  licks]"......set
4e50: 20 66 61 69 6c 65 64 20 30 0a 09 09 09 09 69 66   failed 0.....if
4e60: 20 7b 5b 63 61 74 63 68 20 7b 0a 09 09 09 09 09   {[catch {......
4e70: 66 69 6c 65 20 6d 6b 64 69 72 20 5b 66 69 6c 65  file mkdir [file
4e80: 20 64 69 72 6e 61 6d 65 20 24 6c 6f 63 61 6c 70   dirname $localp
4e90: 61 74 68 5d 0a 09 09 09 09 09 66 69 6c 65 20 63  ath]......file c
4ea0: 6f 70 79 20 2d 66 6f 72 63 65 20 2d 2d 20 24 6c  opy -force -- $l
4eb0: 6f 63 61 6c 63 61 63 68 65 66 69 6c 65 20 24 74  ocalcachefile $t
4ec0: 6d 70 6c 6f 63 61 6c 70 61 74 68 0a 0a 09 09 09  mplocalpath.....
4ed0: 09 09 69 66 20 7b 24 70 6b 67 70 61 74 68 69 6e  ..if {$pkgpathin
4ee0: 66 6f 28 70 65 72 6d 73 29 20 3d 3d 20 22 78 22  fo(perms) == "x"
4ef0: 7d 20 7b 0a 09 09 09 09 09 09 66 69 6c 65 20 61  } {.......file a
4f00: 74 74 72 69 62 75 74 65 73 20 24 74 6d 70 6c 6f  ttributes $tmplo
4f10: 63 61 6c 70 61 74 68 20 2d 70 65 72 6d 69 73 73  calpath -permiss
4f20: 69 6f 6e 73 20 2b 78 0a 09 09 09 09 09 7d 0a 0a  ions +x......}..
4f30: 09 09 09 09 09 66 69 6c 65 20 72 65 6e 61 6d 65  .....file rename
4f40: 20 2d 66 6f 72 63 65 20 2d 2d 20 24 74 6d 70 6c   -force -- $tmpl
4f50: 6f 63 61 6c 70 61 74 68 20 24 6c 6f 63 61 6c 70  ocalpath $localp
4f60: 61 74 68 0a 09 09 09 09 7d 20 65 72 72 5d 7d 20  ath.....} err]} 
4f70: 7b 0a 09 09 09 09 09 73 65 74 20 66 61 69 6c 65  {......set faile
4f80: 64 20 31 0a 09 09 09 09 7d 0a 09 09 09 09 63 61  d 1.....}.....ca
4f90: 74 63 68 20 7b 0a 09 09 09 09 09 66 69 6c 65 20  tch {......file 
4fa0: 64 65 6c 65 74 65 20 2d 66 6f 72 63 65 20 2d 2d  delete -force --
4fb0: 20 24 74 6d 70 6c 6f 63 61 6c 70 61 74 68 0a 09   $tmplocalpath..
4fc0: 09 09 09 7d 0a 09 09 09 7d 0a 0a 09 09 09 69 66  ...}....}.....if
4fd0: 20 7b 24 66 61 69 6c 65 64 7d 20 7b 0a 09 09 09   {$failed} {....
4fe0: 09 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72  .return -code er
4ff0: 72 6f 72 20 24 65 72 72 0a 09 09 09 7d 0a 0a 09  ror $err....}...
5000: 09 09 72 65 74 75 72 6e 20 24 6c 6f 63 61 6c 70  ..return $localp
5010: 61 74 68 0a 09 09 7d 0a 0a 09 09 72 65 74 75 72  ath...}....retur
5020: 6e 20 24 6c 6f 63 61 6c 63 61 63 68 65 66 69 6c  n $localcachefil
5030: 65 0a 09 7d 0a 0a 09 70 72 6f 63 20 6c 6f 63 61  e..}...proc loca
5040: 6c 70 61 74 68 20 7b 70 61 74 68 7d 20 7b 0a 09  lpath {path} {..
5050: 09 61 72 72 61 79 20 73 65 74 20 70 61 74 68 69  .array set pathi
5060: 6e 66 6f 20 5b 5f 70 61 72 73 65 70 61 74 68 20  nfo [_parsepath 
5070: 24 70 61 74 68 5d 0a 0a 09 09 69 66 20 7b 24 70  $path]....if {$p
5080: 61 74 68 69 6e 66 6f 28 5f 74 79 70 65 29 20 21  athinfo(_type) !
5090: 3d 20 22 66 69 6c 65 73 22 7d 20 7b 0a 09 09 09  = "files"} {....
50a0: 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72 72  return -code err
50b0: 6f 72 20 22 69 6e 76 61 6c 69 64 20 74 79 70 65  or "invalid type
50c0: 22 0a 09 09 7d 0a 0a 09 09 73 65 74 20 6c 6f 63  "...}....set loc
50d0: 61 6c 70 61 74 68 20 5b 5f 6c 6f 63 61 6c 70 61  alpath [_localpa
50e0: 74 68 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63  th $pathinfo(pac
50f0: 6b 61 67 65 29 20 24 70 61 74 68 69 6e 66 6f 28  kage) $pathinfo(
5100: 68 6f 73 74 6e 61 6d 65 29 20 24 70 61 74 68 69  hostname) $pathi
5110: 6e 66 6f 28 66 69 6c 65 29 5d 0a 0a 09 09 72 65  nfo(file)]....re
5120: 74 75 72 6e 20 24 6c 6f 63 61 6c 70 61 74 68 0a  turn $localpath.
5130: 09 7d 0a 0a 09 70 72 6f 63 20 65 78 69 73 74 73  .}...proc exists
5140: 20 7b 70 61 74 68 7d 20 7b 0a 09 09 63 61 74 63   {path} {...catc
5150: 68 20 7b 0a 09 09 09 73 65 74 20 69 6e 66 6f 20  h {....set info 
5160: 5b 67 65 74 61 74 74 72 20 24 70 61 74 68 5d 0a  [getattr $path].
5170: 09 09 7d 20 65 72 72 0a 0a 09 09 69 66 20 7b 21  ..} err....if {!
5180: 5b 69 6e 66 6f 20 65 78 69 73 74 73 20 69 6e 66  [info exists inf
5190: 6f 5d 7d 20 7b 0a 09 09 09 69 66 20 7b 24 65 72  o]} {....if {$er
51a0: 72 20 3d 3d 20 22 4e 6f 20 73 75 63 68 20 66 69  r == "No such fi
51b0: 6c 65 20 6f 72 20 64 69 72 65 63 74 6f 72 79 22  le or directory"
51c0: 7d 20 7b 0a 09 09 09 09 72 65 74 75 72 6e 20 5b  } {.....return [
51d0: 6c 69 73 74 5d 0a 09 09 09 7d 20 65 6c 73 65 20  list]....} else 
51e0: 7b 0a 09 09 09 09 72 65 74 75 72 6e 20 2d 63 6f  {.....return -co
51f0: 64 65 20 65 72 72 6f 72 20 24 65 72 72 0a 09 09  de error $err...
5200: 09 7d 0a 09 09 7d 0a 0a 09 09 72 65 74 75 72 6e  .}...}....return
5210: 20 24 69 6e 66 6f 0a 09 7d 0a 0a 09 70 72 6f 63   $info..}...proc
5220: 20 70 72 65 70 61 72 65 5f 74 6f 5f 63 72 65 61   prepare_to_crea
5230: 74 65 20 7b 70 61 74 68 20 7b 6d 75 73 74 5f 6e  te {path {must_n
5240: 6f 74 5f 65 78 69 73 74 20 31 7d 7d 20 7b 0a 09  ot_exist 1}} {..
5250: 09 69 66 20 7b 24 6d 75 73 74 5f 6e 6f 74 5f 65  .if {$must_not_e
5260: 78 69 73 74 7d 20 7b 0a 09 09 09 69 66 20 7b 5b  xist} {....if {[
5270: 65 78 69 73 74 73 20 24 70 61 74 68 5d 20 21 3d  exists $path] !=
5280: 20 22 22 7d 20 7b 0a 09 09 09 09 72 65 74 75 72   ""} {.....retur
5290: 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22 46  n -code error "F
52a0: 69 6c 65 20 61 6c 72 65 61 64 79 20 65 78 69 73  ile already exis
52b0: 74 73 22 0a 09 09 09 7d 0a 09 09 7d 0a 0a 09 09  ts"....}...}....
52c0: 73 65 74 20 66 69 6c 65 6e 61 6d 65 20 5b 6c 6f  set filename [lo
52d0: 63 61 6c 70 61 74 68 20 24 70 61 74 68 5d 0a 0a  calpath $path]..
52e0: 09 09 69 66 20 7b 24 66 69 6c 65 6e 61 6d 65 20  ..if {$filename 
52f0: 3d 3d 20 22 22 7d 20 7b 0a 09 09 09 72 65 74 75  == ""} {....retu
5300: 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22  rn -code error "
5310: 41 73 6b 65 64 20 74 6f 20 63 72 65 61 74 65 2c  Asked to create,
5320: 20 62 75 74 20 6e 6f 20 68 6f 6d 65 20 64 69 72   but no home dir
5330: 65 63 74 6f 72 79 2e 22 0a 09 09 7d 0a 0a 09 09  ectory."...}....
5340: 73 65 74 20 64 69 72 6e 61 6d 65 20 5b 66 69 6c  set dirname [fil
5350: 65 20 64 69 72 6e 61 6d 65 20 24 66 69 6c 65 6e  e dirname $filen
5360: 61 6d 65 5d 0a 0a 09 09 5f 61 73 5f 75 73 65 72  ame]...._as_user
5370: 20 7b 0a 09 09 09 66 69 6c 65 20 6d 6b 64 69 72   {....file mkdir
5380: 20 24 64 69 72 6e 61 6d 65 0a 09 09 7d 0a 0a 09   $dirname...}...
5390: 09 72 65 74 75 72 6e 20 24 66 69 6c 65 6e 61 6d  .return $filenam
53a0: 65 0a 09 7d 0a 0a 09 70 72 6f 63 20 75 6e 6c 69  e..}...proc unli
53b0: 6e 6b 70 61 74 68 20 7b 70 61 74 68 7d 20 7b 0a  nkpath {path} {.
53c0: 09 09 61 72 72 61 79 20 73 65 74 20 70 61 74 68  ..array set path
53d0: 61 74 74 72 73 20 5b 65 78 69 73 74 73 20 24 70  attrs [exists $p
53e0: 61 74 68 5d 0a 0a 09 09 69 66 20 7b 21 5b 69 6e  ath]....if {![in
53f0: 66 6f 20 65 78 69 73 74 73 20 70 61 74 68 61 74  fo exists pathat
5400: 74 72 73 28 70 61 63 6b 61 67 65 64 29 5d 7d 20  trs(packaged)]} 
5410: 7b 0a 09 09 09 72 65 74 75 72 6e 20 2d 63 6f 64  {....return -cod
5420: 65 20 65 72 72 6f 72 20 22 69 6e 76 61 6c 69 64  e error "invalid
5430: 20 74 79 70 65 22 0a 09 09 7d 0a 0a 09 09 73 65   type"...}....se
5440: 74 20 6c 6f 63 61 6c 70 61 74 68 20 24 70 61 74  t localpath $pat
5450: 68 61 74 74 72 73 28 6c 6f 63 61 6c 70 61 74 68  hattrs(localpath
5460: 29 0a 0a 09 09 69 66 20 7b 24 6c 6f 63 61 6c 70  )....if {$localp
5470: 61 74 68 20 3d 3d 20 22 22 7d 20 7b 0a 09 09 09  ath == ""} {....
5480: 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72 72  return -code err
5490: 6f 72 20 22 41 73 6b 65 64 20 74 6f 20 64 65 6c  or "Asked to del
54a0: 65 74 65 2c 20 62 75 74 20 6e 6f 20 68 6f 6d 65  ete, but no home
54b0: 20 64 69 72 65 63 74 6f 72 79 2e 22 0a 09 09 7d   directory."...}
54c0: 0a 0a 09 09 69 66 20 7b 5b 69 6e 66 6f 20 65 78  ....if {[info ex
54d0: 69 73 74 73 20 70 61 74 68 61 74 74 72 73 28 69  ists pathattrs(i
54e0: 73 5f 6c 6f 63 61 6c 66 69 6c 65 29 5d 7d 20 7b  s_localfile)]} {
54f0: 0a 09 09 09 69 66 20 7b 5b 66 69 6c 65 20 69 73  ....if {[file is
5500: 64 69 72 65 63 74 6f 72 79 20 24 6c 6f 63 61 6c  directory $local
5510: 70 61 74 68 5d 7d 20 7b 0a 09 09 09 09 73 65 74  path]} {.....set
5520: 20 63 68 69 6c 64 72 65 6e 20 5b 67 65 74 63 68   children [getch
5530: 69 6c 64 72 65 6e 20 24 70 61 74 68 5d 0a 0a 09  ildren $path]...
5540: 09 09 09 69 66 20 7b 5b 6c 6c 65 6e 67 74 68 20  ...if {[llength 
5550: 24 63 68 69 6c 64 72 65 6e 5d 20 21 3d 20 30 7d  $children] != 0}
5560: 20 7b 0a 09 09 09 09 09 72 65 74 75 72 6e 20 2d   {......return -
5570: 63 6f 64 65 20 65 72 72 6f 72 20 22 41 73 6b 65  code error "Aske
5580: 64 20 74 6f 20 64 65 6c 65 74 65 20 6e 6f 6e 2d  d to delete non-
5590: 65 6d 70 74 79 20 64 69 72 65 63 74 6f 72 79 22  empty directory"
55a0: 0a 09 09 09 09 7d 0a 09 09 09 7d 0a 0a 09 09 09  .....}....}.....
55b0: 5f 61 73 5f 75 73 65 72 20 7b 0a 09 09 09 09 66  _as_user {.....f
55c0: 69 6c 65 20 64 65 6c 65 74 65 20 2d 66 6f 72 63  ile delete -forc
55d0: 65 20 2d 2d 20 24 6c 6f 63 61 6c 70 61 74 68 0a  e -- $localpath.
55e0: 09 09 09 7d 0a 09 09 7d 20 65 6c 73 65 69 66 20  ...}...} elseif 
55f0: 7b 5b 69 6e 66 6f 20 65 78 69 73 74 73 20 70 61  {[info exists pa
5600: 74 68 61 74 74 72 73 28 69 73 5f 72 65 6d 6f 74  thattrs(is_remot
5610: 65 66 69 6c 65 29 5d 7d 20 7b 0a 09 09 09 69 66  efile)]} {....if
5620: 20 7b 24 70 61 74 68 61 74 74 72 73 28 74 79 70   {$pathattrs(typ
5630: 65 29 20 3d 3d 20 22 64 69 72 65 63 74 6f 72 79  e) == "directory
5640: 22 7d 20 7b 0a 09 09 09 09 73 65 74 20 63 68 69  "} {.....set chi
5650: 6c 64 72 65 6e 20 5b 67 65 74 63 68 69 6c 64 72  ldren [getchildr
5660: 65 6e 20 24 70 61 74 68 5d 0a 0a 09 09 09 09 69  en $path]......i
5670: 66 20 7b 5b 6c 6c 65 6e 67 74 68 20 24 63 68 69  f {[llength $chi
5680: 6c 64 72 65 6e 5d 20 21 3d 20 30 7d 20 7b 0a 09  ldren] != 0} {..
5690: 09 09 09 09 72 65 74 75 72 6e 20 2d 63 6f 64 65  ....return -code
56a0: 20 65 72 72 6f 72 20 22 41 73 6b 65 64 20 74 6f   error "Asked to
56b0: 20 64 65 6c 65 74 65 20 6e 6f 6e 2d 65 6d 70 74   delete non-empt
56c0: 79 20 64 69 72 65 63 74 6f 72 79 22 0a 09 09 09  y directory"....
56d0: 09 7d 0a 09 09 09 7d 0a 09 09 7d 20 65 6c 73 65  .}....}...} else
56e0: 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 2d 63 6f   {....return -co
56f0: 64 65 20 65 72 72 6f 72 20 22 55 6e 6b 6e 6f 77  de error "Unknow
5700: 6e 20 69 66 20 66 69 6c 65 20 69 73 20 72 65 6d  n if file is rem
5710: 6f 74 65 20 6f 72 20 6c 6f 63 61 6c 20 21 3f 22  ote or local !?"
5720: 0a 09 09 7d 0a 0a 09 09 73 65 74 20 77 68 69 74  ...}....set whit
5730: 65 6f 75 74 66 69 6c 65 20 24 70 61 74 68 61 74  eoutfile $pathat
5740: 74 72 73 28 77 68 69 74 65 6f 75 74 70 61 74 68  trs(whiteoutpath
5750: 29 0a 09 09 73 65 74 20 77 68 69 74 65 6f 75 74  )...set whiteout
5760: 64 69 72 20 5b 66 69 6c 65 20 64 69 72 6e 61 6d  dir [file dirnam
5770: 65 20 24 77 68 69 74 65 6f 75 74 66 69 6c 65 5d  e $whiteoutfile]
5780: 0a 0a 09 09 5f 61 73 5f 75 73 65 72 20 7b 0a 09  ...._as_user {..
5790: 09 09 66 69 6c 65 20 6d 6b 64 69 72 20 24 77 68  ..file mkdir $wh
57a0: 69 74 65 6f 75 74 64 69 72 0a 09 09 09 63 6c 6f  iteoutdir....clo
57b0: 73 65 20 5b 6f 70 65 6e 20 24 77 68 69 74 65 6f  se [open $whiteo
57c0: 75 74 66 69 6c 65 20 77 5d 0a 09 09 7d 0a 09 7d  utfile w]...}..}
57d0: 0a 7d 0a                                         .}.