Hex Artifact Content

Artifact fbd0fd32b5d423cc6e26ec86ae051d3f44d8e6a6:


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 23 0a 23 20 43 6f 70 79 72  tclsh..#.# Copyr
0020: 69 67 68 74 20 28 63 29 20 32 30 31 34 20 20 52  ight (c) 2014  R
0030: 6f 79 20 4b 65 65 6e 65 0a 23 0a 23 20 50 65 72  oy Keene.#.# Per
0040: 6d 69 73 73 69 6f 6e 20 69 73 20 68 65 72 65 62  mission is hereb
0050: 79 20 67 72 61 6e 74 65 64 2c 20 66 72 65 65 20  y granted, free 
0060: 6f 66 20 63 68 61 72 67 65 2c 20 74 6f 20 61 6e  of charge, to an
0070: 79 20 70 65 72 73 6f 6e 20 6f 62 74 61 69 6e 69  y person obtaini
0080: 6e 67 20 61 20 63 6f 70 79 0a 23 20 6f 66 20 74  ng a copy.# of t
0090: 68 69 73 20 73 6f 66 74 77 61 72 65 20 61 6e 64  his software and
00a0: 20 61 73 73 6f 63 69 61 74 65 64 20 64 6f 63 75   associated docu
00b0: 6d 65 6e 74 61 74 69 6f 6e 20 66 69 6c 65 73 20  mentation files 
00c0: 28 74 68 65 20 22 53 6f 66 74 77 61 72 65 22 29  (the "Software")
00d0: 2c 20 74 6f 20 64 65 61 6c 0a 23 20 69 6e 20 74  , to deal.# in t
00e0: 68 65 20 53 6f 66 74 77 61 72 65 20 77 69 74 68  he Software with
00f0: 6f 75 74 20 72 65 73 74 72 69 63 74 69 6f 6e 2c  out restriction,
0100: 20 69 6e 63 6c 75 64 69 6e 67 20 77 69 74 68 6f   including witho
0110: 75 74 20 6c 69 6d 69 74 61 74 69 6f 6e 20 74 68  ut limitation th
0120: 65 20 72 69 67 68 74 73 0a 23 20 74 6f 20 75 73  e rights.# to us
0130: 65 2c 20 63 6f 70 79 2c 20 6d 6f 64 69 66 79 2c  e, copy, modify,
0140: 20 6d 65 72 67 65 2c 20 70 75 62 6c 69 73 68 2c   merge, publish,
0150: 20 64 69 73 74 72 69 62 75 74 65 2c 20 73 75 62   distribute, sub
0160: 6c 69 63 65 6e 73 65 2c 20 61 6e 64 2f 6f 72 20  license, and/or 
0170: 73 65 6c 6c 0a 23 20 63 6f 70 69 65 73 20 6f 66  sell.# copies of
0180: 20 74 68 65 20 53 6f 66 74 77 61 72 65 2c 20 61   the Software, a
0190: 6e 64 20 74 6f 20 70 65 72 6d 69 74 20 70 65 72  nd to permit per
01a0: 73 6f 6e 73 20 74 6f 20 77 68 6f 6d 20 74 68 65  sons to whom the
01b0: 20 53 6f 66 74 77 61 72 65 20 69 73 0a 23 20 66   Software is.# f
01c0: 75 72 6e 69 73 68 65 64 20 74 6f 20 64 6f 20 73  urnished to do s
01d0: 6f 2c 20 73 75 62 6a 65 63 74 20 74 6f 20 74 68  o, subject to th
01e0: 65 20 66 6f 6c 6c 6f 77 69 6e 67 20 63 6f 6e 64  e following cond
01f0: 69 74 69 6f 6e 73 3a 0a 23 0a 23 20 54 68 65 20  itions:.#.# The 
0200: 61 62 6f 76 65 20 63 6f 70 79 72 69 67 68 74 20  above copyright 
0210: 6e 6f 74 69 63 65 20 61 6e 64 20 74 68 69 73 20  notice and this 
0220: 70 65 72 6d 69 73 73 69 6f 6e 20 6e 6f 74 69 63  permission notic
0230: 65 20 73 68 61 6c 6c 20 62 65 20 69 6e 63 6c 75  e shall be inclu
0240: 64 65 64 20 69 6e 0a 23 20 61 6c 6c 20 63 6f 70  ded in.# all cop
0250: 69 65 73 20 6f 72 20 73 75 62 73 74 61 6e 74 69  ies or substanti
0260: 61 6c 20 70 6f 72 74 69 6f 6e 73 20 6f 66 20 74  al portions of t
0270: 68 65 20 53 6f 66 74 77 61 72 65 2e 0a 23 0a 23  he Software..#.#
0280: 20 54 48 45 20 53 4f 46 54 57 41 52 45 20 49 53   THE SOFTWARE IS
0290: 20 50 52 4f 56 49 44 45 44 20 22 41 53 20 49 53   PROVIDED "AS IS
02a0: 22 2c 20 57 49 54 48 4f 55 54 20 57 41 52 52 41  ", WITHOUT WARRA
02b0: 4e 54 59 20 4f 46 20 41 4e 59 20 4b 49 4e 44 2c  NTY OF ANY KIND,
02c0: 20 45 58 50 52 45 53 53 20 4f 52 0a 23 20 49 4d   EXPRESS OR.# IM
02d0: 50 4c 49 45 44 2c 20 49 4e 43 4c 55 44 49 4e 47  PLIED, INCLUDING
02e0: 20 42 55 54 20 4e 4f 54 20 4c 49 4d 49 54 45 44   BUT NOT LIMITED
02f0: 20 54 4f 20 54 48 45 20 57 41 52 52 41 4e 54 49   TO THE WARRANTI
0300: 45 53 20 4f 46 20 4d 45 52 43 48 41 4e 54 41 42  ES OF MERCHANTAB
0310: 49 4c 49 54 59 2c 0a 23 20 46 49 54 4e 45 53 53  ILITY,.# FITNESS
0320: 20 46 4f 52 20 41 20 50 41 52 54 49 43 55 4c 41   FOR A PARTICULA
0330: 52 20 50 55 52 50 4f 53 45 20 41 4e 44 20 4e 4f  R PURPOSE AND NO
0340: 4e 49 4e 46 52 49 4e 47 45 4d 45 4e 54 2e 20 49  NINFRINGEMENT. I
0350: 4e 20 4e 4f 20 45 56 45 4e 54 20 53 48 41 4c 4c  N NO EVENT SHALL
0360: 20 54 48 45 0a 23 20 41 55 54 48 4f 52 53 20 4f   THE.# AUTHORS O
0370: 52 20 43 4f 50 59 52 49 47 48 54 20 48 4f 4c 44  R COPYRIGHT HOLD
0380: 45 52 53 20 42 45 20 4c 49 41 42 4c 45 20 46 4f  ERS BE LIABLE FO
0390: 52 20 41 4e 59 20 43 4c 41 49 4d 2c 20 44 41 4d  R ANY CLAIM, DAM
03a0: 41 47 45 53 20 4f 52 20 4f 54 48 45 52 0a 23 20  AGES OR OTHER.# 
03b0: 4c 49 41 42 49 4c 49 54 59 2c 20 57 48 45 54 48  LIABILITY, WHETH
03c0: 45 52 20 49 4e 20 41 4e 20 41 43 54 49 4f 4e 20  ER IN AN ACTION 
03d0: 4f 46 20 43 4f 4e 54 52 41 43 54 2c 20 54 4f 52  OF CONTRACT, TOR
03e0: 54 20 4f 52 20 4f 54 48 45 52 57 49 53 45 2c 20  T OR OTHERWISE, 
03f0: 41 52 49 53 49 4e 47 20 46 52 4f 4d 2c 0a 23 20  ARISING FROM,.# 
0400: 4f 55 54 20 4f 46 20 4f 52 20 49 4e 20 43 4f 4e  OUT OF OR IN CON
0410: 4e 45 43 54 49 4f 4e 20 57 49 54 48 20 54 48 45  NECTION WITH THE
0420: 20 53 4f 46 54 57 41 52 45 20 4f 52 20 54 48 45   SOFTWARE OR THE
0430: 20 55 53 45 20 4f 52 20 4f 54 48 45 52 20 44 45   USE OR OTHER DE
0440: 41 4c 49 4e 47 53 20 49 4e 0a 23 20 54 48 45 20  ALINGS IN.# THE 
0450: 53 4f 46 54 57 41 52 45 2e 0a 23 0a 0a 70 61 63  SOFTWARE..#..pac
0460: 6b 61 67 65 20 72 65 71 75 69 72 65 20 68 74 74  kage require htt
0470: 70 20 32 2e 37 0a 70 61 63 6b 61 67 65 20 72 65  p 2.7.package re
0480: 71 75 69 72 65 20 73 71 6c 69 74 65 33 0a 70 61  quire sqlite3.pa
0490: 63 6b 61 67 65 20 72 65 71 75 69 72 65 20 73 68  ckage require sh
04a0: 61 31 0a 70 61 63 6b 61 67 65 20 72 65 71 75 69  a1.package requi
04b0: 72 65 20 61 70 70 66 73 64 0a 70 61 63 6b 61 67  re appfsd.packag
04c0: 65 20 72 65 71 75 69 72 65 20 70 6c 61 74 66 6f  e require platfo
04d0: 72 6d 0a 70 61 63 6b 61 67 65 20 72 65 71 75 69  rm.package requi
04e0: 72 65 20 70 6b 69 0a 0a 23 20 46 75 6e 63 74 69  re pki..# Functi
04f0: 6f 6e 73 20 73 70 65 63 69 66 69 63 61 6c 6c 79  ons specifically
0500: 20 6d 65 61 6e 74 20 66 6f 72 20 75 73 65 72 73   meant for users
0510: 20 74 6f 20 72 65 70 6c 61 63 65 20 61 73 20 61   to replace as a
0520: 20 70 61 72 74 20 6f 66 20 63 6f 6e 66 69 67 75   part of configu
0530: 72 61 74 69 6f 6e 0a 6e 61 6d 65 73 70 61 63 65  ration.namespace
0540: 20 65 76 61 6c 20 3a 3a 61 70 70 66 73 3a 3a 75   eval ::appfs::u
0550: 73 65 72 20 7b 0a 09 76 61 72 69 61 62 6c 65 20  ser {..variable 
0560: 64 6f 77 6e 6c 6f 61 64 5f 6d 65 74 68 6f 64 20  download_method 
0570: 22 74 63 6c 22 0a 0a 09 23 20 55 73 65 72 2d 72  "tcl"...# User-r
0580: 65 70 6c 61 63 61 62 6c 65 20 66 75 6e 63 74 69  eplacable functi
0590: 6f 6e 20 74 6f 20 63 6f 6e 76 65 72 74 20 61 20  on to convert a 
05a0: 68 6f 73 74 6e 61 6d 65 2f 68 61 73 68 2f 6d 65  hostname/hash/me
05b0: 74 68 6f 64 20 74 6f 20 61 6e 20 55 52 4c 0a 09  thod to an URL..
05c0: 70 72 6f 63 20 63 6f 6e 73 74 72 75 63 74 5f 75  proc construct_u
05d0: 72 6c 20 7b 68 6f 73 74 6e 61 6d 65 20 68 61 73  rl {hostname has
05e0: 68 20 6d 65 74 68 6f 64 7d 20 7b 0a 09 09 72 65  h method} {...re
05f0: 74 75 72 6e 20 22 68 74 74 70 3a 2f 2f 24 68 6f  turn "http://$ho
0600: 73 74 6e 61 6d 65 2f 61 70 70 66 73 2f 24 6d 65  stname/appfs/$me
0610: 74 68 6f 64 2f 24 68 61 73 68 22 0a 09 7d 0a 0a  thod/$hash"..}..
0620: 09 23 20 55 73 65 72 2d 72 65 70 6c 61 63 65 61  .# User-replacea
0630: 62 6c 65 20 66 75 6e 63 74 69 6f 6e 20 67 65 74  ble function get
0640: 20 74 68 65 20 68 6f 6d 65 20 64 69 72 65 63 74   the home direct
0650: 6f 72 79 20 6f 66 20 74 68 65 20 63 75 72 72 65  ory of the curre
0660: 6e 74 20 75 73 65 72 0a 09 70 72 6f 63 20 67 65  nt user..proc ge
0670: 74 5f 68 6f 6d 65 64 69 72 20 7b 7d 20 7b 0a 09  t_homedir {} {..
0680: 09 72 65 74 75 72 6e 20 5b 3a 3a 61 70 70 66 73  .return [::appfs
0690: 64 3a 3a 67 65 74 5f 68 6f 6d 65 64 69 72 5d 0a  d::get_homedir].
06a0: 09 7d 0a 0a 09 23 20 55 73 65 72 2d 72 65 70 6c  .}...# User-repl
06b0: 61 63 61 62 6c 65 20 66 75 6e 63 74 69 6f 6e 20  acable function 
06c0: 74 6f 20 75 70 64 61 74 65 20 70 65 72 6d 69 73  to update permis
06d0: 73 69 6f 6e 73 0a 09 70 72 6f 63 20 63 68 61 6e  sions..proc chan
06e0: 67 65 5f 70 65 72 6d 73 20 7b 66 69 6c 65 20 68  ge_perms {file h
06f0: 61 73 68 20 70 65 72 6d 73 20 7b 68 61 73 68 4d  ash perms {hashM
0700: 65 74 68 6f 64 20 22 73 68 61 31 22 7d 7d 20 7b  ethod "sha1"}} {
0710: 0a 09 09 69 66 20 7b 5b 69 6e 66 6f 20 65 78 69  ...if {[info exi
0720: 73 74 73 20 3a 3a 61 70 70 66 73 3a 3a 75 73 65  sts ::appfs::use
0730: 72 3a 3a 61 64 64 5f 70 65 72 6d 73 28 24 66 69  r::add_perms($fi
0740: 6c 65 29 5d 7d 20 7b 0a 09 09 09 61 70 70 65 6e  le)]} {....appen
0750: 64 20 70 65 72 6d 73 20 24 3a 3a 61 70 70 66 73  d perms $::appfs
0760: 3a 3a 75 73 65 72 3a 3a 61 64 64 5f 70 65 72 6d  ::user::add_perm
0770: 73 28 24 66 69 6c 65 29 0a 09 09 7d 0a 0a 09 09  s($file)...}....
0780: 69 66 20 7b 5b 69 6e 66 6f 20 65 78 69 73 74 73  if {[info exists
0790: 20 3a 3a 61 70 70 66 73 3a 3a 75 73 65 72 3a 3a   ::appfs::user::
07a0: 61 64 64 5f 70 65 72 6d 73 28 5b 6c 69 73 74 20  add_perms([list 
07b0: 24 68 61 73 68 4d 65 74 68 6f 64 20 24 68 61 73  $hashMethod $has
07c0: 68 5d 29 5d 7d 20 7b 0a 09 09 09 61 70 70 65 6e  h])]} {....appen
07d0: 64 20 70 65 72 6d 73 20 24 3a 3a 61 70 70 66 73  d perms $::appfs
07e0: 3a 3a 75 73 65 72 3a 3a 61 64 64 5f 70 65 72 6d  ::user::add_perm
07f0: 73 28 5b 6c 69 73 74 20 24 68 61 73 68 4d 65 74  s([list $hashMet
0800: 68 6f 64 20 24 68 61 73 68 5d 29 0a 09 09 7d 20  hod $hash])...} 
0810: 65 6c 73 65 69 66 20 7b 24 68 61 73 68 4d 65 74  elseif {$hashMet
0820: 68 6f 64 20 65 71 20 22 73 68 61 31 22 20 26 26  hod eq "sha1" &&
0830: 20 5b 69 6e 66 6f 20 65 78 69 73 74 73 20 3a 3a   [info exists ::
0840: 61 70 70 66 73 3a 3a 75 73 65 72 3a 3a 61 64 64  appfs::user::add
0850: 5f 70 65 72 6d 73 28 24 68 61 73 68 29 5d 7d 20  _perms($hash)]} 
0860: 7b 0a 09 09 09 61 70 70 65 6e 64 20 70 65 72 6d  {....append perm
0870: 73 20 24 3a 3a 61 70 70 66 73 3a 3a 75 73 65 72  s $::appfs::user
0880: 3a 3a 61 64 64 5f 70 65 72 6d 73 28 24 68 61 73  ::add_perms($has
0890: 68 29 0a 09 09 7d 0a 0a 09 09 72 65 74 75 72 6e  h)...}....return
08a0: 20 24 70 65 72 6d 73 0a 09 7d 0a 0a 09 23 20 55   $perms..}...# U
08b0: 73 65 72 2d 72 65 70 6c 61 63 61 62 6c 65 20 66  ser-replacable f
08c0: 75 6e 63 74 69 6f 6e 20 74 6f 20 66 65 74 63 68  unction to fetch
08d0: 20 61 20 72 65 6d 6f 74 65 20 66 69 6c 65 0a 09   a remote file..
08e0: 70 72 6f 63 20 64 6f 77 6e 6c 6f 61 64 5f 66 69  proc download_fi
08f0: 6c 65 20 7b 75 72 6c 20 7b 6f 75 74 70 75 74 43  le {url {outputC
0900: 68 61 6e 6e 65 6c 20 22 22 7d 7d 20 7b 0a 09 09  hannel ""}} {...
0910: 73 77 69 74 63 68 20 2d 2d 20 24 3a 3a 61 70 70  switch -- $::app
0920: 66 73 3a 3a 75 73 65 72 3a 3a 64 6f 77 6e 6c 6f  fs::user::downlo
0930: 61 64 5f 6d 65 74 68 6f 64 20 7b 0a 09 09 09 22  ad_method {...."
0940: 63 75 72 6c 22 20 7b 0a 09 09 09 09 69 66 20 7b  curl" {.....if {
0950: 24 6f 75 74 70 75 74 43 68 61 6e 6e 65 6c 20 65  $outputChannel e
0960: 71 20 22 22 7d 20 7b 0a 09 09 09 09 09 72 65 74  q ""} {......ret
0970: 75 72 6e 20 5b 65 78 65 63 20 63 75 72 6c 20 2d  urn [exec curl -
0980: 73 53 20 2d 4c 20 2d 2d 20 24 75 72 6c 5d 0a 09  sS -L -- $url]..
0990: 09 09 09 7d 20 65 6c 73 65 20 7b 0a 09 09 09 09  ...} else {.....
09a0: 09 65 78 65 63 20 63 75 72 6c 20 2d 73 53 20 2d  .exec curl -sS -
09b0: 4c 20 2d 2d 20 24 75 72 6c 20 3e 40 20 24 6f 75  L -- $url >@ $ou
09c0: 74 70 75 74 43 68 61 6e 6e 65 6c 0a 0a 09 09 09  tputChannel.....
09d0: 09 09 72 65 74 75 72 6e 20 22 22 0a 09 09 09 09  ..return "".....
09e0: 7d 0a 09 09 09 7d 0a 09 09 09 22 74 63 6c 22 20  }....}...."tcl" 
09f0: 7b 0a 09 09 09 09 63 61 74 63 68 20 7b 0a 09 09  {.....catch {...
0a00: 09 09 09 69 66 20 7b 24 6f 75 74 70 75 74 43 68  ...if {$outputCh
0a10: 61 6e 6e 65 6c 20 65 71 20 22 22 7d 20 7b 0a 09  annel eq ""} {..
0a20: 09 09 09 09 09 73 65 74 20 74 6f 6b 65 6e 20 5b  .....set token [
0a30: 68 74 74 70 3a 3a 67 65 74 75 72 6c 20 24 75 72  http::geturl $ur
0a40: 6c 5d 0a 09 09 09 09 09 09 73 65 74 20 72 65 74  l].......set ret
0a50: 76 61 6c 20 5b 68 74 74 70 3a 3a 64 61 74 61 20  val [http::data 
0a60: 24 74 6f 6b 65 6e 5d 0a 09 09 09 09 09 7d 20 65  $token]......} e
0a70: 6c 73 65 20 7b 0a 09 09 09 09 09 09 73 65 74 20  lse {.......set 
0a80: 74 6f 6b 65 6e 20 5b 68 74 74 70 3a 3a 67 65 74  token [http::get
0a90: 75 72 6c 20 24 75 72 6c 20 2d 62 69 6e 61 72 79  url $url -binary
0aa0: 20 74 72 75 65 20 2d 63 68 61 6e 6e 65 6c 20 24   true -channel $
0ab0: 6f 75 74 70 75 74 43 68 61 6e 6e 65 6c 5d 0a 09  outputChannel]..
0ac0: 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 20  .....set retval 
0ad0: 22 22 0a 09 09 09 09 09 7d 0a 09 09 09 09 7d 20  ""......}.....} 
0ae0: 65 72 72 0a 0a 09 09 09 09 69 66 20 7b 21 5b 69  err......if {![i
0af0: 6e 66 6f 20 65 78 69 73 74 73 20 74 6f 6b 65 6e  nfo exists token
0b00: 5d 7d 20 7b 0a 09 09 09 09 09 72 65 74 75 72 6e  ]} {......return
0b10: 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22 55 6e   -code error "Un
0b20: 61 62 6c 65 20 74 6f 20 64 6f 77 6e 6c 6f 61 64  able to download
0b30: 20 5c 22 24 75 72 6c 5c 22 3a 20 24 65 72 72 22   \"$url\": $err"
0b40: 0a 09 09 09 09 7d 0a 0a 09 09 09 09 73 65 74 20  .....}......set 
0b50: 74 6f 6b 65 6e 43 6f 64 65 20 5b 68 74 74 70 3a  tokenCode [http:
0b60: 3a 6e 63 6f 64 65 20 24 74 6f 6b 65 6e 5d 0a 0a  :ncode $token]..
0b70: 09 09 09 09 68 74 74 70 3a 3a 63 6c 65 61 6e 75  ....http::cleanu
0b80: 70 20 24 74 6f 6b 65 6e 0a 0a 09 09 09 09 69 66  p $token......if
0b90: 20 7b 24 74 6f 6b 65 6e 43 6f 64 65 20 21 3d 20   {$tokenCode != 
0ba0: 22 32 30 30 22 7d 20 7b 0a 09 09 09 09 09 72 65  "200"} {......re
0bb0: 74 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72  turn -code error
0bc0: 20 22 55 6e 61 62 6c 65 20 74 6f 20 64 6f 77 6e   "Unable to down
0bd0: 6c 6f 61 64 20 5c 22 24 75 72 6c 5c 22 3a 20 53  load \"$url\": S
0be0: 69 74 65 20 64 69 64 20 6e 6f 74 20 72 65 74 75  ite did not retu
0bf0: 72 6e 20 61 20 32 30 30 20 28 72 65 74 75 72 6e  rn a 200 (return
0c00: 65 64 20 24 74 6f 6b 65 6e 43 6f 64 65 29 22 0a  ed $tokenCode)".
0c10: 09 09 09 09 7d 0a 0a 09 09 09 09 69 66 20 7b 21  ....}......if {!
0c20: 5b 69 6e 66 6f 20 65 78 69 73 74 73 20 72 65 74  [info exists ret
0c30: 76 61 6c 5d 7d 20 7b 0a 09 09 09 09 09 72 65 74  val]} {......ret
0c40: 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20  urn -code error 
0c50: 22 55 6e 61 62 6c 65 20 74 6f 20 64 6f 77 6e 6c  "Unable to downl
0c60: 6f 61 64 20 5c 22 24 75 72 6c 5c 22 3a 20 53 69  oad \"$url\": Si
0c70: 74 65 20 64 69 64 20 6e 6f 74 20 72 65 74 75 72  te did not retur
0c80: 6e 20 70 72 6f 70 65 72 20 64 61 74 61 3a 20 24  n proper data: $
0c90: 65 72 72 22 0a 09 09 09 09 7d 0a 0a 09 09 09 09  err".....}......
0ca0: 72 65 74 75 72 6e 20 24 72 65 74 76 61 6c 0a 09  return $retval..
0cb0: 09 09 7d 0a 0a 09 09 7d 0a 0a 09 09 72 65 74 75  ..}....}....retu
0cc0: 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22  rn -code error "
0cd0: 55 6e 61 62 6c 65 20 74 6f 20 64 6f 77 6e 6c 6f  Unable to downlo
0ce0: 61 64 22 0a 09 7d 0a 7d 0a 0a 6e 61 6d 65 73 70  ad"..}.}..namesp
0cf0: 61 63 65 20 65 76 61 6c 20 3a 3a 61 70 70 66 73  ace eval ::appfs
0d00: 20 7b 0a 09 76 61 72 69 61 62 6c 65 20 63 61 63   {..variable cac
0d10: 68 65 64 69 72 20 22 2f 74 6d 70 2f 61 70 70 66  hedir "/tmp/appf
0d20: 73 2d 63 61 63 68 65 22 0a 09 76 61 72 69 61 62  s-cache"..variab
0d30: 6c 65 20 74 74 6c 20 33 36 30 30 0a 09 76 61 72  le ttl 3600..var
0d40: 69 61 62 6c 65 20 6e 74 74 6c 20 36 30 0a 09 76  iable nttl 60..v
0d50: 61 72 69 61 62 6c 65 20 74 72 75 73 74 65 64 5f  ariable trusted_
0d60: 63 61 73 20 5b 6c 69 73 74 5d 0a 09 76 61 72 69  cas [list]..vari
0d70: 61 62 6c 65 20 70 6c 61 74 66 6f 72 6d 20 5b 3a  able platform [:
0d80: 3a 70 6c 61 74 66 6f 72 6d 3a 3a 67 65 6e 65 72  :platform::gener
0d90: 69 63 5d 0a 0a 09 70 72 6f 63 20 5f 68 61 73 68  ic]...proc _hash
0da0: 5f 73 65 70 20 7b 68 61 73 68 20 7b 73 65 70 73  _sep {hash {seps
0db0: 20 34 7d 7d 20 7b 0a 09 09 66 6f 72 20 7b 73 65   4}} {...for {se
0dc0: 74 20 69 64 78 20 30 7d 20 7b 24 69 64 78 20 3c  t idx 0} {$idx <
0dd0: 20 24 73 65 70 73 7d 20 7b 69 6e 63 72 20 69 64   $seps} {incr id
0de0: 78 7d 20 7b 0a 09 09 09 61 70 70 65 6e 64 20 72  x} {....append r
0df0: 65 74 76 61 6c 20 22 5b 73 74 72 69 6e 67 20 72  etval "[string r
0e00: 61 6e 67 65 20 24 68 61 73 68 20 5b 65 78 70 72  ange $hash [expr
0e10: 20 7b 24 69 64 78 20 2a 20 32 7d 5d 20 5b 65 78   {$idx * 2}] [ex
0e20: 70 72 20 7b 28 24 69 64 78 20 2a 20 32 29 20 2b  pr {($idx * 2) +
0e30: 20 31 7d 5d 5d 2f 22 0a 09 09 7d 0a 09 09 61 70   1}]]/"...}...ap
0e40: 70 65 6e 64 20 72 65 74 76 61 6c 20 22 5b 73 74  pend retval "[st
0e50: 72 69 6e 67 20 72 61 6e 67 65 20 24 68 61 73 68  ring range $hash
0e60: 20 5b 65 78 70 72 20 7b 24 69 64 78 20 2a 20 32   [expr {$idx * 2
0e70: 7d 5d 20 65 6e 64 5d 22 0a 0a 09 09 72 65 74 75  }] end]"....retu
0e80: 72 6e 20 24 72 65 74 76 61 6c 0a 09 7d 0a 0a 09  rn $retval..}...
0e90: 70 72 6f 63 20 5f 63 61 63 68 65 66 69 6c 65 20  proc _cachefile 
0ea0: 7b 75 72 6c 20 6b 65 79 20 6d 65 74 68 6f 64 20  {url key method 
0eb0: 7b 6b 65 79 49 73 48 61 73 68 20 31 7d 7d 20 7b  {keyIsHash 1}} {
0ec0: 0a 09 09 69 66 20 7b 24 6b 65 79 49 73 48 61 73  ...if {$keyIsHas
0ed0: 68 20 26 26 20 24 6d 65 74 68 6f 64 20 21 3d 20  h && $method != 
0ee0: 22 73 68 61 31 22 7d 20 7b 0a 09 09 09 72 65 74  "sha1"} {....ret
0ef0: 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20  urn -code error 
0f00: 22 4f 6e 6c 79 20 53 48 41 31 20 68 61 73 68 69  "Only SHA1 hashi
0f10: 6e 67 20 6d 65 74 68 6f 64 20 69 73 20 73 75 70  ng method is sup
0f20: 70 6f 72 74 65 64 22 0a 09 09 7d 0a 0a 09 09 73  ported"...}....s
0f30: 65 74 20 66 69 6c 65 6b 65 79 20 24 6b 65 79 0a  et filekey $key.
0f40: 09 09 69 66 20 7b 24 6b 65 79 49 73 48 61 73 68  ..if {$keyIsHash
0f50: 7d 20 7b 0a 09 09 09 73 65 74 20 66 69 6c 65 6b  } {....set filek
0f60: 65 79 20 5b 5f 68 61 73 68 5f 73 65 70 20 24 66  ey [_hash_sep $f
0f70: 69 6c 65 6b 65 79 5d 0a 09 09 7d 0a 0a 09 09 73  ilekey]...}....s
0f80: 65 74 20 66 69 6c 65 20 5b 66 69 6c 65 20 6a 6f  et file [file jo
0f90: 69 6e 20 24 3a 3a 61 70 70 66 73 3a 3a 63 61 63  in $::appfs::cac
0fa0: 68 65 64 69 72 20 24 66 69 6c 65 6b 65 79 5d 0a  hedir $filekey].
0fb0: 0a 09 09 66 69 6c 65 20 6d 6b 64 69 72 20 5b 66  ...file mkdir [f
0fc0: 69 6c 65 20 64 69 72 6e 61 6d 65 20 24 66 69 6c  ile dirname $fil
0fd0: 65 5d 0a 0a 09 09 69 66 20 7b 5b 66 69 6c 65 20  e]....if {[file 
0fe0: 65 78 69 73 74 73 20 24 66 69 6c 65 5d 7d 20 7b  exists $file]} {
0ff0: 0a 09 09 09 72 65 74 75 72 6e 20 24 66 69 6c 65  ....return $file
1000: 0a 09 09 7d 0a 0a 09 09 73 65 74 20 74 6d 70 66  ...}....set tmpf
1010: 69 6c 65 20 22 24 7b 66 69 6c 65 7d 2e 5b 65 78  ile "${file}.[ex
1020: 70 72 20 7b 72 61 6e 64 28 29 7d 5d 5b 63 6c 6f  pr {rand()}][clo
1030: 63 6b 20 63 6c 69 63 6b 73 5d 22 0a 0a 09 09 73  ck clicks]"....s
1040: 65 74 20 66 64 20 5b 6f 70 65 6e 20 24 74 6d 70  et fd [open $tmp
1050: 66 69 6c 65 20 22 77 22 5d 0a 09 09 66 63 6f 6e  file "w"]...fcon
1060: 66 69 67 75 72 65 20 24 66 64 20 2d 74 72 61 6e  figure $fd -tran
1070: 73 6c 61 74 69 6f 6e 20 62 69 6e 61 72 79 0a 0a  slation binary..
1080: 09 09 63 61 74 63 68 20 7b 0a 09 09 09 3a 3a 61  ..catch {....::a
1090: 70 70 66 73 3a 3a 75 73 65 72 3a 3a 64 6f 77 6e  ppfs::user::down
10a0: 6c 6f 61 64 5f 66 69 6c 65 20 24 75 72 6c 20 24  load_file $url $
10b0: 66 64 0a 09 09 7d 0a 0a 09 09 63 6c 6f 73 65 20  fd...}....close 
10c0: 24 66 64 0a 0a 09 09 69 66 20 7b 24 6b 65 79 49  $fd....if {$keyI
10d0: 73 48 61 73 68 7d 20 7b 0a 09 09 09 73 65 74 20  sHash} {....set 
10e0: 68 61 73 68 20 5b 73 74 72 69 6e 67 20 74 6f 6c  hash [string tol
10f0: 6f 77 65 72 20 5b 73 68 61 31 3a 3a 73 68 61 31  ower [sha1::sha1
1100: 20 2d 68 65 78 20 2d 66 69 6c 65 20 24 74 6d 70   -hex -file $tmp
1110: 66 69 6c 65 5d 5d 0a 09 09 7d 20 65 6c 73 65 20  file]]...} else 
1120: 7b 0a 09 09 09 73 65 74 20 68 61 73 68 20 24 6b  {....set hash $k
1130: 65 79 0a 09 09 7d 0a 0a 09 09 69 66 20 7b 24 68  ey...}....if {$h
1140: 61 73 68 20 3d 3d 20 24 6b 65 79 7d 20 7b 0a 09  ash == $key} {..
1150: 09 09 66 69 6c 65 20 72 65 6e 61 6d 65 20 2d 66  ..file rename -f
1160: 6f 72 63 65 20 2d 2d 20 24 74 6d 70 66 69 6c 65  orce -- $tmpfile
1170: 20 24 66 69 6c 65 0a 09 09 7d 20 65 6c 73 65 20   $file...} else 
1180: 7b 0a 09 09 09 66 69 6c 65 20 64 65 6c 65 74 65  {....file delete
1190: 20 2d 66 6f 72 63 65 20 2d 2d 20 24 74 6d 70 66   -force -- $tmpf
11a0: 69 6c 65 0a 09 09 7d 0a 0a 09 09 72 65 74 75 72  ile...}....retur
11b0: 6e 20 24 66 69 6c 65 0a 09 7d 0a 0a 0a 09 70 72  n $file..}....pr
11c0: 6f 63 20 5f 69 73 48 61 73 68 20 7b 76 61 6c 75  oc _isHash {valu
11d0: 65 7d 20 7b 0a 09 09 73 65 74 20 76 61 6c 75 65  e} {...set value
11e0: 20 5b 73 74 72 69 6e 67 20 74 6f 6c 6f 77 65 72   [string tolower
11f0: 20 24 76 61 6c 75 65 5d 0a 0a 09 09 69 66 20 7b   $value]....if {
1200: 21 5b 72 65 67 65 78 70 20 7b 5e 5b 30 2d 39 61  ![regexp {^[0-9a
1210: 2d 66 5d 2a 24 7d 20 24 76 61 6c 75 65 5d 7d 20  -f]*$} $value]} 
1220: 7b 0a 09 09 09 72 65 74 75 72 6e 20 66 61 6c 73  {....return fals
1230: 65 0a 09 09 7d 0a 0a 09 09 72 65 74 75 72 6e 20  e...}....return 
1240: 74 72 75 65 0a 09 7d 0a 0a 09 70 72 6f 63 20 5f  true..}...proc _
1250: 76 65 72 69 66 79 53 69 67 6e 61 74 75 72 65 41  verifySignatureA
1260: 6e 64 43 65 72 74 69 66 69 63 61 74 65 20 7b 68  ndCertificate {h
1270: 6f 73 74 6e 61 6d 65 20 63 65 72 74 69 66 69 63  ostname certific
1280: 61 74 65 20 73 69 67 6e 61 74 75 72 65 20 68 61  ate signature ha
1290: 73 68 20 68 61 73 68 6d 65 74 68 6f 64 7d 20 7b  sh hashmethod} {
12a0: 0a 09 09 73 65 74 20 63 65 72 74 69 66 69 63 61  ...set certifica
12b0: 74 65 20 5b 62 69 6e 61 72 79 20 66 6f 72 6d 61  te [binary forma
12c0: 74 20 22 48 2a 22 20 24 63 65 72 74 69 66 69 63  t "H*" $certific
12d0: 61 74 65 5d 0a 09 09 73 65 74 20 73 69 67 6e 61  ate]...set signa
12e0: 74 75 72 65 20 20 20 5b 62 69 6e 61 72 79 20 66  ture   [binary f
12f0: 6f 72 6d 61 74 20 22 48 2a 22 20 24 73 69 67 6e  ormat "H*" $sign
1300: 61 74 75 72 65 5d 0a 0a 09 09 73 65 74 20 63 65  ature]....set ce
1310: 72 74 69 66 69 63 61 74 65 20 5b 3a 3a 70 6b 69  rtificate [::pki
1320: 3a 3a 78 35 30 39 3a 3a 70 61 72 73 65 5f 63 65  ::x509::parse_ce
1330: 72 74 20 24 63 65 72 74 69 66 69 63 61 74 65 5d  rt $certificate]
1340: 0a 0a 09 09 61 72 72 61 79 20 73 65 74 20 63 65  ....array set ce
1350: 72 74 69 66 69 63 61 74 65 5f 61 72 72 20 24 63  rtificate_arr $c
1360: 65 72 74 69 66 69 63 61 74 65 0a 09 09 73 65 74  ertificate...set
1370: 20 63 65 72 74 69 66 69 63 61 74 65 5f 63 6e 20   certificate_cn 
1380: 5b 3a 3a 70 6b 69 3a 3a 78 35 30 39 3a 3a 5f 64  [::pki::x509::_d
1390: 6e 5f 74 6f 5f 63 6e 20 24 63 65 72 74 69 66 69  n_to_cn $certifi
13a0: 63 61 74 65 5f 61 72 72 28 73 75 62 6a 65 63 74  cate_arr(subject
13b0: 29 5d 0a 0a 09 09 69 66 20 7b 21 5b 3a 3a 70 6b  )]....if {![::pk
13c0: 69 3a 3a 76 65 72 69 66 79 20 24 73 69 67 6e 61  i::verify $signa
13d0: 74 75 72 65 20 22 24 68 61 73 68 2c 24 68 61 73  ture "$hash,$has
13e0: 68 6d 65 74 68 6f 64 22 20 24 63 65 72 74 69 66  hmethod" $certif
13f0: 69 63 61 74 65 5d 7d 20 7b 0a 09 09 09 72 65 74  icate]} {....ret
1400: 75 72 6e 20 66 61 6c 73 65 0a 09 09 7d 0a 0a 09  urn false...}...
1410: 09 69 66 20 7b 5b 73 74 72 69 6e 67 20 74 6f 6c  .if {[string tol
1420: 6f 77 65 72 20 24 63 65 72 74 69 66 69 63 61 74  ower $certificat
1430: 65 5f 63 6e 5d 20 21 3d 20 5b 73 74 72 69 6e 67  e_cn] != [string
1440: 20 74 6f 6c 6f 77 65 72 20 24 68 6f 73 74 6e 61   tolower $hostna
1450: 6d 65 5d 7d 20 7b 0a 09 09 09 72 65 74 75 72 6e  me]} {....return
1460: 20 66 61 6c 73 65 0a 09 09 7d 0a 0a 09 09 69 66   false...}....if
1470: 20 7b 21 5b 3a 3a 70 6b 69 3a 3a 78 35 30 39 3a   {![::pki::x509:
1480: 3a 76 65 72 69 66 79 5f 63 65 72 74 20 24 63 65  :verify_cert $ce
1490: 72 74 69 66 69 63 61 74 65 20 24 3a 3a 61 70 70  rtificate $::app
14a0: 66 73 3a 3a 74 72 75 73 74 65 64 5f 63 61 73 5d  fs::trusted_cas]
14b0: 7d 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 66 61  } {....return fa
14c0: 6c 73 65 0a 09 09 7d 0a 0a 09 09 72 65 74 75 72  lse...}....retur
14d0: 6e 20 74 72 75 65 0a 09 7d 0a 0a 09 70 72 6f 63  n true..}...proc
14e0: 20 5f 6e 6f 72 6d 61 6c 69 7a 65 4f 53 20 7b 6f   _normalizeOS {o
14f0: 73 20 7b 74 6f 6c 65 72 61 6e 74 20 30 7d 7d 20  s {tolerant 0}} 
1500: 7b 0a 09 09 73 65 74 20 6f 73 20 5b 73 74 72 69  {...set os [stri
1510: 6e 67 20 74 6f 6c 6f 77 65 72 20 5b 73 74 72 69  ng tolower [stri
1520: 6e 67 20 74 72 69 6d 20 24 6f 73 5d 5d 0a 0a 09  ng trim $os]]...
1530: 09 73 77 69 74 63 68 20 2d 2d 20 24 6f 73 20 7b  .switch -- $os {
1540: 0a 09 09 09 22 6c 69 6e 75 78 22 20 2d 20 22 66  ...."linux" - "f
1550: 72 65 65 62 73 64 22 20 2d 20 22 6f 70 65 6e 62  reebsd" - "openb
1560: 73 64 22 20 2d 20 22 6e 65 74 62 73 64 22 20 7b  sd" - "netbsd" {
1570: 0a 09 09 09 09 72 65 74 75 72 6e 20 24 6f 73 0a  .....return $os.
1580: 09 09 09 7d 0a 09 09 09 22 73 75 6e 6f 73 22 20  ...}...."sunos" 
1590: 7b 0a 09 09 09 09 72 65 74 75 72 6e 20 22 73 6f  {.....return "so
15a0: 6c 61 72 69 73 22 0a 09 09 09 7d 0a 09 09 09 22  laris"....}...."
15b0: 6e 6f 61 72 63 68 22 20 2d 20 22 6e 6f 6e 65 22  noarch" - "none"
15c0: 20 2d 20 22 61 6e 79 22 20 2d 20 22 61 6c 6c 22   - "any" - "all"
15d0: 20 7b 0a 09 09 09 09 72 65 74 75 72 6e 20 22 6e   {.....return "n
15e0: 6f 61 72 63 68 22 0a 09 09 09 7d 0a 09 09 7d 0a  oarch"....}...}.
15f0: 0a 09 09 69 66 20 7b 24 74 6f 6c 65 72 61 6e 74  ...if {$tolerant
1600: 7d 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 24 6f  } {....return $o
1610: 73 0a 09 09 7d 0a 0a 09 09 72 65 74 75 72 6e 20  s...}....return 
1620: 2d 63 6f 64 65 20 65 72 72 6f 72 20 22 55 6e 61  -code error "Una
1630: 62 6c 65 20 74 6f 20 6e 6f 72 6d 61 6c 69 7a 65  ble to normalize
1640: 20 4f 53 3a 20 24 6f 73 22 0a 09 7d 0a 0a 09 70   OS: $os"..}...p
1650: 72 6f 63 20 5f 6e 6f 72 6d 61 6c 69 7a 65 43 50  roc _normalizeCP
1660: 55 20 7b 63 70 75 20 7b 74 6f 6c 65 72 61 6e 74  U {cpu {tolerant
1670: 20 30 7d 7d 20 7b 0a 09 09 73 65 74 20 63 70 75   0}} {...set cpu
1680: 20 5b 73 74 72 69 6e 67 20 74 6f 6c 6f 77 65 72   [string tolower
1690: 20 5b 73 74 72 69 6e 67 20 74 72 69 6d 20 24 63   [string trim $c
16a0: 70 75 5d 5d 0a 0a 09 09 73 77 69 74 63 68 20 2d  pu]]....switch -
16b0: 67 6c 6f 62 20 2d 2d 20 24 63 70 75 20 7b 0a 09  glob -- $cpu {..
16c0: 09 09 22 69 3f 38 36 22 20 7b 0a 09 09 09 09 72  .."i?86" {.....r
16d0: 65 74 75 72 6e 20 22 69 78 38 36 22 0a 09 09 09  eturn "ix86"....
16e0: 7d 0a 09 09 09 22 78 38 36 5f 36 34 22 20 7b 0a  }...."x86_64" {.
16f0: 09 09 09 09 72 65 74 75 72 6e 20 24 63 70 75 0a  ....return $cpu.
1700: 09 09 09 7d 0a 09 09 09 22 6e 6f 61 72 63 68 22  ...}...."noarch"
1710: 20 2d 20 22 6e 6f 6e 65 22 20 2d 20 22 61 6e 79   - "none" - "any
1720: 22 20 2d 20 22 61 6c 6c 22 20 7b 0a 09 09 09 09  " - "all" {.....
1730: 72 65 74 75 72 6e 20 22 6e 6f 61 72 63 68 22 0a  return "noarch".
1740: 09 09 09 7d 0a 09 09 7d 0a 0a 09 09 69 66 20 7b  ...}...}....if {
1750: 24 74 6f 6c 65 72 61 6e 74 7d 20 7b 0a 09 09 09  $tolerant} {....
1760: 72 65 74 75 72 6e 20 24 63 70 75 0a 09 09 7d 0a  return $cpu...}.
1770: 0a 09 09 72 65 74 75 72 6e 20 2d 63 6f 64 65 20  ...return -code 
1780: 65 72 72 6f 72 20 22 55 6e 61 62 6c 65 20 74 6f  error "Unable to
1790: 20 6e 6f 72 6d 61 6c 69 7a 65 20 43 50 55 3a 20   normalize CPU: 
17a0: 24 63 70 75 22 0a 09 7d 0a 0a 09 70 72 6f 63 20  $cpu"..}...proc 
17b0: 5f 61 73 5f 75 73 65 72 20 7b 63 6f 64 65 7d 20  _as_user {code} 
17c0: 7b 0a 09 09 3a 3a 61 70 70 66 73 64 3a 3a 73 69  {...::appfsd::si
17d0: 6d 75 6c 61 74 65 5f 75 73 65 72 5f 66 73 5f 65  mulate_user_fs_e
17e0: 6e 74 65 72 0a 0a 09 09 73 65 74 20 72 65 74 63  nter....set retc
17f0: 6f 64 65 20 5b 63 61 74 63 68 20 5b 6c 69 73 74  ode [catch [list
1800: 20 75 70 6c 65 76 65 6c 20 24 63 6f 64 65 5d 20   uplevel $code] 
1810: 72 65 74 73 74 72 5d 0a 0a 09 09 3a 3a 61 70 70  retstr]....::app
1820: 66 73 64 3a 3a 73 69 6d 75 6c 61 74 65 5f 75 73  fsd::simulate_us
1830: 65 72 5f 66 73 5f 6c 65 61 76 65 0a 0a 09 09 72  er_fs_leave....r
1840: 65 74 75 72 6e 20 2d 63 6f 64 65 20 24 72 65 74  eturn -code $ret
1850: 63 6f 64 65 20 24 72 65 74 73 74 72 0a 09 7d 0a  code $retstr..}.
1860: 0a 09 70 72 6f 63 20 69 6e 69 74 20 7b 7d 20 7b  ..proc init {} {
1870: 0a 09 09 69 66 20 7b 5b 69 6e 66 6f 20 65 78 69  ...if {[info exi
1880: 73 74 73 20 3a 3a 61 70 70 66 73 3a 3a 69 6e 69  sts ::appfs::ini
1890: 74 5f 63 61 6c 6c 65 64 5d 7d 20 7b 0a 09 09 09  t_called]} {....
18a0: 72 65 74 75 72 6e 0a 09 09 7d 0a 0a 09 09 23 20  return...}....# 
18b0: 46 6f 72 63 65 20 5b 70 61 72 72 61 79 5d 20 61  Force [parray] a
18c0: 6e 64 20 5b 63 6c 6f 63 6b 5d 20 74 6f 20 62 65  nd [clock] to be
18d0: 20 6c 6f 61 64 65 64 0a 09 09 63 61 74 63 68 20   loaded...catch 
18e0: 7b 0a 09 09 09 70 61 72 72 61 79 20 64 6f 65 73  {....parray does
18f0: 5f 6e 6f 74 5f 65 78 69 73 74 0a 09 09 7d 0a 09  _not_exist...}..
1900: 09 63 61 74 63 68 20 7b 0a 09 09 09 63 6c 6f 63  .catch {....cloc
1910: 6b 20 73 65 63 6f 6e 64 73 0a 09 09 7d 0a 09 09  k seconds...}...
1920: 63 61 74 63 68 20 7b 0a 09 09 09 63 6c 6f 63 6b  catch {....clock
1930: 20 61 64 64 20 5b 63 6c 6f 63 6b 20 73 65 63 6f   add [clock seco
1940: 6e 64 73 5d 20 33 20 73 65 63 6f 6e 64 73 0a 09  nds] 3 seconds..
1950: 09 7d 0a 0a 09 09 73 65 74 20 3a 3a 61 70 70 66  .}....set ::appf
1960: 73 3a 3a 69 6e 69 74 5f 63 61 6c 6c 65 64 20 31  s::init_called 1
1970: 0a 0a 09 09 23 20 41 64 64 20 61 20 64 65 66 61  ....# Add a defa
1980: 75 6c 74 20 43 41 20 74 6f 20 6c 69 73 74 20 6f  ult CA to list o
1990: 66 20 74 72 75 73 74 65 64 20 43 41 73 0a 09 09  f trusted CAs...
19a0: 6c 61 70 70 65 6e 64 20 3a 3a 61 70 70 66 73 3a  lappend ::appfs:
19b0: 3a 74 72 75 73 74 65 64 5f 63 61 73 20 5b 3a 3a  :trusted_cas [::
19c0: 70 6b 69 3a 3a 78 35 30 39 3a 3a 70 61 72 73 65  pki::x509::parse
19d0: 5f 63 65 72 74 20 7b 0a 2d 2d 2d 2d 2d 42 45 47  _cert {.-----BEG
19e0: 49 4e 20 43 45 52 54 49 46 49 43 41 54 45 2d 2d  IN CERTIFICATE--
19f0: 2d 2d 2d 0a 4d 49 49 43 37 44 43 43 41 64 53 67  ---.MIIC7DCCAdSg
1a00: 41 77 49 42 41 67 49 42 41 54 41 4e 42 67 6b 71  AwIBAgIBATANBgkq
1a10: 68 6b 69 47 39 77 30 42 41 51 55 46 41 44 41 76  hkiG9w0BAQUFADAv
1a20: 4d 52 49 77 45 41 59 44 56 51 51 4b 45 77 6c 53  MRIwEAYDVQQKEwlS
1a30: 62 33 6b 67 0a 53 32 56 6c 62 6d 55 78 47 54 41  b3kg.S2VlbmUxGTA
1a40: 58 42 67 4e 56 42 41 4d 54 45 45 46 77 63 45 5a  XBgNVBAMTEEFwcEZ
1a50: 54 49 45 74 6c 65 53 42 4e 59 58 4e 30 5a 58 49  TIEtleSBNYXN0ZXI
1a60: 77 48 68 63 4e 4d 54 51 78 4d 54 45 33 4d 6a 41  wHhcNMTQxMTE3MjA
1a70: 78 4e 7a 49 34 0a 57 68 63 4e 4d 54 6b 78 4d 54  xNzI4.WhcNMTkxMT
1a80: 45 33 4d 6a 41 78 4e 7a 49 34 57 6a 41 76 4d 52  E3MjAxNzI4WjAvMR
1a90: 49 77 45 41 59 44 56 51 51 4b 45 77 6c 53 62 33  IwEAYDVQQKEwlSb3
1aa0: 6b 67 53 32 56 6c 62 6d 55 78 47 54 41 58 42 67  kgS2VlbmUxGTAXBg
1ab0: 4e 56 42 41 4d 54 0a 45 45 46 77 63 45 5a 54 49  NVBAMT.EEFwcEZTI
1ac0: 45 74 6c 65 53 42 4e 59 58 4e 30 5a 58 49 77 67  EtleSBNYXN0ZXIwg
1ad0: 67 45 69 4d 41 30 47 43 53 71 47 53 49 62 33 44  gEiMA0GCSqGSIb3D
1ae0: 51 45 42 41 51 55 41 41 34 49 42 44 77 41 77 67  QEBAQUAA4IBDwAwg
1af0: 67 45 4b 41 6f 49 42 0a 41 51 43 71 36 75 53 4b  gEKAoIB.AQCq6uSK
1b00: 34 36 79 47 35 62 36 52 4a 57 77 52 6c 76 77 35  46yG5b6RJWwRlvw5
1b10: 67 6c 41 6e 6a 73 63 31 47 69 58 33 64 75 58 41  glAnjsc1GiX3duXA
1b20: 30 76 47 34 71 6e 4b 55 6e 44 74 6c 2f 6a 63 4d  0vG4qnKUnDtl/jcM
1b30: 6d 71 32 47 4d 4f 42 39 0a 49 79 31 74 6a 61 62  mq2GMOB9.Iy1tjab
1b40: 45 48 41 30 4d 68 57 32 6a 37 56 77 65 2f 4f 39  EHA0MhW2j7Vwe/O9
1b50: 4d 4c 46 4a 6b 4a 33 30 4d 31 50 56 44 37 59 5a  MLFJkJ30M1PVD7YZ
1b60: 52 52 4e 61 41 73 7a 33 55 57 49 4b 45 6a 50 49  RRNaAsz3UWIKEjPI
1b70: 37 42 42 63 33 32 4b 4f 6d 0a 42 4c 33 43 54 58  7BBc32KOm.BL3CTX
1b80: 43 43 64 7a 6c 6c 4c 31 48 68 56 62 6e 4d 35 69  CCdzllL1HhVbnM5i
1b90: 43 41 6d 67 48 63 67 31 44 55 6b 2f 45 76 57 58  CAmgHcg1DUk/EvWX
1ba0: 76 6e 45 44 78 58 52 79 32 6c 56 39 6d 51 73 6d  vnEDxXRy2lV9mQsm
1bb0: 44 65 64 72 66 66 59 37 57 6c 0a 4f 72 35 37 6e  DedrffY7Wl.Or57n
1bc0: 6c 63 7a 61 4d 75 50 4c 70 79 52 53 6b 76 37 35  lczaMuPLpyRSkv75
1bd0: 50 41 6e 6a 51 4a 78 54 33 73 57 6c 42 70 79 2b  PAnjQJxT3sWlBpy+
1be0: 2f 48 39 49 6d 75 64 51 64 70 4a 4e 66 2f 46 74  /H9ImudQdpJNf/Ft
1bf0: 78 63 71 4e 37 69 44 77 48 35 42 0a 76 49 63 65  xcqN7iDwH5B.vIce
1c00: 59 45 74 44 56 78 46 73 76 6f 35 48 4f 56 6b 53  YEtDVxFsvo5HOVkS
1c10: 6c 39 6a 65 6f 35 45 34 47 70 65 33 77 79 66 52  l9jeo5E4Gpe3wyfR
1c20: 68 6f 71 42 32 55 6b 61 57 31 4b 71 30 69 48 35  hoqB2UkaW1Kq0iH5
1c30: 52 2b 30 30 53 37 36 30 78 51 4d 78 0a 4c 4c 39  R+00S760xQMx.LL9
1c40: 4c 31 64 75 68 75 31 64 4c 37 48 73 6d 45 77 37  L1duhu1dL7HsmEw7
1c50: 49 65 59 55 52 41 67 4d 42 41 41 47 6a 45 7a 41  IeYURAgMBAAGjEzA
1c60: 52 4d 41 38 47 41 31 55 64 45 77 45 42 2f 77 51  RMA8GA1UdEwEB/wQ
1c70: 46 4d 41 4d 42 41 66 38 77 44 51 59 4a 0a 4b 6f  FMAMBAf8wDQYJ.Ko
1c80: 5a 49 68 76 63 4e 41 51 45 46 42 51 41 44 67 67  ZIhvcNAQEFBQADgg
1c90: 45 42 41 4b 68 4f 34 5a 53 7a 59 50 33 37 42 71  EBAKhO4ZSzYP37Bq
1ca0: 69 78 4e 48 4b 4b 39 2b 67 53 65 43 36 46 67 61  ixNHKK9+gSeC6Fga
1cb0: 38 35 69 4c 57 68 77 70 50 57 30 6b 53 6c 0a 7a  85iLWhwpPW0kSl.z
1cc0: 30 33 68 61 6c 38 30 4b 5a 2b 6b 50 4d 7a 62 38  03hal80KZ+kPMzb8
1cd0: 43 35 32 4e 32 38 33 74 51 4e 41 71 4a 39 51 38  C52N283tQNAqJ9Q8
1ce0: 61 6b 44 50 5a 78 53 7a 7a 4d 55 56 4f 47 70 47  akDPZxSzzMUVOGpG
1cf0: 77 32 70 4a 37 5a 73 77 4b 44 7a 30 5a 54 61 0a  w2pJ7ZswKDz0ZTa.
1d00: 30 65 64 71 2f 67 64 54 2f 48 72 64 65 67 76 4e  0edq/gdT/HrdegvN
1d10: 74 44 50 63 32 6a 6f 6e 61 35 46 56 4f 59 71 77  tDPc2jona5FVOYqw
1d20: 64 63 7a 35 6b 62 6c 31 55 57 42 61 42 70 33 56  dcz5kbl1UWBaBp3V
1d30: 58 55 67 63 59 6a 58 53 52 61 42 4b 34 33 57 64  XUgcYjXSRaBK43Wd
1d40: 0a 63 76 65 69 44 55 65 5a 77 37 67 48 71 52 53  .cveiDUeZw7gHqRS
1d50: 4e 2f 41 79 59 55 43 74 4a 7a 57 6d 76 47 73 4a  N/AyYUCtJzWmvGsJ
1d60: 75 49 46 68 4d 42 6f 6e 75 7a 38 6a 79 6c 68 79  uIFhMBonuz8jylhy
1d70: 4d 4a 43 59 4a 46 54 34 69 4d 55 43 38 4d 4e 49  MJCYJFT4iMUC8MNI
1d80: 77 0a 6e 69 58 31 78 78 2b 4e 75 36 66 50 56 35  w.niX1xx+Nu6fPV5
1d90: 5a 5a 48 6a 39 72 62 68 69 42 61 4c 6a 6d 2b 74  ZZHj9rbhiBaLjm+t
1da0: 6b 44 77 74 50 67 41 33 6a 32 70 78 76 48 4b 59  kDwtPgA3j2pxvHKY
1db0: 70 74 75 57 78 65 59 4f 2b 39 44 44 4e 61 39 73  ptuWxeYO+9DDNa9s
1dc0: 43 62 0a 45 35 41 6e 4a 49 6c 4f 6e 64 2f 74 47  Cb.E5AnJIlOnd/tG
1dd0: 65 30 43 68 66 30 73 46 51 67 2b 6c 39 6e 4e 69  e0Chf0sFQg+l9nNi
1de0: 4e 72 57 47 67 7a 64 64 39 5a 50 4a 4b 34 3d 0a  NrWGgzdd9ZPJK4=.
1df0: 2d 2d 2d 2d 2d 45 4e 44 20 43 45 52 54 49 46 49  -----END CERTIFI
1e00: 43 41 54 45 2d 2d 2d 2d 2d 0a 7d 5d 0a 0a 09 09  CATE-----.}]....
1e10: 23 20 4c 6f 61 64 20 63 6f 6e 66 69 67 75 72 61  # Load configura
1e20: 74 69 6f 6e 20 66 69 6c 65 0a 09 09 73 65 74 20  tion file...set 
1e30: 63 6f 6e 66 69 67 5f 66 69 6c 65 20 5b 66 69 6c  config_file [fil
1e40: 65 20 6a 6f 69 6e 20 24 3a 3a 61 70 70 66 73 3a  e join $::appfs:
1e50: 3a 63 61 63 68 65 64 69 72 20 63 6f 6e 66 69 67  :cachedir config
1e60: 5d 0a 09 09 69 66 20 7b 5b 66 69 6c 65 20 65 78  ]...if {[file ex
1e70: 69 73 74 73 20 24 63 6f 6e 66 69 67 5f 66 69 6c  ists $config_fil
1e80: 65 5d 7d 20 7b 0a 09 09 09 73 6f 75 72 63 65 20  e]} {....source 
1e90: 24 63 6f 6e 66 69 67 5f 66 69 6c 65 0a 09 09 7d  $config_file...}
1ea0: 0a 0a 09 09 69 66 20 7b 21 5b 69 6e 66 6f 20 65  ....if {![info e
1eb0: 78 69 73 74 73 20 3a 3a 61 70 70 66 73 3a 3a 64  xists ::appfs::d
1ec0: 62 5d 7d 20 7b 0a 09 09 09 66 69 6c 65 20 6d 6b  b]} {....file mk
1ed0: 64 69 72 20 24 3a 3a 61 70 70 66 73 3a 3a 63 61  dir $::appfs::ca
1ee0: 63 68 65 64 69 72 0a 0a 09 09 09 73 71 6c 69 74  chedir.....sqlit
1ef0: 65 33 20 3a 3a 61 70 70 66 73 3a 3a 64 62 20 5b  e3 ::appfs::db [
1f00: 66 69 6c 65 20 6a 6f 69 6e 20 24 3a 3a 61 70 70  file join $::app
1f10: 66 73 3a 3a 63 61 63 68 65 64 69 72 20 63 61 63  fs::cachedir cac
1f20: 68 65 2e 64 62 5d 0a 0a 09 09 09 3a 3a 61 70 70  he.db].....::app
1f30: 66 73 3a 3a 64 62 20 74 69 6d 65 6f 75 74 20 33  fs::db timeout 3
1f40: 30 30 30 30 0a 09 09 7d 0a 0a 09 09 23 20 43 72  0000...}....# Cr
1f50: 65 61 74 65 20 74 61 62 6c 65 73 0a 09 09 64 62  eate tables...db
1f60: 20 65 76 61 6c 20 7b 43 52 45 41 54 45 20 54 41   eval {CREATE TA
1f70: 42 4c 45 20 49 46 20 4e 4f 54 20 45 58 49 53 54  BLE IF NOT EXIST
1f80: 53 20 73 69 74 65 73 28 68 6f 73 74 6e 61 6d 65  S sites(hostname
1f90: 20 50 52 49 4d 41 52 59 20 4b 45 59 2c 20 68 61   PRIMARY KEY, ha
1fa0: 73 68 4d 65 74 68 6f 64 2c 20 6c 61 73 74 55 70  shMethod, lastUp
1fb0: 64 61 74 65 2c 20 74 74 6c 29 3b 7d 0a 09 09 64  date, ttl);}...d
1fc0: 62 20 65 76 61 6c 20 7b 43 52 45 41 54 45 20 54  b eval {CREATE T
1fd0: 41 42 4c 45 20 49 46 20 4e 4f 54 20 45 58 49 53  ABLE IF NOT EXIS
1fe0: 54 53 20 70 61 63 6b 61 67 65 73 28 68 6f 73 74  TS packages(host
1ff0: 6e 61 6d 65 2c 20 70 61 63 6b 61 67 65 4d 61 6e  name, packageMan
2000: 69 66 65 73 74 48 61 73 68 2c 20 70 61 63 6b 61  ifestHash, packa
2010: 67 65 2c 20 76 65 72 73 69 6f 6e 2c 20 6f 73 2c  ge, version, os,
2020: 20 63 70 75 41 72 63 68 2c 20 69 73 4c 61 74 65   cpuArch, isLate
2030: 73 74 2c 20 68 61 76 65 4d 61 6e 69 66 65 73 74  st, haveManifest
2040: 29 3b 7d 0a 09 09 64 62 20 65 76 61 6c 20 7b 43  );}...db eval {C
2050: 52 45 41 54 45 20 54 41 42 4c 45 20 49 46 20 4e  REATE TABLE IF N
2060: 4f 54 20 45 58 49 53 54 53 20 66 69 6c 65 73 28  OT EXISTS files(
2070: 70 61 63 6b 61 67 65 4d 61 6e 69 66 65 73 74 48  packageManifestH
2080: 61 73 68 2c 20 68 61 73 68 4d 65 74 68 6f 64 2c  ash, hashMethod,
2090: 20 74 79 70 65 2c 20 74 69 6d 65 2c 20 73 6f 75   type, time, sou
20a0: 72 63 65 2c 20 73 69 7a 65 2c 20 70 65 72 6d 73  rce, size, perms
20b0: 2c 20 66 69 6c 65 48 61 73 68 2c 20 66 69 6c 65  , fileHash, file
20c0: 5f 6e 61 6d 65 2c 20 66 69 6c 65 5f 64 69 72 65  _name, file_dire
20d0: 63 74 6f 72 79 29 3b 7d 0a 0a 09 09 23 20 43 72  ctory);}....# Cr
20e0: 65 61 74 65 20 69 6e 64 65 78 65 73 0a 09 09 64  eate indexes...d
20f0: 62 20 65 76 61 6c 20 7b 43 52 45 41 54 45 20 49  b eval {CREATE I
2100: 4e 44 45 58 20 49 46 20 4e 4f 54 20 45 58 49 53  NDEX IF NOT EXIS
2110: 54 53 20 73 69 74 65 73 5f 69 6e 64 65 78 20 4f  TS sites_index O
2120: 4e 20 73 69 74 65 73 20 28 68 6f 73 74 6e 61 6d  N sites (hostnam
2130: 65 29 3b 7d 0a 09 09 64 62 20 65 76 61 6c 20 7b  e);}...db eval {
2140: 43 52 45 41 54 45 20 49 4e 44 45 58 20 49 46 20  CREATE INDEX IF 
2150: 4e 4f 54 20 45 58 49 53 54 53 20 70 61 63 6b 61  NOT EXISTS packa
2160: 67 65 73 5f 69 6e 64 65 78 20 4f 4e 20 70 61 63  ges_index ON pac
2170: 6b 61 67 65 73 20 28 68 6f 73 74 6e 61 6d 65 2c  kages (hostname,
2180: 20 70 61 63 6b 61 67 65 4d 61 6e 69 66 65 73 74   packageManifest
2190: 48 61 73 68 2c 20 70 61 63 6b 61 67 65 2c 20 76  Hash, package, v
21a0: 65 72 73 69 6f 6e 2c 20 6f 73 2c 20 63 70 75 41  ersion, os, cpuA
21b0: 72 63 68 29 3b 7d 0a 09 09 64 62 20 65 76 61 6c  rch);}...db eval
21c0: 20 7b 43 52 45 41 54 45 20 49 4e 44 45 58 20 49   {CREATE INDEX I
21d0: 46 20 4e 4f 54 20 45 58 49 53 54 53 20 66 69 6c  F NOT EXISTS fil
21e0: 65 73 5f 69 6e 64 65 78 20 4f 4e 20 66 69 6c 65  es_index ON file
21f0: 73 20 28 70 61 63 6b 61 67 65 4d 61 6e 69 66 65  s (packageManife
2200: 73 74 48 61 73 68 2c 20 66 69 6c 65 5f 6e 61 6d  stHash, file_nam
2210: 65 2c 20 66 69 6c 65 5f 64 69 72 65 63 74 6f 72  e, file_director
2220: 79 29 3b 7d 0a 09 7d 0a 0a 09 70 72 6f 63 20 64  y);}..}...proc d
2230: 6f 77 6e 6c 6f 61 64 20 7b 68 6f 73 74 6e 61 6d  ownload {hostnam
2240: 65 20 68 61 73 68 20 7b 6d 65 74 68 6f 64 20 73  e hash {method s
2250: 68 61 31 7d 7d 20 7b 0a 09 09 73 65 74 20 75 72  ha1}} {...set ur
2260: 6c 20 5b 3a 3a 61 70 70 66 73 3a 3a 75 73 65 72  l [::appfs::user
2270: 3a 3a 63 6f 6e 73 74 72 75 63 74 5f 75 72 6c 20  ::construct_url 
2280: 24 68 6f 73 74 6e 61 6d 65 20 24 68 61 73 68 20  $hostname $hash 
2290: 24 6d 65 74 68 6f 64 5d 0a 09 09 73 65 74 20 66  $method]...set f
22a0: 69 6c 65 20 5b 5f 63 61 63 68 65 66 69 6c 65 20  ile [_cachefile 
22b0: 24 75 72 6c 20 24 68 61 73 68 20 24 6d 65 74 68  $url $hash $meth
22c0: 6f 64 5d 0a 0a 09 09 69 66 20 7b 21 5b 66 69 6c  od]....if {![fil
22d0: 65 20 65 78 69 73 74 73 20 24 66 69 6c 65 5d 7d  e exists $file]}
22e0: 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 2d 63 6f   {....return -co
22f0: 64 65 20 65 72 72 6f 72 20 22 55 6e 61 62 6c 65  de error "Unable
2300: 20 74 6f 20 66 65 74 63 68 20 28 66 69 6c 65 20   to fetch (file 
2310: 64 6f 65 73 20 6e 6f 74 20 65 78 69 73 74 3a 20  does not exist: 
2320: 24 66 69 6c 65 29 22 0a 09 09 7d 0a 0a 09 09 72  $file)"...}....r
2330: 65 74 75 72 6e 20 24 66 69 6c 65 0a 09 7d 0a 0a  eturn $file..}..
2340: 09 70 72 6f 63 20 67 65 74 69 6e 64 65 78 20 7b  .proc getindex {
2350: 68 6f 73 74 6e 61 6d 65 7d 20 7b 0a 09 09 69 66  hostname} {...if
2360: 20 7b 5b 73 74 72 69 6e 67 20 6d 61 74 63 68 20   {[string match 
2370: 22 2a 5c 5b 2f 7e 5c 5d 2a 22 20 24 68 6f 73 74  "*\[/~\]*" $host
2380: 6e 61 6d 65 5d 7d 20 7b 0a 09 09 09 72 65 74 75  name]} {....retu
2390: 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22  rn -code error "
23a0: 49 6e 76 61 6c 69 64 20 68 6f 73 74 6e 61 6d 65  Invalid hostname
23b0: 22 0a 09 09 7d 0a 0a 09 09 73 65 74 20 6e 6f 77  "...}....set now
23c0: 20 5b 63 6c 6f 63 6b 20 73 65 63 6f 6e 64 73 5d   [clock seconds]
23d0: 0a 0a 09 09 73 65 74 20 6c 61 73 74 55 70 64 61  ....set lastUpda
23e0: 74 65 73 20 5b 64 62 20 65 76 61 6c 20 7b 53 45  tes [db eval {SE
23f0: 4c 45 43 54 20 6c 61 73 74 55 70 64 61 74 65 2c  LECT lastUpdate,
2400: 20 74 74 6c 20 46 52 4f 4d 20 73 69 74 65 73 20   ttl FROM sites 
2410: 57 48 45 52 45 20 68 6f 73 74 6e 61 6d 65 20 3d  WHERE hostname =
2420: 20 24 68 6f 73 74 6e 61 6d 65 20 4c 49 4d 49 54   $hostname LIMIT
2430: 20 31 3b 7d 5d 0a 09 09 69 66 20 7b 5b 6c 6c 65   1;}]...if {[lle
2440: 6e 67 74 68 20 24 6c 61 73 74 55 70 64 61 74 65  ngth $lastUpdate
2450: 73 5d 20 3d 3d 20 30 7d 20 7b 0a 09 09 09 73 65  s] == 0} {....se
2460: 74 20 6c 61 73 74 55 70 64 61 74 65 20 30 0a 09  t lastUpdate 0..
2470: 09 09 73 65 74 20 74 74 6c 20 30 0a 09 09 7d 20  ..set ttl 0...} 
2480: 65 6c 73 65 20 7b 0a 09 09 09 73 65 74 20 6c 61  else {....set la
2490: 73 74 55 70 64 61 74 65 20 5b 6c 69 6e 64 65 78  stUpdate [lindex
24a0: 20 24 6c 61 73 74 55 70 64 61 74 65 73 20 30 5d   $lastUpdates 0]
24b0: 0a 09 09 09 73 65 74 20 74 74 6c 20 5b 6c 69 6e  ....set ttl [lin
24c0: 64 65 78 20 24 6c 61 73 74 55 70 64 61 74 65 73  dex $lastUpdates
24d0: 20 31 5d 0a 09 09 7d 0a 0a 09 09 69 66 20 7b 24   1]...}....if {$
24e0: 6e 6f 77 20 3c 20 28 24 6c 61 73 74 55 70 64 61  now < ($lastUpda
24f0: 74 65 20 2b 20 24 74 74 6c 29 7d 20 7b 0a 09 09  te + $ttl)} {...
2500: 09 72 65 74 75 72 6e 20 43 4f 4d 50 4c 45 54 45  .return COMPLETE
2510: 0a 09 09 7d 0a 0a 09 09 73 65 74 20 75 72 6c 20  ...}....set url 
2520: 22 68 74 74 70 3a 2f 2f 24 68 6f 73 74 6e 61 6d  "http://$hostnam
2530: 65 2f 61 70 70 66 73 2f 69 6e 64 65 78 22 0a 0a  e/appfs/index"..
2540: 09 09 63 61 74 63 68 20 7b 0a 09 09 09 73 65 74  ..catch {....set
2550: 20 69 6e 64 65 78 68 61 73 68 5f 64 61 74 61 20   indexhash_data 
2560: 5b 3a 3a 61 70 70 66 73 3a 3a 75 73 65 72 3a 3a  [::appfs::user::
2570: 64 6f 77 6e 6c 6f 61 64 5f 66 69 6c 65 20 24 75  download_file $u
2580: 72 6c 5d 0a 09 09 7d 0a 0a 09 09 23 20 4e 6f 74  rl]...}....# Not
2590: 65 20 74 68 61 74 20 77 65 20 61 74 74 65 6d 70  e that we attemp
25a0: 74 65 64 20 74 6f 20 66 65 74 63 68 20 74 68 69  ted to fetch thi
25b0: 73 20 69 6e 64 65 78 20 61 6e 64 20 64 6f 20 6e  s index and do n
25c0: 6f 74 20 74 72 79 0a 09 09 23 20 61 67 61 69 6e  ot try...# again
25d0: 20 66 6f 72 20 61 20 77 68 69 6c 65 0a 09 09 64   for a while...d
25e0: 62 20 65 76 61 6c 20 7b 49 4e 53 45 52 54 20 4f  b eval {INSERT O
25f0: 52 20 52 45 50 4c 41 43 45 20 49 4e 54 4f 20 73  R REPLACE INTO s
2600: 69 74 65 73 20 28 68 6f 73 74 6e 61 6d 65 2c 20  ites (hostname, 
2610: 6c 61 73 74 55 70 64 61 74 65 2c 20 74 74 6c 29  lastUpdate, ttl)
2620: 20 56 41 4c 55 45 53 20 28 24 68 6f 73 74 6e 61   VALUES ($hostna
2630: 6d 65 2c 20 24 6e 6f 77 2c 20 24 3a 3a 61 70 70  me, $now, $::app
2640: 66 73 3a 3a 6e 74 74 6c 29 3b 7d 0a 0a 09 09 69  fs::nttl);}....i
2650: 66 20 7b 21 5b 69 6e 66 6f 20 65 78 69 73 74 73  f {![info exists
2660: 20 69 6e 64 65 78 68 61 73 68 5f 64 61 74 61 5d   indexhash_data]
2670: 7d 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 2d 63  } {....return -c
2680: 6f 64 65 20 65 72 72 6f 72 20 22 55 6e 61 62 6c  ode error "Unabl
2690: 65 20 74 6f 20 66 65 74 63 68 20 24 75 72 6c 22  e to fetch $url"
26a0: 0a 09 09 7d 0a 0a 09 09 73 65 74 20 69 6e 64 65  ...}....set inde
26b0: 78 68 61 73 68 5f 64 61 74 61 20 5b 73 74 72 69  xhash_data [stri
26c0: 6e 67 20 74 72 69 6d 20 24 69 6e 64 65 78 68 61  ng trim $indexha
26d0: 73 68 5f 64 61 74 61 20 22 5c 72 5c 6e 22 5d 0a  sh_data "\r\n"].
26e0: 09 09 73 65 74 20 69 6e 64 65 78 68 61 73 68 5f  ..set indexhash_
26f0: 64 61 74 61 20 5b 73 70 6c 69 74 20 24 69 6e 64  data [split $ind
2700: 65 78 68 61 73 68 5f 64 61 74 61 20 22 2c 22 5d  exhash_data ","]
2710: 0a 09 09 73 65 74 20 69 6e 64 65 78 68 61 73 68  ...set indexhash
2720: 20 20 20 20 20 20 20 5b 6c 69 6e 64 65 78 20 24         [lindex $
2730: 69 6e 64 65 78 68 61 73 68 5f 64 61 74 61 20 30  indexhash_data 0
2740: 5d 0a 09 09 73 65 74 20 69 6e 64 65 78 68 61 73  ]...set indexhas
2750: 68 6d 65 74 68 6f 64 20 5b 6c 69 6e 64 65 78 20  hmethod [lindex 
2760: 24 69 6e 64 65 78 68 61 73 68 5f 64 61 74 61 20  $indexhash_data 
2770: 31 5d 0a 09 09 73 65 74 20 69 6e 64 65 78 68 61  1]...set indexha
2780: 73 68 63 65 72 74 20 20 20 5b 6c 69 6e 64 65 78  shcert   [lindex
2790: 20 24 69 6e 64 65 78 68 61 73 68 5f 64 61 74 61   $indexhash_data
27a0: 20 32 5d 0a 09 09 73 65 74 20 69 6e 64 65 78 68   2]...set indexh
27b0: 61 73 68 73 69 67 20 20 20 20 5b 6c 69 6e 64 65  ashsig    [linde
27c0: 78 20 24 69 6e 64 65 78 68 61 73 68 5f 64 61 74  x $indexhash_dat
27d0: 61 20 33 5d 0a 0a 09 09 69 66 20 7b 21 5b 5f 69  a 3]....if {![_i
27e0: 73 48 61 73 68 20 24 69 6e 64 65 78 68 61 73 68  sHash $indexhash
27f0: 5d 7d 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 2d  ]} {....return -
2800: 63 6f 64 65 20 65 72 72 6f 72 20 22 49 6e 76 61  code error "Inva
2810: 6c 69 64 20 68 61 73 68 3a 20 24 69 6e 64 65 78  lid hash: $index
2820: 68 61 73 68 22 0a 09 09 7d 0a 0a 09 09 69 66 20  hash"...}....if 
2830: 7b 21 5b 5f 76 65 72 69 66 79 53 69 67 6e 61 74  {![_verifySignat
2840: 75 72 65 41 6e 64 43 65 72 74 69 66 69 63 61 74  ureAndCertificat
2850: 65 20 24 68 6f 73 74 6e 61 6d 65 20 24 69 6e 64  e $hostname $ind
2860: 65 78 68 61 73 68 63 65 72 74 20 24 69 6e 64 65  exhashcert $inde
2870: 78 68 61 73 68 73 69 67 20 24 69 6e 64 65 78 68  xhashsig $indexh
2880: 61 73 68 20 24 69 6e 64 65 78 68 61 73 68 6d 65  ash $indexhashme
2890: 74 68 6f 64 5d 7d 20 7b 0a 09 09 09 72 65 74 75  thod]} {....retu
28a0: 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22  rn -code error "
28b0: 49 6e 76 61 6c 69 64 20 73 69 67 6e 61 74 75 72  Invalid signatur
28c0: 65 20 6f 72 20 63 65 72 74 69 66 69 63 61 74 65  e or certificate
28d0: 20 66 72 6f 6d 20 24 68 6f 73 74 6e 61 6d 65 22   from $hostname"
28e0: 0a 09 09 7d 0a 0a 09 09 73 65 74 20 66 69 6c 65  ...}....set file
28f0: 20 5b 64 6f 77 6e 6c 6f 61 64 20 24 68 6f 73 74   [download $host
2900: 6e 61 6d 65 20 24 69 6e 64 65 78 68 61 73 68 20  name $indexhash 
2910: 24 69 6e 64 65 78 68 61 73 68 6d 65 74 68 6f 64  $indexhashmethod
2920: 5d 0a 09 09 63 61 74 63 68 20 7b 0a 09 09 09 73  ]...catch {....s
2930: 65 74 20 66 64 20 5b 6f 70 65 6e 20 24 66 69 6c  et fd [open $fil
2940: 65 5d 0a 09 09 7d 0a 0a 09 09 69 66 20 7b 21 5b  e]...}....if {![
2950: 69 6e 66 6f 20 65 78 69 73 74 73 20 66 64 5d 7d  info exists fd]}
2960: 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 2d 63 6f   {....return -co
2970: 64 65 20 65 72 72 6f 72 20 22 55 6e 61 62 6c 65  de error "Unable
2980: 20 74 6f 20 64 6f 77 6e 6c 6f 61 64 20 6f 72 20   to download or 
2990: 6f 70 65 6e 20 24 66 69 6c 65 22 0a 09 09 7d 0a  open $file"...}.
29a0: 0a 09 09 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70  ...unset -nocomp
29b0: 6c 61 69 6e 20 64 61 74 61 0a 09 09 63 61 74 63  lain data...catc
29c0: 68 20 7b 0a 09 09 09 73 65 74 20 64 61 74 61 20  h {....set data 
29d0: 5b 72 65 61 64 20 24 66 64 5d 0a 09 09 7d 0a 0a  [read $fd]...}..
29e0: 09 09 63 6c 6f 73 65 20 24 66 64 0a 0a 09 09 73  ..close $fd....s
29f0: 65 74 20 63 75 72 72 5f 70 61 63 6b 61 67 65 73  et curr_packages
2a00: 20 5b 6c 69 73 74 5d 0a 09 09 66 6f 72 65 61 63   [list]...foreac
2a10: 68 20 6c 69 6e 65 20 5b 73 70 6c 69 74 20 24 64  h line [split $d
2a20: 61 74 61 20 22 5c 6e 22 5d 20 7b 0a 09 09 09 73  ata "\n"] {....s
2a30: 65 74 20 6c 69 6e 65 20 5b 73 74 72 69 6e 67 20  et line [string 
2a40: 74 72 69 6d 20 24 6c 69 6e 65 5d 0a 0a 09 09 09  trim $line].....
2a50: 69 66 20 7b 5b 73 74 72 69 6e 67 20 6d 61 74 63  if {[string matc
2a60: 68 20 22 2a 2f 2a 22 20 24 6c 69 6e 65 5d 7d 20  h "*/*" $line]} 
2a70: 7b 0a 09 09 09 09 63 6f 6e 74 69 6e 75 65 0a 09  {.....continue..
2a80: 09 09 7d 0a 0a 09 09 09 69 66 20 7b 24 6c 69 6e  ..}.....if {$lin
2a90: 65 20 3d 3d 20 22 22 7d 20 7b 0a 09 09 09 09 63  e == ""} {.....c
2aa0: 6f 6e 74 69 6e 75 65 0a 09 09 09 7d 0a 0a 09 09  ontinue....}....
2ab0: 09 73 65 74 20 77 6f 72 6b 20 5b 73 70 6c 69 74  .set work [split
2ac0: 20 24 6c 69 6e 65 20 22 2c 22 5d 0a 0a 09 09 09   $line ","].....
2ad0: 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69  unset -nocomplai
2ae0: 6e 20 70 6b 67 49 6e 66 6f 0a 09 09 09 69 66 20  n pkgInfo....if 
2af0: 7b 5b 63 61 74 63 68 20 7b 0a 09 09 09 09 73 65  {[catch {.....se
2b00: 74 20 70 6b 67 49 6e 66 6f 28 70 61 63 6b 61 67  t pkgInfo(packag
2b10: 65 29 20 20 5b 6c 69 6e 64 65 78 20 24 77 6f 72  e)  [lindex $wor
2b20: 6b 20 30 5d 0a 09 09 09 09 73 65 74 20 70 6b 67  k 0].....set pkg
2b30: 49 6e 66 6f 28 76 65 72 73 69 6f 6e 29 20 20 5b  Info(version)  [
2b40: 6c 69 6e 64 65 78 20 24 77 6f 72 6b 20 31 5d 0a  lindex $work 1].
2b50: 09 09 09 09 73 65 74 20 70 6b 67 49 6e 66 6f 28  ....set pkgInfo(
2b60: 6f 73 29 20 20 20 20 20 20 20 5b 5f 6e 6f 72 6d  os)       [_norm
2b70: 61 6c 69 7a 65 4f 53 20 5b 6c 69 6e 64 65 78 20  alizeOS [lindex 
2b80: 24 77 6f 72 6b 20 32 5d 5d 0a 09 09 09 09 73 65  $work 2]].....se
2b90: 74 20 70 6b 67 49 6e 66 6f 28 63 70 75 41 72 63  t pkgInfo(cpuArc
2ba0: 68 29 20 20 5b 5f 6e 6f 72 6d 61 6c 69 7a 65 43  h)  [_normalizeC
2bb0: 50 55 20 5b 6c 69 6e 64 65 78 20 24 77 6f 72 6b  PU [lindex $work
2bc0: 20 33 5d 5d 0a 09 09 09 09 73 65 74 20 70 6b 67   3]].....set pkg
2bd0: 49 6e 66 6f 28 68 61 73 68 29 20 20 20 20 20 5b  Info(hash)     [
2be0: 73 74 72 69 6e 67 20 74 6f 6c 6f 77 65 72 20 5b  string tolower [
2bf0: 6c 69 6e 64 65 78 20 24 77 6f 72 6b 20 34 5d 5d  lindex $work 4]]
2c00: 0a 09 09 09 09 73 65 74 20 70 6b 67 49 6e 66 6f  .....set pkgInfo
2c10: 28 68 61 73 68 5f 74 79 70 65 29 20 24 69 6e 64  (hash_type) $ind
2c20: 65 78 68 61 73 68 6d 65 74 68 6f 64 0a 09 09 09  exhashmethod....
2c30: 09 73 65 74 20 70 6b 67 49 6e 66 6f 28 69 73 4c  .set pkgInfo(isL
2c40: 61 74 65 73 74 29 20 5b 65 78 70 72 20 7b 21 21  atest) [expr {!!
2c50: 5b 6c 69 6e 64 65 78 20 24 77 6f 72 6b 20 35 5d  [lindex $work 5]
2c60: 7d 5d 0a 09 09 09 7d 5d 7d 20 7b 0a 09 09 09 09  }]....}]} {.....
2c70: 63 6f 6e 74 69 6e 75 65 0a 09 09 09 7d 0a 0a 09  continue....}...
2c80: 09 09 69 66 20 7b 21 5b 5f 69 73 48 61 73 68 20  ..if {![_isHash 
2c90: 24 70 6b 67 49 6e 66 6f 28 68 61 73 68 29 5d 7d  $pkgInfo(hash)]}
2ca0: 20 7b 0a 09 09 09 09 63 6f 6e 74 69 6e 75 65 0a   {.....continue.
2cb0: 09 09 09 7d 0a 0a 09 09 09 6c 61 70 70 65 6e 64  ...}.....lappend
2cc0: 20 63 75 72 72 5f 70 61 63 6b 61 67 65 73 20 24   curr_packages $
2cd0: 70 6b 67 49 6e 66 6f 28 68 61 73 68 29 0a 0a 09  pkgInfo(hash)...
2ce0: 09 09 23 20 44 6f 20 6e 6f 74 20 64 6f 20 61 6e  ..# Do not do an
2cf0: 79 20 61 64 64 69 74 69 6f 6e 61 6c 20 77 6f 72  y additional wor
2d00: 6b 20 69 66 20 77 65 20 61 6c 72 65 61 64 79 20  k if we already 
2d10: 68 61 76 65 20 74 68 69 73 20 70 61 63 6b 61 67  have this packag
2d20: 65 0a 09 09 09 73 65 74 20 65 78 69 73 74 69 6e  e....set existin
2d30: 67 5f 70 61 63 6b 61 67 65 73 20 5b 64 62 20 65  g_packages [db e
2d40: 76 61 6c 20 7b 53 45 4c 45 43 54 20 70 61 63 6b  val {SELECT pack
2d50: 61 67 65 20 46 52 4f 4d 20 70 61 63 6b 61 67 65  age FROM package
2d60: 73 20 57 48 45 52 45 20 68 6f 73 74 6e 61 6d 65  s WHERE hostname
2d70: 20 3d 20 24 68 6f 73 74 6e 61 6d 65 20 41 4e 44   = $hostname AND
2d80: 20 70 61 63 6b 61 67 65 4d 61 6e 69 66 65 73 74   packageManifest
2d90: 48 61 73 68 20 3d 20 24 70 6b 67 49 6e 66 6f 28  Hash = $pkgInfo(
2da0: 68 61 73 68 29 3b 7d 5d 0a 09 09 09 69 66 20 7b  hash);}]....if {
2db0: 5b 6c 73 65 61 72 63 68 20 2d 65 78 61 63 74 20  [lsearch -exact 
2dc0: 24 65 78 69 73 74 69 6e 67 5f 70 61 63 6b 61 67  $existing_packag
2dd0: 65 73 20 24 70 6b 67 49 6e 66 6f 28 70 61 63 6b  es $pkgInfo(pack
2de0: 61 67 65 29 5d 20 21 3d 20 2d 31 7d 20 7b 0a 09  age)] != -1} {..
2df0: 09 09 09 63 6f 6e 74 69 6e 75 65 0a 09 09 09 7d  ...continue....}
2e00: 0a 0a 09 09 09 69 66 20 7b 24 70 6b 67 49 6e 66  .....if {$pkgInf
2e10: 6f 28 69 73 4c 61 74 65 73 74 29 7d 20 7b 0a 09  o(isLatest)} {..
2e20: 09 09 09 64 62 20 65 76 61 6c 20 7b 55 50 44 41  ...db eval {UPDA
2e30: 54 45 20 70 61 63 6b 61 67 65 73 20 53 45 54 20  TE packages SET 
2e40: 69 73 4c 61 74 65 73 74 20 3d 20 30 20 57 48 45  isLatest = 0 WHE
2e50: 52 45 20 68 6f 73 74 6e 61 6d 65 20 3d 20 24 68  RE hostname = $h
2e60: 6f 73 74 6e 61 6d 65 20 41 4e 44 20 70 61 63 6b  ostname AND pack
2e70: 61 67 65 20 3d 20 24 70 6b 67 49 6e 66 6f 28 70  age = $pkgInfo(p
2e80: 61 63 6b 61 67 65 29 20 41 4e 44 20 6f 73 20 3d  ackage) AND os =
2e90: 20 24 70 6b 67 49 6e 66 6f 28 6f 73 29 20 41 4e   $pkgInfo(os) AN
2ea0: 44 20 63 70 75 41 72 63 68 20 3d 20 24 70 6b 67  D cpuArch = $pkg
2eb0: 49 6e 66 6f 28 63 70 75 41 72 63 68 29 3b 7d 0a  Info(cpuArch);}.
2ec0: 09 09 09 7d 0a 0a 09 09 09 64 62 20 65 76 61 6c  ...}.....db eval
2ed0: 20 7b 49 4e 53 45 52 54 20 49 4e 54 4f 20 70 61   {INSERT INTO pa
2ee0: 63 6b 61 67 65 73 20 28 68 6f 73 74 6e 61 6d 65  ckages (hostname
2ef0: 2c 20 70 61 63 6b 61 67 65 4d 61 6e 69 66 65 73  , packageManifes
2f00: 74 48 61 73 68 2c 20 70 61 63 6b 61 67 65 2c 20  tHash, package, 
2f10: 76 65 72 73 69 6f 6e 2c 20 6f 73 2c 20 63 70 75  version, os, cpu
2f20: 41 72 63 68 2c 20 69 73 4c 61 74 65 73 74 2c 20  Arch, isLatest, 
2f30: 68 61 76 65 4d 61 6e 69 66 65 73 74 29 20 56 41  haveManifest) VA
2f40: 4c 55 45 53 20 28 24 68 6f 73 74 6e 61 6d 65 2c  LUES ($hostname,
2f50: 20 24 70 6b 67 49 6e 66 6f 28 68 61 73 68 29 2c   $pkgInfo(hash),
2f60: 20 24 70 6b 67 49 6e 66 6f 28 70 61 63 6b 61 67   $pkgInfo(packag
2f70: 65 29 2c 20 24 70 6b 67 49 6e 66 6f 28 76 65 72  e), $pkgInfo(ver
2f80: 73 69 6f 6e 29 2c 20 24 70 6b 67 49 6e 66 6f 28  sion), $pkgInfo(
2f90: 6f 73 29 2c 20 24 70 6b 67 49 6e 66 6f 28 63 70  os), $pkgInfo(cp
2fa0: 75 41 72 63 68 29 2c 20 24 70 6b 67 49 6e 66 6f  uArch), $pkgInfo
2fb0: 28 69 73 4c 61 74 65 73 74 29 2c 20 30 29 3b 7d  (isLatest), 0);}
2fc0: 0a 09 09 7d 0a 0a 09 09 23 20 4c 6f 6f 6b 20 66  ...}....# Look f
2fd0: 6f 72 20 70 61 63 6b 61 67 65 73 20 74 68 61 74  or packages that
2fe0: 20 68 61 76 65 20 62 65 65 6e 20 64 65 6c 65 74   have been delet
2ff0: 65 64 0a 09 09 73 65 74 20 66 6f 75 6e 64 5f 70  ed...set found_p
3000: 61 63 6b 61 67 65 73 20 5b 64 62 20 65 76 61 6c  ackages [db eval
3010: 20 7b 53 45 4c 45 43 54 20 73 68 61 31 20 46 52   {SELECT sha1 FR
3020: 4f 4d 20 70 61 63 6b 61 67 65 73 20 57 48 45 52  OM packages WHER
3030: 45 20 68 6f 73 74 6e 61 6d 65 20 3d 20 24 68 6f  E hostname = $ho
3040: 73 74 6e 61 6d 65 3b 7d 5d 0a 09 09 66 6f 72 65  stname;}]...fore
3050: 61 63 68 20 70 61 63 6b 61 67 65 20 24 66 6f 75  ach package $fou
3060: 6e 64 5f 70 61 63 6b 61 67 65 73 20 7b 0a 09 09  nd_packages {...
3070: 09 73 65 74 20 66 6f 75 6e 64 5f 70 61 63 6b 61  .set found_packa
3080: 67 65 73 5f 61 72 72 28 24 70 61 63 6b 61 67 65  ges_arr($package
3090: 29 20 31 0a 09 09 7d 0a 0a 09 09 66 6f 72 65 61  ) 1...}....forea
30a0: 63 68 20 70 61 63 6b 61 67 65 20 24 63 75 72 72  ch package $curr
30b0: 5f 70 61 63 6b 61 67 65 73 20 7b 0a 09 09 09 75  _packages {....u
30c0: 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e  nset -nocomplain
30d0: 20 66 6f 75 6e 64 5f 70 61 63 6b 61 67 65 73 5f   found_packages_
30e0: 61 72 72 28 24 70 61 63 6b 61 67 65 29 0a 09 09  arr($package)...
30f0: 7d 0a 0a 09 09 66 6f 72 65 61 63 68 20 70 61 63  }....foreach pac
3100: 6b 61 67 65 20 5b 61 72 72 61 79 20 6e 61 6d 65  kage [array name
3110: 73 20 66 6f 75 6e 64 5f 70 61 63 6b 61 67 65 73  s found_packages
3120: 5f 61 72 72 5d 20 7b 0a 09 09 09 64 62 20 65 76  _arr] {....db ev
3130: 61 6c 20 7b 44 45 4c 45 54 45 20 46 52 4f 4d 20  al {DELETE FROM 
3140: 70 61 63 6b 61 67 65 73 20 57 48 45 52 45 20 68  packages WHERE h
3150: 6f 73 74 6e 61 6d 65 20 3d 20 24 68 6f 73 74 6e  ostname = $hostn
3160: 61 6d 65 20 41 4e 44 20 70 61 63 6b 61 67 65 4d  ame AND packageM
3170: 61 6e 69 66 65 73 74 48 61 73 68 20 3d 20 24 70  anifestHash = $p
3180: 61 63 6b 61 67 65 3b 7d 0a 09 09 7d 0a 0a 09 09  ackage;}...}....
3190: 64 62 20 65 76 61 6c 20 7b 49 4e 53 45 52 54 20  db eval {INSERT 
31a0: 4f 52 20 52 45 50 4c 41 43 45 20 49 4e 54 4f 20  OR REPLACE INTO 
31b0: 73 69 74 65 73 20 28 68 6f 73 74 6e 61 6d 65 2c  sites (hostname,
31c0: 20 68 61 73 68 4d 65 74 68 6f 64 2c 20 6c 61 73   hashMethod, las
31d0: 74 55 70 64 61 74 65 2c 20 74 74 6c 29 20 56 41  tUpdate, ttl) VA
31e0: 4c 55 45 53 20 28 24 68 6f 73 74 6e 61 6d 65 2c  LUES ($hostname,
31f0: 20 24 69 6e 64 65 78 68 61 73 68 6d 65 74 68 6f   $indexhashmetho
3200: 64 2c 20 24 6e 6f 77 2c 20 24 3a 3a 61 70 70 66  d, $now, $::appf
3210: 73 3a 3a 74 74 6c 29 3b 7d 0a 0a 09 09 61 70 70  s::ttl);}....app
3220: 66 73 64 3a 3a 67 65 74 5f 70 61 74 68 5f 69 6e  fsd::get_path_in
3230: 66 6f 5f 63 61 63 68 65 5f 66 6c 75 73 68 0a 0a  fo_cache_flush..
3240: 09 09 72 65 74 75 72 6e 20 43 4f 4d 50 4c 45 54  ..return COMPLET
3250: 45 0a 09 7d 0a 0a 09 70 72 6f 63 20 67 65 74 70  E..}...proc getp
3260: 6b 67 6d 61 6e 69 66 65 73 74 20 7b 68 6f 73 74  kgmanifest {host
3270: 6e 61 6d 65 20 70 61 63 6b 61 67 65 4d 61 6e 69  name packageMani
3280: 66 65 73 74 48 61 73 68 7d 20 7b 0a 09 09 73 65  festHash} {...se
3290: 74 20 68 61 76 65 4d 61 6e 69 66 65 73 74 20 5b  t haveManifest [
32a0: 64 62 20 6f 6e 65 63 6f 6c 75 6d 6e 20 7b 53 45  db onecolumn {SE
32b0: 4c 45 43 54 20 68 61 76 65 4d 61 6e 69 66 65 73  LECT haveManifes
32c0: 74 20 46 52 4f 4d 20 70 61 63 6b 61 67 65 73 20  t FROM packages 
32d0: 57 48 45 52 45 20 70 61 63 6b 61 67 65 4d 61 6e  WHERE packageMan
32e0: 69 66 65 73 74 48 61 73 68 20 3d 20 24 70 61 63  ifestHash = $pac
32f0: 6b 61 67 65 4d 61 6e 69 66 65 73 74 48 61 73 68  kageManifestHash
3300: 20 4c 49 4d 49 54 20 31 3b 7d 5d 0a 09 09 73 65   LIMIT 1;}]...se
3310: 74 20 73 69 74 65 48 61 73 68 4d 65 74 68 6f 64  t siteHashMethod
3320: 20 5b 64 62 20 6f 6e 65 63 6f 6c 75 6d 6e 20 7b   [db onecolumn {
3330: 53 45 4c 45 43 54 20 68 61 73 68 4d 65 74 68 6f  SELECT hashMetho
3340: 64 20 46 52 4f 4d 20 73 69 74 65 73 20 57 48 45  d FROM sites WHE
3350: 52 45 20 68 6f 73 74 6e 61 6d 65 20 3d 20 24 68  RE hostname = $h
3360: 6f 73 74 6e 61 6d 65 20 4c 49 4d 49 54 20 31 3b  ostname LIMIT 1;
3370: 7d 0a 0a 09 09 69 66 20 7b 24 68 61 76 65 4d 61  }....if {$haveMa
3380: 6e 69 66 65 73 74 20 3d 3d 20 22 31 22 7d 20 7b  nifest == "1"} {
3390: 0a 09 09 09 72 65 74 75 72 6e 20 43 4f 4d 50 4c  ....return COMPL
33a0: 45 54 45 0a 09 09 7d 0a 0a 09 09 69 66 20 7b 21  ETE...}....if {!
33b0: 5b 5f 69 73 48 61 73 68 20 24 70 61 63 6b 61 67  [_isHash $packag
33c0: 65 4d 61 6e 69 66 65 73 74 48 61 73 68 5d 7d 20  eManifestHash]} 
33d0: 7b 0a 09 09 09 72 65 74 75 72 6e 20 46 41 49 4c  {....return FAIL
33e0: 0a 09 09 7d 0a 0a 09 09 73 65 74 20 66 69 6c 65  ...}....set file
33f0: 20 5b 64 6f 77 6e 6c 6f 61 64 20 24 68 6f 73 74   [download $host
3400: 6e 61 6d 65 20 24 70 61 63 6b 61 67 65 4d 61 6e  name $packageMan
3410: 69 66 65 73 74 48 61 73 68 20 24 73 69 74 65 48  ifestHash $siteH
3420: 61 73 68 4d 65 74 68 6f 64 5d 0a 0a 09 09 63 61  ashMethod]....ca
3430: 74 63 68 20 7b 0a 09 09 09 73 65 74 20 66 64 20  tch {....set fd 
3440: 5b 6f 70 65 6e 20 24 66 69 6c 65 5d 0a 09 09 7d  [open $file]...}
3450: 0a 0a 09 09 69 66 20 7b 21 5b 69 6e 66 6f 20 65  ....if {![info e
3460: 78 69 73 74 73 20 66 64 5d 7d 20 7b 0a 09 09 09  xists fd]} {....
3470: 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72 72  return -code err
3480: 6f 72 20 22 55 6e 61 62 6c 65 20 74 6f 20 64 6f  or "Unable to do
3490: 77 6e 6c 6f 61 64 20 6f 72 20 6f 70 65 6e 20 24  wnload or open $
34a0: 66 69 6c 65 22 0a 09 09 7d 0a 0a 09 09 63 61 74  file"...}....cat
34b0: 63 68 20 7b 0a 09 09 09 73 65 74 20 70 6b 67 64  ch {....set pkgd
34c0: 61 74 61 20 5b 72 65 61 64 20 24 66 64 5d 0a 09  ata [read $fd]..
34d0: 09 7d 0a 0a 09 09 63 6c 6f 73 65 20 24 66 64 0a  .}....close $fd.
34e0: 0a 09 09 64 62 20 74 72 61 6e 73 61 63 74 69 6f  ...db transactio
34f0: 6e 20 7b 0a 09 09 09 66 6f 72 65 61 63 68 20 6c  n {....foreach l
3500: 69 6e 65 20 5b 73 70 6c 69 74 20 24 70 6b 67 64  ine [split $pkgd
3510: 61 74 61 20 22 5c 6e 22 5d 20 7b 0a 09 09 09 09  ata "\n"] {.....
3520: 73 65 74 20 6c 69 6e 65 20 5b 73 74 72 69 6e 67  set line [string
3530: 20 74 72 69 6d 20 24 6c 69 6e 65 5d 0a 0a 09 09   trim $line]....
3540: 09 09 69 66 20 7b 24 6c 69 6e 65 20 3d 3d 20 22  ..if {$line == "
3550: 22 7d 20 7b 0a 09 09 09 09 09 63 6f 6e 74 69 6e  "} {......contin
3560: 75 65 0a 09 09 09 09 7d 0a 0a 09 09 09 09 73 65  ue.....}......se
3570: 74 20 77 6f 72 6b 20 5b 73 70 6c 69 74 20 24 6c  t work [split $l
3580: 69 6e 65 20 22 2c 22 5d 0a 0a 09 09 09 09 75 6e  ine ","]......un
3590: 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e 20  set -nocomplain 
35a0: 66 69 6c 65 49 6e 66 6f 0a 09 09 09 09 73 65 74  fileInfo.....set
35b0: 20 66 69 6c 65 49 6e 66 6f 28 74 79 70 65 29 20   fileInfo(type) 
35c0: 5b 6c 69 6e 64 65 78 20 24 77 6f 72 6b 20 30 5d  [lindex $work 0]
35d0: 0a 09 09 09 09 73 65 74 20 66 69 6c 65 49 6e 66  .....set fileInf
35e0: 6f 28 74 69 6d 65 29 20 5b 6c 69 6e 64 65 78 20  o(time) [lindex 
35f0: 24 77 6f 72 6b 20 31 5d 0a 0a 09 09 09 09 73 65  $work 1]......se
3600: 74 20 77 6f 72 6b 20 5b 6c 72 61 6e 67 65 20 24  t work [lrange $
3610: 77 6f 72 6b 20 32 20 65 6e 64 5d 0a 09 09 09 09  work 2 end].....
3620: 73 77 69 74 63 68 20 2d 2d 20 24 66 69 6c 65 49  switch -- $fileI
3630: 6e 66 6f 28 74 79 70 65 29 20 7b 0a 09 09 09 09  nfo(type) {.....
3640: 09 22 23 6d 61 6e 69 66 65 73 74 6d 65 74 61 64  ."#manifestmetad
3650: 61 74 61 22 20 7b 0a 09 09 09 09 09 09 75 6e 73  ata" {.......uns
3660: 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e 20 66  et -nocomplain f
3670: 69 6c 65 49 6e 66 6f 0a 09 09 09 09 09 09 63 6f  ileInfo.......co
3680: 6e 74 69 6e 75 65 0a 09 09 09 09 09 7d 0a 09 09  ntinue......}...
3690: 09 09 09 22 66 69 6c 65 22 20 7b 0a 09 09 09 09  ..."file" {.....
36a0: 09 09 73 65 74 20 66 69 6c 65 49 6e 66 6f 28 73  ..set fileInfo(s
36b0: 69 7a 65 29 20 5b 6c 69 6e 64 65 78 20 24 77 6f  ize) [lindex $wo
36c0: 72 6b 20 30 5d 0a 0a 09 09 09 09 09 09 23 20 57  rk 0]........# W
36d0: 65 20 6c 6f 77 65 72 2d 63 61 73 65 20 74 68 65  e lower-case the
36e0: 20 70 65 72 6d 69 73 73 69 6f 6e 73 20 62 65 63   permissions bec
36f0: 61 75 73 65 20 75 70 70 65 72 2d 63 61 73 65 20  ause upper-case 
3700: 70 65 72 6d 69 73 73 69 6f 6e 73 0a 09 09 09 09  permissions.....
3710: 09 09 23 20 73 68 6f 75 6c 64 20 6e 6f 74 20 62  ..# should not b
3720: 65 20 73 65 74 20 72 65 6d 6f 74 65 6c 79 20 61  e set remotely a
3730: 73 20 74 68 65 79 20 6d 61 79 20 69 6e 66 6c 75  s they may influ
3740: 65 6e 63 65 20 74 68 65 20 73 65 63 75 72 69 74  ence the securit
3750: 79 0a 09 09 09 09 09 09 23 20 6f 66 20 74 68 65  y.......# of the
3760: 20 73 79 73 74 65 6d 2e 0a 09 09 09 09 09 09 73   system........s
3770: 65 74 20 66 69 6c 65 49 6e 66 6f 28 70 65 72 6d  et fileInfo(perm
3780: 73 29 20 5b 73 74 72 69 6e 67 20 74 6f 6c 6f 77  s) [string tolow
3790: 65 72 20 5b 6c 69 6e 64 65 78 20 24 77 6f 72 6b  er [lindex $work
37a0: 20 31 5d 5d 0a 0a 09 09 09 09 09 09 73 65 74 20   1]]........set 
37b0: 66 69 6c 65 49 6e 66 6f 28 73 68 61 31 29 20 5b  fileInfo(sha1) [
37c0: 6c 69 6e 64 65 78 20 24 77 6f 72 6b 20 32 5d 0a  lindex $work 2].
37d0: 0a 09 09 09 09 09 09 73 65 74 20 77 6f 72 6b 20  .......set work 
37e0: 5b 6c 72 61 6e 67 65 20 24 77 6f 72 6b 20 33 20  [lrange $work 3 
37f0: 65 6e 64 5d 0a 09 09 09 09 09 7d 0a 09 09 09 09  end]......}.....
3800: 09 22 73 79 6d 6c 69 6e 6b 22 20 7b 0a 09 09 09  ."symlink" {....
3810: 09 09 09 73 65 74 20 66 69 6c 65 49 6e 66 6f 28  ...set fileInfo(
3820: 73 6f 75 72 63 65 29 20 5b 6c 69 6e 64 65 78 20  source) [lindex 
3830: 24 77 6f 72 6b 20 30 5d 0a 09 09 09 09 09 09 73  $work 0].......s
3840: 65 74 20 77 6f 72 6b 20 5b 6c 72 61 6e 67 65 20  et work [lrange 
3850: 24 77 6f 72 6b 20 31 20 65 6e 64 5d 0a 09 09 09  $work 1 end]....
3860: 09 09 7d 0a 09 09 09 09 09 22 64 69 72 65 63 74  ..}......"direct
3870: 6f 72 79 22 20 7b 0a 09 09 09 09 09 09 23 20 4e  ory" {.......# N
3880: 6f 20 65 78 74 72 61 20 64 61 74 61 20 72 65 71  o extra data req
3890: 75 69 72 65 64 0a 09 09 09 09 09 7d 0a 09 09 09  uired......}....
38a0: 09 09 64 65 66 61 75 6c 74 20 7b 0a 09 09 09 09  ..default {.....
38b0: 09 09 23 20 48 61 6e 64 6c 65 20 75 6e 6b 6e 6f  ..# Handle unkno
38c0: 77 6e 20 74 79 70 65 73 0a 09 09 09 09 09 09 69  wn types.......i
38d0: 66 20 7b 5b 73 74 72 69 6e 67 20 69 6e 64 65 78  f {[string index
38e0: 20 24 66 69 6c 65 49 6e 66 6f 28 74 79 70 65 29   $fileInfo(type)
38f0: 20 30 5d 20 3d 3d 20 22 23 22 7d 20 7b 0a 09 09   0] == "#"} {...
3900: 09 09 09 09 09 23 20 4d 65 74 61 64 61 74 61 20  .....# Metadata 
3910: 74 79 70 65 2c 20 69 67 6e 6f 72 65 0a 09 09 09  type, ignore....
3920: 09 09 09 09 23 20 69 74 20 69 66 20 77 65 20 64  ....# it if we d
3930: 6f 6e 27 74 0a 09 09 09 09 09 09 09 23 20 75 6e  on't........# un
3940: 64 65 72 73 74 61 6e 64 20 74 68 69 73 20 74 79  derstand this ty
3950: 70 65 0a 09 09 09 09 09 09 09 63 6f 6e 74 69 6e  pe........contin
3960: 75 65 0a 09 09 09 09 09 09 7d 20 65 6c 73 65 20  ue.......} else 
3970: 7b 0a 09 09 09 09 09 09 09 23 20 55 6e 6b 6e 6f  {........# Unkno
3980: 77 6e 20 74 79 70 65 2c 0a 09 09 09 09 09 09 09  wn type,........
3990: 23 20 67 65 6e 65 72 61 74 65 20 61 6e 20 65 72  # generate an er
39a0: 72 6f 72 0a 09 09 09 09 09 09 09 65 72 72 6f 72  ror........error
39b0: 20 22 4d 61 6e 69 66 65 73 74 20 63 61 6e 6e 6f   "Manifest canno
39c0: 74 20 62 65 20 70 61 72 73 65 64 22 0a 09 09 09  t be parsed"....
39d0: 09 09 09 7d 0a 09 09 09 09 09 7d 0a 09 09 09 09  ...}......}.....
39e0: 7d 0a 0a 09 09 09 09 73 65 74 20 66 69 6c 65 49  }......set fileI
39f0: 6e 66 6f 28 6e 61 6d 65 29 20 5b 6a 6f 69 6e 20  nfo(name) [join 
3a00: 24 77 6f 72 6b 20 22 2c 22 5d 0a 09 09 09 09 73  $work ","].....s
3a10: 65 74 20 66 69 6c 65 49 6e 66 6f 28 6e 61 6d 65  et fileInfo(name
3a20: 29 20 5b 73 70 6c 69 74 20 5b 73 74 72 69 6e 67  ) [split [string
3a30: 20 74 72 69 6d 20 24 66 69 6c 65 49 6e 66 6f 28   trim $fileInfo(
3a40: 6e 61 6d 65 29 20 22 2f 22 5d 20 22 2f 22 5d 0a  name) "/"] "/"].
3a50: 09 09 09 09 73 65 74 20 66 69 6c 65 49 6e 66 6f  ....set fileInfo
3a60: 28 64 69 72 65 63 74 6f 72 79 29 20 5b 6a 6f 69  (directory) [joi
3a70: 6e 20 5b 6c 72 61 6e 67 65 20 24 66 69 6c 65 49  n [lrange $fileI
3a80: 6e 66 6f 28 6e 61 6d 65 29 20 30 20 65 6e 64 2d  nfo(name) 0 end-
3a90: 31 5d 20 22 2f 22 5d 0a 09 09 09 09 73 65 74 20  1] "/"].....set 
3aa0: 66 69 6c 65 49 6e 66 6f 28 6e 61 6d 65 29 20 5b  fileInfo(name) [
3ab0: 6c 69 6e 64 65 78 20 24 66 69 6c 65 49 6e 66 6f  lindex $fileInfo
3ac0: 28 6e 61 6d 65 29 20 65 6e 64 5d 0a 0a 09 09 09  (name) end].....
3ad0: 09 64 62 20 65 76 61 6c 20 7b 49 4e 53 45 52 54  .db eval {INSERT
3ae0: 20 49 4e 54 4f 20 66 69 6c 65 73 20 28 70 61 63   INTO files (pac
3af0: 6b 61 67 65 5f 73 68 61 31 2c 20 74 79 70 65 2c  kage_sha1, type,
3b00: 20 74 69 6d 65 2c 20 73 6f 75 72 63 65 2c 20 73   time, source, s
3b10: 69 7a 65 2c 20 70 65 72 6d 73 2c 20 66 69 6c 65  ize, perms, file
3b20: 5f 73 68 61 31 2c 20 66 69 6c 65 5f 6e 61 6d 65  _sha1, file_name
3b30: 2c 20 66 69 6c 65 5f 64 69 72 65 63 74 6f 72 79  , file_directory
3b40: 29 20 56 41 4c 55 45 53 20 28 24 70 61 63 6b 61  ) VALUES ($packa
3b50: 67 65 5f 73 68 61 31 2c 20 24 66 69 6c 65 49 6e  ge_sha1, $fileIn
3b60: 66 6f 28 74 79 70 65 29 2c 20 24 66 69 6c 65 49  fo(type), $fileI
3b70: 6e 66 6f 28 74 69 6d 65 29 2c 20 24 66 69 6c 65  nfo(time), $file
3b80: 49 6e 66 6f 28 73 6f 75 72 63 65 29 2c 20 24 66  Info(source), $f
3b90: 69 6c 65 49 6e 66 6f 28 73 69 7a 65 29 2c 20 24  ileInfo(size), $
3ba0: 66 69 6c 65 49 6e 66 6f 28 70 65 72 6d 73 29 2c  fileInfo(perms),
3bb0: 20 24 66 69 6c 65 49 6e 66 6f 28 73 68 61 31 29   $fileInfo(sha1)
3bc0: 2c 20 24 66 69 6c 65 49 6e 66 6f 28 6e 61 6d 65  , $fileInfo(name
3bd0: 29 2c 20 24 66 69 6c 65 49 6e 66 6f 28 64 69 72  ), $fileInfo(dir
3be0: 65 63 74 6f 72 79 29 20 29 3b 7d 0a 09 09 09 09  ectory) );}.....
3bf0: 64 62 20 65 76 61 6c 20 7b 55 50 44 41 54 45 20  db eval {UPDATE 
3c00: 70 61 63 6b 61 67 65 73 20 53 45 54 20 68 61 76  packages SET hav
3c10: 65 4d 61 6e 69 66 65 73 74 20 3d 20 31 20 57 48  eManifest = 1 WH
3c20: 45 52 45 20 73 68 61 31 20 3d 20 24 70 61 63 6b  ERE sha1 = $pack
3c30: 61 67 65 5f 73 68 61 31 3b 7d 0a 09 09 09 7d 0a  age_sha1;}....}.
3c40: 09 09 7d 0a 0a 09 09 61 70 70 66 73 64 3a 3a 67  ..}....appfsd::g
3c50: 65 74 5f 70 61 74 68 5f 69 6e 66 6f 5f 63 61 63  et_path_info_cac
3c60: 68 65 5f 66 6c 75 73 68 0a 0a 09 09 72 65 74 75  he_flush....retu
3c70: 72 6e 20 43 4f 4d 50 4c 45 54 45 0a 09 7d 0a 0a  rn COMPLETE..}..
3c80: 09 70 72 6f 63 20 5f 6c 6f 63 61 6c 70 61 74 68  .proc _localpath
3c90: 20 7b 70 61 63 6b 61 67 65 20 68 6f 73 74 6e 61   {package hostna
3ca0: 6d 65 20 66 69 6c 65 7d 20 7b 0a 09 09 73 65 74  me file} {...set
3cb0: 20 64 69 72 20 22 22 0a 09 09 63 61 74 63 68 20   dir ""...catch 
3cc0: 7b 0a 09 09 09 73 65 74 20 68 6f 6d 65 64 69 72  {....set homedir
3cd0: 20 5b 3a 3a 61 70 70 66 73 3a 3a 75 73 65 72 3a   [::appfs::user:
3ce0: 3a 67 65 74 5f 68 6f 6d 65 64 69 72 5d 0a 09 09  :get_homedir]...
3cf0: 09 73 65 74 20 64 69 72 20 5b 66 69 6c 65 20 6a  .set dir [file j
3d00: 6f 69 6e 20 24 68 6f 6d 65 64 69 72 20 2e 61 70  oin $homedir .ap
3d10: 70 66 73 20 22 2e 2f 24 7b 70 61 63 6b 61 67 65  pfs "./${package
3d20: 7d 40 24 7b 68 6f 73 74 6e 61 6d 65 7d 22 20 22  }@${hostname}" "
3d30: 2e 2f 24 7b 66 69 6c 65 7d 22 5d 0a 09 09 7d 0a  ./${file}"]...}.
3d40: 09 09 72 65 74 75 72 6e 20 24 64 69 72 0a 09 7d  ..return $dir..}
3d50: 0a 0a 09 70 72 6f 63 20 5f 77 68 69 74 65 6f 75  ...proc _whiteou
3d60: 74 70 61 74 68 20 7b 70 61 63 6b 61 67 65 20 68  tpath {package h
3d70: 6f 73 74 6e 61 6d 65 20 66 69 6c 65 7d 20 7b 0a  ostname file} {.
3d80: 09 09 73 65 74 20 64 69 72 20 22 22 0a 09 09 63  ..set dir ""...c
3d90: 61 74 63 68 20 7b 0a 09 09 09 73 65 74 20 68 6f  atch {....set ho
3da0: 6d 65 64 69 72 20 5b 3a 3a 61 70 70 66 73 3a 3a  medir [::appfs::
3db0: 75 73 65 72 3a 3a 67 65 74 5f 68 6f 6d 65 64 69  user::get_homedi
3dc0: 72 5d 0a 09 09 09 73 65 74 20 64 69 72 20 5b 66  r]....set dir [f
3dd0: 69 6c 65 20 6a 6f 69 6e 20 24 68 6f 6d 65 64 69  ile join $homedi
3de0: 72 20 2e 61 70 70 66 73 20 22 2e 2f 24 7b 70 61  r .appfs "./${pa
3df0: 63 6b 61 67 65 7d 40 24 7b 68 6f 73 74 6e 61 6d  ckage}@${hostnam
3e00: 65 7d 22 20 22 2e 41 50 50 46 53 2e 57 48 49 54  e}" ".APPFS.WHIT
3e10: 45 4f 55 54 22 20 22 2e 2f 24 7b 66 69 6c 65 7d  EOUT" "./${file}
3e20: 2e 41 50 50 46 53 2e 57 48 49 54 45 4f 55 54 22  .APPFS.WHITEOUT"
3e30: 5d 0a 09 09 7d 0a 09 09 72 65 74 75 72 6e 20 24  ]...}...return $
3e40: 64 69 72 0a 09 7d 0a 0a 09 70 72 6f 63 20 5f 70  dir..}...proc _p
3e50: 61 72 73 65 70 61 74 68 20 7b 70 61 74 68 7d 20  arsepath {path} 
3e60: 7b 0a 09 09 73 65 74 20 70 61 74 68 20 5b 73 74  {...set path [st
3e70: 72 69 6e 67 20 74 72 69 6d 20 24 70 61 74 68 20  ring trim $path 
3e80: 22 2f 22 5d 0a 09 09 73 65 74 20 70 61 74 68 20  "/"]...set path 
3e90: 5b 73 70 6c 69 74 20 24 70 61 74 68 20 22 2f 22  [split $path "/"
3ea0: 5d 0a 09 09 73 65 74 20 70 61 74 68 6c 65 6e 20  ]...set pathlen 
3eb0: 5b 6c 6c 65 6e 67 74 68 20 24 70 61 74 68 5d 0a  [llength $path].
3ec0: 0a 09 09 61 72 72 61 79 20 73 65 74 20 72 65 74  ...array set ret
3ed0: 76 61 6c 20 5b 6c 69 73 74 20 5f 63 68 69 6c 64  val [list _child
3ee0: 72 65 6e 20 73 69 74 65 73 20 5f 74 79 70 65 20  ren sites _type 
3ef0: 74 6f 70 6c 65 76 65 6c 5d 0a 0a 09 09 69 66 20  toplevel]....if 
3f00: 7b 24 70 61 74 68 6c 65 6e 20 3e 20 30 7d 20 7b  {$pathlen > 0} {
3f10: 0a 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 68  ....set retval(h
3f20: 6f 73 74 6e 61 6d 65 29 20 5b 6c 69 6e 64 65 78  ostname) [lindex
3f30: 20 24 70 61 74 68 20 30 5d 0a 09 09 09 73 65 74   $path 0]....set
3f40: 20 72 65 74 76 61 6c 28 5f 63 68 69 6c 64 72 65   retval(_childre
3f50: 6e 29 20 70 61 63 6b 61 67 65 73 0a 09 09 09 73  n) packages....s
3f60: 65 74 20 72 65 74 76 61 6c 28 5f 74 79 70 65 29  et retval(_type)
3f70: 20 73 69 74 65 73 0a 0a 09 09 09 69 66 20 7b 24   sites.....if {$
3f80: 70 61 74 68 6c 65 6e 20 3e 20 31 7d 20 7b 0a 09  pathlen > 1} {..
3f90: 09 09 09 73 65 74 20 70 61 63 6b 61 67 65 20 5b  ...set package [
3fa0: 6c 69 6e 64 65 78 20 24 70 61 74 68 20 31 5d 0a  lindex $path 1].
3fb0: 09 09 09 09 69 66 20 7b 5b 73 74 72 69 6e 67 20  ....if {[string 
3fc0: 6c 65 6e 67 74 68 20 24 70 61 63 6b 61 67 65 5d  length $package]
3fd0: 20 3d 3d 20 22 34 30 22 20 26 26 20 5b 72 65 67   == "40" && [reg
3fe0: 65 78 70 20 7b 5e 5b 61 2d 66 41 2d 46 30 2d 39  exp {^[a-fA-F0-9
3ff0: 5d 2a 24 7d 20 24 70 61 63 6b 61 67 65 5d 7d 20  ]*$} $package]} 
4000: 7b 0a 09 09 09 09 09 73 65 74 20 72 65 74 76 61  {......set retva
4010: 6c 28 70 61 63 6b 61 67 65 5f 73 68 61 31 29 20  l(package_sha1) 
4020: 24 70 61 63 6b 61 67 65 0a 09 09 09 09 09 73 65  $package......se
4030: 74 20 72 65 74 76 61 6c 28 5f 63 68 69 6c 64 72  t retval(_childr
4040: 65 6e 29 20 66 69 6c 65 73 0a 09 09 09 09 09 73  en) files......s
4050: 65 74 20 72 65 74 76 61 6c 28 5f 74 79 70 65 29  et retval(_type)
4060: 20 66 69 6c 65 73 0a 0a 09 09 09 09 09 3a 3a 61   files.......::a
4070: 70 70 66 73 3a 3a 64 62 20 65 76 61 6c 20 7b 53  ppfs::db eval {S
4080: 45 4c 45 43 54 20 70 61 63 6b 61 67 65 2c 20 6f  ELECT package, o
4090: 73 2c 20 63 70 75 41 72 63 68 2c 20 76 65 72 73  s, cpuArch, vers
40a0: 69 6f 6e 20 46 52 4f 4d 20 70 61 63 6b 61 67 65  ion FROM package
40b0: 73 20 57 48 45 52 45 20 73 68 61 31 20 3d 20 24  s WHERE sha1 = $
40c0: 72 65 74 76 61 6c 28 70 61 63 6b 61 67 65 5f 73  retval(package_s
40d0: 68 61 31 29 3b 7d 20 70 6b 67 69 6e 66 6f 20 7b  ha1);} pkginfo {
40e0: 7d 0a 09 09 09 09 09 73 65 74 20 72 65 74 76 61  }......set retva
40f0: 6c 28 70 61 63 6b 61 67 65 29 20 24 70 6b 67 69  l(package) $pkgi
4100: 6e 66 6f 28 70 61 63 6b 61 67 65 29 0a 09 09 09  nfo(package)....
4110: 09 09 73 65 74 20 72 65 74 76 61 6c 28 6f 73 29  ..set retval(os)
4120: 20 24 70 6b 67 69 6e 66 6f 28 6f 73 29 0a 09 09   $pkginfo(os)...
4130: 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 63 70  ...set retval(cp
4140: 75 29 20 24 70 6b 67 69 6e 66 6f 28 63 70 75 41  u) $pkginfo(cpuA
4150: 72 63 68 29 0a 09 09 09 09 09 73 65 74 20 72 65  rch)......set re
4160: 74 76 61 6c 28 76 65 72 73 69 6f 6e 29 20 24 70  tval(version) $p
4170: 6b 67 69 6e 66 6f 28 76 65 72 73 69 6f 6e 29 0a  kginfo(version).
4180: 0a 09 09 09 09 09 69 66 20 7b 24 70 61 74 68 6c  ......if {$pathl
4190: 65 6e 20 3e 20 32 7d 20 7b 0a 09 09 09 09 09 09  en > 2} {.......
41a0: 73 65 74 20 72 65 74 76 61 6c 28 66 69 6c 65 29  set retval(file)
41b0: 20 5b 6a 6f 69 6e 20 5b 6c 72 61 6e 67 65 20 24   [join [lrange $
41c0: 70 61 74 68 20 32 20 65 6e 64 5d 20 22 2f 22 5d  path 2 end] "/"]
41d0: 0a 09 09 09 09 09 7d 20 65 6c 73 65 20 7b 0a 09  ......} else {..
41e0: 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28  .....set retval(
41f0: 66 69 6c 65 29 20 22 22 0a 09 09 09 09 09 7d 0a  file) ""......}.
4200: 09 09 09 09 7d 20 65 6c 73 65 20 7b 0a 09 09 09  ....} else {....
4210: 09 09 73 65 74 20 72 65 74 76 61 6c 28 70 61 63  ..set retval(pac
4220: 6b 61 67 65 29 20 24 70 61 63 6b 61 67 65 0a 09  kage) $package..
4230: 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 5f  ....set retval(_
4240: 63 68 69 6c 64 72 65 6e 29 20 6f 73 2d 63 70 75  children) os-cpu
4250: 0a 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c  ......set retval
4260: 28 5f 74 79 70 65 29 20 70 61 63 6b 61 67 65 73  (_type) packages
4270: 0a 0a 09 09 09 09 09 69 66 20 7b 24 70 61 74 68  .......if {$path
4280: 6c 65 6e 20 3e 20 32 7d 20 7b 0a 09 09 09 09 09  len > 2} {......
4290: 09 73 65 74 20 6f 73 5f 63 70 75 20 5b 6c 69 6e  .set os_cpu [lin
42a0: 64 65 78 20 24 70 61 74 68 20 32 5d 0a 09 09 09  dex $path 2]....
42b0: 09 09 09 73 65 74 20 6f 73 5f 63 70 75 20 5b 73  ...set os_cpu [s
42c0: 70 6c 69 74 20 24 6f 73 5f 63 70 75 20 22 2d 22  plit $os_cpu "-"
42d0: 5d 0a 0a 09 09 09 09 09 09 73 65 74 20 72 65 74  ]........set ret
42e0: 76 61 6c 28 6f 73 29 20 5b 5f 6e 6f 72 6d 61 6c  val(os) [_normal
42f0: 69 7a 65 4f 53 20 5b 6c 69 6e 64 65 78 20 24 6f  izeOS [lindex $o
4300: 73 5f 63 70 75 20 30 5d 20 31 5d 0a 09 09 09 09  s_cpu 0] 1].....
4310: 09 09 73 65 74 20 72 65 74 76 61 6c 28 63 70 75  ..set retval(cpu
4320: 29 20 5b 5f 6e 6f 72 6d 61 6c 69 7a 65 43 50 55  ) [_normalizeCPU
4330: 20 5b 6c 69 6e 64 65 78 20 24 6f 73 5f 63 70 75   [lindex $os_cpu
4340: 20 31 5d 20 31 5d 0a 09 09 09 09 09 09 73 65 74   1] 1].......set
4350: 20 72 65 74 76 61 6c 28 5f 63 68 69 6c 64 72 65   retval(_childre
4360: 6e 29 20 76 65 72 73 69 6f 6e 73 0a 09 09 09 09  n) versions.....
4370: 09 09 73 65 74 20 72 65 74 76 61 6c 28 5f 74 79  ..set retval(_ty
4380: 70 65 29 20 6f 73 2d 63 70 75 0a 0a 09 09 09 09  pe) os-cpu......
4390: 09 09 69 66 20 7b 24 70 61 74 68 6c 65 6e 20 3e  ..if {$pathlen >
43a0: 20 33 7d 20 7b 0a 09 09 09 09 09 09 09 73 65 74   3} {........set
43b0: 20 72 65 74 76 61 6c 28 76 65 72 73 69 6f 6e 29   retval(version)
43c0: 20 5b 6c 69 6e 64 65 78 20 24 70 61 74 68 20 33   [lindex $path 3
43d0: 5d 0a 09 09 09 09 09 09 09 73 65 74 20 72 65 74  ]........set ret
43e0: 76 61 6c 28 5f 63 68 69 6c 64 72 65 6e 29 20 66  val(_children) f
43f0: 69 6c 65 73 0a 09 09 09 09 09 09 09 73 65 74 20  iles........set 
4400: 72 65 74 76 61 6c 28 5f 74 79 70 65 29 20 76 65  retval(_type) ve
4410: 72 73 69 6f 6e 73 0a 0a 09 09 09 09 09 09 09 73  rsions.........s
4420: 65 74 20 72 65 74 76 61 6c 28 70 61 63 6b 61 67  et retval(packag
4430: 65 5f 73 68 61 31 29 20 5b 3a 3a 61 70 70 66 73  e_sha1) [::appfs
4440: 3a 3a 64 62 20 6f 6e 65 63 6f 6c 75 6d 6e 20 7b  ::db onecolumn {
4450: 53 45 4c 45 43 54 20 73 68 61 31 20 46 52 4f 4d  SELECT sha1 FROM
4460: 20 70 61 63 6b 61 67 65 73 20 57 48 45 52 45 20   packages WHERE 
4470: 68 6f 73 74 6e 61 6d 65 20 3d 20 24 72 65 74 76  hostname = $retv
4480: 61 6c 28 68 6f 73 74 6e 61 6d 65 29 20 41 4e 44  al(hostname) AND
4490: 20 70 61 63 6b 61 67 65 20 3d 20 24 72 65 74 76   package = $retv
44a0: 61 6c 28 70 61 63 6b 61 67 65 29 20 41 4e 44 20  al(package) AND 
44b0: 6f 73 20 3d 20 24 72 65 74 76 61 6c 28 6f 73 29  os = $retval(os)
44c0: 20 41 4e 44 20 63 70 75 41 72 63 68 20 3d 20 24   AND cpuArch = $
44d0: 72 65 74 76 61 6c 28 63 70 75 29 20 41 4e 44 20  retval(cpu) AND 
44e0: 76 65 72 73 69 6f 6e 20 3d 20 24 72 65 74 76 61  version = $retva
44f0: 6c 28 76 65 72 73 69 6f 6e 29 3b 7d 5d 0a 09 09  l(version);}]...
4500: 09 09 09 09 09 69 66 20 7b 24 72 65 74 76 61 6c  .....if {$retval
4510: 28 70 61 63 6b 61 67 65 5f 73 68 61 31 29 20 3d  (package_sha1) =
4520: 3d 20 22 22 7d 20 7b 0a 09 09 09 09 09 09 09 09  = ""} {.........
4530: 73 65 74 20 72 65 74 76 61 6c 28 5f 63 68 69 6c  set retval(_chil
4540: 64 72 65 6e 29 20 64 65 61 64 0a 09 09 09 09 09  dren) dead......
4550: 09 09 09 72 65 74 75 72 6e 20 5b 61 72 72 61 79  ...return [array
4560: 20 67 65 74 20 72 65 74 76 61 6c 5d 0a 09 09 09   get retval]....
4570: 09 09 09 09 7d 0a 0a 09 09 09 09 09 09 09 69 66  ....}.........if
4580: 20 7b 24 70 61 74 68 6c 65 6e 20 3e 20 34 7d 20   {$pathlen > 4} 
4590: 7b 0a 09 09 09 09 09 09 09 09 73 65 74 20 72 65  {.........set re
45a0: 74 76 61 6c 28 5f 74 79 70 65 29 20 66 69 6c 65  tval(_type) file
45b0: 73 0a 09 09 09 09 09 09 09 09 73 65 74 20 72 65  s.........set re
45c0: 74 76 61 6c 28 66 69 6c 65 29 20 5b 6a 6f 69 6e  tval(file) [join
45d0: 20 5b 6c 72 61 6e 67 65 20 24 70 61 74 68 20 34   [lrange $path 4
45e0: 20 65 6e 64 5d 20 22 2f 22 5d 0a 09 09 09 09 09   end] "/"]......
45f0: 09 09 7d 20 65 6c 73 65 20 7b 0a 09 09 09 09 09  ..} else {......
4600: 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 5f 74  ...set retval(_t
4610: 79 70 65 29 20 66 69 6c 65 73 0a 09 09 09 09 09  ype) files......
4620: 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 66 69  ...set retval(fi
4630: 6c 65 29 20 22 22 0a 09 09 09 09 09 09 09 7d 0a  le) ""........}.
4640: 09 09 09 09 09 09 7d 0a 09 09 09 09 09 7d 0a 09  ......}......}..
4650: 09 09 09 7d 0a 09 09 09 7d 0a 09 09 7d 0a 0a 09  ...}....}...}...
4660: 09 72 65 74 75 72 6e 20 5b 61 72 72 61 79 20 67  .return [array g
4670: 65 74 20 72 65 74 76 61 6c 5d 0a 09 7d 0a 0a 09  et retval]..}...
4680: 70 72 6f 63 20 67 65 74 63 68 69 6c 64 72 65 6e  proc getchildren
4690: 20 7b 64 69 72 7d 20 7b 0a 09 09 61 72 72 61 79   {dir} {...array
46a0: 20 73 65 74 20 70 61 74 68 69 6e 66 6f 20 5b 5f   set pathinfo [_
46b0: 70 61 72 73 65 70 61 74 68 20 24 64 69 72 5d 0a  parsepath $dir].
46c0: 0a 09 09 73 77 69 74 63 68 20 2d 2d 20 24 70 61  ...switch -- $pa
46d0: 74 68 69 6e 66 6f 28 5f 63 68 69 6c 64 72 65 6e  thinfo(_children
46e0: 29 20 7b 0a 09 09 09 22 73 69 74 65 73 22 20 7b  ) {...."sites" {
46f0: 0a 09 09 09 09 72 65 74 75 72 6e 20 5b 3a 3a 61  .....return [::a
4700: 70 70 66 73 3a 3a 64 62 20 65 76 61 6c 20 7b 53  ppfs::db eval {S
4710: 45 4c 45 43 54 20 44 49 53 54 49 4e 43 54 20 68  ELECT DISTINCT h
4720: 6f 73 74 6e 61 6d 65 20 46 52 4f 4d 20 70 61 63  ostname FROM pac
4730: 6b 61 67 65 73 3b 7d 5d 0a 09 09 09 7d 0a 09 09  kages;}]....}...
4740: 09 22 70 61 63 6b 61 67 65 73 22 20 7b 0a 09 09  ."packages" {...
4750: 09 09 63 61 74 63 68 20 7b 0a 09 09 09 09 09 3a  ..catch {......:
4760: 3a 61 70 70 66 73 3a 3a 67 65 74 69 6e 64 65 78  :appfs::getindex
4770: 20 24 70 61 74 68 69 6e 66 6f 28 68 6f 73 74 6e   $pathinfo(hostn
4780: 61 6d 65 29 0a 09 09 09 09 7d 0a 0a 09 09 09 09  ame).....}......
4790: 72 65 74 75 72 6e 20 5b 3a 3a 61 70 70 66 73 3a  return [::appfs:
47a0: 3a 64 62 20 65 76 61 6c 20 7b 53 45 4c 45 43 54  :db eval {SELECT
47b0: 20 44 49 53 54 49 4e 43 54 20 70 61 63 6b 61 67   DISTINCT packag
47c0: 65 20 46 52 4f 4d 20 70 61 63 6b 61 67 65 73 20  e FROM packages 
47d0: 57 48 45 52 45 20 68 6f 73 74 6e 61 6d 65 20 3d  WHERE hostname =
47e0: 20 24 70 61 74 68 69 6e 66 6f 28 68 6f 73 74 6e   $pathinfo(hostn
47f0: 61 6d 65 29 3b 7d 5d 0a 09 09 09 7d 0a 09 09 09  ame);}]....}....
4800: 22 6f 73 2d 63 70 75 22 20 7b 0a 09 09 09 09 73  "os-cpu" {.....s
4810: 65 74 20 72 65 74 76 61 6c 20 5b 3a 3a 61 70 70  et retval [::app
4820: 66 73 3a 3a 64 62 20 65 76 61 6c 20 7b 53 45 4c  fs::db eval {SEL
4830: 45 43 54 20 44 49 53 54 49 4e 43 54 20 6f 73 20  ECT DISTINCT os 
4840: 7c 7c 20 22 2d 22 20 7c 7c 20 63 70 75 41 72 63  || "-" || cpuArc
4850: 68 20 46 52 4f 4d 20 70 61 63 6b 61 67 65 73 20  h FROM packages 
4860: 57 48 45 52 45 20 68 6f 73 74 6e 61 6d 65 20 3d  WHERE hostname =
4870: 20 24 70 61 74 68 69 6e 66 6f 28 68 6f 73 74 6e   $pathinfo(hostn
4880: 61 6d 65 29 20 41 4e 44 20 70 61 63 6b 61 67 65  ame) AND package
4890: 20 3d 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63   = $pathinfo(pac
48a0: 6b 61 67 65 29 3b 7d 5d 0a 0a 09 09 09 09 6c 61  kage);}]......la
48b0: 70 70 65 6e 64 20 72 65 74 76 61 6c 20 22 70 6c  ppend retval "pl
48c0: 61 74 66 6f 72 6d 22 0a 0a 09 09 09 09 72 65 74  atform"......ret
48d0: 75 72 6e 20 24 72 65 74 76 61 6c 0a 09 09 09 7d  urn $retval....}
48e0: 0a 09 09 09 22 76 65 72 73 69 6f 6e 73 22 20 7b  ...."versions" {
48f0: 0a 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 20  .....set retval 
4900: 5b 3a 3a 61 70 70 66 73 3a 3a 64 62 20 65 76 61  [::appfs::db eva
4910: 6c 20 7b 0a 09 09 09 09 09 53 45 4c 45 43 54 20  l {......SELECT 
4920: 44 49 53 54 49 4e 43 54 20 76 65 72 73 69 6f 6e  DISTINCT version
4930: 20 46 52 4f 4d 20 70 61 63 6b 61 67 65 73 20 57   FROM packages W
4940: 48 45 52 45 20 68 6f 73 74 6e 61 6d 65 20 3d 20  HERE hostname = 
4950: 24 70 61 74 68 69 6e 66 6f 28 68 6f 73 74 6e 61  $pathinfo(hostna
4960: 6d 65 29 20 41 4e 44 20 70 61 63 6b 61 67 65 20  me) AND package 
4970: 3d 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63 6b  = $pathinfo(pack
4980: 61 67 65 29 20 41 4e 44 20 6f 73 20 3d 20 24 70  age) AND os = $p
4990: 61 74 68 69 6e 66 6f 28 6f 73 29 20 41 4e 44 20  athinfo(os) AND 
49a0: 63 70 75 41 72 63 68 20 3d 20 24 70 61 74 68 69  cpuArch = $pathi
49b0: 6e 66 6f 28 63 70 75 29 3b 0a 09 09 09 09 7d 5d  nfo(cpu);.....}]
49c0: 0a 0a 09 09 09 09 3a 3a 61 70 70 66 73 3a 3a 64  ......::appfs::d
49d0: 62 20 65 76 61 6c 20 7b 53 45 4c 45 43 54 20 76  b eval {SELECT v
49e0: 65 72 73 69 6f 6e 20 46 52 4f 4d 20 70 61 63 6b  ersion FROM pack
49f0: 61 67 65 73 20 57 48 45 52 45 20 69 73 4c 61 74  ages WHERE isLat
4a00: 65 73 74 20 3d 20 31 20 41 4e 44 20 68 6f 73 74  est = 1 AND host
4a10: 6e 61 6d 65 20 3d 20 24 70 61 74 68 69 6e 66 6f  name = $pathinfo
4a20: 28 68 6f 73 74 6e 61 6d 65 29 20 41 4e 44 20 70  (hostname) AND p
4a30: 61 63 6b 61 67 65 20 3d 20 24 70 61 74 68 69 6e  ackage = $pathin
4a40: 66 6f 28 70 61 63 6b 61 67 65 29 20 41 4e 44 20  fo(package) AND 
4a50: 6f 73 20 3d 20 24 70 61 74 68 69 6e 66 6f 28 6f  os = $pathinfo(o
4a60: 73 29 20 41 4e 44 20 63 70 75 41 72 63 68 20 3d  s) AND cpuArch =
4a70: 20 24 70 61 74 68 69 6e 66 6f 28 63 70 75 29 20   $pathinfo(cpu) 
4a80: 4c 49 4d 49 54 20 31 3b 7d 20 6c 61 74 65 73 74  LIMIT 1;} latest
4a90: 5f 69 6e 66 6f 20 7b 7d 0a 0a 09 09 09 09 69 66  _info {}......if
4aa0: 20 7b 5b 69 6e 66 6f 20 65 78 69 73 74 73 20 6c   {[info exists l
4ab0: 61 74 65 73 74 5f 69 6e 66 6f 28 76 65 72 73 69  atest_info(versi
4ac0: 6f 6e 29 5d 7d 20 7b 0a 09 09 09 09 09 6c 61 70  on)]} {......lap
4ad0: 70 65 6e 64 20 72 65 74 76 61 6c 20 22 6c 61 74  pend retval "lat
4ae0: 65 73 74 22 0a 09 09 09 09 7d 0a 0a 09 09 09 09  est".....}......
4af0: 72 65 74 75 72 6e 20 24 72 65 74 76 61 6c 0a 09  return $retval..
4b00: 09 09 7d 0a 09 09 09 22 66 69 6c 65 73 22 20 7b  ..}...."files" {
4b10: 0a 09 09 09 09 63 61 74 63 68 20 7b 0a 09 09 09  .....catch {....
4b20: 09 09 3a 3a 61 70 70 66 73 3a 3a 67 65 74 69 6e  ..::appfs::getin
4b30: 64 65 78 20 24 70 61 74 68 69 6e 66 6f 28 68 6f  dex $pathinfo(ho
4b40: 73 74 6e 61 6d 65 29 0a 09 09 09 09 09 3a 3a 61  stname)......::a
4b50: 70 70 66 73 3a 3a 67 65 74 70 6b 67 6d 61 6e 69  ppfs::getpkgmani
4b60: 66 65 73 74 20 24 70 61 74 68 69 6e 66 6f 28 68  fest $pathinfo(h
4b70: 6f 73 74 6e 61 6d 65 29 20 24 70 61 74 68 69 6e  ostname) $pathin
4b80: 66 6f 28 70 61 63 6b 61 67 65 5f 73 68 61 31 29  fo(package_sha1)
4b90: 0a 09 09 09 09 7d 0a 0a 09 09 09 09 73 65 74 20  .....}......set 
4ba0: 72 65 74 76 61 6c 20 5b 3a 3a 61 70 70 66 73 3a  retval [::appfs:
4bb0: 3a 64 62 20 65 76 61 6c 20 7b 53 45 4c 45 43 54  :db eval {SELECT
4bc0: 20 44 49 53 54 49 4e 43 54 20 66 69 6c 65 5f 6e   DISTINCT file_n
4bd0: 61 6d 65 20 46 52 4f 4d 20 66 69 6c 65 73 20 57  ame FROM files W
4be0: 48 45 52 45 20 70 61 63 6b 61 67 65 5f 73 68 61  HERE package_sha
4bf0: 31 20 3d 20 24 70 61 74 68 69 6e 66 6f 28 70 61  1 = $pathinfo(pa
4c00: 63 6b 61 67 65 5f 73 68 61 31 29 20 41 4e 44 20  ckage_sha1) AND 
4c10: 66 69 6c 65 5f 64 69 72 65 63 74 6f 72 79 20 3d  file_directory =
4c20: 20 24 70 61 74 68 69 6e 66 6f 28 66 69 6c 65 29   $pathinfo(file)
4c30: 3b 7d 5d 0a 0a 09 09 09 09 69 66 20 7b 5b 69 6e  ;}]......if {[in
4c40: 66 6f 20 65 78 69 73 74 73 20 70 61 74 68 69 6e  fo exists pathin
4c50: 66 6f 28 70 61 63 6b 61 67 65 29 5d 20 26 26 20  fo(package)] && 
4c60: 5b 69 6e 66 6f 20 65 78 69 73 74 73 20 70 61 74  [info exists pat
4c70: 68 69 6e 66 6f 28 68 6f 73 74 6e 61 6d 65 29 5d  hinfo(hostname)]
4c80: 20 26 26 20 5b 69 6e 66 6f 20 65 78 69 73 74 73   && [info exists
4c90: 20 70 61 74 68 69 6e 66 6f 28 66 69 6c 65 29 5d   pathinfo(file)]
4ca0: 7d 20 7b 0a 09 09 09 09 09 5f 61 73 5f 75 73 65  } {......_as_use
4cb0: 72 20 7b 0a 09 09 09 09 09 09 73 65 74 20 64 69  r {.......set di
4cc0: 72 20 5b 5f 6c 6f 63 61 6c 70 61 74 68 20 24 70  r [_localpath $p
4cd0: 61 74 68 69 6e 66 6f 28 70 61 63 6b 61 67 65 29  athinfo(package)
4ce0: 20 24 70 61 74 68 69 6e 66 6f 28 68 6f 73 74 6e   $pathinfo(hostn
4cf0: 61 6d 65 29 20 24 70 61 74 68 69 6e 66 6f 28 66  ame) $pathinfo(f
4d00: 69 6c 65 29 5d 0a 09 09 09 09 09 09 73 65 74 20  ile)].......set 
4d10: 77 68 69 74 65 6f 75 74 64 69 72 20 5b 73 74 72  whiteoutdir [str
4d20: 69 6e 67 20 72 61 6e 67 65 20 5b 5f 77 68 69 74  ing range [_whit
4d30: 65 6f 75 74 70 61 74 68 20 24 70 61 74 68 69 6e  eoutpath $pathin
4d40: 66 6f 28 70 61 63 6b 61 67 65 29 20 24 70 61 74  fo(package) $pat
4d50: 68 69 6e 66 6f 28 68 6f 73 74 6e 61 6d 65 29 20  hinfo(hostname) 
4d60: 24 70 61 74 68 69 6e 66 6f 28 66 69 6c 65 29 5d  $pathinfo(file)]
4d70: 20 30 20 65 6e 64 2d 31 35 5d 0a 0a 09 09 09 09   0 end-15]......
4d80: 09 09 69 66 20 7b 24 77 68 69 74 65 6f 75 74 64  ..if {$whiteoutd
4d90: 69 72 20 21 3d 20 22 22 7d 20 7b 0a 09 09 09 09  ir != ""} {.....
4da0: 09 09 09 66 6f 72 65 61 63 68 20 66 69 6c 65 20  ...foreach file 
4db0: 5b 67 6c 6f 62 20 2d 6e 6f 63 6f 6d 70 6c 61 69  [glob -nocomplai
4dc0: 6e 20 2d 74 61 69 6c 73 20 2d 64 69 72 65 63 74  n -tails -direct
4dd0: 6f 72 79 20 24 77 68 69 74 65 6f 75 74 64 69 72  ory $whiteoutdir
4de0: 20 7b 7b 2e 2c 7d 2a 2e 41 50 50 46 53 2e 57 48   {{.,}*.APPFS.WH
4df0: 49 54 45 4f 55 54 7d 5d 20 7b 0a 09 09 09 09 09  ITEOUT}] {......
4e00: 09 09 09 73 65 74 20 72 65 6d 6f 76 65 20 5b 73  ...set remove [s
4e10: 74 72 69 6e 67 20 72 61 6e 67 65 20 24 66 69 6c  tring range $fil
4e20: 65 20 30 20 65 6e 64 2d 31 35 5d 0a 09 09 09 09  e 0 end-15].....
4e30: 09 09 09 09 73 65 74 20 69 64 78 20 5b 6c 73 65  ....set idx [lse
4e40: 61 72 63 68 20 2d 65 78 61 63 74 20 24 72 65 74  arch -exact $ret
4e50: 76 61 6c 20 24 72 65 6d 6f 76 65 5d 0a 09 09 09  val $remove]....
4e60: 09 09 09 09 09 69 66 20 7b 24 69 64 78 20 21 3d  .....if {$idx !=
4e70: 20 2d 31 7d 20 7b 0a 09 09 09 09 09 09 09 09 09   -1} {..........
4e80: 73 65 74 20 72 65 74 76 61 6c 20 5b 6c 72 65 70  set retval [lrep
4e90: 6c 61 63 65 20 24 72 65 74 76 61 6c 20 24 69 64  lace $retval $id
4ea0: 78 20 24 69 64 78 5d 0a 09 09 09 09 09 09 09 09  x $idx].........
4eb0: 7d 0a 09 09 09 09 09 09 09 7d 0a 09 09 09 09 09  }........}......
4ec0: 09 7d 0a 0a 09 09 09 09 09 09 69 66 20 7b 24 64  .}........if {$d
4ed0: 69 72 20 21 3d 20 22 22 7d 20 7b 0a 09 09 09 09  ir != ""} {.....
4ee0: 09 09 09 66 6f 72 65 61 63 68 20 66 69 6c 65 20  ...foreach file 
4ef0: 5b 67 6c 6f 62 20 2d 6e 6f 63 6f 6d 70 6c 61 69  [glob -nocomplai
4f00: 6e 20 2d 74 61 69 6c 73 20 2d 64 69 72 65 63 74  n -tails -direct
4f10: 6f 72 79 20 24 64 69 72 20 7b 7b 2e 2c 7d 2a 7d  ory $dir {{.,}*}
4f20: 5d 20 7b 0a 09 09 09 09 09 09 09 09 69 66 20 7b  ] {.........if {
4f30: 24 66 69 6c 65 20 3d 3d 20 22 2e 22 20 7c 7c 20  $file == "." || 
4f40: 24 66 69 6c 65 20 3d 3d 20 22 2e 2e 22 7d 20 7b  $file == ".."} {
4f50: 0a 09 09 09 09 09 09 09 09 09 63 6f 6e 74 69 6e  ..........contin
4f60: 75 65 0a 09 09 09 09 09 09 09 09 7d 0a 0a 09 09  ue.........}....
4f70: 09 09 09 09 09 09 69 66 20 7b 24 66 69 6c 65 20  ......if {$file 
4f80: 3d 3d 20 22 2e 41 50 50 46 53 2e 57 48 49 54 45  == ".APPFS.WHITE
4f90: 4f 55 54 22 7d 20 7b 0a 09 09 09 09 09 09 09 09  OUT"} {.........
4fa0: 09 63 6f 6e 74 69 6e 75 65 0a 09 09 09 09 09 09  .continue.......
4fb0: 09 09 7d 0a 0a 09 09 09 09 09 09 09 09 69 66 20  ..}..........if 
4fc0: 7b 5b 6c 73 65 61 72 63 68 20 2d 65 78 61 63 74  {[lsearch -exact
4fd0: 20 24 72 65 74 76 61 6c 20 24 66 69 6c 65 5d 20   $retval $file] 
4fe0: 21 3d 20 2d 31 7d 20 7b 0a 09 09 09 09 09 09 09  != -1} {........
4ff0: 09 09 63 6f 6e 74 69 6e 75 65 0a 09 09 09 09 09  ..continue......
5000: 09 09 09 7d 0a 0a 09 09 09 09 09 09 09 09 6c 61  ...}..........la
5010: 70 70 65 6e 64 20 72 65 74 76 61 6c 20 24 66 69  ppend retval $fi
5020: 6c 65 0a 09 09 09 09 09 09 09 7d 0a 09 09 09 09  le........}.....
5030: 09 09 7d 0a 09 09 09 09 09 7d 0a 09 09 09 09 7d  ..}......}.....}
5040: 0a 0a 09 09 09 09 72 65 74 75 72 6e 20 24 72 65  ......return $re
5050: 74 76 61 6c 0a 09 09 09 7d 0a 09 09 7d 0a 0a 09  tval....}...}...
5060: 09 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72  .return -code er
5070: 72 6f 72 20 22 49 6e 76 61 6c 69 64 20 6f 72 20  ror "Invalid or 
5080: 75 6e 61 63 63 65 70 74 61 62 6c 65 20 70 61 74  unacceptable pat
5090: 68 3a 20 24 64 69 72 22 0a 09 7d 0a 0a 09 70 72  h: $dir"..}...pr
50a0: 6f 63 20 67 65 74 61 74 74 72 20 7b 70 61 74 68  oc getattr {path
50b0: 7d 20 7b 0a 09 09 61 72 72 61 79 20 73 65 74 20  } {...array set 
50c0: 70 61 74 68 69 6e 66 6f 20 5b 5f 70 61 72 73 65  pathinfo [_parse
50d0: 70 61 74 68 20 24 70 61 74 68 5d 0a 09 09 61 72  path $path]...ar
50e0: 72 61 79 20 73 65 74 20 72 65 74 76 61 6c 20 5b  ray set retval [
50f0: 6c 69 73 74 5d 0a 0a 09 09 63 61 74 63 68 20 7b  list]....catch {
5100: 0a 09 09 09 3a 3a 61 70 70 66 73 3a 3a 67 65 74  ....::appfs::get
5110: 69 6e 64 65 78 20 24 70 61 74 68 69 6e 66 6f 28  index $pathinfo(
5120: 68 6f 73 74 6e 61 6d 65 29 0a 09 09 09 3a 3a 61  hostname)....::a
5130: 70 70 66 73 3a 3a 67 65 74 70 6b 67 6d 61 6e 69  ppfs::getpkgmani
5140: 66 65 73 74 20 24 70 61 74 68 69 6e 66 6f 28 68  fest $pathinfo(h
5150: 6f 73 74 6e 61 6d 65 29 20 24 70 61 74 68 69 6e  ostname) $pathin
5160: 66 6f 28 70 61 63 6b 61 67 65 5f 73 68 61 31 29  fo(package_sha1)
5170: 0a 09 09 7d 0a 0a 09 09 73 65 74 20 72 65 74 76  ...}....set retv
5180: 61 6c 28 70 61 74 68 5f 74 79 70 65 29 20 24 70  al(path_type) $p
5190: 61 74 68 69 6e 66 6f 28 5f 74 79 70 65 29 0a 0a  athinfo(_type)..
51a0: 09 09 73 77 69 74 63 68 20 2d 2d 20 24 70 61 74  ..switch -- $pat
51b0: 68 69 6e 66 6f 28 5f 74 79 70 65 29 20 7b 0a 09  hinfo(_type) {..
51c0: 09 09 22 74 6f 70 6c 65 76 65 6c 22 20 7b 0a 09  .."toplevel" {..
51d0: 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 74 79  ...set retval(ty
51e0: 70 65 29 20 64 69 72 65 63 74 6f 72 79 0a 09 09  pe) directory...
51f0: 09 09 73 65 74 20 72 65 74 76 61 6c 28 63 68 69  ..set retval(chi
5200: 6c 64 63 6f 75 6e 74 29 20 5b 6c 6c 65 6e 67 74  ldcount) [llengt
5210: 68 20 5b 67 65 74 63 68 69 6c 64 72 65 6e 20 24  h [getchildren $
5220: 70 61 74 68 5d 5d 0a 09 09 09 7d 0a 09 09 09 22  path]]....}...."
5230: 73 69 74 65 73 22 20 7b 0a 09 09 09 09 73 65 74  sites" {.....set
5240: 20 63 68 65 63 6b 20 5b 3a 3a 61 70 70 66 73 3a   check [::appfs:
5250: 3a 64 62 20 6f 6e 65 63 6f 6c 75 6d 6e 20 7b 53  :db onecolumn {S
5260: 45 4c 45 43 54 20 31 20 46 52 4f 4d 20 70 61 63  ELECT 1 FROM pac
5270: 6b 61 67 65 73 20 57 48 45 52 45 20 68 6f 73 74  kages WHERE host
5280: 6e 61 6d 65 20 3d 20 24 70 61 74 68 69 6e 66 6f  name = $pathinfo
5290: 28 68 6f 73 74 6e 61 6d 65 29 3b 7d 5d 0a 09 09  (hostname);}]...
52a0: 09 09 69 66 20 7b 24 63 68 65 63 6b 20 3d 3d 20  ..if {$check == 
52b0: 22 31 22 7d 20 7b 0a 09 09 09 09 09 73 65 74 20  "1"} {......set 
52c0: 72 65 74 76 61 6c 28 74 79 70 65 29 20 64 69 72  retval(type) dir
52d0: 65 63 74 6f 72 79 0a 09 09 09 09 09 73 65 74 20  ectory......set 
52e0: 72 65 74 76 61 6c 28 63 68 69 6c 64 63 6f 75 6e  retval(childcoun
52f0: 74 29 20 30 0a 09 09 09 09 7d 0a 09 09 09 7d 0a  t) 0.....}....}.
5300: 09 09 09 22 70 61 63 6b 61 67 65 73 22 20 7b 0a  ..."packages" {.
5310: 09 09 09 09 73 65 74 20 63 68 65 63 6b 20 5b 3a  ....set check [:
5320: 3a 61 70 70 66 73 3a 3a 64 62 20 6f 6e 65 63 6f  :appfs::db oneco
5330: 6c 75 6d 6e 20 7b 53 45 4c 45 43 54 20 31 20 46  lumn {SELECT 1 F
5340: 52 4f 4d 20 70 61 63 6b 61 67 65 73 20 57 48 45  ROM packages WHE
5350: 52 45 20 68 6f 73 74 6e 61 6d 65 20 3d 20 24 70  RE hostname = $p
5360: 61 74 68 69 6e 66 6f 28 68 6f 73 74 6e 61 6d 65  athinfo(hostname
5370: 29 20 41 4e 44 20 70 61 63 6b 61 67 65 20 3d 20  ) AND package = 
5380: 24 70 61 74 68 69 6e 66 6f 28 70 61 63 6b 61 67  $pathinfo(packag
5390: 65 29 3b 7d 5d 0a 09 09 09 09 69 66 20 7b 24 63  e);}].....if {$c
53a0: 68 65 63 6b 20 3d 3d 20 22 31 22 7d 20 7b 0a 09  heck == "1"} {..
53b0: 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 74  ....set retval(t
53c0: 79 70 65 29 20 64 69 72 65 63 74 6f 72 79 0a 09  ype) directory..
53d0: 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 63  ....set retval(c
53e0: 68 69 6c 64 63 6f 75 6e 74 29 20 5b 6c 6c 65 6e  hildcount) [llen
53f0: 67 74 68 20 5b 67 65 74 63 68 69 6c 64 72 65 6e  gth [getchildren
5400: 20 24 70 61 74 68 5d 5d 0a 09 09 09 09 7d 0a 09   $path]].....}..
5410: 09 09 7d 0a 09 09 09 22 6f 73 2d 63 70 75 22 20  ..}...."os-cpu" 
5420: 7b 0a 09 09 09 09 69 66 20 7b 24 70 61 74 68 69  {.....if {$pathi
5430: 6e 66 6f 28 6f 73 29 20 3d 3d 20 22 70 6c 61 74  nfo(os) == "plat
5440: 66 6f 72 6d 22 20 26 26 20 24 70 61 74 68 69 6e  form" && $pathin
5450: 66 6f 28 63 70 75 29 20 3d 3d 20 22 22 7d 20 7b  fo(cpu) == ""} {
5460: 0a 09 09 09 09 09 73 65 74 20 63 68 65 63 6b 20  ......set check 
5470: 5b 3a 3a 61 70 70 66 73 3a 3a 64 62 20 65 76 61  [::appfs::db eva
5480: 6c 20 7b 0a 09 09 09 09 09 09 53 45 4c 45 43 54  l {.......SELECT
5490: 20 44 49 53 54 49 4e 43 54 20 6f 73 2c 20 63 70   DISTINCT os, cp
54a0: 75 41 72 63 68 20 46 52 4f 4d 20 70 61 63 6b 61  uArch FROM packa
54b0: 67 65 73 20 57 48 45 52 45 20 68 6f 73 74 6e 61  ges WHERE hostna
54c0: 6d 65 20 3d 20 24 70 61 74 68 69 6e 66 6f 28 68  me = $pathinfo(h
54d0: 6f 73 74 6e 61 6d 65 29 20 41 4e 44 20 70 61 63  ostname) AND pac
54e0: 6b 61 67 65 20 3d 20 24 70 61 74 68 69 6e 66 6f  kage = $pathinfo
54f0: 28 70 61 63 6b 61 67 65 29 3b 0a 09 09 09 09 09  (package);......
5500: 7d 5d 0a 0a 09 09 09 09 09 73 65 74 20 72 65 74  }].......set ret
5510: 76 61 6c 28 74 79 70 65 29 20 73 79 6d 6c 69 6e  val(type) symlin
5520: 6b 0a 0a 09 09 09 09 09 69 66 20 7b 24 63 68 65  k.......if {$che
5530: 63 6b 20 3d 3d 20 5b 6c 69 73 74 20 22 6e 6f 61  ck == [list "noa
5540: 72 63 68 22 20 22 6e 6f 61 72 63 68 22 5d 7d 20  rch" "noarch"]} 
5550: 7b 0a 09 09 09 09 09 09 73 65 74 20 72 65 74 76  {.......set retv
5560: 61 6c 28 73 6f 75 72 63 65 29 20 22 6e 6f 61 72  al(source) "noar
5570: 63 68 2d 6e 6f 61 72 63 68 22 0a 09 09 09 09 09  ch-noarch"......
5580: 7d 20 65 6c 73 65 20 7b 0a 09 09 09 09 09 09 73  } else {.......s
5590: 65 74 20 72 65 74 76 61 6c 28 73 6f 75 72 63 65  et retval(source
55a0: 29 20 24 3a 3a 61 70 70 66 73 3a 3a 70 6c 61 74  ) $::appfs::plat
55b0: 66 6f 72 6d 0a 09 09 09 09 09 7d 0a 09 09 09 09  form......}.....
55c0: 7d 20 65 6c 73 65 20 7b 0a 09 09 09 09 09 73 65  } else {......se
55d0: 74 20 63 68 65 63 6b 20 5b 3a 3a 61 70 70 66 73  t check [::appfs
55e0: 3a 3a 64 62 20 6f 6e 65 63 6f 6c 75 6d 6e 20 7b  ::db onecolumn {
55f0: 0a 09 09 09 09 09 09 53 45 4c 45 43 54 20 31 20  .......SELECT 1 
5600: 46 52 4f 4d 20 70 61 63 6b 61 67 65 73 20 57 48  FROM packages WH
5610: 45 52 45 20 68 6f 73 74 6e 61 6d 65 20 3d 20 24  ERE hostname = $
5620: 70 61 74 68 69 6e 66 6f 28 68 6f 73 74 6e 61 6d  pathinfo(hostnam
5630: 65 29 20 41 4e 44 20 70 61 63 6b 61 67 65 20 3d  e) AND package =
5640: 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63 6b 61   $pathinfo(packa
5650: 67 65 29 20 41 4e 44 20 6f 73 20 3d 20 24 70 61  ge) AND os = $pa
5660: 74 68 69 6e 66 6f 28 6f 73 29 20 41 4e 44 20 63  thinfo(os) AND c
5670: 70 75 41 72 63 68 20 3d 20 24 70 61 74 68 69 6e  puArch = $pathin
5680: 66 6f 28 63 70 75 29 3b 0a 09 09 09 09 09 7d 5d  fo(cpu);......}]
5690: 0a 09 09 09 09 09 69 66 20 7b 24 63 68 65 63 6b  ......if {$check
56a0: 20 3d 3d 20 22 31 22 7d 20 7b 0a 09 09 09 09 09   == "1"} {......
56b0: 09 73 65 74 20 72 65 74 76 61 6c 28 74 79 70 65  .set retval(type
56c0: 29 20 64 69 72 65 63 74 6f 72 79 0a 09 09 09 09  ) directory.....
56d0: 09 09 73 65 74 20 72 65 74 76 61 6c 28 63 68 69  ..set retval(chi
56e0: 6c 64 63 6f 75 6e 74 29 20 5b 6c 6c 65 6e 67 74  ldcount) [llengt
56f0: 68 20 5b 67 65 74 63 68 69 6c 64 72 65 6e 20 24  h [getchildren $
5700: 70 61 74 68 5d 5d 0a 09 09 09 09 09 7d 0a 09 09  path]]......}...
5710: 09 09 7d 0a 09 09 09 7d 0a 09 09 09 22 76 65 72  ..}....}...."ver
5720: 73 69 6f 6e 73 22 20 7b 0a 09 09 09 09 69 66 20  sions" {.....if 
5730: 7b 24 70 61 74 68 69 6e 66 6f 28 76 65 72 73 69  {$pathinfo(versi
5740: 6f 6e 29 20 3d 3d 20 22 6c 61 74 65 73 74 22 7d  on) == "latest"}
5750: 20 7b 0a 09 09 09 09 09 3a 3a 61 70 70 66 73 3a   {......::appfs:
5760: 3a 64 62 20 65 76 61 6c 20 7b 53 45 4c 45 43 54  :db eval {SELECT
5770: 20 76 65 72 73 69 6f 6e 20 46 52 4f 4d 20 70 61   version FROM pa
5780: 63 6b 61 67 65 73 20 57 48 45 52 45 20 69 73 4c  ckages WHERE isL
5790: 61 74 65 73 74 20 3d 20 31 20 41 4e 44 20 68 6f  atest = 1 AND ho
57a0: 73 74 6e 61 6d 65 20 3d 20 24 70 61 74 68 69 6e  stname = $pathin
57b0: 66 6f 28 68 6f 73 74 6e 61 6d 65 29 20 41 4e 44  fo(hostname) AND
57c0: 20 70 61 63 6b 61 67 65 20 3d 20 24 70 61 74 68   package = $path
57d0: 69 6e 66 6f 28 70 61 63 6b 61 67 65 29 20 41 4e  info(package) AN
57e0: 44 20 6f 73 20 3d 20 24 70 61 74 68 69 6e 66 6f  D os = $pathinfo
57f0: 28 6f 73 29 20 41 4e 44 20 63 70 75 41 72 63 68  (os) AND cpuArch
5800: 20 3d 20 24 70 61 74 68 69 6e 66 6f 28 63 70 75   = $pathinfo(cpu
5810: 29 20 4c 49 4d 49 54 20 31 3b 7d 20 6c 61 74 65  ) LIMIT 1;} late
5820: 73 74 5f 69 6e 66 6f 20 7b 7d 0a 0a 09 09 09 09  st_info {}......
5830: 09 69 66 20 7b 5b 69 6e 66 6f 20 65 78 69 73 74  .if {[info exist
5840: 73 20 6c 61 74 65 73 74 5f 69 6e 66 6f 28 76 65  s latest_info(ve
5850: 72 73 69 6f 6e 29 5d 7d 20 7b 0a 09 09 09 09 09  rsion)]} {......
5860: 09 73 65 74 20 72 65 74 76 61 6c 28 74 79 70 65  .set retval(type
5870: 29 20 73 79 6d 6c 69 6e 6b 0a 09 09 09 09 09 09  ) symlink.......
5880: 73 65 74 20 72 65 74 76 61 6c 28 73 6f 75 72 63  set retval(sourc
5890: 65 29 20 24 6c 61 74 65 73 74 5f 69 6e 66 6f 28  e) $latest_info(
58a0: 76 65 72 73 69 6f 6e 29 0a 09 09 09 09 09 7d 0a  version)......}.
58b0: 09 09 09 09 7d 20 65 6c 73 65 20 7b 0a 09 09 09  ....} else {....
58c0: 09 09 69 66 20 7b 5b 69 6e 66 6f 20 65 78 69 73  ..if {[info exis
58d0: 74 73 20 70 61 74 68 69 6e 66 6f 28 70 61 63 6b  ts pathinfo(pack
58e0: 61 67 65 5f 73 68 61 31 29 5d 20 26 26 20 24 70  age_sha1)] && $p
58f0: 61 74 68 69 6e 66 6f 28 70 61 63 6b 61 67 65 5f  athinfo(package_
5900: 73 68 61 31 29 20 21 3d 20 22 22 7d 20 7b 0a 09  sha1) != ""} {..
5910: 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28  .....set retval(
5920: 74 79 70 65 29 20 64 69 72 65 63 74 6f 72 79 0a  type) directory.
5930: 09 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c  ......set retval
5940: 28 63 68 69 6c 64 63 6f 75 6e 74 29 20 5b 6c 6c  (childcount) [ll
5950: 65 6e 67 74 68 20 5b 67 65 74 63 68 69 6c 64 72  ength [getchildr
5960: 65 6e 20 24 70 61 74 68 5d 5d 0a 09 09 09 09 09  en $path]]......
5970: 7d 0a 09 09 09 09 7d 0a 09 09 09 7d 0a 09 09 09  }.....}....}....
5980: 22 66 69 6c 65 73 22 20 7b 0a 09 09 09 09 73 65  "files" {.....se
5990: 74 20 72 65 74 76 61 6c 28 70 61 63 6b 61 67 65  t retval(package
59a0: 64 29 20 31 0a 0a 09 09 09 09 73 65 74 20 6c 6f  d) 1......set lo
59b0: 63 61 6c 70 61 74 68 20 5b 5f 6c 6f 63 61 6c 70  calpath [_localp
59c0: 61 74 68 20 24 70 61 74 68 69 6e 66 6f 28 70 61  ath $pathinfo(pa
59d0: 63 6b 61 67 65 29 20 24 70 61 74 68 69 6e 66 6f  ckage) $pathinfo
59e0: 28 68 6f 73 74 6e 61 6d 65 29 20 24 70 61 74 68  (hostname) $path
59f0: 69 6e 66 6f 28 66 69 6c 65 29 5d 0a 09 09 09 09  info(file)].....
5a00: 73 65 74 20 77 68 69 74 65 6f 75 74 70 61 74 68  set whiteoutpath
5a10: 20 20 5b 5f 77 68 69 74 65 6f 75 74 70 61 74 68    [_whiteoutpath
5a20: 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63 6b 61   $pathinfo(packa
5a30: 67 65 29 20 24 70 61 74 68 69 6e 66 6f 28 68 6f  ge) $pathinfo(ho
5a40: 73 74 6e 61 6d 65 29 20 24 70 61 74 68 69 6e 66  stname) $pathinf
5a50: 6f 28 66 69 6c 65 29 5d 0a 0a 09 09 09 09 73 65  o(file)]......se
5a60: 74 20 72 65 74 76 61 6c 28 6c 6f 63 61 6c 70 61  t retval(localpa
5a70: 74 68 29 20 24 6c 6f 63 61 6c 70 61 74 68 0a 09  th) $localpath..
5a80: 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 77 68  ...set retval(wh
5a90: 69 74 65 6f 75 74 70 61 74 68 29 20 24 77 68 69  iteoutpath) $whi
5aa0: 74 65 6f 75 74 70 61 74 68 0a 0a 09 09 09 09 75  teoutpath......u
5ab0: 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e  nset -nocomplain
5ac0: 20 6c 6f 63 61 6c 70 61 74 68 69 6e 66 6f 0a 09   localpathinfo..
5ad0: 09 09 09 69 66 20 7b 24 6c 6f 63 61 6c 70 61 74  ...if {$localpat
5ae0: 68 20 21 3d 20 22 22 7d 20 7b 0a 09 09 09 09 09  h != ""} {......
5af0: 5f 61 73 5f 75 73 65 72 20 7b 0a 09 09 09 09 09  _as_user {......
5b00: 09 63 61 74 63 68 20 7b 0a 09 09 09 09 09 09 09  .catch {........
5b10: 66 69 6c 65 20 6c 73 74 61 74 20 24 6c 6f 63 61  file lstat $loca
5b20: 6c 70 61 74 68 20 6c 6f 63 61 6c 70 61 74 68 69  lpath localpathi
5b30: 6e 66 6f 0a 09 09 09 09 09 09 7d 0a 09 09 09 09  nfo.......}.....
5b40: 09 7d 0a 09 09 09 09 7d 0a 0a 09 09 09 09 69 66  .}.....}......if
5b50: 20 7b 24 6c 6f 63 61 6c 70 61 74 68 20 21 3d 20   {$localpath != 
5b60: 22 22 20 26 26 20 5b 69 6e 66 6f 20 65 78 69 73  "" && [info exis
5b70: 74 73 20 6c 6f 63 61 6c 70 61 74 68 69 6e 66 6f  ts localpathinfo
5b80: 5d 7d 20 7b 0a 09 09 09 09 09 73 65 74 20 72 65  ]} {......set re
5b90: 74 76 61 6c 28 69 73 5f 6c 6f 63 61 6c 66 69 6c  tval(is_localfil
5ba0: 65 29 20 31 0a 09 09 09 09 09 75 6e 73 65 74 20  e) 1......unset 
5bb0: 72 65 74 76 61 6c 28 70 61 63 6b 61 67 65 64 29  retval(packaged)
5bc0: 0a 09 09 09 09 09 63 61 74 63 68 20 7b 0a 09 09  ......catch {...
5bd0: 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 74  ....set retval(t
5be0: 69 6d 65 29 20 24 6c 6f 63 61 6c 70 61 74 68 69  ime) $localpathi
5bf0: 6e 66 6f 28 6d 74 69 6d 65 29 0a 0a 09 09 09 09  nfo(mtime)......
5c00: 09 09 73 77 69 74 63 68 20 2d 2d 20 24 6c 6f 63  ..switch -- $loc
5c10: 61 6c 70 61 74 68 69 6e 66 6f 28 74 79 70 65 29  alpathinfo(type)
5c20: 20 7b 0a 09 09 09 09 09 09 09 22 64 69 72 65 63   {........"direc
5c30: 74 6f 72 79 22 20 7b 0a 09 09 09 09 09 09 09 09  tory" {.........
5c40: 73 65 74 20 72 65 74 76 61 6c 28 74 79 70 65 29  set retval(type)
5c50: 20 22 64 69 72 65 63 74 6f 72 79 22 0a 09 09 09   "directory"....
5c60: 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28  .....set retval(
5c70: 63 68 69 6c 64 63 6f 75 6e 74 29 20 5b 6c 6c 65  childcount) [lle
5c80: 6e 67 74 68 20 5b 67 65 74 63 68 69 6c 64 72 65  ngth [getchildre
5c90: 6e 20 24 70 61 74 68 5d 5d 0a 09 09 09 09 09 09  n $path]].......
5ca0: 09 7d 0a 09 09 09 09 09 09 09 22 66 69 6c 65 22  .}........"file"
5cb0: 20 7b 0a 09 09 09 09 09 09 09 09 73 65 74 20 72   {.........set r
5cc0: 65 74 76 61 6c 28 74 79 70 65 29 20 22 66 69 6c  etval(type) "fil
5cd0: 65 22 0a 09 09 09 09 09 09 09 09 73 65 74 20 72  e".........set r
5ce0: 65 74 76 61 6c 28 73 69 7a 65 29 20 24 6c 6f 63  etval(size) $loc
5cf0: 61 6c 70 61 74 68 69 6e 66 6f 28 73 69 7a 65 29  alpathinfo(size)
5d00: 0a 0a 09 09 09 09 09 09 09 09 23 20 4f 6e 63 65  ..........# Once
5d10: 20 74 68 65 20 75 73 65 72 20 77 72 69 74 65 73   the user writes
5d20: 20 74 6f 20 61 20 66 69 6c 65 2c 20 61 6c 6c 20   to a file, all 
5d30: 69 74 73 20 6f 74 68 65 72 0a 09 09 09 09 09 09  its other.......
5d40: 09 09 23 20 61 74 74 72 69 62 75 74 65 73 20 28  ..# attributes (
5d50: 73 75 63 68 20 61 73 20 73 75 69 64 29 20 61 72  such as suid) ar
5d60: 65 20 6c 6f 73 74 0a 0a 09 09 09 09 09 09 09 09  e lost..........
5d70: 5f 61 73 5f 75 73 65 72 20 7b 0a 09 09 09 09 09  _as_user {......
5d80: 09 09 09 09 69 66 20 7b 5b 66 69 6c 65 20 65 78  ....if {[file ex
5d90: 65 63 75 74 61 62 6c 65 20 24 6c 6f 63 61 6c 70  ecutable $localp
5da0: 61 74 68 5d 7d 20 7b 0a 09 09 09 09 09 09 09 09  ath]} {.........
5db0: 09 09 73 65 74 20 72 65 74 76 61 6c 28 70 65 72  ..set retval(per
5dc0: 6d 73 29 20 22 78 2d 22 0a 09 09 09 09 09 09 09  ms) "x-"........
5dd0: 09 09 7d 20 65 6c 73 65 20 7b 0a 09 09 09 09 09  ..} else {......
5de0: 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28  .....set retval(
5df0: 70 65 72 6d 73 29 20 22 2d 22 0a 09 09 09 09 09  perms) "-"......
5e00: 09 09 09 09 7d 0a 09 09 09 09 09 09 09 09 7d 0a  ....}.........}.
5e10: 09 09 09 09 09 09 09 7d 0a 09 09 09 09 09 09 09  .......}........
5e20: 22 6c 69 6e 6b 22 20 7b 0a 09 09 09 09 09 09 09  "link" {........
5e30: 09 73 65 74 20 72 65 74 76 61 6c 28 74 79 70 65  .set retval(type
5e40: 29 20 22 73 79 6d 6c 69 6e 6b 22 0a 0a 09 09 09  ) "symlink".....
5e50: 09 09 09 09 09 5f 61 73 5f 75 73 65 72 20 7b 0a  ....._as_user {.
5e60: 09 09 09 09 09 09 09 09 09 73 65 74 20 72 65 74  .........set ret
5e70: 76 61 6c 28 73 6f 75 72 63 65 29 20 5b 66 69 6c  val(source) [fil
5e80: 65 20 72 65 61 64 6c 69 6e 6b 20 24 6c 6f 63 61  e readlink $loca
5e90: 6c 70 61 74 68 5d 0a 09 09 09 09 09 09 09 09 7d  lpath].........}
5ea0: 0a 09 09 09 09 09 09 09 7d 0a 09 09 09 09 09 09  ........}.......
5eb0: 09 22 66 69 66 6f 22 20 7b 0a 09 09 09 09 09 09  ."fifo" {.......
5ec0: 09 09 23 20 43 61 70 69 74 61 6c 69 7a 65 64 20  ..# Capitalized 
5ed0: 73 6f 20 74 68 61 74 20 74 68 65 20 66 69 72 73  so that the firs
5ee0: 74 20 63 68 61 72 20 69 73 20 75 6e 69 71 75 65  t char is unique
5ef0: 0a 09 09 09 09 09 09 09 09 73 65 74 20 72 65 74  .........set ret
5f00: 76 61 6c 28 74 79 70 65 29 20 22 46 69 66 6f 22  val(type) "Fifo"
5f10: 0a 09 09 09 09 09 09 09 7d 0a 09 09 09 09 09 09  ........}.......
5f20: 09 22 73 6f 63 6b 65 74 22 20 7b 0a 09 09 09 09  ."socket" {.....
5f30: 09 09 09 09 23 20 43 61 70 69 74 61 6c 69 7a 65  ....# Capitalize
5f40: 64 20 73 6f 20 74 68 61 74 20 74 68 65 20 66 69  d so that the fi
5f50: 72 73 74 20 63 68 61 72 20 69 73 20 75 6e 69 71  rst char is uniq
5f60: 75 65 0a 09 09 09 09 09 09 09 09 73 65 74 20 72  ue.........set r
5f70: 65 74 76 61 6c 28 74 79 70 65 29 20 22 53 6f 63  etval(type) "Soc
5f80: 6b 65 74 22 0a 09 09 09 09 09 09 09 7d 0a 09 09  ket"........}...
5f90: 09 09 09 09 7d 0a 09 09 09 09 09 7d 20 65 72 72  ....}......} err
5fa0: 0a 09 09 09 09 7d 20 65 6c 73 65 20 7b 0a 09 09  .....} else {...
5fb0: 09 09 09 69 66 20 7b 24 77 68 69 74 65 6f 75 74  ...if {$whiteout
5fc0: 70 61 74 68 20 3d 3d 20 22 22 20 7c 7c 20 21 5b  path == "" || ![
5fd0: 66 69 6c 65 20 65 78 69 73 74 73 20 24 77 68 69  file exists $whi
5fe0: 74 65 6f 75 74 70 61 74 68 5d 7d 20 7b 0a 09 09  teoutpath]} {...
5ff0: 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 69  ....set retval(i
6000: 73 5f 72 65 6d 6f 74 65 66 69 6c 65 29 20 31 0a  s_remotefile) 1.
6010: 0a 09 09 09 09 09 09 73 65 74 20 77 6f 72 6b 20  .......set work 
6020: 5b 73 70 6c 69 74 20 24 70 61 74 68 69 6e 66 6f  [split $pathinfo
6030: 28 66 69 6c 65 29 20 22 2f 22 5d 0a 09 09 09 09  (file) "/"].....
6040: 09 09 73 65 74 20 64 69 72 65 63 74 6f 72 79 20  ..set directory 
6050: 5b 6a 6f 69 6e 20 5b 6c 72 61 6e 67 65 20 24 77  [join [lrange $w
6060: 6f 72 6b 20 30 20 65 6e 64 2d 31 5d 20 22 2f 22  ork 0 end-1] "/"
6070: 5d 0a 09 09 09 09 09 09 73 65 74 20 66 69 6c 65  ].......set file
6080: 20 5b 6c 69 6e 64 65 78 20 24 77 6f 72 6b 20 65   [lindex $work e
6090: 6e 64 5d 0a 0a 09 09 09 09 09 09 69 66 20 7b 24  nd]........if {$
60a0: 64 69 72 65 63 74 6f 72 79 20 3d 3d 20 22 22 20  directory == "" 
60b0: 26 26 20 24 66 69 6c 65 20 3d 3d 20 22 22 7d 20  && $file == ""} 
60c0: 7b 0a 09 09 09 09 09 09 09 61 72 72 61 79 20 73  {........array s
60d0: 65 74 20 72 65 74 76 61 6c 20 5b 6c 69 73 74 20  et retval [list 
60e0: 74 79 70 65 20 64 69 72 65 63 74 6f 72 79 5d 0a  type directory].
60f0: 09 09 09 09 09 09 7d 0a 0a 09 09 09 09 09 09 3a  ......}........:
6100: 3a 61 70 70 66 73 3a 3a 64 62 20 65 76 61 6c 20  :appfs::db eval 
6110: 7b 53 45 4c 45 43 54 20 74 79 70 65 2c 20 74 69  {SELECT type, ti
6120: 6d 65 2c 20 73 6f 75 72 63 65 2c 20 73 69 7a 65  me, source, size
6130: 2c 20 70 65 72 6d 73 2c 20 66 69 6c 65 5f 73 68  , perms, file_sh
6140: 61 31 20 46 52 4f 4d 20 66 69 6c 65 73 20 57 48  a1 FROM files WH
6150: 45 52 45 20 70 61 63 6b 61 67 65 5f 73 68 61 31  ERE package_sha1
6160: 20 3d 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63   = $pathinfo(pac
6170: 6b 61 67 65 5f 73 68 61 31 29 20 41 4e 44 20 66  kage_sha1) AND f
6180: 69 6c 65 5f 64 69 72 65 63 74 6f 72 79 20 3d 20  ile_directory = 
6190: 24 64 69 72 65 63 74 6f 72 79 20 41 4e 44 20 66  $directory AND f
61a0: 69 6c 65 5f 6e 61 6d 65 20 3d 20 24 66 69 6c 65  ile_name = $file
61b0: 3b 7d 20 72 65 74 76 61 6c 20 7b 7d 0a 0a 09 09  ;} retval {}....
61c0: 09 09 09 09 23 20 41 6c 6c 6f 77 20 61 6e 20 61  ....# Allow an a
61d0: 64 6d 69 6e 69 73 74 72 61 74 6f 72 20 74 6f 20  dministrator to 
61e0: 73 75 70 70 6c 79 20 61 64 64 69 74 69 6f 6e 61  supply additiona
61f0: 6c 20 70 65 72 6d 69 73 73 69 6f 6e 73 20 74 6f  l permissions to
6200: 20 72 65 6d 6f 74 65 20 66 69 6c 65 73 0a 09 09   remote files...
6210: 09 09 09 09 69 66 20 7b 5b 69 6e 66 6f 20 65 78  ....if {[info ex
6220: 69 73 74 73 20 72 65 74 76 61 6c 28 70 65 72 6d  ists retval(perm
6230: 73 29 5d 7d 20 7b 0a 09 09 09 09 09 09 09 23 20  s)]} {........# 
6240: 4c 6f 77 65 72 20 63 61 73 65 20 74 68 69 73 20  Lower case this 
6250: 69 6e 20 63 61 73 65 20 61 6e 20 75 70 70 65 72  in case an upper
6260: 2d 63 61 73 65 64 20 76 61 6c 75 65 20 77 61 73  -cased value was
6270: 20 70 75 74 20 69 6e 0a 09 09 09 09 09 09 09 23   put in........#
6280: 20 74 68 65 20 64 61 74 61 62 61 73 65 20 62 65   the database be
6290: 66 6f 72 65 20 77 65 20 73 74 61 72 74 65 64 20  fore we started 
62a0: 6c 6f 77 65 72 63 61 73 69 6e 67 20 74 68 65 6d  lowercasing them
62b0: 0a 09 09 09 09 09 09 09 73 65 74 20 72 65 74 76  ........set retv
62c0: 61 6c 28 70 65 72 6d 73 29 20 5b 73 74 72 69 6e  al(perms) [strin
62d0: 67 20 74 6f 6c 6f 77 65 72 20 24 72 65 74 76 61  g tolower $retva
62e0: 6c 28 70 65 72 6d 73 29 5d 0a 0a 09 09 09 09 09  l(perms)].......
62f0: 09 09 73 65 74 20 72 65 74 76 61 6c 28 70 65 72  ..set retval(per
6300: 6d 73 29 20 5b 3a 3a 61 70 70 66 73 3a 3a 75 73  ms) [::appfs::us
6310: 65 72 3a 3a 63 68 61 6e 67 65 5f 70 65 72 6d 73  er::change_perms
6320: 20 24 70 61 74 68 20 24 72 65 74 76 61 6c 28 66   $path $retval(f
6330: 69 6c 65 5f 73 68 61 31 29 20 24 72 65 74 76 61  ile_sha1) $retva
6340: 6c 28 70 65 72 6d 73 29 5d 0a 09 09 09 09 09 09  l(perms)].......
6350: 7d 0a 0a 09 09 09 09 09 09 69 66 20 7b 5b 69 6e  }........if {[in
6360: 66 6f 20 65 78 69 73 74 73 20 72 65 74 76 61 6c  fo exists retval
6370: 28 74 79 70 65 29 5d 20 26 26 20 24 72 65 74 76  (type)] && $retv
6380: 61 6c 28 74 79 70 65 29 20 3d 3d 20 22 64 69 72  al(type) == "dir
6390: 65 63 74 6f 72 79 22 7d 20 7b 0a 09 09 09 09 09  ectory"} {......
63a0: 09 09 73 65 74 20 72 65 74 76 61 6c 28 63 68 69  ..set retval(chi
63b0: 6c 64 63 6f 75 6e 74 29 20 5b 6c 6c 65 6e 67 74  ldcount) [llengt
63c0: 68 20 5b 67 65 74 63 68 69 6c 64 72 65 6e 20 24  h [getchildren $
63d0: 70 61 74 68 5d 5d 0a 09 09 09 09 09 09 7d 0a 0a  path]].......}..
63e0: 09 09 09 09 09 09 75 6e 73 65 74 20 2d 6e 6f 63  ......unset -noc
63f0: 6f 6d 70 6c 61 69 6e 20 72 65 74 76 61 6c 28 2a  omplain retval(*
6400: 29 0a 09 09 09 09 09 7d 0a 09 09 09 09 7d 0a 0a  )......}.....}..
6410: 09 09 09 7d 0a 09 09 7d 0a 0a 09 09 69 66 20 7b  ...}...}....if {
6420: 21 5b 69 6e 66 6f 20 65 78 69 73 74 73 20 72 65  ![info exists re
6430: 74 76 61 6c 28 74 79 70 65 29 5d 7d 20 7b 0a 09  tval(type)]} {..
6440: 09 09 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 65  ..return -code e
6450: 72 72 6f 72 20 22 4e 6f 20 73 75 63 68 20 66 69  rror "No such fi
6460: 6c 65 20 6f 72 20 64 69 72 65 63 74 6f 72 79 22  le or directory"
6470: 0a 09 09 7d 0a 0a 09 09 72 65 74 75 72 6e 20 5b  ...}....return [
6480: 61 72 72 61 79 20 67 65 74 20 72 65 74 76 61 6c  array get retval
6490: 5d 0a 09 7d 0a 0a 09 70 72 6f 63 20 6f 70 65 6e  ]..}...proc open
64a0: 70 61 74 68 20 7b 70 61 74 68 20 6d 6f 64 65 7d  path {path mode}
64b0: 20 7b 0a 09 09 61 72 72 61 79 20 73 65 74 20 70   {...array set p
64c0: 61 74 68 69 6e 66 6f 20 5b 5f 70 61 72 73 65 70  athinfo [_parsep
64d0: 61 74 68 20 24 70 61 74 68 5d 0a 0a 09 09 69 66  ath $path]....if
64e0: 20 7b 24 70 61 74 68 69 6e 66 6f 28 5f 74 79 70   {$pathinfo(_typ
64f0: 65 29 20 21 3d 20 22 66 69 6c 65 73 22 7d 20 7b  e) != "files"} {
6500: 0a 09 09 09 72 65 74 75 72 6e 20 2d 63 6f 64 65  ....return -code
6510: 20 65 72 72 6f 72 20 22 69 6e 76 61 6c 69 64 20   error "invalid 
6520: 70 61 74 68 20 74 79 70 65 3a 20 47 6f 74 20 5c  path type: Got \
6530: 22 24 70 61 74 68 69 6e 66 6f 28 5f 74 79 70 65  "$pathinfo(_type
6540: 29 5c 22 2c 20 6e 65 65 64 20 5c 22 66 69 6c 65  )\", need \"file
6550: 73 5c 22 22 0a 09 09 7d 0a 0a 09 09 73 65 74 20  s\""...}....set 
6560: 6c 6f 63 61 6c 70 61 74 68 20 5b 5f 6c 6f 63 61  localpath [_loca
6570: 6c 70 61 74 68 20 24 70 61 74 68 69 6e 66 6f 28  lpath $pathinfo(
6580: 70 61 63 6b 61 67 65 29 20 24 70 61 74 68 69 6e  package) $pathin
6590: 66 6f 28 68 6f 73 74 6e 61 6d 65 29 20 24 70 61  fo(hostname) $pa
65a0: 74 68 69 6e 66 6f 28 66 69 6c 65 29 5d 0a 0a 09  thinfo(file)]...
65b0: 09 69 66 20 7b 24 6d 6f 64 65 20 3d 3d 20 22 63  .if {$mode == "c
65c0: 72 65 61 74 65 22 7d 20 7b 0a 09 09 09 69 66 20  reate"} {....if 
65d0: 7b 24 6c 6f 63 61 6c 70 61 74 68 20 3d 3d 20 22  {$localpath == "
65e0: 22 7d 20 7b 0a 09 09 09 09 72 65 74 75 72 6e 20  "} {.....return 
65f0: 2d 63 6f 64 65 20 65 72 72 6f 72 20 22 41 73 6b  -code error "Ask
6600: 65 64 20 74 6f 20 63 72 65 61 74 65 2c 20 62 75  ed to create, bu
6610: 74 20 6e 6f 20 68 6f 6d 65 20 64 69 72 65 63 74  t no home direct
6620: 6f 72 79 2e 22 0a 09 09 09 7d 0a 0a 09 09 09 72  ory."....}.....r
6630: 65 74 75 72 6e 20 24 6c 6f 63 61 6c 70 61 74 68  eturn $localpath
6640: 0a 09 09 7d 0a 0a 09 09 69 66 20 7b 24 6c 6f 63  ...}....if {$loc
6650: 61 6c 70 61 74 68 20 21 3d 20 22 22 20 26 26 20  alpath != "" && 
6660: 5b 66 69 6c 65 20 65 78 69 73 74 73 20 24 6c 6f  [file exists $lo
6670: 63 61 6c 70 61 74 68 5d 7d 20 7b 0a 09 09 09 72  calpath]} {....r
6680: 65 74 75 72 6e 20 24 6c 6f 63 61 6c 70 61 74 68  eturn $localpath
6690: 0a 09 09 7d 0a 0a 09 09 73 65 74 20 77 6f 72 6b  ...}....set work
66a0: 20 5b 73 70 6c 69 74 20 24 70 61 74 68 69 6e 66   [split $pathinf
66b0: 6f 28 66 69 6c 65 29 20 22 2f 22 5d 0a 09 09 73  o(file) "/"]...s
66c0: 65 74 20 64 69 72 65 63 74 6f 72 79 20 5b 6a 6f  et directory [jo
66d0: 69 6e 20 5b 6c 72 61 6e 67 65 20 24 77 6f 72 6b  in [lrange $work
66e0: 20 30 20 65 6e 64 2d 31 5d 20 22 2f 22 5d 0a 09   0 end-1] "/"]..
66f0: 09 73 65 74 20 66 69 6c 65 20 5b 6c 69 6e 64 65  .set file [linde
6700: 78 20 24 77 6f 72 6b 20 65 6e 64 5d 0a 09 09 3a  x $work end]...:
6710: 3a 61 70 70 66 73 3a 3a 64 62 20 65 76 61 6c 20  :appfs::db eval 
6720: 7b 53 45 4c 45 43 54 20 66 69 6c 65 5f 73 68 61  {SELECT file_sha
6730: 31 2c 20 70 65 72 6d 73 20 46 52 4f 4d 20 66 69  1, perms FROM fi
6740: 6c 65 73 20 57 48 45 52 45 20 70 61 63 6b 61 67  les WHERE packag
6750: 65 5f 73 68 61 31 20 3d 20 24 70 61 74 68 69 6e  e_sha1 = $pathin
6760: 66 6f 28 70 61 63 6b 61 67 65 5f 73 68 61 31 29  fo(package_sha1)
6770: 20 41 4e 44 20 66 69 6c 65 5f 6e 61 6d 65 20 3d   AND file_name =
6780: 20 24 66 69 6c 65 20 41 4e 44 20 66 69 6c 65 5f   $file AND file_
6790: 64 69 72 65 63 74 6f 72 79 20 3d 20 24 64 69 72  directory = $dir
67a0: 65 63 74 6f 72 79 3b 7d 20 70 6b 67 70 61 74 68  ectory;} pkgpath
67b0: 69 6e 66 6f 20 7b 7d 0a 0a 09 09 69 66 20 7b 24  info {}....if {$
67c0: 70 6b 67 70 61 74 68 69 6e 66 6f 28 66 69 6c 65  pkgpathinfo(file
67d0: 5f 73 68 61 31 29 20 3d 3d 20 22 22 7d 20 7b 0a  _sha1) == ""} {.
67e0: 09 09 09 72 65 74 75 72 6e 20 2d 63 6f 64 65 20  ...return -code 
67f0: 65 72 72 6f 72 20 22 4e 6f 20 73 75 63 68 20 66  error "No such f
6800: 69 6c 65 20 6f 72 20 64 69 72 65 63 74 6f 72 79  ile or directory
6810: 22 0a 09 09 7d 0a 0a 09 09 73 65 74 20 6c 6f 63  "...}....set loc
6820: 61 6c 63 61 63 68 65 66 69 6c 65 20 5b 64 6f 77  alcachefile [dow
6830: 6e 6c 6f 61 64 20 24 70 61 74 68 69 6e 66 6f 28  nload $pathinfo(
6840: 68 6f 73 74 6e 61 6d 65 29 20 24 70 6b 67 70 61  hostname) $pkgpa
6850: 74 68 69 6e 66 6f 28 66 69 6c 65 5f 73 68 61 31  thinfo(file_sha1
6860: 29 5d 0a 0a 09 09 69 66 20 7b 24 6d 6f 64 65 20  )]....if {$mode 
6870: 3d 3d 20 22 77 72 69 74 65 22 7d 20 7b 0a 09 09  == "write"} {...
6880: 09 5f 61 73 5f 75 73 65 72 20 7b 0a 09 09 09 09  ._as_user {.....
6890: 73 65 74 20 74 6d 70 6c 6f 63 61 6c 70 61 74 68  set tmplocalpath
68a0: 20 22 24 7b 6c 6f 63 61 6c 70 61 74 68 7d 2e 5b   "${localpath}.[
68b0: 65 78 70 72 20 72 61 6e 64 28 29 5d 5b 63 6c 6f  expr rand()][clo
68c0: 63 6b 20 63 6c 69 63 6b 73 5d 22 0a 0a 09 09 09  ck clicks]".....
68d0: 09 73 65 74 20 66 61 69 6c 65 64 20 30 0a 09 09  .set failed 0...
68e0: 09 09 69 66 20 7b 5b 63 61 74 63 68 20 7b 0a 09  ..if {[catch {..
68f0: 09 09 09 09 66 69 6c 65 20 6d 6b 64 69 72 20 5b  ....file mkdir [
6900: 66 69 6c 65 20 64 69 72 6e 61 6d 65 20 24 6c 6f  file dirname $lo
6910: 63 61 6c 70 61 74 68 5d 0a 09 09 09 09 09 66 69  calpath]......fi
6920: 6c 65 20 63 6f 70 79 20 2d 66 6f 72 63 65 20 2d  le copy -force -
6930: 2d 20 24 6c 6f 63 61 6c 63 61 63 68 65 66 69 6c  - $localcachefil
6940: 65 20 24 74 6d 70 6c 6f 63 61 6c 70 61 74 68 0a  e $tmplocalpath.
6950: 0a 09 09 09 09 09 69 66 20 7b 24 70 6b 67 70 61  ......if {$pkgpa
6960: 74 68 69 6e 66 6f 28 70 65 72 6d 73 29 20 3d 3d  thinfo(perms) ==
6970: 20 22 78 22 7d 20 7b 0a 09 09 09 09 09 09 66 69   "x"} {.......fi
6980: 6c 65 20 61 74 74 72 69 62 75 74 65 73 20 24 74  le attributes $t
6990: 6d 70 6c 6f 63 61 6c 70 61 74 68 20 2d 70 65 72  mplocalpath -per
69a0: 6d 69 73 73 69 6f 6e 73 20 2b 78 0a 09 09 09 09  missions +x.....
69b0: 09 7d 0a 0a 09 09 09 09 09 66 69 6c 65 20 72 65  .}.......file re
69c0: 6e 61 6d 65 20 2d 66 6f 72 63 65 20 2d 2d 20 24  name -force -- $
69d0: 74 6d 70 6c 6f 63 61 6c 70 61 74 68 20 24 6c 6f  tmplocalpath $lo
69e0: 63 61 6c 70 61 74 68 0a 09 09 09 09 7d 20 65 72  calpath.....} er
69f0: 72 5d 7d 20 7b 0a 09 09 09 09 09 73 65 74 20 66  r]} {......set f
6a00: 61 69 6c 65 64 20 31 0a 09 09 09 09 7d 0a 09 09  ailed 1.....}...
6a10: 09 09 63 61 74 63 68 20 7b 0a 09 09 09 09 09 66  ..catch {......f
6a20: 69 6c 65 20 64 65 6c 65 74 65 20 2d 66 6f 72 63  ile delete -forc
6a30: 65 20 2d 2d 20 24 74 6d 70 6c 6f 63 61 6c 70 61  e -- $tmplocalpa
6a40: 74 68 0a 09 09 09 09 7d 0a 09 09 09 7d 0a 0a 09  th.....}....}...
6a50: 09 09 69 66 20 7b 24 66 61 69 6c 65 64 7d 20 7b  ..if {$failed} {
6a60: 0a 09 09 09 09 72 65 74 75 72 6e 20 2d 63 6f 64  .....return -cod
6a70: 65 20 65 72 72 6f 72 20 24 65 72 72 0a 09 09 09  e error $err....
6a80: 7d 0a 0a 09 09 09 72 65 74 75 72 6e 20 24 6c 6f  }.....return $lo
6a90: 63 61 6c 70 61 74 68 0a 09 09 7d 0a 0a 09 09 72  calpath...}....r
6aa0: 65 74 75 72 6e 20 24 6c 6f 63 61 6c 63 61 63 68  eturn $localcach
6ab0: 65 66 69 6c 65 0a 09 7d 0a 0a 09 70 72 6f 63 20  efile..}...proc 
6ac0: 6c 6f 63 61 6c 70 61 74 68 20 7b 70 61 74 68 7d  localpath {path}
6ad0: 20 7b 0a 09 09 61 72 72 61 79 20 73 65 74 20 70   {...array set p
6ae0: 61 74 68 69 6e 66 6f 20 5b 5f 70 61 72 73 65 70  athinfo [_parsep
6af0: 61 74 68 20 24 70 61 74 68 5d 0a 0a 09 09 69 66  ath $path]....if
6b00: 20 7b 24 70 61 74 68 69 6e 66 6f 28 5f 74 79 70   {$pathinfo(_typ
6b10: 65 29 20 21 3d 20 22 66 69 6c 65 73 22 7d 20 7b  e) != "files"} {
6b20: 0a 09 09 09 72 65 74 75 72 6e 20 2d 63 6f 64 65  ....return -code
6b30: 20 65 72 72 6f 72 20 22 69 6e 76 61 6c 69 64 20   error "invalid 
6b40: 70 61 74 68 20 74 79 70 65 3a 20 47 6f 74 20 5c  path type: Got \
6b50: 22 24 70 61 74 68 69 6e 66 6f 28 5f 74 79 70 65  "$pathinfo(_type
6b60: 29 5c 22 2c 20 6e 65 65 64 20 5c 22 66 69 6c 65  )\", need \"file
6b70: 73 5c 22 22 0a 09 09 7d 0a 0a 09 09 73 65 74 20  s\""...}....set 
6b80: 6c 6f 63 61 6c 70 61 74 68 20 5b 5f 6c 6f 63 61  localpath [_loca
6b90: 6c 70 61 74 68 20 24 70 61 74 68 69 6e 66 6f 28  lpath $pathinfo(
6ba0: 70 61 63 6b 61 67 65 29 20 24 70 61 74 68 69 6e  package) $pathin
6bb0: 66 6f 28 68 6f 73 74 6e 61 6d 65 29 20 24 70 61  fo(hostname) $pa
6bc0: 74 68 69 6e 66 6f 28 66 69 6c 65 29 5d 0a 0a 09  thinfo(file)]...
6bd0: 09 72 65 74 75 72 6e 20 24 6c 6f 63 61 6c 70 61  .return $localpa
6be0: 74 68 0a 09 7d 0a 0a 09 70 72 6f 63 20 65 78 69  th..}...proc exi
6bf0: 73 74 73 20 7b 70 61 74 68 7d 20 7b 0a 09 09 63  sts {path} {...c
6c00: 61 74 63 68 20 7b 0a 09 09 09 73 65 74 20 69 6e  atch {....set in
6c10: 66 6f 20 5b 67 65 74 61 74 74 72 20 24 70 61 74  fo [getattr $pat
6c20: 68 5d 0a 09 09 7d 20 65 72 72 0a 0a 09 09 69 66  h]...} err....if
6c30: 20 7b 21 5b 69 6e 66 6f 20 65 78 69 73 74 73 20   {![info exists 
6c40: 69 6e 66 6f 5d 7d 20 7b 0a 09 09 09 69 66 20 7b  info]} {....if {
6c50: 24 65 72 72 20 3d 3d 20 22 4e 6f 20 73 75 63 68  $err == "No such
6c60: 20 66 69 6c 65 20 6f 72 20 64 69 72 65 63 74 6f   file or directo
6c70: 72 79 22 7d 20 7b 0a 09 09 09 09 72 65 74 75 72  ry"} {.....retur
6c80: 6e 20 5b 6c 69 73 74 5d 0a 09 09 09 7d 20 65 6c  n [list]....} el
6c90: 73 65 20 7b 0a 09 09 09 09 72 65 74 75 72 6e 20  se {.....return 
6ca0: 2d 63 6f 64 65 20 65 72 72 6f 72 20 24 65 72 72  -code error $err
6cb0: 0a 09 09 09 7d 0a 09 09 7d 0a 0a 09 09 72 65 74  ....}...}....ret
6cc0: 75 72 6e 20 24 69 6e 66 6f 0a 09 7d 0a 0a 09 70  urn $info..}...p
6cd0: 72 6f 63 20 70 72 65 70 61 72 65 5f 74 6f 5f 63  roc prepare_to_c
6ce0: 72 65 61 74 65 20 7b 70 61 74 68 20 7b 6d 75 73  reate {path {mus
6cf0: 74 5f 6e 6f 74 5f 65 78 69 73 74 20 31 7d 7d 20  t_not_exist 1}} 
6d00: 7b 0a 09 09 69 66 20 7b 24 6d 75 73 74 5f 6e 6f  {...if {$must_no
6d10: 74 5f 65 78 69 73 74 7d 20 7b 0a 09 09 09 69 66  t_exist} {....if
6d20: 20 7b 5b 65 78 69 73 74 73 20 24 70 61 74 68 5d   {[exists $path]
6d30: 20 21 3d 20 22 22 7d 20 7b 0a 09 09 09 09 72 65   != ""} {.....re
6d40: 74 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72  turn -code error
6d50: 20 22 46 69 6c 65 20 61 6c 72 65 61 64 79 20 65   "File already e
6d60: 78 69 73 74 73 22 0a 09 09 09 7d 0a 09 09 7d 0a  xists"....}...}.
6d70: 0a 09 09 73 65 74 20 66 69 6c 65 6e 61 6d 65 20  ...set filename 
6d80: 5b 6c 6f 63 61 6c 70 61 74 68 20 24 70 61 74 68  [localpath $path
6d90: 5d 0a 0a 09 09 69 66 20 7b 24 66 69 6c 65 6e 61  ]....if {$filena
6da0: 6d 65 20 3d 3d 20 22 22 7d 20 7b 0a 09 09 09 72  me == ""} {....r
6db0: 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f  eturn -code erro
6dc0: 72 20 22 41 73 6b 65 64 20 74 6f 20 63 72 65 61  r "Asked to crea
6dd0: 74 65 2c 20 62 75 74 20 6e 6f 20 68 6f 6d 65 20  te, but no home 
6de0: 64 69 72 65 63 74 6f 72 79 2e 22 0a 09 09 7d 0a  directory."...}.
6df0: 0a 09 09 73 65 74 20 64 69 72 6e 61 6d 65 20 5b  ...set dirname [
6e00: 66 69 6c 65 20 64 69 72 6e 61 6d 65 20 24 66 69  file dirname $fi
6e10: 6c 65 6e 61 6d 65 5d 0a 0a 09 09 5f 61 73 5f 75  lename]...._as_u
6e20: 73 65 72 20 7b 0a 09 09 09 66 69 6c 65 20 6d 6b  ser {....file mk
6e30: 64 69 72 20 24 64 69 72 6e 61 6d 65 0a 09 09 7d  dir $dirname...}
6e40: 0a 0a 09 09 72 65 74 75 72 6e 20 24 66 69 6c 65  ....return $file
6e50: 6e 61 6d 65 0a 09 7d 0a 0a 09 70 72 6f 63 20 75  name..}...proc u
6e60: 6e 6c 69 6e 6b 70 61 74 68 20 7b 70 61 74 68 7d  nlinkpath {path}
6e70: 20 7b 0a 09 09 61 72 72 61 79 20 73 65 74 20 70   {...array set p
6e80: 61 74 68 61 74 74 72 73 20 5b 65 78 69 73 74 73  athattrs [exists
6e90: 20 24 70 61 74 68 5d 0a 0a 09 09 69 66 20 7b 24   $path]....if {$
6ea0: 70 61 74 68 61 74 74 72 73 28 70 61 74 68 5f 74  pathattrs(path_t
6eb0: 79 70 65 29 20 21 3d 20 22 66 69 6c 65 73 22 7d  ype) != "files"}
6ec0: 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 2d 63 6f   {....return -co
6ed0: 64 65 20 65 72 72 6f 72 20 22 69 6e 76 61 6c 69  de error "invali
6ee0: 64 20 70 61 74 68 20 74 79 70 65 3a 20 63 61 6e  d path type: can
6ef0: 20 6f 6e 6c 79 20 64 65 6c 65 74 65 20 74 79 70   only delete typ
6f00: 65 20 5c 22 66 69 6c 65 73 5c 22 20 74 68 69 73  e \"files\" this
6f10: 20 69 73 20 74 79 70 65 20 5c 22 24 70 61 74 68   is type \"$path
6f20: 61 74 74 72 73 28 70 61 74 68 5f 74 79 70 65 29  attrs(path_type)
6f30: 5c 22 22 0a 09 09 7d 0a 0a 09 09 73 65 74 20 6c  \""...}....set l
6f40: 6f 63 61 6c 70 61 74 68 20 24 70 61 74 68 61 74  ocalpath $pathat
6f50: 74 72 73 28 6c 6f 63 61 6c 70 61 74 68 29 0a 0a  trs(localpath)..
6f60: 09 09 69 66 20 7b 24 6c 6f 63 61 6c 70 61 74 68  ..if {$localpath
6f70: 20 3d 3d 20 22 22 7d 20 7b 0a 09 09 09 72 65 74   == ""} {....ret
6f80: 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20  urn -code error 
6f90: 22 41 73 6b 65 64 20 74 6f 20 64 65 6c 65 74 65  "Asked to delete
6fa0: 2c 20 62 75 74 20 6e 6f 20 68 6f 6d 65 20 64 69  , but no home di
6fb0: 72 65 63 74 6f 72 79 2e 22 0a 09 09 7d 0a 0a 09  rectory."...}...
6fc0: 09 69 66 20 7b 5b 69 6e 66 6f 20 65 78 69 73 74  .if {[info exist
6fd0: 73 20 70 61 74 68 61 74 74 72 73 28 69 73 5f 6c  s pathattrs(is_l
6fe0: 6f 63 61 6c 66 69 6c 65 29 5d 7d 20 7b 0a 09 09  ocalfile)]} {...
6ff0: 09 69 66 20 7b 5b 66 69 6c 65 20 69 73 64 69 72  .if {[file isdir
7000: 65 63 74 6f 72 79 20 24 6c 6f 63 61 6c 70 61 74  ectory $localpat
7010: 68 5d 7d 20 7b 0a 09 09 09 09 73 65 74 20 63 68  h]} {.....set ch
7020: 69 6c 64 72 65 6e 20 5b 67 65 74 63 68 69 6c 64  ildren [getchild
7030: 72 65 6e 20 24 70 61 74 68 5d 0a 0a 09 09 09 09  ren $path]......
7040: 69 66 20 7b 5b 6c 6c 65 6e 67 74 68 20 24 63 68  if {[llength $ch
7050: 69 6c 64 72 65 6e 5d 20 21 3d 20 30 7d 20 7b 0a  ildren] != 0} {.
7060: 09 09 09 09 09 72 65 74 75 72 6e 20 2d 63 6f 64  .....return -cod
7070: 65 20 65 72 72 6f 72 20 22 41 73 6b 65 64 20 74  e error "Asked t
7080: 6f 20 64 65 6c 65 74 65 20 6e 6f 6e 2d 65 6d 70  o delete non-emp
7090: 74 79 20 64 69 72 65 63 74 6f 72 79 22 0a 09 09  ty directory"...
70a0: 09 09 7d 0a 09 09 09 7d 0a 0a 09 09 09 5f 61 73  ..}....}....._as
70b0: 5f 75 73 65 72 20 7b 0a 09 09 09 09 66 69 6c 65  _user {.....file
70c0: 20 64 65 6c 65 74 65 20 2d 66 6f 72 63 65 20 2d   delete -force -
70d0: 2d 20 24 6c 6f 63 61 6c 70 61 74 68 0a 09 09 09  - $localpath....
70e0: 7d 0a 09 09 7d 20 65 6c 73 65 69 66 20 7b 5b 69  }...} elseif {[i
70f0: 6e 66 6f 20 65 78 69 73 74 73 20 70 61 74 68 61  nfo exists patha
7100: 74 74 72 73 28 69 73 5f 72 65 6d 6f 74 65 66 69  ttrs(is_remotefi
7110: 6c 65 29 5d 7d 20 7b 0a 09 09 09 69 66 20 7b 24  le)]} {....if {$
7120: 70 61 74 68 61 74 74 72 73 28 74 79 70 65 29 20  pathattrs(type) 
7130: 3d 3d 20 22 64 69 72 65 63 74 6f 72 79 22 7d 20  == "directory"} 
7140: 7b 0a 09 09 09 09 73 65 74 20 63 68 69 6c 64 72  {.....set childr
7150: 65 6e 20 5b 67 65 74 63 68 69 6c 64 72 65 6e 20  en [getchildren 
7160: 24 70 61 74 68 5d 0a 0a 09 09 09 09 69 66 20 7b  $path]......if {
7170: 5b 6c 6c 65 6e 67 74 68 20 24 63 68 69 6c 64 72  [llength $childr
7180: 65 6e 5d 20 21 3d 20 30 7d 20 7b 0a 09 09 09 09  en] != 0} {.....
7190: 09 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72  .return -code er
71a0: 72 6f 72 20 22 41 73 6b 65 64 20 74 6f 20 64 65  ror "Asked to de
71b0: 6c 65 74 65 20 6e 6f 6e 2d 65 6d 70 74 79 20 64  lete non-empty d
71c0: 69 72 65 63 74 6f 72 79 22 0a 09 09 09 09 7d 0a  irectory".....}.
71d0: 09 09 09 7d 0a 09 09 7d 20 65 6c 73 65 20 7b 0a  ...}...} else {.
71e0: 09 09 09 72 65 74 75 72 6e 20 2d 63 6f 64 65 20  ...return -code 
71f0: 65 72 72 6f 72 20 22 55 6e 6b 6e 6f 77 6e 20 69  error "Unknown i
7200: 66 20 66 69 6c 65 20 69 73 20 72 65 6d 6f 74 65  f file is remote
7210: 20 6f 72 20 6c 6f 63 61 6c 20 21 3f 22 0a 09 09   or local !?"...
7220: 7d 0a 0a 09 09 73 65 74 20 77 68 69 74 65 6f 75  }....set whiteou
7230: 74 66 69 6c 65 20 24 70 61 74 68 61 74 74 72 73  tfile $pathattrs
7240: 28 77 68 69 74 65 6f 75 74 70 61 74 68 29 0a 09  (whiteoutpath)..
7250: 09 73 65 74 20 77 68 69 74 65 6f 75 74 64 69 72  .set whiteoutdir
7260: 20 5b 66 69 6c 65 20 64 69 72 6e 61 6d 65 20 24   [file dirname $
7270: 77 68 69 74 65 6f 75 74 66 69 6c 65 5d 0a 0a 09  whiteoutfile]...
7280: 09 5f 61 73 5f 75 73 65 72 20 7b 0a 09 09 09 66  ._as_user {....f
7290: 69 6c 65 20 6d 6b 64 69 72 20 24 77 68 69 74 65  ile mkdir $white
72a0: 6f 75 74 64 69 72 0a 09 09 09 63 6c 6f 73 65 20  outdir....close 
72b0: 5b 6f 70 65 6e 20 24 77 68 69 74 65 6f 75 74 66  [open $whiteoutf
72c0: 69 6c 65 20 77 5d 0a 09 09 7d 0a 09 7d 0a 7d 0a  ile w]...}..}.}.