Hex Artifact Content

Artifact 649eb3a6a117a8431d0aef5366b89ee243f821cf:


0000: 23 21 20 2f 75 73 72 2f 62 69 6e 2f 65 6e 76 20  #! /usr/bin/env 
0010: 74 63 6c 73 68 0a 0a 70 61 63 6b 61 67 65 20 72  tclsh..package r
0020: 65 71 75 69 72 65 20 68 74 74 70 20 32 2e 37 0a  equire http 2.7.
0030: 70 61 63 6b 61 67 65 20 72 65 71 75 69 72 65 20  package require 
0040: 73 71 6c 69 74 65 33 0a 70 61 63 6b 61 67 65 20  sqlite3.package 
0050: 72 65 71 75 69 72 65 20 73 68 61 31 0a 70 61 63  require sha1.pac
0060: 6b 61 67 65 20 72 65 71 75 69 72 65 20 61 70 70  kage require app
0070: 66 73 64 0a 70 61 63 6b 61 67 65 20 72 65 71 75  fsd.package requ
0080: 69 72 65 20 70 6c 61 74 66 6f 72 6d 0a 70 61 63  ire platform.pac
0090: 6b 61 67 65 20 72 65 71 75 69 72 65 20 70 6b 69  kage require pki
00a0: 0a 0a 6e 61 6d 65 73 70 61 63 65 20 65 76 61 6c  ..namespace eval
00b0: 20 3a 3a 61 70 70 66 73 20 7b 0a 09 76 61 72 69   ::appfs {..vari
00c0: 61 62 6c 65 20 63 61 63 68 65 64 69 72 20 22 2f  able cachedir "/
00d0: 74 6d 70 2f 61 70 70 66 73 2d 63 61 63 68 65 22  tmp/appfs-cache"
00e0: 0a 09 76 61 72 69 61 62 6c 65 20 74 74 6c 20 33  ..variable ttl 3
00f0: 36 30 30 0a 09 76 61 72 69 61 62 6c 65 20 6e 74  600..variable nt
0100: 74 6c 20 36 30 0a 0a 09 23 20 55 73 65 72 2d 72  tl 60...# User-r
0110: 65 70 6c 61 63 61 62 6c 65 20 66 75 6e 63 74 69  eplacable functi
0120: 6f 6e 20 74 6f 20 63 6f 6e 76 65 72 74 20 61 20  on to convert a 
0130: 68 6f 73 74 6e 61 6d 65 2f 68 61 73 68 2f 6d 65  hostname/hash/me
0140: 74 68 6f 64 20 74 6f 20 61 6e 20 55 52 4c 0a 09  thod to an URL..
0150: 70 72 6f 63 20 5f 63 6f 6e 73 74 72 75 63 74 5f  proc _construct_
0160: 75 72 6c 20 7b 68 6f 73 74 6e 61 6d 65 20 68 61  url {hostname ha
0170: 73 68 20 6d 65 74 68 6f 64 7d 20 7b 0a 09 09 72  sh method} {...r
0180: 65 74 75 72 6e 20 22 68 74 74 70 3a 2f 2f 24 68  eturn "http://$h
0190: 6f 73 74 6e 61 6d 65 2f 61 70 70 66 73 2f 24 6d  ostname/appfs/$m
01a0: 65 74 68 6f 64 2f 24 68 61 73 68 22 0a 09 7d 0a  ethod/$hash"..}.
01b0: 0a 09 70 72 6f 63 20 5f 68 61 73 68 5f 73 65 70  ..proc _hash_sep
01c0: 20 7b 68 61 73 68 20 7b 73 65 70 73 20 34 7d 7d   {hash {seps 4}}
01d0: 20 7b 0a 09 09 66 6f 72 20 7b 73 65 74 20 69 64   {...for {set id
01e0: 78 20 30 7d 20 7b 24 69 64 78 20 3c 20 24 73 65  x 0} {$idx < $se
01f0: 70 73 7d 20 7b 69 6e 63 72 20 69 64 78 7d 20 7b  ps} {incr idx} {
0200: 0a 09 09 09 61 70 70 65 6e 64 20 72 65 74 76 61  ....append retva
0210: 6c 20 22 5b 73 74 72 69 6e 67 20 72 61 6e 67 65  l "[string range
0220: 20 24 68 61 73 68 20 5b 65 78 70 72 20 7b 24 69   $hash [expr {$i
0230: 64 78 20 2a 20 32 7d 5d 20 5b 65 78 70 72 20 7b  dx * 2}] [expr {
0240: 28 24 69 64 78 20 2a 20 32 29 20 2b 20 31 7d 5d  ($idx * 2) + 1}]
0250: 5d 2f 22 0a 09 09 7d 0a 09 09 61 70 70 65 6e 64  ]/"...}...append
0260: 20 72 65 74 76 61 6c 20 22 5b 73 74 72 69 6e 67   retval "[string
0270: 20 72 61 6e 67 65 20 24 68 61 73 68 20 5b 65 78   range $hash [ex
0280: 70 72 20 7b 24 69 64 78 20 2a 20 32 7d 5d 20 65  pr {$idx * 2}] e
0290: 6e 64 5d 22 0a 0a 09 09 72 65 74 75 72 6e 20 24  nd]"....return $
02a0: 72 65 74 76 61 6c 0a 09 7d 0a 0a 09 70 72 6f 63  retval..}...proc
02b0: 20 5f 63 61 63 68 65 66 69 6c 65 20 7b 75 72 6c   _cachefile {url
02c0: 20 6b 65 79 20 7b 6b 65 79 49 73 48 61 73 68 20   key {keyIsHash 
02d0: 31 7d 7d 20 7b 0a 09 09 73 65 74 20 66 69 6c 65  1}} {...set file
02e0: 6b 65 79 20 24 6b 65 79 0a 09 09 69 66 20 7b 24  key $key...if {$
02f0: 6b 65 79 49 73 48 61 73 68 7d 20 7b 0a 09 09 09  keyIsHash} {....
0300: 73 65 74 20 66 69 6c 65 6b 65 79 20 5b 5f 68 61  set filekey [_ha
0310: 73 68 5f 73 65 70 20 24 66 69 6c 65 6b 65 79 5d  sh_sep $filekey]
0320: 0a 09 09 7d 0a 0a 09 09 73 65 74 20 66 69 6c 65  ...}....set file
0330: 20 5b 66 69 6c 65 20 6a 6f 69 6e 20 24 3a 3a 61   [file join $::a
0340: 70 70 66 73 3a 3a 63 61 63 68 65 64 69 72 20 24  ppfs::cachedir $
0350: 66 69 6c 65 6b 65 79 5d 0a 0a 09 09 66 69 6c 65  filekey]....file
0360: 20 6d 6b 64 69 72 20 5b 66 69 6c 65 20 64 69 72   mkdir [file dir
0370: 6e 61 6d 65 20 24 66 69 6c 65 5d 0a 0a 09 09 69  name $file]....i
0380: 66 20 7b 5b 66 69 6c 65 20 65 78 69 73 74 73 20  f {[file exists 
0390: 24 66 69 6c 65 5d 7d 20 7b 0a 09 09 09 72 65 74  $file]} {....ret
03a0: 75 72 6e 20 24 66 69 6c 65 0a 09 09 7d 0a 0a 09  urn $file...}...
03b0: 09 73 65 74 20 74 6d 70 66 69 6c 65 20 22 24 7b  .set tmpfile "${
03c0: 66 69 6c 65 7d 2e 5b 65 78 70 72 20 7b 72 61 6e  file}.[expr {ran
03d0: 64 28 29 7d 5d 5b 63 6c 6f 63 6b 20 63 6c 69 63  d()}][clock clic
03e0: 6b 73 5d 22 0a 0a 09 09 73 65 74 20 66 64 20 5b  ks]"....set fd [
03f0: 6f 70 65 6e 20 24 74 6d 70 66 69 6c 65 20 22 77  open $tmpfile "w
0400: 22 5d 0a 09 09 66 63 6f 6e 66 69 67 75 72 65 20  "]...fconfigure 
0410: 24 66 64 20 2d 74 72 61 6e 73 6c 61 74 69 6f 6e  $fd -translation
0420: 20 62 69 6e 61 72 79 0a 0a 09 09 63 61 74 63 68   binary....catch
0430: 20 7b 0a 09 09 09 73 65 74 20 74 6f 6b 65 6e 20   {....set token 
0440: 5b 3a 3a 68 74 74 70 3a 3a 67 65 74 75 72 6c 20  [::http::geturl 
0450: 24 75 72 6c 20 2d 63 68 61 6e 6e 65 6c 20 24 66  $url -channel $f
0460: 64 20 2d 62 69 6e 61 72 79 20 74 72 75 65 5d 0a  d -binary true].
0470: 09 09 7d 0a 0a 09 09 69 66 20 7b 5b 69 6e 66 6f  ..}....if {[info
0480: 20 65 78 69 73 74 73 20 74 6f 6b 65 6e 5d 7d 20   exists token]} 
0490: 7b 0a 09 09 09 73 65 74 20 6e 63 6f 64 65 20 5b  {....set ncode [
04a0: 3a 3a 68 74 74 70 3a 3a 6e 63 6f 64 65 20 24 74  ::http::ncode $t
04b0: 6f 6b 65 6e 5d 0a 09 09 09 3a 3a 68 74 74 70 3a  oken]....::http:
04c0: 3a 72 65 73 65 74 20 24 74 6f 6b 65 6e 0a 09 09  :reset $token...
04d0: 7d 20 65 6c 73 65 20 7b 0a 09 09 09 73 65 74 20  } else {....set 
04e0: 6e 63 6f 64 65 20 22 39 30 30 22 0a 09 09 7d 0a  ncode "900"...}.
04f0: 0a 09 09 63 6c 6f 73 65 20 24 66 64 0a 0a 09 09  ...close $fd....
0500: 69 66 20 7b 24 6b 65 79 49 73 48 61 73 68 7d 20  if {$keyIsHash} 
0510: 7b 0a 09 09 09 73 65 74 20 68 61 73 68 20 5b 73  {....set hash [s
0520: 74 72 69 6e 67 20 74 6f 6c 6f 77 65 72 20 5b 73  tring tolower [s
0530: 68 61 31 3a 3a 73 68 61 31 20 2d 68 65 78 20 2d  ha1::sha1 -hex -
0540: 66 69 6c 65 20 24 74 6d 70 66 69 6c 65 5d 5d 0a  file $tmpfile]].
0550: 09 09 7d 20 65 6c 73 65 20 7b 0a 09 09 09 73 65  ..} else {....se
0560: 74 20 68 61 73 68 20 24 6b 65 79 0a 09 09 7d 0a  t hash $key...}.
0570: 0a 09 09 69 66 20 7b 24 6e 63 6f 64 65 20 3d 3d  ...if {$ncode ==
0580: 20 22 32 30 30 22 20 26 26 20 24 68 61 73 68 20   "200" && $hash 
0590: 3d 3d 20 24 6b 65 79 7d 20 7b 0a 09 09 09 66 69  == $key} {....fi
05a0: 6c 65 20 72 65 6e 61 6d 65 20 2d 66 6f 72 63 65  le rename -force
05b0: 20 2d 2d 20 24 74 6d 70 66 69 6c 65 20 24 66 69   -- $tmpfile $fi
05c0: 6c 65 0a 09 09 7d 20 65 6c 73 65 20 7b 0a 09 09  le...} else {...
05d0: 09 66 69 6c 65 20 64 65 6c 65 74 65 20 2d 66 6f  .file delete -fo
05e0: 72 63 65 20 2d 2d 20 24 74 6d 70 66 69 6c 65 0a  rce -- $tmpfile.
05f0: 09 09 7d 0a 0a 09 09 72 65 74 75 72 6e 20 24 66  ..}....return $f
0600: 69 6c 65 0a 09 7d 0a 0a 0a 09 70 72 6f 63 20 5f  ile..}....proc _
0610: 69 73 48 61 73 68 20 7b 76 61 6c 75 65 7d 20 7b  isHash {value} {
0620: 0a 09 09 73 65 74 20 76 61 6c 75 65 20 5b 73 74  ...set value [st
0630: 72 69 6e 67 20 74 6f 6c 6f 77 65 72 20 24 76 61  ring tolower $va
0640: 6c 75 65 5d 0a 0a 09 09 69 66 20 7b 5b 73 74 72  lue]....if {[str
0650: 69 6e 67 20 6c 65 6e 67 74 68 20 24 76 61 6c 75  ing length $valu
0660: 65 5d 20 21 3d 20 34 30 7d 20 7b 0a 09 09 09 72  e] != 40} {....r
0670: 65 74 75 72 6e 20 66 61 6c 73 65 0a 09 09 7d 0a  eturn false...}.
0680: 0a 09 09 69 66 20 7b 21 5b 72 65 67 65 78 70 20  ...if {![regexp 
0690: 7b 5e 5b 30 2d 39 61 2d 66 5d 2a 24 7d 20 24 76  {^[0-9a-f]*$} $v
06a0: 61 6c 75 65 5d 7d 20 7b 0a 09 09 09 72 65 74 75  alue]} {....retu
06b0: 72 6e 20 66 61 6c 73 65 0a 09 09 7d 0a 0a 09 09  rn false...}....
06c0: 72 65 74 75 72 6e 20 74 72 75 65 0a 09 7d 0a 0a  return true..}..
06d0: 09 70 72 6f 63 20 5f 6e 6f 72 6d 61 6c 69 7a 65  .proc _normalize
06e0: 4f 53 20 7b 6f 73 7d 20 7b 0a 09 09 73 65 74 20  OS {os} {...set 
06f0: 6f 73 20 5b 73 74 72 69 6e 67 20 74 6f 6c 6f 77  os [string tolow
0700: 65 72 20 5b 73 74 72 69 6e 67 20 74 72 69 6d 20  er [string trim 
0710: 24 6f 73 5d 5d 0a 0a 09 09 73 77 69 74 63 68 20  $os]]....switch 
0720: 2d 2d 20 24 6f 73 20 7b 0a 09 09 09 22 6c 69 6e  -- $os {...."lin
0730: 75 78 22 20 2d 20 22 66 72 65 65 62 73 64 22 20  ux" - "freebsd" 
0740: 2d 20 22 6f 70 65 6e 62 73 64 22 20 2d 20 22 6e  - "openbsd" - "n
0750: 65 74 62 73 64 22 20 7b 0a 09 09 09 09 72 65 74  etbsd" {.....ret
0760: 75 72 6e 20 24 6f 73 0a 09 09 09 7d 0a 09 09 09  urn $os....}....
0770: 22 73 75 6e 6f 73 22 20 7b 0a 09 09 09 09 72 65  "sunos" {.....re
0780: 74 75 72 6e 20 22 73 6f 6c 61 72 69 73 22 0a 09  turn "solaris"..
0790: 09 09 7d 0a 09 09 09 22 6e 6f 61 72 63 68 22 20  ..}...."noarch" 
07a0: 2d 20 22 6e 6f 6e 65 22 20 2d 20 22 61 6e 79 22  - "none" - "any"
07b0: 20 2d 20 22 61 6c 6c 22 20 7b 0a 09 09 09 09 72   - "all" {.....r
07c0: 65 74 75 72 6e 20 22 6e 6f 61 72 63 68 22 0a 09  eturn "noarch"..
07d0: 09 09 7d 0a 09 09 7d 0a 0a 09 09 72 65 74 75 72  ..}...}....retur
07e0: 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22 55  n -code error "U
07f0: 6e 61 62 6c 65 20 74 6f 20 6e 6f 72 6d 61 6c 69  nable to normali
0800: 7a 65 20 4f 53 3a 20 24 6f 73 22 0a 09 7d 0a 0a  ze OS: $os"..}..
0810: 09 70 72 6f 63 20 5f 6e 6f 72 6d 61 6c 69 7a 65  .proc _normalize
0820: 43 50 55 20 7b 63 70 75 7d 20 7b 0a 09 09 73 65  CPU {cpu} {...se
0830: 74 20 63 70 75 20 5b 73 74 72 69 6e 67 20 74 6f  t cpu [string to
0840: 6c 6f 77 65 72 20 5b 73 74 72 69 6e 67 20 74 72  lower [string tr
0850: 69 6d 20 24 63 70 75 5d 5d 0a 0a 09 09 73 77 69  im $cpu]]....swi
0860: 74 63 68 20 2d 67 6c 6f 62 20 2d 2d 20 24 63 70  tch -glob -- $cp
0870: 75 20 7b 0a 09 09 09 22 69 3f 38 36 22 20 7b 0a  u {...."i?86" {.
0880: 09 09 09 09 72 65 74 75 72 6e 20 22 69 78 38 36  ....return "ix86
0890: 22 0a 09 09 09 7d 0a 09 09 09 22 78 38 36 5f 36  "....}...."x86_6
08a0: 34 22 20 7b 0a 09 09 09 09 72 65 74 75 72 6e 20  4" {.....return 
08b0: 24 63 70 75 0a 09 09 09 7d 0a 09 09 09 22 6e 6f  $cpu....}...."no
08c0: 61 72 63 68 22 20 2d 20 22 6e 6f 6e 65 22 20 2d  arch" - "none" -
08d0: 20 22 61 6e 79 22 20 2d 20 22 61 6c 6c 22 20 7b   "any" - "all" {
08e0: 0a 09 09 09 09 72 65 74 75 72 6e 20 22 6e 6f 61  .....return "noa
08f0: 72 63 68 22 0a 09 09 09 7d 0a 09 09 7d 0a 0a 09  rch"....}...}...
0900: 09 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72  .return -code er
0910: 72 6f 72 20 22 55 6e 61 62 6c 65 20 74 6f 20 6e  ror "Unable to n
0920: 6f 72 6d 61 6c 69 7a 65 20 43 50 55 3a 20 24 63  ormalize CPU: $c
0930: 70 75 22 0a 09 7d 0a 0a 09 70 72 6f 63 20 69 6e  pu"..}...proc in
0940: 69 74 20 7b 7d 20 7b 0a 09 09 69 66 20 7b 5b 69  it {} {...if {[i
0950: 6e 66 6f 20 65 78 69 73 74 73 20 3a 3a 61 70 70  nfo exists ::app
0960: 66 73 3a 3a 69 6e 69 74 5f 63 61 6c 6c 65 64 5d  fs::init_called]
0970: 7d 20 7b 0a 09 09 09 72 65 74 75 72 6e 0a 09 09  } {....return...
0980: 7d 0a 0a 09 09 23 20 46 6f 72 63 65 20 5b 70 61  }....# Force [pa
0990: 72 72 61 79 5d 20 74 6f 20 62 65 20 6c 6f 61 64  rray] to be load
09a0: 65 64 0a 09 09 63 61 74 63 68 20 7b 0a 09 09 09  ed...catch {....
09b0: 70 61 72 72 61 79 20 64 6f 65 73 5f 6e 6f 74 5f  parray does_not_
09c0: 65 78 69 73 74 0a 09 09 7d 0a 0a 09 09 73 65 74  exist...}....set
09d0: 20 3a 3a 61 70 70 66 73 3a 3a 69 6e 69 74 5f 63   ::appfs::init_c
09e0: 61 6c 6c 65 64 20 31 0a 0a 09 09 23 20 4c 6f 61  alled 1....# Loa
09f0: 64 20 63 6f 6e 66 69 67 75 72 61 74 69 6f 6e 20  d configuration 
0a00: 66 69 6c 65 0a 09 09 73 65 74 20 63 6f 6e 66 69  file...set confi
0a10: 67 5f 66 69 6c 65 20 5b 66 69 6c 65 20 6a 6f 69  g_file [file joi
0a20: 6e 20 24 3a 3a 61 70 70 66 73 3a 3a 63 61 63 68  n $::appfs::cach
0a30: 65 64 69 72 20 63 6f 6e 66 69 67 5d 0a 09 09 69  edir config]...i
0a40: 66 20 7b 5b 66 69 6c 65 20 65 78 69 73 74 73 20  f {[file exists 
0a50: 24 63 6f 6e 66 69 67 5f 66 69 6c 65 5d 7d 20 7b  $config_file]} {
0a60: 0a 09 09 09 73 6f 75 72 63 65 20 24 63 6f 6e 66  ....source $conf
0a70: 69 67 5f 66 69 6c 65 0a 09 09 7d 0a 0a 09 09 69  ig_file...}....i
0a80: 66 20 7b 21 5b 69 6e 66 6f 20 65 78 69 73 74 73  f {![info exists
0a90: 20 3a 3a 61 70 70 66 73 3a 3a 64 62 5d 7d 20 7b   ::appfs::db]} {
0aa0: 0a 09 09 09 66 69 6c 65 20 6d 6b 64 69 72 20 24  ....file mkdir $
0ab0: 3a 3a 61 70 70 66 73 3a 3a 63 61 63 68 65 64 69  ::appfs::cachedi
0ac0: 72 0a 0a 09 09 09 73 71 6c 69 74 65 33 20 3a 3a  r.....sqlite3 ::
0ad0: 61 70 70 66 73 3a 3a 64 62 20 5b 66 69 6c 65 20  appfs::db [file 
0ae0: 6a 6f 69 6e 20 24 3a 3a 61 70 70 66 73 3a 3a 63  join $::appfs::c
0af0: 61 63 68 65 64 69 72 20 63 61 63 68 65 2e 64 62  achedir cache.db
0b00: 5d 0a 09 09 7d 0a 0a 09 09 23 20 43 72 65 61 74  ]...}....# Creat
0b10: 65 20 74 61 62 6c 65 73 0a 09 09 64 62 20 65 76  e tables...db ev
0b20: 61 6c 20 7b 43 52 45 41 54 45 20 54 41 42 4c 45  al {CREATE TABLE
0b30: 20 49 46 20 4e 4f 54 20 45 58 49 53 54 53 20 73   IF NOT EXISTS s
0b40: 69 74 65 73 28 68 6f 73 74 6e 61 6d 65 20 50 52  ites(hostname PR
0b50: 49 4d 41 52 59 20 4b 45 59 2c 20 6c 61 73 74 55  IMARY KEY, lastU
0b60: 70 64 61 74 65 2c 20 74 74 6c 29 3b 7d 0a 09 09  pdate, ttl);}...
0b70: 64 62 20 65 76 61 6c 20 7b 43 52 45 41 54 45 20  db eval {CREATE 
0b80: 54 41 42 4c 45 20 49 46 20 4e 4f 54 20 45 58 49  TABLE IF NOT EXI
0b90: 53 54 53 20 70 61 63 6b 61 67 65 73 28 68 6f 73  STS packages(hos
0ba0: 74 6e 61 6d 65 2c 20 73 68 61 31 2c 20 70 61 63  tname, sha1, pac
0bb0: 6b 61 67 65 2c 20 76 65 72 73 69 6f 6e 2c 20 6f  kage, version, o
0bc0: 73 2c 20 63 70 75 41 72 63 68 2c 20 69 73 4c 61  s, cpuArch, isLa
0bd0: 74 65 73 74 2c 20 68 61 76 65 4d 61 6e 69 66 65  test, haveManife
0be0: 73 74 29 3b 7d 0a 09 09 64 62 20 65 76 61 6c 20  st);}...db eval 
0bf0: 7b 43 52 45 41 54 45 20 54 41 42 4c 45 20 49 46  {CREATE TABLE IF
0c00: 20 4e 4f 54 20 45 58 49 53 54 53 20 66 69 6c 65   NOT EXISTS file
0c10: 73 28 70 61 63 6b 61 67 65 5f 73 68 61 31 2c 20  s(package_sha1, 
0c20: 74 79 70 65 2c 20 74 69 6d 65 2c 20 73 6f 75 72  type, time, sour
0c30: 63 65 2c 20 73 69 7a 65 2c 20 70 65 72 6d 73 2c  ce, size, perms,
0c40: 20 66 69 6c 65 5f 73 68 61 31 2c 20 66 69 6c 65   file_sha1, file
0c50: 5f 6e 61 6d 65 2c 20 66 69 6c 65 5f 64 69 72 65  _name, file_dire
0c60: 63 74 6f 72 79 29 3b 7d 0a 0a 09 09 23 20 43 72  ctory);}....# Cr
0c70: 65 61 74 65 20 69 6e 64 65 78 65 73 0a 09 09 64  eate indexes...d
0c80: 62 20 65 76 61 6c 20 7b 43 52 45 41 54 45 20 49  b eval {CREATE I
0c90: 4e 44 45 58 20 49 46 20 4e 4f 54 20 45 58 49 53  NDEX IF NOT EXIS
0ca0: 54 53 20 73 69 74 65 73 5f 69 6e 64 65 78 20 4f  TS sites_index O
0cb0: 4e 20 73 69 74 65 73 20 28 68 6f 73 74 6e 61 6d  N sites (hostnam
0cc0: 65 29 3b 7d 0a 09 09 64 62 20 65 76 61 6c 20 7b  e);}...db eval {
0cd0: 43 52 45 41 54 45 20 49 4e 44 45 58 20 49 46 20  CREATE INDEX IF 
0ce0: 4e 4f 54 20 45 58 49 53 54 53 20 70 61 63 6b 61  NOT EXISTS packa
0cf0: 67 65 73 5f 69 6e 64 65 78 20 4f 4e 20 70 61 63  ges_index ON pac
0d00: 6b 61 67 65 73 20 28 68 6f 73 74 6e 61 6d 65 2c  kages (hostname,
0d10: 20 70 61 63 6b 61 67 65 2c 20 76 65 72 73 69 6f   package, versio
0d20: 6e 2c 20 6f 73 2c 20 63 70 75 41 72 63 68 29 3b  n, os, cpuArch);
0d30: 7d 0a 09 09 64 62 20 65 76 61 6c 20 7b 43 52 45  }...db eval {CRE
0d40: 41 54 45 20 49 4e 44 45 58 20 49 46 20 4e 4f 54  ATE INDEX IF NOT
0d50: 20 45 58 49 53 54 53 20 66 69 6c 65 73 5f 69 6e   EXISTS files_in
0d60: 64 65 78 20 4f 4e 20 66 69 6c 65 73 20 28 70 61  dex ON files (pa
0d70: 63 6b 61 67 65 5f 73 68 61 31 2c 20 66 69 6c 65  ckage_sha1, file
0d80: 5f 6e 61 6d 65 2c 20 66 69 6c 65 5f 64 69 72 65  _name, file_dire
0d90: 63 74 6f 72 79 29 3b 7d 0a 09 7d 0a 0a 09 70 72  ctory);}..}...pr
0da0: 6f 63 20 64 6f 77 6e 6c 6f 61 64 20 7b 68 6f 73  oc download {hos
0db0: 74 6e 61 6d 65 20 68 61 73 68 20 7b 6d 65 74 68  tname hash {meth
0dc0: 6f 64 20 73 68 61 31 7d 7d 20 7b 0a 09 09 3a 3a  od sha1}} {...::
0dd0: 61 70 70 66 73 64 3a 3a 73 69 6d 75 6c 61 74 65  appfsd::simulate
0de0: 5f 75 73 65 72 5f 66 73 5f 6c 65 61 76 65 0a 0a  _user_fs_leave..
0df0: 09 09 73 65 74 20 75 72 6c 20 5b 5f 63 6f 6e 73  ..set url [_cons
0e00: 74 72 75 63 74 5f 75 72 6c 20 24 68 6f 73 74 6e  truct_url $hostn
0e10: 61 6d 65 20 24 68 61 73 68 20 24 6d 65 74 68 6f  ame $hash $metho
0e20: 64 5d 0a 09 09 73 65 74 20 66 69 6c 65 20 5b 5f  d]...set file [_
0e30: 63 61 63 68 65 66 69 6c 65 20 24 75 72 6c 20 24  cachefile $url $
0e40: 68 61 73 68 5d 0a 0a 09 09 3a 3a 61 70 70 66 73  hash]....::appfs
0e50: 64 3a 3a 73 69 6d 75 6c 61 74 65 5f 75 73 65 72  d::simulate_user
0e60: 5f 66 73 5f 65 6e 74 65 72 0a 0a 09 09 69 66 20  _fs_enter....if 
0e70: 7b 21 5b 66 69 6c 65 20 65 78 69 73 74 73 20 24  {![file exists $
0e80: 66 69 6c 65 5d 7d 20 7b 0a 09 09 09 72 65 74 75  file]} {....retu
0e90: 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22  rn -code error "
0ea0: 55 6e 61 62 6c 65 20 74 6f 20 66 65 74 63 68 20  Unable to fetch 
0eb0: 28 66 69 6c 65 20 64 6f 65 73 20 6e 6f 74 20 65  (file does not e
0ec0: 78 69 73 74 3a 20 24 66 69 6c 65 29 22 0a 09 09  xist: $file)"...
0ed0: 7d 0a 0a 09 09 72 65 74 75 72 6e 20 24 66 69 6c  }....return $fil
0ee0: 65 0a 09 7d 0a 0a 09 70 72 6f 63 20 67 65 74 69  e..}...proc geti
0ef0: 6e 64 65 78 20 7b 68 6f 73 74 6e 61 6d 65 7d 20  ndex {hostname} 
0f00: 7b 0a 09 09 73 65 74 20 6e 6f 77 20 5b 63 6c 6f  {...set now [clo
0f10: 63 6b 20 73 65 63 6f 6e 64 73 5d 0a 0a 09 09 73  ck seconds]....s
0f20: 65 74 20 6c 61 73 74 55 70 64 61 74 65 73 20 5b  et lastUpdates [
0f30: 64 62 20 65 76 61 6c 20 7b 53 45 4c 45 43 54 20  db eval {SELECT 
0f40: 6c 61 73 74 55 70 64 61 74 65 2c 20 74 74 6c 20  lastUpdate, ttl 
0f50: 46 52 4f 4d 20 73 69 74 65 73 20 57 48 45 52 45  FROM sites WHERE
0f60: 20 68 6f 73 74 6e 61 6d 65 20 3d 20 24 68 6f 73   hostname = $hos
0f70: 74 6e 61 6d 65 20 4c 49 4d 49 54 20 31 3b 7d 5d  tname LIMIT 1;}]
0f80: 0a 09 09 69 66 20 7b 5b 6c 6c 65 6e 67 74 68 20  ...if {[llength 
0f90: 24 6c 61 73 74 55 70 64 61 74 65 73 5d 20 3d 3d  $lastUpdates] ==
0fa0: 20 30 7d 20 7b 0a 09 09 09 73 65 74 20 6c 61 73   0} {....set las
0fb0: 74 55 70 64 61 74 65 20 30 0a 09 09 09 73 65 74  tUpdate 0....set
0fc0: 20 74 74 6c 20 30 0a 09 09 7d 20 65 6c 73 65 20   ttl 0...} else 
0fd0: 7b 0a 09 09 09 73 65 74 20 6c 61 73 74 55 70 64  {....set lastUpd
0fe0: 61 74 65 20 5b 6c 69 6e 64 65 78 20 24 6c 61 73  ate [lindex $las
0ff0: 74 55 70 64 61 74 65 73 20 30 5d 0a 09 09 09 73  tUpdates 0]....s
1000: 65 74 20 74 74 6c 20 5b 6c 69 6e 64 65 78 20 24  et ttl [lindex $
1010: 6c 61 73 74 55 70 64 61 74 65 73 20 31 5d 0a 09  lastUpdates 1]..
1020: 09 7d 0a 0a 09 09 69 66 20 7b 24 6e 6f 77 20 3c  .}....if {$now <
1030: 20 28 24 6c 61 73 74 55 70 64 61 74 65 20 2b 20   ($lastUpdate + 
1040: 24 74 74 6c 29 7d 20 7b 0a 09 09 09 72 65 74 75  $ttl)} {....retu
1050: 72 6e 20 43 4f 4d 50 4c 45 54 45 0a 09 09 7d 0a  rn COMPLETE...}.
1060: 0a 09 09 69 66 20 7b 5b 73 74 72 69 6e 67 20 6d  ...if {[string m
1070: 61 74 63 68 20 22 2a 5c 5b 2f 7e 5c 5d 2a 22 20  atch "*\[/~\]*" 
1080: 24 68 6f 73 74 6e 61 6d 65 5d 7d 20 7b 0a 09 09  $hostname]} {...
1090: 09 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72  .return -code er
10a0: 72 6f 72 20 22 49 6e 76 61 6c 69 64 20 68 6f 73  ror "Invalid hos
10b0: 74 6e 61 6d 65 22 0a 09 09 7d 0a 0a 09 09 73 65  tname"...}....se
10c0: 74 20 75 72 6c 20 22 68 74 74 70 3a 2f 2f 24 68  t url "http://$h
10d0: 6f 73 74 6e 61 6d 65 2f 61 70 70 66 73 2f 69 6e  ostname/appfs/in
10e0: 64 65 78 22 0a 0a 09 09 63 61 74 63 68 20 7b 0a  dex"....catch {.
10f0: 09 09 09 73 65 74 20 74 6f 6b 65 6e 20 5b 3a 3a  ...set token [::
1100: 68 74 74 70 3a 3a 67 65 74 75 72 6c 20 24 75 72  http::geturl $ur
1110: 6c 5d 0a 09 09 09 69 66 20 7b 5b 3a 3a 68 74 74  l]....if {[::htt
1120: 70 3a 3a 6e 63 6f 64 65 20 24 74 6f 6b 65 6e 5d  p::ncode $token]
1130: 20 3d 3d 20 22 32 30 30 22 7d 20 7b 0a 09 09 09   == "200"} {....
1140: 09 73 65 74 20 69 6e 64 65 78 68 61 73 68 5f 64  .set indexhash_d
1150: 61 74 61 20 5b 3a 3a 68 74 74 70 3a 3a 64 61 74  ata [::http::dat
1160: 61 20 24 74 6f 6b 65 6e 5d 0a 09 09 09 7d 0a 09  a $token]....}..
1170: 09 09 3a 3a 68 74 74 70 3a 3a 72 65 73 65 74 20  ..::http::reset 
1180: 24 74 6f 6b 65 6e 0a 09 09 09 3a 3a 68 74 74 70  $token....::http
1190: 3a 3a 63 6c 65 61 6e 75 70 20 24 74 6f 6b 65 6e  ::cleanup $token
11a0: 0a 09 09 7d 0a 0a 09 09 69 66 20 7b 21 5b 69 6e  ...}....if {![in
11b0: 66 6f 20 65 78 69 73 74 73 20 69 6e 64 65 78 68  fo exists indexh
11c0: 61 73 68 5f 64 61 74 61 5d 7d 20 7b 0a 09 09 09  ash_data]} {....
11d0: 23 20 43 61 63 68 65 20 74 68 69 73 20 72 65 73  # Cache this res
11e0: 75 6c 74 20 66 6f 72 20 36 30 20 73 65 63 6f 6e  ult for 60 secon
11f0: 64 73 0a 09 09 09 64 62 20 65 76 61 6c 20 7b 49  ds....db eval {I
1200: 4e 53 45 52 54 20 4f 52 20 52 45 50 4c 41 43 45  NSERT OR REPLACE
1210: 20 49 4e 54 4f 20 73 69 74 65 73 20 28 68 6f 73   INTO sites (hos
1220: 74 6e 61 6d 65 2c 20 6c 61 73 74 55 70 64 61 74  tname, lastUpdat
1230: 65 2c 20 74 74 6c 29 20 56 41 4c 55 45 53 20 28  e, ttl) VALUES (
1240: 24 68 6f 73 74 6e 61 6d 65 2c 20 24 6e 6f 77 2c  $hostname, $now,
1250: 20 24 3a 3a 61 70 70 66 73 3a 3a 6e 74 74 6c 29   $::appfs::nttl)
1260: 3b 7d 0a 0a 09 09 09 72 65 74 75 72 6e 20 2d 63  ;}.....return -c
1270: 6f 64 65 20 65 72 72 6f 72 20 22 55 6e 61 62 6c  ode error "Unabl
1280: 65 20 74 6f 20 66 65 74 63 68 20 24 75 72 6c 22  e to fetch $url"
1290: 0a 09 09 7d 0a 0a 09 09 73 65 74 20 69 6e 64 65  ...}....set inde
12a0: 78 68 61 73 68 20 5b 6c 69 6e 64 65 78 20 5b 73  xhash [lindex [s
12b0: 70 6c 69 74 20 24 69 6e 64 65 78 68 61 73 68 5f  plit $indexhash_
12c0: 64 61 74 61 20 22 2c 22 5d 20 30 5d 0a 0a 09 09  data ","] 0]....
12d0: 69 66 20 7b 21 5b 5f 69 73 48 61 73 68 20 24 69  if {![_isHash $i
12e0: 6e 64 65 78 68 61 73 68 5d 7d 20 7b 0a 09 09 09  ndexhash]} {....
12f0: 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72 72  return -code err
1300: 6f 72 20 22 49 6e 76 61 6c 69 64 20 68 61 73 68  or "Invalid hash
1310: 3a 20 24 69 6e 64 65 78 68 61 73 68 22 0a 09 09  : $indexhash"...
1320: 7d 0a 0a 09 09 73 65 74 20 66 69 6c 65 20 5b 64  }....set file [d
1330: 6f 77 6e 6c 6f 61 64 20 24 68 6f 73 74 6e 61 6d  ownload $hostnam
1340: 65 20 24 69 6e 64 65 78 68 61 73 68 5d 0a 09 09  e $indexhash]...
1350: 73 65 74 20 66 64 20 5b 6f 70 65 6e 20 24 66 69  set fd [open $fi
1360: 6c 65 5d 0a 09 09 73 65 74 20 64 61 74 61 20 5b  le]...set data [
1370: 72 65 61 64 20 24 66 64 5d 0a 09 09 63 6c 6f 73  read $fd]...clos
1380: 65 20 24 66 64 0a 0a 09 09 73 65 74 20 63 75 72  e $fd....set cur
1390: 72 5f 70 61 63 6b 61 67 65 73 20 5b 6c 69 73 74  r_packages [list
13a0: 5d 0a 09 09 66 6f 72 65 61 63 68 20 6c 69 6e 65  ]...foreach line
13b0: 20 5b 73 70 6c 69 74 20 24 64 61 74 61 20 22 5c   [split $data "\
13c0: 6e 22 5d 20 7b 0a 09 09 09 73 65 74 20 6c 69 6e  n"] {....set lin
13d0: 65 20 5b 73 74 72 69 6e 67 20 74 72 69 6d 20 24  e [string trim $
13e0: 6c 69 6e 65 5d 0a 0a 09 09 09 69 66 20 7b 5b 73  line].....if {[s
13f0: 74 72 69 6e 67 20 6d 61 74 63 68 20 22 2a 2f 2a  tring match "*/*
1400: 22 20 24 6c 69 6e 65 5d 7d 20 7b 0a 09 09 09 09  " $line]} {.....
1410: 63 6f 6e 74 69 6e 75 65 0a 09 09 09 7d 0a 0a 09  continue....}...
1420: 09 09 69 66 20 7b 24 6c 69 6e 65 20 3d 3d 20 22  ..if {$line == "
1430: 22 7d 20 7b 0a 09 09 09 09 63 6f 6e 74 69 6e 75  "} {.....continu
1440: 65 0a 09 09 09 7d 0a 0a 09 09 09 73 65 74 20 77  e....}.....set w
1450: 6f 72 6b 20 5b 73 70 6c 69 74 20 24 6c 69 6e 65  ork [split $line
1460: 20 22 2c 22 5d 0a 0a 09 09 09 75 6e 73 65 74 20   ","].....unset 
1470: 2d 6e 6f 63 6f 6d 70 6c 61 69 6e 20 70 6b 67 49  -nocomplain pkgI
1480: 6e 66 6f 0a 09 09 09 69 66 20 7b 5b 63 61 74 63  nfo....if {[catc
1490: 68 20 7b 0a 09 09 09 09 73 65 74 20 70 6b 67 49  h {.....set pkgI
14a0: 6e 66 6f 28 70 61 63 6b 61 67 65 29 20 20 5b 6c  nfo(package)  [l
14b0: 69 6e 64 65 78 20 24 77 6f 72 6b 20 30 5d 0a 09  index $work 0]..
14c0: 09 09 09 73 65 74 20 70 6b 67 49 6e 66 6f 28 76  ...set pkgInfo(v
14d0: 65 72 73 69 6f 6e 29 20 20 5b 6c 69 6e 64 65 78  ersion)  [lindex
14e0: 20 24 77 6f 72 6b 20 31 5d 0a 09 09 09 09 73 65   $work 1].....se
14f0: 74 20 70 6b 67 49 6e 66 6f 28 6f 73 29 20 20 20  t pkgInfo(os)   
1500: 20 20 20 20 5b 5f 6e 6f 72 6d 61 6c 69 7a 65 4f      [_normalizeO
1510: 53 20 5b 6c 69 6e 64 65 78 20 24 77 6f 72 6b 20  S [lindex $work 
1520: 32 5d 5d 0a 09 09 09 09 73 65 74 20 70 6b 67 49  2]].....set pkgI
1530: 6e 66 6f 28 63 70 75 41 72 63 68 29 20 20 5b 5f  nfo(cpuArch)  [_
1540: 6e 6f 72 6d 61 6c 69 7a 65 43 50 55 20 5b 6c 69  normalizeCPU [li
1550: 6e 64 65 78 20 24 77 6f 72 6b 20 33 5d 5d 0a 09  ndex $work 3]]..
1560: 09 09 09 73 65 74 20 70 6b 67 49 6e 66 6f 28 68  ...set pkgInfo(h
1570: 61 73 68 29 20 20 20 20 20 5b 73 74 72 69 6e 67  ash)     [string
1580: 20 74 6f 6c 6f 77 65 72 20 5b 6c 69 6e 64 65 78   tolower [lindex
1590: 20 24 77 6f 72 6b 20 34 5d 5d 0a 09 09 09 09 73   $work 4]].....s
15a0: 65 74 20 70 6b 67 49 6e 66 6f 28 68 61 73 68 5f  et pkgInfo(hash_
15b0: 74 79 70 65 29 20 22 73 68 61 31 22 0a 09 09 09  type) "sha1"....
15c0: 09 73 65 74 20 70 6b 67 49 6e 66 6f 28 69 73 4c  .set pkgInfo(isL
15d0: 61 74 65 73 74 29 20 5b 65 78 70 72 20 7b 21 21  atest) [expr {!!
15e0: 5b 6c 69 6e 64 65 78 20 24 77 6f 72 6b 20 35 5d  [lindex $work 5]
15f0: 7d 5d 0a 09 09 09 7d 5d 7d 20 7b 0a 09 09 09 09  }]....}]} {.....
1600: 63 6f 6e 74 69 6e 75 65 0a 09 09 09 7d 0a 0a 09  continue....}...
1610: 09 09 69 66 20 7b 21 5b 5f 69 73 48 61 73 68 20  ..if {![_isHash 
1620: 24 70 6b 67 49 6e 66 6f 28 68 61 73 68 29 5d 7d  $pkgInfo(hash)]}
1630: 20 7b 0a 09 09 09 09 63 6f 6e 74 69 6e 75 65 0a   {.....continue.
1640: 09 09 09 7d 0a 0a 09 09 09 6c 61 70 70 65 6e 64  ...}.....lappend
1650: 20 63 75 72 72 5f 70 61 63 6b 61 67 65 73 20 24   curr_packages $
1660: 70 6b 67 49 6e 66 6f 28 68 61 73 68 29 0a 0a 09  pkgInfo(hash)...
1670: 09 09 23 20 44 6f 20 6e 6f 74 20 64 6f 20 61 6e  ..# Do not do an
1680: 79 20 61 64 64 69 74 69 6f 6e 61 6c 20 77 6f 72  y additional wor
1690: 6b 20 69 66 20 77 65 20 61 6c 72 65 61 64 79 20  k if we already 
16a0: 68 61 76 65 20 74 68 69 73 20 70 61 63 6b 61 67  have this packag
16b0: 65 0a 09 09 09 73 65 74 20 65 78 69 73 74 69 6e  e....set existin
16c0: 67 5f 70 61 63 6b 61 67 65 73 20 5b 64 62 20 65  g_packages [db e
16d0: 76 61 6c 20 7b 53 45 4c 45 43 54 20 70 61 63 6b  val {SELECT pack
16e0: 61 67 65 20 46 52 4f 4d 20 70 61 63 6b 61 67 65  age FROM package
16f0: 73 20 57 48 45 52 45 20 68 6f 73 74 6e 61 6d 65  s WHERE hostname
1700: 20 3d 20 24 68 6f 73 74 6e 61 6d 65 20 41 4e 44   = $hostname AND
1710: 20 73 68 61 31 20 3d 20 24 70 6b 67 49 6e 66 6f   sha1 = $pkgInfo
1720: 28 68 61 73 68 29 3b 7d 5d 0a 09 09 09 69 66 20  (hash);}]....if 
1730: 7b 5b 6c 73 65 61 72 63 68 20 2d 65 78 61 63 74  {[lsearch -exact
1740: 20 24 65 78 69 73 74 69 6e 67 5f 70 61 63 6b 61   $existing_packa
1750: 67 65 73 20 24 70 6b 67 49 6e 66 6f 28 70 61 63  ges $pkgInfo(pac
1760: 6b 61 67 65 29 5d 20 21 3d 20 2d 31 7d 20 7b 0a  kage)] != -1} {.
1770: 09 09 09 09 63 6f 6e 74 69 6e 75 65 0a 09 09 09  ....continue....
1780: 7d 0a 0a 09 09 09 69 66 20 7b 24 70 6b 67 49 6e  }.....if {$pkgIn
1790: 66 6f 28 69 73 4c 61 74 65 73 74 29 7d 20 7b 0a  fo(isLatest)} {.
17a0: 09 09 09 09 64 62 20 65 76 61 6c 20 7b 55 50 44  ....db eval {UPD
17b0: 41 54 45 20 70 61 63 6b 61 67 65 73 20 53 45 54  ATE packages SET
17c0: 20 69 73 4c 61 74 65 73 74 20 3d 20 30 20 57 48   isLatest = 0 WH
17d0: 45 52 45 20 68 6f 73 74 6e 61 6d 65 20 3d 20 24  ERE hostname = $
17e0: 68 6f 73 74 6e 61 6d 65 20 41 4e 44 20 70 61 63  hostname AND pac
17f0: 6b 61 67 65 20 3d 20 24 70 6b 67 49 6e 66 6f 28  kage = $pkgInfo(
1800: 24 70 61 63 6b 61 67 65 29 20 41 4e 44 20 6f 73  $package) AND os
1810: 20 3d 20 24 70 6b 67 49 6e 66 6f 28 24 70 61 63   = $pkgInfo($pac
1820: 6b 61 67 65 29 20 41 4e 44 20 63 70 75 41 72 63  kage) AND cpuArc
1830: 68 20 3d 20 24 70 6b 67 49 6e 66 6f 28 63 70 75  h = $pkgInfo(cpu
1840: 41 72 63 68 29 3b 7d 0a 09 09 09 7d 0a 0a 09 09  Arch);}....}....
1850: 09 64 62 20 65 76 61 6c 20 7b 49 4e 53 45 52 54  .db eval {INSERT
1860: 20 49 4e 54 4f 20 70 61 63 6b 61 67 65 73 20 28   INTO packages (
1870: 68 6f 73 74 6e 61 6d 65 2c 20 73 68 61 31 2c 20  hostname, sha1, 
1880: 70 61 63 6b 61 67 65 2c 20 76 65 72 73 69 6f 6e  package, version
1890: 2c 20 6f 73 2c 20 63 70 75 41 72 63 68 2c 20 69  , os, cpuArch, i
18a0: 73 4c 61 74 65 73 74 2c 20 68 61 76 65 4d 61 6e  sLatest, haveMan
18b0: 69 66 65 73 74 29 20 56 41 4c 55 45 53 20 28 24  ifest) VALUES ($
18c0: 68 6f 73 74 6e 61 6d 65 2c 20 24 70 6b 67 49 6e  hostname, $pkgIn
18d0: 66 6f 28 68 61 73 68 29 2c 20 24 70 6b 67 49 6e  fo(hash), $pkgIn
18e0: 66 6f 28 70 61 63 6b 61 67 65 29 2c 20 24 70 6b  fo(package), $pk
18f0: 67 49 6e 66 6f 28 76 65 72 73 69 6f 6e 29 2c 20  gInfo(version), 
1900: 24 70 6b 67 49 6e 66 6f 28 6f 73 29 2c 20 24 70  $pkgInfo(os), $p
1910: 6b 67 49 6e 66 6f 28 63 70 75 41 72 63 68 29 2c  kgInfo(cpuArch),
1920: 20 24 70 6b 67 49 6e 66 6f 28 69 73 4c 61 74 65   $pkgInfo(isLate
1930: 73 74 29 2c 20 30 29 3b 7d 0a 09 09 7d 0a 0a 09  st), 0);}...}...
1940: 09 23 20 4c 6f 6f 6b 20 66 6f 72 20 70 61 63 6b  .# Look for pack
1950: 61 67 65 73 20 74 68 61 74 20 68 61 76 65 20 62  ages that have b
1960: 65 65 6e 20 64 65 6c 65 74 65 64 0a 09 09 73 65  een deleted...se
1970: 74 20 66 6f 75 6e 64 5f 70 61 63 6b 61 67 65 73  t found_packages
1980: 20 5b 64 62 20 65 76 61 6c 20 7b 53 45 4c 45 43   [db eval {SELEC
1990: 54 20 73 68 61 31 20 46 52 4f 4d 20 70 61 63 6b  T sha1 FROM pack
19a0: 61 67 65 73 20 57 48 45 52 45 20 68 6f 73 74 6e  ages WHERE hostn
19b0: 61 6d 65 20 3d 20 24 68 6f 73 74 6e 61 6d 65 3b  ame = $hostname;
19c0: 7d 5d 0a 09 09 66 6f 72 65 61 63 68 20 70 61 63  }]...foreach pac
19d0: 6b 61 67 65 20 24 66 6f 75 6e 64 5f 70 61 63 6b  kage $found_pack
19e0: 61 67 65 73 20 7b 0a 09 09 09 73 65 74 20 66 6f  ages {....set fo
19f0: 75 6e 64 5f 70 61 63 6b 61 67 65 73 5f 61 72 72  und_packages_arr
1a00: 28 24 70 61 63 6b 61 67 65 29 20 31 0a 09 09 7d  ($package) 1...}
1a10: 0a 0a 09 09 66 6f 72 65 61 63 68 20 70 61 63 6b  ....foreach pack
1a20: 61 67 65 20 24 63 75 72 72 5f 70 61 63 6b 61 67  age $curr_packag
1a30: 65 73 20 7b 0a 09 09 09 75 6e 73 65 74 20 2d 6e  es {....unset -n
1a40: 6f 63 6f 6d 70 6c 61 69 6e 20 66 6f 75 6e 64 5f  ocomplain found_
1a50: 70 61 63 6b 61 67 65 73 5f 61 72 72 28 24 70 61  packages_arr($pa
1a60: 63 6b 61 67 65 29 0a 09 09 7d 0a 0a 09 09 66 6f  ckage)...}....fo
1a70: 72 65 61 63 68 20 70 61 63 6b 61 67 65 20 5b 61  reach package [a
1a80: 72 72 61 79 20 6e 61 6d 65 73 20 66 6f 75 6e 64  rray names found
1a90: 5f 70 61 63 6b 61 67 65 73 5f 61 72 72 5d 20 7b  _packages_arr] {
1aa0: 0a 09 09 09 64 62 20 65 76 61 6c 20 7b 44 45 4c  ....db eval {DEL
1ab0: 45 54 45 20 46 52 4f 4d 20 70 61 63 6b 61 67 65  ETE FROM package
1ac0: 73 20 57 48 45 52 45 20 68 6f 73 74 6e 61 6d 65  s WHERE hostname
1ad0: 20 3d 20 24 68 6f 73 74 6e 61 6d 65 20 41 4e 44   = $hostname AND
1ae0: 20 73 68 61 31 20 3d 20 24 70 61 63 6b 61 67 65   sha1 = $package
1af0: 3b 7d 0a 09 09 7d 0a 0a 09 09 64 62 20 65 76 61  ;}...}....db eva
1b00: 6c 20 7b 49 4e 53 45 52 54 20 4f 52 20 52 45 50  l {INSERT OR REP
1b10: 4c 41 43 45 20 49 4e 54 4f 20 73 69 74 65 73 20  LACE INTO sites 
1b20: 28 68 6f 73 74 6e 61 6d 65 2c 20 6c 61 73 74 55  (hostname, lastU
1b30: 70 64 61 74 65 2c 20 74 74 6c 29 20 56 41 4c 55  pdate, ttl) VALU
1b40: 45 53 20 28 24 68 6f 73 74 6e 61 6d 65 2c 20 24  ES ($hostname, $
1b50: 6e 6f 77 2c 20 24 3a 3a 61 70 70 66 73 3a 3a 74  now, $::appfs::t
1b60: 74 6c 29 3b 7d 0a 0a 09 09 72 65 74 75 72 6e 20  tl);}....return 
1b70: 43 4f 4d 50 4c 45 54 45 0a 09 7d 0a 0a 09 70 72  COMPLETE..}...pr
1b80: 6f 63 20 67 65 74 70 6b 67 6d 61 6e 69 66 65 73  oc getpkgmanifes
1b90: 74 20 7b 68 6f 73 74 6e 61 6d 65 20 70 61 63 6b  t {hostname pack
1ba0: 61 67 65 5f 73 68 61 31 7d 20 7b 0a 09 09 73 65  age_sha1} {...se
1bb0: 74 20 68 61 76 65 4d 61 6e 69 66 65 73 74 73 20  t haveManifests 
1bc0: 5b 64 62 20 65 76 61 6c 20 7b 53 45 4c 45 43 54  [db eval {SELECT
1bd0: 20 68 61 76 65 4d 61 6e 69 66 65 73 74 20 46 52   haveManifest FR
1be0: 4f 4d 20 70 61 63 6b 61 67 65 73 20 57 48 45 52  OM packages WHER
1bf0: 45 20 73 68 61 31 20 3d 20 24 70 61 63 6b 61 67  E sha1 = $packag
1c00: 65 5f 73 68 61 31 20 4c 49 4d 49 54 20 31 3b 7d  e_sha1 LIMIT 1;}
1c10: 5d 0a 09 09 73 65 74 20 68 61 76 65 4d 61 6e 69  ]...set haveMani
1c20: 66 65 73 74 20 5b 6c 69 6e 64 65 78 20 24 68 61  fest [lindex $ha
1c30: 76 65 4d 61 6e 69 66 65 73 74 73 20 30 5d 0a 0a  veManifests 0]..
1c40: 09 09 69 66 20 7b 24 68 61 76 65 4d 61 6e 69 66  ..if {$haveManif
1c50: 65 73 74 7d 20 7b 0a 09 09 09 72 65 74 75 72 6e  est} {....return
1c60: 20 43 4f 4d 50 4c 45 54 45 0a 09 09 7d 0a 0a 09   COMPLETE...}...
1c70: 09 69 66 20 7b 21 5b 5f 69 73 48 61 73 68 20 24  .if {![_isHash $
1c80: 70 61 63 6b 61 67 65 5f 73 68 61 31 5d 7d 20 7b  package_sha1]} {
1c90: 0a 09 09 09 72 65 74 75 72 6e 20 46 41 49 4c 0a  ....return FAIL.
1ca0: 09 09 7d 0a 0a 09 09 73 65 74 20 66 69 6c 65 20  ..}....set file 
1cb0: 5b 64 6f 77 6e 6c 6f 61 64 20 24 68 6f 73 74 6e  [download $hostn
1cc0: 61 6d 65 20 24 70 61 63 6b 61 67 65 5f 73 68 61  ame $package_sha
1cd0: 31 5d 0a 09 09 73 65 74 20 66 64 20 5b 6f 70 65  1]...set fd [ope
1ce0: 6e 20 24 66 69 6c 65 5d 0a 09 09 73 65 74 20 70  n $file]...set p
1cf0: 6b 67 64 61 74 61 20 5b 72 65 61 64 20 24 66 64  kgdata [read $fd
1d00: 5d 0a 09 09 63 6c 6f 73 65 20 24 66 64 0a 0a 09  ]...close $fd...
1d10: 09 64 62 20 74 72 61 6e 73 61 63 74 69 6f 6e 20  .db transaction 
1d20: 7b 0a 09 09 09 66 6f 72 65 61 63 68 20 6c 69 6e  {....foreach lin
1d30: 65 20 5b 73 70 6c 69 74 20 24 70 6b 67 64 61 74  e [split $pkgdat
1d40: 61 20 22 5c 6e 22 5d 20 7b 0a 09 09 09 09 73 65  a "\n"] {.....se
1d50: 74 20 6c 69 6e 65 20 5b 73 74 72 69 6e 67 20 74  t line [string t
1d60: 72 69 6d 20 24 6c 69 6e 65 5d 0a 0a 09 09 09 09  rim $line]......
1d70: 69 66 20 7b 24 6c 69 6e 65 20 3d 3d 20 22 22 7d  if {$line == ""}
1d80: 20 7b 0a 09 09 09 09 09 63 6f 6e 74 69 6e 75 65   {......continue
1d90: 0a 09 09 09 09 7d 0a 0a 09 09 09 09 73 65 74 20  .....}......set 
1da0: 77 6f 72 6b 20 5b 73 70 6c 69 74 20 24 6c 69 6e  work [split $lin
1db0: 65 20 22 2c 22 5d 0a 0a 09 09 09 09 75 6e 73 65  e ","]......unse
1dc0: 74 20 2d 6e 6f 63 6f 6d 70 6c 61 69 6e 20 66 69  t -nocomplain fi
1dd0: 6c 65 49 6e 66 6f 0a 09 09 09 09 73 65 74 20 66  leInfo.....set f
1de0: 69 6c 65 49 6e 66 6f 28 74 79 70 65 29 20 5b 6c  ileInfo(type) [l
1df0: 69 6e 64 65 78 20 24 77 6f 72 6b 20 30 5d 0a 09  index $work 0]..
1e00: 09 09 09 73 65 74 20 66 69 6c 65 49 6e 66 6f 28  ...set fileInfo(
1e10: 74 69 6d 65 29 20 5b 6c 69 6e 64 65 78 20 24 77  time) [lindex $w
1e20: 6f 72 6b 20 31 5d 0a 0a 09 09 09 09 73 65 74 20  ork 1]......set 
1e30: 77 6f 72 6b 20 5b 6c 72 61 6e 67 65 20 24 77 6f  work [lrange $wo
1e40: 72 6b 20 32 20 65 6e 64 5d 0a 09 09 09 09 73 77  rk 2 end].....sw
1e50: 69 74 63 68 20 2d 2d 20 24 66 69 6c 65 49 6e 66  itch -- $fileInf
1e60: 6f 28 74 79 70 65 29 20 7b 0a 09 09 09 09 09 22  o(type) {......"
1e70: 66 69 6c 65 22 20 7b 0a 09 09 09 09 09 09 73 65  file" {.......se
1e80: 74 20 66 69 6c 65 49 6e 66 6f 28 73 69 7a 65 29  t fileInfo(size)
1e90: 20 5b 6c 69 6e 64 65 78 20 24 77 6f 72 6b 20 30   [lindex $work 0
1ea0: 5d 0a 09 09 09 09 09 09 73 65 74 20 66 69 6c 65  ].......set file
1eb0: 49 6e 66 6f 28 70 65 72 6d 73 29 20 5b 6c 69 6e  Info(perms) [lin
1ec0: 64 65 78 20 24 77 6f 72 6b 20 31 5d 0a 09 09 09  dex $work 1]....
1ed0: 09 09 09 73 65 74 20 66 69 6c 65 49 6e 66 6f 28  ...set fileInfo(
1ee0: 73 68 61 31 29 20 5b 6c 69 6e 64 65 78 20 24 77  sha1) [lindex $w
1ef0: 6f 72 6b 20 32 5d 0a 0a 09 09 09 09 09 09 73 65  ork 2]........se
1f00: 74 20 77 6f 72 6b 20 5b 6c 72 61 6e 67 65 20 24  t work [lrange $
1f10: 77 6f 72 6b 20 33 20 65 6e 64 5d 0a 09 09 09 09  work 3 end].....
1f20: 09 7d 0a 09 09 09 09 09 22 73 79 6d 6c 69 6e 6b  .}......"symlink
1f30: 22 20 7b 0a 09 09 09 09 09 09 73 65 74 20 66 69  " {.......set fi
1f40: 6c 65 49 6e 66 6f 28 73 6f 75 72 63 65 29 20 5b  leInfo(source) [
1f50: 6c 69 6e 64 65 78 20 24 77 6f 72 6b 20 30 5d 0a  lindex $work 0].
1f60: 09 09 09 09 09 09 73 65 74 20 77 6f 72 6b 20 5b  ......set work [
1f70: 6c 72 61 6e 67 65 20 24 77 6f 72 6b 20 31 20 65  lrange $work 1 e
1f80: 6e 64 5d 0a 09 09 09 09 09 7d 0a 09 09 09 09 7d  nd]......}.....}
1f90: 0a 0a 09 09 09 09 73 65 74 20 66 69 6c 65 49 6e  ......set fileIn
1fa0: 66 6f 28 6e 61 6d 65 29 20 5b 6a 6f 69 6e 20 24  fo(name) [join $
1fb0: 77 6f 72 6b 20 22 2c 22 5d 0a 09 09 09 09 73 65  work ","].....se
1fc0: 74 20 66 69 6c 65 49 6e 66 6f 28 6e 61 6d 65 29  t fileInfo(name)
1fd0: 20 5b 73 70 6c 69 74 20 5b 73 74 72 69 6e 67 20   [split [string 
1fe0: 74 72 69 6d 20 24 66 69 6c 65 49 6e 66 6f 28 6e  trim $fileInfo(n
1ff0: 61 6d 65 29 20 22 2f 22 5d 20 22 2f 22 5d 0a 09  ame) "/"] "/"]..
2000: 09 09 09 73 65 74 20 66 69 6c 65 49 6e 66 6f 28  ...set fileInfo(
2010: 64 69 72 65 63 74 6f 72 79 29 20 5b 6a 6f 69 6e  directory) [join
2020: 20 5b 6c 72 61 6e 67 65 20 24 66 69 6c 65 49 6e   [lrange $fileIn
2030: 66 6f 28 6e 61 6d 65 29 20 30 20 65 6e 64 2d 31  fo(name) 0 end-1
2040: 5d 20 22 2f 22 5d 0a 09 09 09 09 73 65 74 20 66  ] "/"].....set f
2050: 69 6c 65 49 6e 66 6f 28 6e 61 6d 65 29 20 5b 6c  ileInfo(name) [l
2060: 69 6e 64 65 78 20 24 66 69 6c 65 49 6e 66 6f 28  index $fileInfo(
2070: 6e 61 6d 65 29 20 65 6e 64 5d 0a 0a 09 09 09 09  name) end]......
2080: 64 62 20 65 76 61 6c 20 7b 49 4e 53 45 52 54 20  db eval {INSERT 
2090: 49 4e 54 4f 20 66 69 6c 65 73 20 28 70 61 63 6b  INTO files (pack
20a0: 61 67 65 5f 73 68 61 31 2c 20 74 79 70 65 2c 20  age_sha1, type, 
20b0: 74 69 6d 65 2c 20 73 6f 75 72 63 65 2c 20 73 69  time, source, si
20c0: 7a 65 2c 20 70 65 72 6d 73 2c 20 66 69 6c 65 5f  ze, perms, file_
20d0: 73 68 61 31 2c 20 66 69 6c 65 5f 6e 61 6d 65 2c  sha1, file_name,
20e0: 20 66 69 6c 65 5f 64 69 72 65 63 74 6f 72 79 29   file_directory)
20f0: 20 56 41 4c 55 45 53 20 28 24 70 61 63 6b 61 67   VALUES ($packag
2100: 65 5f 73 68 61 31 2c 20 24 66 69 6c 65 49 6e 66  e_sha1, $fileInf
2110: 6f 28 74 79 70 65 29 2c 20 24 66 69 6c 65 49 6e  o(type), $fileIn
2120: 66 6f 28 74 69 6d 65 29 2c 20 24 66 69 6c 65 49  fo(time), $fileI
2130: 6e 66 6f 28 73 6f 75 72 63 65 29 2c 20 24 66 69  nfo(source), $fi
2140: 6c 65 49 6e 66 6f 28 73 69 7a 65 29 2c 20 24 66  leInfo(size), $f
2150: 69 6c 65 49 6e 66 6f 28 70 65 72 6d 73 29 2c 20  ileInfo(perms), 
2160: 24 66 69 6c 65 49 6e 66 6f 28 73 68 61 31 29 2c  $fileInfo(sha1),
2170: 20 24 66 69 6c 65 49 6e 66 6f 28 6e 61 6d 65 29   $fileInfo(name)
2180: 2c 20 24 66 69 6c 65 49 6e 66 6f 28 64 69 72 65  , $fileInfo(dire
2190: 63 74 6f 72 79 29 20 29 3b 7d 0a 09 09 09 09 64  ctory) );}.....d
21a0: 62 20 65 76 61 6c 20 7b 55 50 44 41 54 45 20 70  b eval {UPDATE p
21b0: 61 63 6b 61 67 65 73 20 53 45 54 20 68 61 76 65  ackages SET have
21c0: 4d 61 6e 69 66 65 73 74 20 3d 20 31 20 57 48 45  Manifest = 1 WHE
21d0: 52 45 20 73 68 61 31 20 3d 20 24 70 61 63 6b 61  RE sha1 = $packa
21e0: 67 65 5f 73 68 61 31 3b 7d 0a 09 09 09 7d 0a 09  ge_sha1;}....}..
21f0: 09 7d 0a 0a 09 09 72 65 74 75 72 6e 20 43 4f 4d  .}....return COM
2200: 50 4c 45 54 45 0a 09 7d 0a 0a 09 70 72 6f 63 20  PLETE..}...proc 
2210: 5f 6c 6f 63 61 6c 70 61 74 68 20 7b 70 61 63 6b  _localpath {pack
2220: 61 67 65 20 68 6f 73 74 6e 61 6d 65 20 66 69 6c  age hostname fil
2230: 65 7d 20 7b 0a 09 09 73 65 74 20 68 6f 6d 65 64  e} {...set homed
2240: 69 72 20 5b 3a 3a 61 70 70 66 73 64 3a 3a 67 65  ir [::appfsd::ge
2250: 74 5f 68 6f 6d 65 64 69 72 5d 0a 09 09 73 65 74  t_homedir]...set
2260: 20 64 69 72 20 5b 66 69 6c 65 20 6a 6f 69 6e 20   dir [file join 
2270: 24 68 6f 6d 65 64 69 72 20 2e 61 70 70 66 73 20  $homedir .appfs 
2280: 22 2e 2f 24 7b 70 61 63 6b 61 67 65 7d 40 24 7b  "./${package}@${
2290: 68 6f 73 74 6e 61 6d 65 7d 22 20 22 2e 2f 24 7b  hostname}" "./${
22a0: 66 69 6c 65 7d 22 5d 0a 09 09 72 65 74 75 72 6e  file}"]...return
22b0: 20 24 64 69 72 0a 09 7d 0a 0a 09 70 72 6f 63 20   $dir..}...proc 
22c0: 5f 77 68 69 74 65 6f 75 74 70 61 74 68 20 7b 70  _whiteoutpath {p
22d0: 61 63 6b 61 67 65 20 68 6f 73 74 6e 61 6d 65 20  ackage hostname 
22e0: 66 69 6c 65 7d 20 7b 0a 09 09 73 65 74 20 68 6f  file} {...set ho
22f0: 6d 65 64 69 72 20 5b 3a 3a 61 70 70 66 73 64 3a  medir [::appfsd:
2300: 3a 67 65 74 5f 68 6f 6d 65 64 69 72 5d 0a 09 09  :get_homedir]...
2310: 73 65 74 20 64 69 72 20 5b 66 69 6c 65 20 6a 6f  set dir [file jo
2320: 69 6e 20 24 68 6f 6d 65 64 69 72 20 2e 61 70 70  in $homedir .app
2330: 66 73 20 22 2e 2f 24 7b 70 61 63 6b 61 67 65 7d  fs "./${package}
2340: 40 24 7b 68 6f 73 74 6e 61 6d 65 7d 22 20 22 2e  @${hostname}" ".
2350: 41 50 50 46 53 2e 57 48 49 54 45 4f 55 54 22 20  APPFS.WHITEOUT" 
2360: 22 2e 2f 24 7b 66 69 6c 65 7d 2e 41 50 50 46 53  "./${file}.APPFS
2370: 2e 57 48 49 54 45 4f 55 54 22 5d 0a 09 09 72 65  .WHITEOUT"]...re
2380: 74 75 72 6e 20 24 64 69 72 0a 09 7d 0a 0a 09 70  turn $dir..}...p
2390: 72 6f 63 20 5f 70 61 72 73 65 70 61 74 68 20 7b  roc _parsepath {
23a0: 70 61 74 68 7d 20 7b 0a 09 09 73 65 74 20 70 61  path} {...set pa
23b0: 74 68 20 5b 73 74 72 69 6e 67 20 74 72 69 6d 20  th [string trim 
23c0: 24 70 61 74 68 20 22 2f 22 5d 0a 09 09 73 65 74  $path "/"]...set
23d0: 20 70 61 74 68 20 5b 73 70 6c 69 74 20 24 70 61   path [split $pa
23e0: 74 68 20 22 2f 22 5d 0a 09 09 73 65 74 20 70 61  th "/"]...set pa
23f0: 74 68 6c 65 6e 20 5b 6c 6c 65 6e 67 74 68 20 24  thlen [llength $
2400: 70 61 74 68 5d 0a 0a 09 09 61 72 72 61 79 20 73  path]....array s
2410: 65 74 20 72 65 74 76 61 6c 20 5b 6c 69 73 74 20  et retval [list 
2420: 5f 63 68 69 6c 64 72 65 6e 20 73 69 74 65 73 20  _children sites 
2430: 5f 74 79 70 65 20 74 6f 70 6c 65 76 65 6c 5d 0a  _type toplevel].
2440: 0a 09 09 69 66 20 7b 24 70 61 74 68 6c 65 6e 20  ...if {$pathlen 
2450: 3e 20 30 7d 20 7b 0a 09 09 09 73 65 74 20 72 65  > 0} {....set re
2460: 74 76 61 6c 28 68 6f 73 74 6e 61 6d 65 29 20 5b  tval(hostname) [
2470: 6c 69 6e 64 65 78 20 24 70 61 74 68 20 30 5d 0a  lindex $path 0].
2480: 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 5f 63  ...set retval(_c
2490: 68 69 6c 64 72 65 6e 29 20 70 61 63 6b 61 67 65  hildren) package
24a0: 73 0a 09 09 09 73 65 74 20 72 65 74 76 61 6c 28  s....set retval(
24b0: 5f 74 79 70 65 29 20 73 69 74 65 73 0a 0a 09 09  _type) sites....
24c0: 09 69 66 20 7b 24 70 61 74 68 6c 65 6e 20 3e 20  .if {$pathlen > 
24d0: 31 7d 20 7b 0a 09 09 09 09 73 65 74 20 70 61 63  1} {.....set pac
24e0: 6b 61 67 65 20 5b 6c 69 6e 64 65 78 20 24 70 61  kage [lindex $pa
24f0: 74 68 20 31 5d 0a 09 09 09 09 69 66 20 7b 5b 73  th 1].....if {[s
2500: 74 72 69 6e 67 20 6c 65 6e 67 74 68 20 24 70 61  tring length $pa
2510: 63 6b 61 67 65 5d 20 3d 3d 20 22 34 30 22 20 26  ckage] == "40" &
2520: 26 20 5b 72 65 67 65 78 70 20 7b 5e 5b 61 2d 66  & [regexp {^[a-f
2530: 41 2d 46 30 2d 39 5d 2a 24 7d 20 24 70 61 63 6b  A-F0-9]*$} $pack
2540: 61 67 65 5d 7d 20 7b 0a 09 09 09 09 09 73 65 74  age]} {......set
2550: 20 72 65 74 76 61 6c 28 70 61 63 6b 61 67 65 5f   retval(package_
2560: 73 68 61 31 29 20 24 70 61 63 6b 61 67 65 0a 09  sha1) $package..
2570: 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 5f  ....set retval(_
2580: 63 68 69 6c 64 72 65 6e 29 20 66 69 6c 65 73 0a  children) files.
2590: 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28  .....set retval(
25a0: 5f 74 79 70 65 29 20 66 69 6c 65 73 0a 0a 09 09  _type) files....
25b0: 09 09 09 3a 3a 61 70 70 66 73 3a 3a 64 62 20 65  ...::appfs::db e
25c0: 76 61 6c 20 7b 53 45 4c 45 43 54 20 70 61 63 6b  val {SELECT pack
25d0: 61 67 65 2c 20 6f 73 2c 20 63 70 75 41 72 63 68  age, os, cpuArch
25e0: 2c 20 76 65 72 73 69 6f 6e 20 46 52 4f 4d 20 70  , version FROM p
25f0: 61 63 6b 61 67 65 73 20 57 48 45 52 45 20 73 68  ackages WHERE sh
2600: 61 31 20 3d 20 24 72 65 74 76 61 6c 28 70 61 63  a1 = $retval(pac
2610: 6b 61 67 65 5f 73 68 61 31 29 3b 7d 20 70 6b 67  kage_sha1);} pkg
2620: 69 6e 66 6f 20 7b 7d 0a 09 09 09 09 09 73 65 74  info {}......set
2630: 20 72 65 74 76 61 6c 28 70 61 63 6b 61 67 65 29   retval(package)
2640: 20 24 70 6b 67 69 6e 66 6f 28 70 61 63 6b 61 67   $pkginfo(packag
2650: 65 29 0a 09 09 09 09 09 73 65 74 20 72 65 74 76  e)......set retv
2660: 61 6c 28 6f 73 29 20 24 70 6b 67 69 6e 66 6f 28  al(os) $pkginfo(
2670: 6f 73 29 0a 09 09 09 09 09 73 65 74 20 72 65 74  os)......set ret
2680: 76 61 6c 28 63 70 75 29 20 24 70 6b 67 69 6e 66  val(cpu) $pkginf
2690: 6f 28 63 70 75 41 72 63 68 29 0a 09 09 09 09 09  o(cpuArch)......
26a0: 73 65 74 20 72 65 74 76 61 6c 28 76 65 72 73 69  set retval(versi
26b0: 6f 6e 29 20 24 70 6b 67 69 6e 66 6f 28 76 65 72  on) $pkginfo(ver
26c0: 73 69 6f 6e 29 0a 0a 09 09 09 09 09 69 66 20 7b  sion).......if {
26d0: 24 70 61 74 68 6c 65 6e 20 3e 20 32 7d 20 7b 0a  $pathlen > 2} {.
26e0: 09 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c  ......set retval
26f0: 28 66 69 6c 65 29 20 5b 6a 6f 69 6e 20 5b 6c 72  (file) [join [lr
2700: 61 6e 67 65 20 24 70 61 74 68 20 32 20 65 6e 64  ange $path 2 end
2710: 5d 20 22 2f 22 5d 0a 09 09 09 09 09 7d 20 65 6c  ] "/"]......} el
2720: 73 65 20 7b 0a 09 09 09 09 09 09 73 65 74 20 72  se {.......set r
2730: 65 74 76 61 6c 28 66 69 6c 65 29 20 22 22 0a 09  etval(file) ""..
2740: 09 09 09 09 7d 0a 09 09 09 09 7d 20 65 6c 73 65  ....}.....} else
2750: 20 7b 0a 09 09 09 09 09 73 65 74 20 72 65 74 76   {......set retv
2760: 61 6c 28 70 61 63 6b 61 67 65 29 20 24 70 61 63  al(package) $pac
2770: 6b 61 67 65 0a 09 09 09 09 09 73 65 74 20 72 65  kage......set re
2780: 74 76 61 6c 28 5f 63 68 69 6c 64 72 65 6e 29 20  tval(_children) 
2790: 6f 73 2d 63 70 75 0a 09 09 09 09 09 73 65 74 20  os-cpu......set 
27a0: 72 65 74 76 61 6c 28 5f 74 79 70 65 29 20 70 61  retval(_type) pa
27b0: 63 6b 61 67 65 73 0a 0a 09 09 09 09 09 69 66 20  ckages.......if 
27c0: 7b 24 70 61 74 68 6c 65 6e 20 3e 20 32 7d 20 7b  {$pathlen > 2} {
27d0: 0a 09 09 09 09 09 09 73 65 74 20 6f 73 5f 63 70  .......set os_cp
27e0: 75 20 5b 6c 69 6e 64 65 78 20 24 70 61 74 68 20  u [lindex $path 
27f0: 32 5d 0a 09 09 09 09 09 09 73 65 74 20 6f 73 5f  2].......set os_
2800: 63 70 75 20 5b 73 70 6c 69 74 20 24 6f 73 5f 63  cpu [split $os_c
2810: 70 75 20 22 2d 22 5d 0a 0a 09 09 09 09 09 09 73  pu "-"]........s
2820: 65 74 20 72 65 74 76 61 6c 28 6f 73 29 20 5b 6c  et retval(os) [l
2830: 69 6e 64 65 78 20 24 6f 73 5f 63 70 75 20 30 5d  index $os_cpu 0]
2840: 0a 09 09 09 09 09 09 73 65 74 20 72 65 74 76 61  .......set retva
2850: 6c 28 63 70 75 29 20 5b 6c 69 6e 64 65 78 20 24  l(cpu) [lindex $
2860: 6f 73 5f 63 70 75 20 31 5d 0a 09 09 09 09 09 09  os_cpu 1].......
2870: 73 65 74 20 72 65 74 76 61 6c 28 5f 63 68 69 6c  set retval(_chil
2880: 64 72 65 6e 29 20 76 65 72 73 69 6f 6e 73 0a 09  dren) versions..
2890: 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28  .....set retval(
28a0: 5f 74 79 70 65 29 20 6f 73 2d 63 70 75 0a 0a 09  _type) os-cpu...
28b0: 09 09 09 09 09 69 66 20 7b 24 70 61 74 68 6c 65  .....if {$pathle
28c0: 6e 20 3e 20 33 7d 20 7b 0a 09 09 09 09 09 09 09  n > 3} {........
28d0: 73 65 74 20 72 65 74 76 61 6c 28 76 65 72 73 69  set retval(versi
28e0: 6f 6e 29 20 5b 6c 69 6e 64 65 78 20 24 70 61 74  on) [lindex $pat
28f0: 68 20 33 5d 0a 09 09 09 09 09 09 09 73 65 74 20  h 3]........set 
2900: 72 65 74 76 61 6c 28 5f 63 68 69 6c 64 72 65 6e  retval(_children
2910: 29 20 66 69 6c 65 73 0a 09 09 09 09 09 09 09 73  ) files........s
2920: 65 74 20 72 65 74 76 61 6c 28 5f 74 79 70 65 29  et retval(_type)
2930: 20 76 65 72 73 69 6f 6e 73 0a 0a 09 09 09 09 09   versions.......
2940: 09 09 73 65 74 20 72 65 74 76 61 6c 28 70 61 63  ..set retval(pac
2950: 6b 61 67 65 5f 73 68 61 31 29 20 5b 3a 3a 61 70  kage_sha1) [::ap
2960: 70 66 73 3a 3a 64 62 20 6f 6e 65 63 6f 6c 75 6d  pfs::db onecolum
2970: 6e 20 7b 53 45 4c 45 43 54 20 73 68 61 31 20 46  n {SELECT sha1 F
2980: 52 4f 4d 20 70 61 63 6b 61 67 65 73 20 57 48 45  ROM packages WHE
2990: 52 45 20 68 6f 73 74 6e 61 6d 65 20 3d 20 24 72  RE hostname = $r
29a0: 65 74 76 61 6c 28 68 6f 73 74 6e 61 6d 65 29 20  etval(hostname) 
29b0: 41 4e 44 20 6f 73 20 3d 20 24 72 65 74 76 61 6c  AND os = $retval
29c0: 28 6f 73 29 20 41 4e 44 20 63 70 75 41 72 63 68  (os) AND cpuArch
29d0: 20 3d 20 24 72 65 74 76 61 6c 28 63 70 75 29 20   = $retval(cpu) 
29e0: 41 4e 44 20 76 65 72 73 69 6f 6e 20 3d 20 24 72  AND version = $r
29f0: 65 74 76 61 6c 28 76 65 72 73 69 6f 6e 29 3b 7d  etval(version);}
2a00: 5d 0a 09 09 09 09 09 09 09 69 66 20 7b 24 72 65  ]........if {$re
2a10: 74 76 61 6c 28 70 61 63 6b 61 67 65 5f 73 68 61  tval(package_sha
2a20: 31 29 20 3d 3d 20 22 22 7d 20 7b 0a 09 09 09 09  1) == ""} {.....
2a30: 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 5f  ....set retval(_
2a40: 63 68 69 6c 64 72 65 6e 29 20 64 65 61 64 0a 09  children) dead..
2a50: 09 09 09 09 09 09 09 72 65 74 75 72 6e 20 5b 61  .......return [a
2a60: 72 72 61 79 20 67 65 74 20 72 65 74 76 61 6c 5d  rray get retval]
2a70: 0a 09 09 09 09 09 09 09 7d 0a 0a 09 09 09 09 09  ........}.......
2a80: 09 09 69 66 20 7b 24 70 61 74 68 6c 65 6e 20 3e  ..if {$pathlen >
2a90: 20 34 7d 20 7b 0a 09 09 09 09 09 09 09 09 73 65   4} {.........se
2aa0: 74 20 72 65 74 76 61 6c 28 5f 74 79 70 65 29 20  t retval(_type) 
2ab0: 66 69 6c 65 73 0a 09 09 09 09 09 09 09 09 73 65  files.........se
2ac0: 74 20 72 65 74 76 61 6c 28 66 69 6c 65 29 20 5b  t retval(file) [
2ad0: 6a 6f 69 6e 20 5b 6c 72 61 6e 67 65 20 24 70 61  join [lrange $pa
2ae0: 74 68 20 34 20 65 6e 64 5d 20 22 2f 22 5d 0a 09  th 4 end] "/"]..
2af0: 09 09 09 09 09 09 7d 20 65 6c 73 65 20 7b 0a 09  ......} else {..
2b00: 09 09 09 09 09 09 09 73 65 74 20 72 65 74 76 61  .......set retva
2b10: 6c 28 5f 74 79 70 65 29 20 66 69 6c 65 73 0a 09  l(_type) files..
2b20: 09 09 09 09 09 09 09 73 65 74 20 72 65 74 76 61  .......set retva
2b30: 6c 28 66 69 6c 65 29 20 22 22 0a 09 09 09 09 09  l(file) ""......
2b40: 09 09 7d 0a 09 09 09 09 09 09 7d 0a 09 09 09 09  ..}.......}.....
2b50: 09 7d 0a 09 09 09 09 7d 0a 09 09 09 7d 0a 09 09  .}.....}....}...
2b60: 7d 0a 0a 09 09 72 65 74 75 72 6e 20 5b 61 72 72  }....return [arr
2b70: 61 79 20 67 65 74 20 72 65 74 76 61 6c 5d 0a 09  ay get retval]..
2b80: 7d 0a 0a 09 70 72 6f 63 20 67 65 74 63 68 69 6c  }...proc getchil
2b90: 64 72 65 6e 20 7b 64 69 72 7d 20 7b 0a 09 09 61  dren {dir} {...a
2ba0: 72 72 61 79 20 73 65 74 20 70 61 74 68 69 6e 66  rray set pathinf
2bb0: 6f 20 5b 5f 70 61 72 73 65 70 61 74 68 20 24 64  o [_parsepath $d
2bc0: 69 72 5d 0a 0a 09 09 73 77 69 74 63 68 20 2d 2d  ir]....switch --
2bd0: 20 24 70 61 74 68 69 6e 66 6f 28 5f 63 68 69 6c   $pathinfo(_chil
2be0: 64 72 65 6e 29 20 7b 0a 09 09 09 22 73 69 74 65  dren) {...."site
2bf0: 73 22 20 7b 0a 09 09 09 09 72 65 74 75 72 6e 20  s" {.....return 
2c00: 5b 3a 3a 61 70 70 66 73 3a 3a 64 62 20 65 76 61  [::appfs::db eva
2c10: 6c 20 7b 53 45 4c 45 43 54 20 44 49 53 54 49 4e  l {SELECT DISTIN
2c20: 43 54 20 68 6f 73 74 6e 61 6d 65 20 46 52 4f 4d  CT hostname FROM
2c30: 20 70 61 63 6b 61 67 65 73 3b 7d 5d 0a 09 09 09   packages;}]....
2c40: 7d 0a 09 09 09 22 70 61 63 6b 61 67 65 73 22 20  }...."packages" 
2c50: 7b 0a 09 09 09 09 63 61 74 63 68 20 7b 0a 09 09  {.....catch {...
2c60: 09 09 09 3a 3a 61 70 70 66 73 3a 3a 67 65 74 69  ...::appfs::geti
2c70: 6e 64 65 78 20 24 70 61 74 68 69 6e 66 6f 28 68  ndex $pathinfo(h
2c80: 6f 73 74 6e 61 6d 65 29 0a 09 09 09 09 7d 0a 0a  ostname).....}..
2c90: 09 09 09 09 72 65 74 75 72 6e 20 5b 3a 3a 61 70  ....return [::ap
2ca0: 70 66 73 3a 3a 64 62 20 65 76 61 6c 20 7b 53 45  pfs::db eval {SE
2cb0: 4c 45 43 54 20 44 49 53 54 49 4e 43 54 20 70 61  LECT DISTINCT pa
2cc0: 63 6b 61 67 65 20 46 52 4f 4d 20 70 61 63 6b 61  ckage FROM packa
2cd0: 67 65 73 20 57 48 45 52 45 20 68 6f 73 74 6e 61  ges WHERE hostna
2ce0: 6d 65 20 3d 20 24 70 61 74 68 69 6e 66 6f 28 68  me = $pathinfo(h
2cf0: 6f 73 74 6e 61 6d 65 29 3b 7d 5d 0a 09 09 09 7d  ostname);}]....}
2d00: 0a 09 09 09 22 6f 73 2d 63 70 75 22 20 7b 0a 09  ...."os-cpu" {..
2d10: 09 09 09 73 65 74 20 72 65 74 76 61 6c 20 5b 3a  ...set retval [:
2d20: 3a 61 70 70 66 73 3a 3a 64 62 20 65 76 61 6c 20  :appfs::db eval 
2d30: 7b 53 45 4c 45 43 54 20 44 49 53 54 49 4e 43 54  {SELECT DISTINCT
2d40: 20 6f 73 20 7c 7c 20 22 2d 22 20 7c 7c 20 63 70   os || "-" || cp
2d50: 75 41 72 63 68 20 46 52 4f 4d 20 70 61 63 6b 61  uArch FROM packa
2d60: 67 65 73 20 57 48 45 52 45 20 68 6f 73 74 6e 61  ges WHERE hostna
2d70: 6d 65 20 3d 20 24 70 61 74 68 69 6e 66 6f 28 68  me = $pathinfo(h
2d80: 6f 73 74 6e 61 6d 65 29 20 41 4e 44 20 70 61 63  ostname) AND pac
2d90: 6b 61 67 65 20 3d 20 24 70 61 74 68 69 6e 66 6f  kage = $pathinfo
2da0: 28 70 61 63 6b 61 67 65 29 3b 7d 5d 0a 0a 09 09  (package);}]....
2db0: 09 09 6c 61 70 70 65 6e 64 20 72 65 74 76 61 6c  ..lappend retval
2dc0: 20 22 70 6c 61 74 66 6f 72 6d 22 0a 0a 09 09 09   "platform".....
2dd0: 09 72 65 74 75 72 6e 20 24 72 65 74 76 61 6c 0a  .return $retval.
2de0: 09 09 09 7d 0a 09 09 09 22 76 65 72 73 69 6f 6e  ...}...."version
2df0: 73 22 20 7b 0a 09 09 09 09 73 65 74 20 72 65 74  s" {.....set ret
2e00: 76 61 6c 20 5b 3a 3a 61 70 70 66 73 3a 3a 64 62  val [::appfs::db
2e10: 20 65 76 61 6c 20 7b 0a 09 09 09 09 09 53 45 4c   eval {......SEL
2e20: 45 43 54 20 44 49 53 54 49 4e 43 54 20 76 65 72  ECT DISTINCT ver
2e30: 73 69 6f 6e 20 46 52 4f 4d 20 70 61 63 6b 61 67  sion FROM packag
2e40: 65 73 20 57 48 45 52 45 20 68 6f 73 74 6e 61 6d  es WHERE hostnam
2e50: 65 20 3d 20 24 70 61 74 68 69 6e 66 6f 28 68 6f  e = $pathinfo(ho
2e60: 73 74 6e 61 6d 65 29 20 41 4e 44 20 70 61 63 6b  stname) AND pack
2e70: 61 67 65 20 3d 20 24 70 61 74 68 69 6e 66 6f 28  age = $pathinfo(
2e80: 70 61 63 6b 61 67 65 29 20 41 4e 44 20 6f 73 20  package) AND os 
2e90: 3d 20 24 70 61 74 68 69 6e 66 6f 28 6f 73 29 20  = $pathinfo(os) 
2ea0: 41 4e 44 20 63 70 75 41 72 63 68 20 3d 20 24 70  AND cpuArch = $p
2eb0: 61 74 68 69 6e 66 6f 28 63 70 75 29 3b 0a 09 09  athinfo(cpu);...
2ec0: 09 09 7d 5d 0a 0a 09 09 09 09 6c 61 70 70 65 6e  ..}]......lappen
2ed0: 64 20 72 65 74 76 61 6c 20 22 6c 61 74 65 73 74  d retval "latest
2ee0: 22 0a 0a 09 09 09 09 72 65 74 75 72 6e 20 24 72  "......return $r
2ef0: 65 74 76 61 6c 0a 09 09 09 7d 0a 09 09 09 22 66  etval....}...."f
2f00: 69 6c 65 73 22 20 7b 0a 09 09 09 09 63 61 74 63  iles" {.....catc
2f10: 68 20 7b 0a 09 09 09 09 09 3a 3a 61 70 70 66 73  h {......::appfs
2f20: 3a 3a 67 65 74 70 6b 67 6d 61 6e 69 66 65 73 74  ::getpkgmanifest
2f30: 20 24 70 61 74 68 69 6e 66 6f 28 68 6f 73 74 6e   $pathinfo(hostn
2f40: 61 6d 65 29 20 24 70 61 74 68 69 6e 66 6f 28 70  ame) $pathinfo(p
2f50: 61 63 6b 61 67 65 5f 73 68 61 31 29 0a 09 09 09  ackage_sha1)....
2f60: 09 7d 0a 0a 09 09 09 09 73 65 74 20 72 65 74 76  .}......set retv
2f70: 61 6c 20 5b 3a 3a 61 70 70 66 73 3a 3a 64 62 20  al [::appfs::db 
2f80: 65 76 61 6c 20 7b 53 45 4c 45 43 54 20 44 49 53  eval {SELECT DIS
2f90: 54 49 4e 43 54 20 66 69 6c 65 5f 6e 61 6d 65 20  TINCT file_name 
2fa0: 46 52 4f 4d 20 66 69 6c 65 73 20 57 48 45 52 45  FROM files WHERE
2fb0: 20 70 61 63 6b 61 67 65 5f 73 68 61 31 20 3d 20   package_sha1 = 
2fc0: 24 70 61 74 68 69 6e 66 6f 28 70 61 63 6b 61 67  $pathinfo(packag
2fd0: 65 5f 73 68 61 31 29 20 41 4e 44 20 66 69 6c 65  e_sha1) AND file
2fe0: 5f 64 69 72 65 63 74 6f 72 79 20 3d 20 24 70 61  _directory = $pa
2ff0: 74 68 69 6e 66 6f 28 66 69 6c 65 29 3b 7d 5d 0a  thinfo(file);}].
3000: 0a 09 09 09 09 69 66 20 7b 5b 69 6e 66 6f 20 65  .....if {[info e
3010: 78 69 73 74 73 20 70 61 74 68 69 6e 66 6f 28 70  xists pathinfo(p
3020: 61 63 6b 61 67 65 29 5d 20 26 26 20 5b 69 6e 66  ackage)] && [inf
3030: 6f 20 65 78 69 73 74 73 20 70 61 74 68 69 6e 66  o exists pathinf
3040: 6f 28 68 6f 73 74 6e 61 6d 65 29 5d 20 26 26 20  o(hostname)] && 
3050: 5b 69 6e 66 6f 20 65 78 69 73 74 73 20 70 61 74  [info exists pat
3060: 68 69 6e 66 6f 28 66 69 6c 65 29 5d 7d 20 7b 0a  hinfo(file)]} {.
3070: 09 09 09 09 09 73 65 74 20 64 69 72 20 5b 5f 6c  .....set dir [_l
3080: 6f 63 61 6c 70 61 74 68 20 24 70 61 74 68 69 6e  ocalpath $pathin
3090: 66 6f 28 70 61 63 6b 61 67 65 29 20 24 70 61 74  fo(package) $pat
30a0: 68 69 6e 66 6f 28 68 6f 73 74 6e 61 6d 65 29 20  hinfo(hostname) 
30b0: 24 70 61 74 68 69 6e 66 6f 28 66 69 6c 65 29 5d  $pathinfo(file)]
30c0: 0a 09 09 09 09 09 73 65 74 20 77 68 69 74 65 6f  ......set whiteo
30d0: 75 74 64 69 72 20 5b 73 74 72 69 6e 67 20 72 61  utdir [string ra
30e0: 6e 67 65 20 5b 5f 77 68 69 74 65 6f 75 74 70 61  nge [_whiteoutpa
30f0: 74 68 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63  th $pathinfo(pac
3100: 6b 61 67 65 29 20 24 70 61 74 68 69 6e 66 6f 28  kage) $pathinfo(
3110: 68 6f 73 74 6e 61 6d 65 29 20 24 70 61 74 68 69  hostname) $pathi
3120: 6e 66 6f 28 66 69 6c 65 29 5d 20 30 20 65 6e 64  nfo(file)] 0 end
3130: 2d 31 35 5d 0a 0a 09 09 09 09 09 66 6f 72 65 61  -15].......forea
3140: 63 68 20 66 69 6c 65 20 5b 67 6c 6f 62 20 2d 6e  ch file [glob -n
3150: 6f 63 6f 6d 70 6c 61 69 6e 20 2d 74 61 69 6c 73  ocomplain -tails
3160: 20 2d 64 69 72 65 63 74 6f 72 79 20 24 77 68 69   -directory $whi
3170: 74 65 6f 75 74 64 69 72 20 7b 7b 2e 2c 7d 2a 2e  teoutdir {{.,}*.
3180: 41 50 50 46 53 2e 57 48 49 54 45 4f 55 54 7d 5d  APPFS.WHITEOUT}]
3190: 20 7b 0a 09 09 09 09 09 09 73 65 74 20 72 65 6d   {.......set rem
31a0: 6f 76 65 20 5b 73 74 72 69 6e 67 20 72 61 6e 67  ove [string rang
31b0: 65 20 24 66 69 6c 65 20 30 20 65 6e 64 2d 31 35  e $file 0 end-15
31c0: 5d 0a 09 09 09 09 09 09 73 65 74 20 69 64 78 20  ].......set idx 
31d0: 5b 6c 73 65 61 72 63 68 20 2d 65 78 61 63 74 20  [lsearch -exact 
31e0: 24 72 65 74 76 61 6c 20 24 72 65 6d 6f 76 65 5d  $retval $remove]
31f0: 0a 09 09 09 09 09 09 69 66 20 7b 24 69 64 78 20  .......if {$idx 
3200: 21 3d 20 2d 31 7d 20 7b 0a 09 09 09 09 09 09 09  != -1} {........
3210: 73 65 74 20 72 65 74 76 61 6c 20 5b 6c 72 65 70  set retval [lrep
3220: 6c 61 63 65 20 24 72 65 74 76 61 6c 20 24 69 64  lace $retval $id
3230: 78 20 24 69 64 78 5d 0a 09 09 09 09 09 09 7d 0a  x $idx].......}.
3240: 09 09 09 09 09 7d 0a 0a 09 09 09 09 09 66 6f 72  .....}.......for
3250: 65 61 63 68 20 66 69 6c 65 20 5b 67 6c 6f 62 20  each file [glob 
3260: 2d 6e 6f 63 6f 6d 70 6c 61 69 6e 20 2d 74 61 69  -nocomplain -tai
3270: 6c 73 20 2d 64 69 72 65 63 74 6f 72 79 20 24 64  ls -directory $d
3280: 69 72 20 2d 74 79 70 65 73 20 7b 64 20 66 20 6c  ir -types {d f l
3290: 20 70 20 73 7d 20 7b 7b 2e 2c 7d 2a 7d 5d 20 7b   p s} {{.,}*}] {
32a0: 0a 09 09 09 09 09 09 69 66 20 7b 24 66 69 6c 65  .......if {$file
32b0: 20 3d 3d 20 22 2e 22 20 7c 7c 20 24 66 69 6c 65   == "." || $file
32c0: 20 3d 3d 20 22 2e 2e 22 7d 20 7b 0a 09 09 09 09   == ".."} {.....
32d0: 09 09 09 63 6f 6e 74 69 6e 75 65 0a 09 09 09 09  ...continue.....
32e0: 09 09 7d 0a 0a 09 09 09 09 09 09 69 66 20 7b 24  ..}........if {$
32f0: 66 69 6c 65 20 3d 3d 20 22 2e 41 50 50 46 53 2e  file == ".APPFS.
3300: 57 48 49 54 45 4f 55 54 22 7d 20 7b 0a 09 09 09  WHITEOUT"} {....
3310: 09 09 09 09 63 6f 6e 74 69 6e 75 65 0a 09 09 09  ....continue....
3320: 09 09 09 7d 0a 0a 09 09 09 09 09 09 69 66 20 7b  ...}........if {
3330: 5b 6c 73 65 61 72 63 68 20 2d 65 78 61 63 74 20  [lsearch -exact 
3340: 24 72 65 74 76 61 6c 20 24 66 69 6c 65 5d 20 21  $retval $file] !
3350: 3d 20 2d 31 7d 20 7b 0a 09 09 09 09 09 09 09 63  = -1} {........c
3360: 6f 6e 74 69 6e 75 65 0a 09 09 09 09 09 09 7d 0a  ontinue.......}.
3370: 0a 09 09 09 09 09 09 6c 61 70 70 65 6e 64 20 72  .......lappend r
3380: 65 74 76 61 6c 20 24 66 69 6c 65 0a 09 09 09 09  etval $file.....
3390: 09 7d 0a 09 09 09 09 7d 0a 0a 09 09 09 09 72 65  .}.....}......re
33a0: 74 75 72 6e 20 24 72 65 74 76 61 6c 0a 09 09 09  turn $retval....
33b0: 7d 0a 09 09 7d 0a 0a 09 09 72 65 74 75 72 6e 20  }...}....return 
33c0: 2d 63 6f 64 65 20 65 72 72 6f 72 20 22 49 6e 76  -code error "Inv
33d0: 61 6c 69 64 20 6f 72 20 75 6e 61 63 63 65 70 74  alid or unaccept
33e0: 61 62 6c 65 20 70 61 74 68 3a 20 24 64 69 72 22  able path: $dir"
33f0: 0a 09 7d 0a 0a 09 70 72 6f 63 20 67 65 74 61 74  ..}...proc getat
3400: 74 72 20 7b 70 61 74 68 7d 20 7b 0a 09 09 61 72  tr {path} {...ar
3410: 72 61 79 20 73 65 74 20 70 61 74 68 69 6e 66 6f  ray set pathinfo
3420: 20 5b 5f 70 61 72 73 65 70 61 74 68 20 24 70 61   [_parsepath $pa
3430: 74 68 5d 0a 09 09 61 72 72 61 79 20 73 65 74 20  th]...array set 
3440: 72 65 74 76 61 6c 20 5b 6c 69 73 74 5d 0a 0a 09  retval [list]...
3450: 09 63 61 74 63 68 20 7b 0a 09 09 09 3a 3a 61 70  .catch {....::ap
3460: 70 66 73 3a 3a 67 65 74 69 6e 64 65 78 20 24 70  pfs::getindex $p
3470: 61 74 68 69 6e 66 6f 28 68 6f 73 74 6e 61 6d 65  athinfo(hostname
3480: 29 0a 09 09 09 3a 3a 61 70 70 66 73 3a 3a 67 65  )....::appfs::ge
3490: 74 70 6b 67 6d 61 6e 69 66 65 73 74 20 24 70 61  tpkgmanifest $pa
34a0: 74 68 69 6e 66 6f 28 68 6f 73 74 6e 61 6d 65 29  thinfo(hostname)
34b0: 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63 6b 61   $pathinfo(packa
34c0: 67 65 5f 73 68 61 31 29 0a 09 09 7d 0a 0a 09 09  ge_sha1)...}....
34d0: 73 77 69 74 63 68 20 2d 2d 20 24 70 61 74 68 69  switch -- $pathi
34e0: 6e 66 6f 28 5f 74 79 70 65 29 20 7b 0a 09 09 09  nfo(_type) {....
34f0: 22 74 6f 70 6c 65 76 65 6c 22 20 7b 0a 09 09 09  "toplevel" {....
3500: 09 73 65 74 20 72 65 74 76 61 6c 28 74 79 70 65  .set retval(type
3510: 29 20 64 69 72 65 63 74 6f 72 79 0a 09 09 09 09  ) directory.....
3520: 73 65 74 20 72 65 74 76 61 6c 28 63 68 69 6c 64  set retval(child
3530: 63 6f 75 6e 74 29 20 32 3b 0a 09 09 09 7d 0a 09  count) 2;....}..
3540: 09 09 22 73 69 74 65 73 22 20 7b 0a 09 09 09 09  .."sites" {.....
3550: 73 65 74 20 63 68 65 63 6b 20 5b 3a 3a 61 70 70  set check [::app
3560: 66 73 3a 3a 64 62 20 6f 6e 65 63 6f 6c 75 6d 6e  fs::db onecolumn
3570: 20 7b 53 45 4c 45 43 54 20 31 20 46 52 4f 4d 20   {SELECT 1 FROM 
3580: 70 61 63 6b 61 67 65 73 20 57 48 45 52 45 20 68  packages WHERE h
3590: 6f 73 74 6e 61 6d 65 20 3d 20 24 70 61 74 68 69  ostname = $pathi
35a0: 6e 66 6f 28 68 6f 73 74 6e 61 6d 65 29 3b 7d 5d  nfo(hostname);}]
35b0: 0a 09 09 09 09 69 66 20 7b 24 63 68 65 63 6b 20  .....if {$check 
35c0: 3d 3d 20 22 31 22 7d 20 7b 0a 09 09 09 09 09 73  == "1"} {......s
35d0: 65 74 20 72 65 74 76 61 6c 28 74 79 70 65 29 20  et retval(type) 
35e0: 64 69 72 65 63 74 6f 72 79 0a 09 09 09 09 09 73  directory......s
35f0: 65 74 20 72 65 74 76 61 6c 28 63 68 69 6c 64 63  et retval(childc
3600: 6f 75 6e 74 29 20 32 3b 0a 09 09 09 09 7d 0a 09  ount) 2;.....}..
3610: 09 09 7d 0a 09 09 09 22 70 61 63 6b 61 67 65 73  ..}...."packages
3620: 22 20 7b 0a 09 09 09 09 73 65 74 20 63 68 65 63  " {.....set chec
3630: 6b 20 5b 3a 3a 61 70 70 66 73 3a 3a 64 62 20 6f  k [::appfs::db o
3640: 6e 65 63 6f 6c 75 6d 6e 20 7b 53 45 4c 45 43 54  necolumn {SELECT
3650: 20 31 20 46 52 4f 4d 20 70 61 63 6b 61 67 65 73   1 FROM packages
3660: 20 57 48 45 52 45 20 68 6f 73 74 6e 61 6d 65 20   WHERE hostname 
3670: 3d 20 24 70 61 74 68 69 6e 66 6f 28 68 6f 73 74  = $pathinfo(host
3680: 6e 61 6d 65 29 20 41 4e 44 20 70 61 63 6b 61 67  name) AND packag
3690: 65 20 3d 20 24 70 61 74 68 69 6e 66 6f 28 70 61  e = $pathinfo(pa
36a0: 63 6b 61 67 65 29 3b 7d 5d 0a 09 09 09 09 69 66  ckage);}].....if
36b0: 20 7b 24 63 68 65 63 6b 20 3d 3d 20 22 31 22 7d   {$check == "1"}
36c0: 20 7b 0a 09 09 09 09 09 73 65 74 20 72 65 74 76   {......set retv
36d0: 61 6c 28 74 79 70 65 29 20 64 69 72 65 63 74 6f  al(type) directo
36e0: 72 79 0a 09 09 09 09 09 73 65 74 20 72 65 74 76  ry......set retv
36f0: 61 6c 28 63 68 69 6c 64 63 6f 75 6e 74 29 20 32  al(childcount) 2
3700: 3b 0a 09 09 09 09 7d 0a 09 09 09 7d 0a 09 09 09  ;.....}....}....
3710: 22 6f 73 2d 63 70 75 22 20 7b 0a 09 09 09 09 69  "os-cpu" {.....i
3720: 66 20 7b 24 70 61 74 68 69 6e 66 6f 28 6f 73 29  f {$pathinfo(os)
3730: 20 3d 3d 20 22 70 6c 61 74 66 6f 72 6d 22 20 26   == "platform" &
3740: 26 20 24 70 61 74 68 69 6e 66 6f 28 63 70 75 29  & $pathinfo(cpu)
3750: 20 3d 3d 20 22 22 7d 20 7b 0a 09 09 09 09 09 73   == ""} {......s
3760: 65 74 20 72 65 74 76 61 6c 28 74 79 70 65 29 20  et retval(type) 
3770: 73 79 6d 6c 69 6e 6b 0a 09 09 09 09 09 73 65 74  symlink......set
3780: 20 72 65 74 76 61 6c 28 73 6f 75 72 63 65 29 20   retval(source) 
3790: 5b 70 6c 61 74 66 6f 72 6d 3a 3a 67 65 6e 65 72  [platform::gener
37a0: 69 63 5d 0a 09 09 09 09 7d 20 65 6c 73 65 20 7b  ic].....} else {
37b0: 0a 09 09 09 09 09 73 65 74 20 63 68 65 63 6b 20  ......set check 
37c0: 5b 3a 3a 61 70 70 66 73 3a 3a 64 62 20 6f 6e 65  [::appfs::db one
37d0: 63 6f 6c 75 6d 6e 20 7b 0a 09 09 09 09 09 09 53  column {.......S
37e0: 45 4c 45 43 54 20 31 20 46 52 4f 4d 20 70 61 63  ELECT 1 FROM pac
37f0: 6b 61 67 65 73 20 57 48 45 52 45 20 68 6f 73 74  kages WHERE host
3800: 6e 61 6d 65 20 3d 20 24 70 61 74 68 69 6e 66 6f  name = $pathinfo
3810: 28 68 6f 73 74 6e 61 6d 65 29 20 41 4e 44 20 70  (hostname) AND p
3820: 61 63 6b 61 67 65 20 3d 20 24 70 61 74 68 69 6e  ackage = $pathin
3830: 66 6f 28 70 61 63 6b 61 67 65 29 20 41 4e 44 20  fo(package) AND 
3840: 6f 73 20 3d 20 24 70 61 74 68 69 6e 66 6f 28 6f  os = $pathinfo(o
3850: 73 29 20 41 4e 44 20 63 70 75 41 72 63 68 20 3d  s) AND cpuArch =
3860: 20 24 70 61 74 68 69 6e 66 6f 28 63 70 75 29 3b   $pathinfo(cpu);
3870: 0a 09 09 09 09 09 7d 5d 0a 09 09 09 09 09 69 66  ......}]......if
3880: 20 7b 24 63 68 65 63 6b 20 3d 3d 20 22 31 22 7d   {$check == "1"}
3890: 20 7b 0a 09 09 09 09 09 09 73 65 74 20 72 65 74   {.......set ret
38a0: 76 61 6c 28 74 79 70 65 29 20 64 69 72 65 63 74  val(type) direct
38b0: 6f 72 79 0a 09 09 09 09 09 09 73 65 74 20 72 65  ory.......set re
38c0: 74 76 61 6c 28 63 68 69 6c 64 63 6f 75 6e 74 29  tval(childcount)
38d0: 20 32 3b 0a 09 09 09 09 09 7d 0a 09 09 09 09 7d   2;......}.....}
38e0: 0a 09 09 09 7d 0a 09 09 09 22 76 65 72 73 69 6f  ....}...."versio
38f0: 6e 73 22 20 7b 0a 09 09 09 09 69 66 20 7b 24 70  ns" {.....if {$p
3900: 61 74 68 69 6e 66 6f 28 76 65 72 73 69 6f 6e 29  athinfo(version)
3910: 20 3d 3d 20 22 6c 61 74 65 73 74 22 7d 20 7b 0a   == "latest"} {.
3920: 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28  .....set retval(
3930: 74 79 70 65 29 20 73 79 6d 6c 69 6e 6b 0a 09 09  type) symlink...
3940: 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 73 6f  ...set retval(so
3950: 75 72 63 65 29 20 22 31 2e 30 22 0a 09 09 09 09  urce) "1.0".....
3960: 7d 20 65 6c 73 65 20 7b 0a 09 09 09 09 09 69 66  } else {......if
3970: 20 7b 5b 69 6e 66 6f 20 65 78 69 73 74 73 20 70   {[info exists p
3980: 61 74 68 69 6e 66 6f 28 70 61 63 6b 61 67 65 5f  athinfo(package_
3990: 73 68 61 31 29 5d 20 26 26 20 24 70 61 74 68 69  sha1)] && $pathi
39a0: 6e 66 6f 28 70 61 63 6b 61 67 65 5f 73 68 61 31  nfo(package_sha1
39b0: 29 20 21 3d 20 22 22 7d 20 7b 0a 09 09 09 09 09  ) != ""} {......
39c0: 09 73 65 74 20 72 65 74 76 61 6c 28 74 79 70 65  .set retval(type
39d0: 29 20 64 69 72 65 63 74 6f 72 79 0a 09 09 09 09  ) directory.....
39e0: 09 09 73 65 74 20 72 65 74 76 61 6c 28 63 68 69  ..set retval(chi
39f0: 6c 64 63 6f 75 6e 74 29 20 32 3b 0a 09 09 09 09  ldcount) 2;.....
3a00: 09 7d 0a 09 09 09 09 7d 0a 09 09 09 7d 0a 09 09  .}.....}....}...
3a10: 09 22 66 69 6c 65 73 22 20 7b 0a 09 09 09 09 73  ."files" {.....s
3a20: 65 74 20 72 65 74 76 61 6c 28 70 61 63 6b 61 67  et retval(packag
3a30: 65 64 29 20 31 0a 0a 09 09 09 09 73 65 74 20 6c  ed) 1......set l
3a40: 6f 63 61 6c 70 61 74 68 20 5b 5f 6c 6f 63 61 6c  ocalpath [_local
3a50: 70 61 74 68 20 24 70 61 74 68 69 6e 66 6f 28 70  path $pathinfo(p
3a60: 61 63 6b 61 67 65 29 20 24 70 61 74 68 69 6e 66  ackage) $pathinf
3a70: 6f 28 68 6f 73 74 6e 61 6d 65 29 20 24 70 61 74  o(hostname) $pat
3a80: 68 69 6e 66 6f 28 66 69 6c 65 29 5d 0a 09 09 09  hinfo(file)]....
3a90: 09 73 65 74 20 77 68 69 74 65 6f 75 74 70 61 74  .set whiteoutpat
3aa0: 68 20 20 5b 5f 77 68 69 74 65 6f 75 74 70 61 74  h  [_whiteoutpat
3ab0: 68 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63 6b  h $pathinfo(pack
3ac0: 61 67 65 29 20 24 70 61 74 68 69 6e 66 6f 28 68  age) $pathinfo(h
3ad0: 6f 73 74 6e 61 6d 65 29 20 24 70 61 74 68 69 6e  ostname) $pathin
3ae0: 66 6f 28 66 69 6c 65 29 5d 0a 0a 09 09 09 09 73  fo(file)]......s
3af0: 65 74 20 72 65 74 76 61 6c 28 6c 6f 63 61 6c 70  et retval(localp
3b00: 61 74 68 29 20 24 6c 6f 63 61 6c 70 61 74 68 0a  ath) $localpath.
3b10: 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 77  ....set retval(w
3b20: 68 69 74 65 6f 75 74 70 61 74 68 29 20 24 77 68  hiteoutpath) $wh
3b30: 69 74 65 6f 75 74 70 61 74 68 0a 0a 09 09 09 09  iteoutpath......
3b40: 69 66 20 7b 5b 66 69 6c 65 20 65 78 69 73 74 73  if {[file exists
3b50: 20 24 6c 6f 63 61 6c 70 61 74 68 5d 7d 20 7b 0a   $localpath]} {.
3b60: 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c 28  .....set retval(
3b70: 69 73 5f 6c 6f 63 61 6c 66 69 6c 65 29 20 31 0a  is_localfile) 1.
3b80: 09 09 09 09 09 63 61 74 63 68 20 7b 0a 09 09 09  .....catch {....
3b90: 09 09 09 66 69 6c 65 20 6c 73 74 61 74 20 24 6c  ...file lstat $l
3ba0: 6f 63 61 6c 70 61 74 68 20 6c 6f 63 61 6c 70 61  ocalpath localpa
3bb0: 74 68 69 6e 66 6f 0a 09 09 09 09 09 09 73 65 74  thinfo.......set
3bc0: 20 72 65 74 76 61 6c 28 74 69 6d 65 29 20 24 6c   retval(time) $l
3bd0: 6f 63 61 6c 70 61 74 68 69 6e 66 6f 28 6d 74 69  ocalpathinfo(mti
3be0: 6d 65 29 0a 0a 09 09 09 09 09 09 73 77 69 74 63  me)........switc
3bf0: 68 20 2d 2d 20 24 6c 6f 63 61 6c 70 61 74 68 69  h -- $localpathi
3c00: 6e 66 6f 28 74 79 70 65 29 20 7b 0a 09 09 09 09  nfo(type) {.....
3c10: 09 09 09 22 64 69 72 65 63 74 6f 72 79 22 20 7b  ..."directory" {
3c20: 0a 09 09 09 09 09 09 09 09 73 65 74 20 72 65 74  .........set ret
3c30: 76 61 6c 28 74 79 70 65 29 20 22 64 69 72 65 63  val(type) "direc
3c40: 74 6f 72 79 22 0a 09 09 09 09 09 09 09 09 73 65  tory".........se
3c50: 74 20 72 65 74 76 61 6c 28 63 68 69 6c 64 63 6f  t retval(childco
3c60: 75 6e 74 29 20 32 0a 09 09 09 09 09 09 09 7d 0a  unt) 2........}.
3c70: 09 09 09 09 09 09 09 22 66 69 6c 65 22 20 7b 0a  ......."file" {.
3c80: 09 09 09 09 09 09 09 09 73 65 74 20 72 65 74 76  ........set retv
3c90: 61 6c 28 74 79 70 65 29 20 22 66 69 6c 65 22 0a  al(type) "file".
3ca0: 09 09 09 09 09 09 09 09 73 65 74 20 72 65 74 76  ........set retv
3cb0: 61 6c 28 73 69 7a 65 29 20 24 6c 6f 63 61 6c 70  al(size) $localp
3cc0: 61 74 68 69 6e 66 6f 28 73 69 7a 65 29 0a 09 09  athinfo(size)...
3cd0: 09 09 09 09 09 09 69 66 20 7b 5b 66 69 6c 65 20  ......if {[file 
3ce0: 65 78 65 63 75 74 61 62 6c 65 20 24 6c 6f 63 61  executable $loca
3cf0: 6c 70 61 74 68 5d 7d 20 7b 0a 09 09 09 09 09 09  lpath]} {.......
3d00: 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 70 65  ...set retval(pe
3d10: 72 6d 73 29 20 22 78 22 0a 09 09 09 09 09 09 09  rms) "x"........
3d20: 09 7d 20 65 6c 73 65 20 7b 0a 09 09 09 09 09 09  .} else {.......
3d30: 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 70 65  ...set retval(pe
3d40: 72 6d 73 29 20 22 22 0a 09 09 09 09 09 09 09 09  rms) "".........
3d50: 7d 0a 09 09 09 09 09 09 09 7d 0a 09 09 09 09 09  }........}......
3d60: 09 09 22 6c 69 6e 6b 22 20 7b 0a 09 09 09 09 09  .."link" {......
3d70: 09 09 09 73 65 74 20 72 65 74 76 61 6c 28 74 79  ...set retval(ty
3d80: 70 65 29 20 22 73 79 6d 6c 69 6e 6b 22 0a 09 09  pe) "symlink"...
3d90: 09 09 09 09 09 09 73 65 74 20 72 65 74 76 61 6c  ......set retval
3da0: 28 73 6f 75 72 63 65 29 20 5b 66 69 6c 65 20 72  (source) [file r
3db0: 65 61 64 6c 69 6e 6b 20 24 6c 6f 63 61 6c 70 61  eadlink $localpa
3dc0: 74 68 5d 0a 09 09 09 09 09 09 09 7d 0a 09 09 09  th]........}....
3dd0: 09 09 09 09 22 66 69 66 6f 22 20 7b 0a 09 09 09  ...."fifo" {....
3de0: 09 09 09 09 09 23 20 43 61 70 69 74 61 6c 69 7a  .....# Capitaliz
3df0: 65 64 20 73 6f 20 74 68 61 74 20 74 68 65 20 66  ed so that the f
3e00: 69 72 73 74 20 63 68 61 72 20 69 73 20 75 6e 69  irst char is uni
3e10: 71 75 65 0a 09 09 09 09 09 09 09 09 73 65 74 20  que.........set 
3e20: 72 65 74 76 61 6c 28 74 79 70 65 29 20 22 46 69  retval(type) "Fi
3e30: 66 6f 22 0a 09 09 09 09 09 09 09 7d 0a 09 09 09  fo"........}....
3e40: 09 09 09 09 22 73 6f 63 6b 65 74 22 20 7b 0a 09  ...."socket" {..
3e50: 09 09 09 09 09 09 09 23 20 43 61 70 69 74 61 6c  .......# Capital
3e60: 69 7a 65 64 20 73 6f 20 74 68 61 74 20 74 68 65  ized so that the
3e70: 20 66 69 72 73 74 20 63 68 61 72 20 69 73 20 75   first char is u
3e80: 6e 69 71 75 65 0a 09 09 09 09 09 09 09 09 73 65  nique.........se
3e90: 74 20 72 65 74 76 61 6c 28 74 79 70 65 29 20 22  t retval(type) "
3ea0: 53 6f 63 6b 65 74 22 0a 09 09 09 09 09 09 09 7d  Socket"........}
3eb0: 0a 09 09 09 09 09 09 7d 0a 09 09 09 09 09 7d 20  .......}......} 
3ec0: 65 72 72 0a 09 09 09 09 7d 20 65 6c 73 65 20 7b  err.....} else {
3ed0: 0a 09 09 09 09 09 69 66 20 7b 21 5b 66 69 6c 65  ......if {![file
3ee0: 20 65 78 69 73 74 73 20 24 77 68 69 74 65 6f 75   exists $whiteou
3ef0: 74 70 61 74 68 5d 7d 20 7b 0a 09 09 09 09 09 09  tpath]} {.......
3f00: 73 65 74 20 72 65 74 76 61 6c 28 69 73 5f 72 65  set retval(is_re
3f10: 6d 6f 74 65 66 69 6c 65 29 20 31 0a 0a 09 09 09  motefile) 1.....
3f20: 09 09 09 73 65 74 20 77 6f 72 6b 20 5b 73 70 6c  ...set work [spl
3f30: 69 74 20 24 70 61 74 68 69 6e 66 6f 28 66 69 6c  it $pathinfo(fil
3f40: 65 29 20 22 2f 22 5d 0a 09 09 09 09 09 09 73 65  e) "/"].......se
3f50: 74 20 64 69 72 65 63 74 6f 72 79 20 5b 6a 6f 69  t directory [joi
3f60: 6e 20 5b 6c 72 61 6e 67 65 20 24 77 6f 72 6b 20  n [lrange $work 
3f70: 30 20 65 6e 64 2d 31 5d 20 22 2f 22 5d 0a 09 09  0 end-1] "/"]...
3f80: 09 09 09 09 73 65 74 20 66 69 6c 65 20 5b 6c 69  ....set file [li
3f90: 6e 64 65 78 20 24 77 6f 72 6b 20 65 6e 64 5d 0a  ndex $work end].
3fa0: 0a 09 09 09 09 09 09 69 66 20 7b 24 64 69 72 65  .......if {$dire
3fb0: 63 74 6f 72 79 20 3d 3d 20 22 22 20 26 26 20 24  ctory == "" && $
3fc0: 66 69 6c 65 20 3d 3d 20 22 22 7d 20 7b 0a 09 09  file == ""} {...
3fd0: 09 09 09 09 09 61 72 72 61 79 20 73 65 74 20 72  .....array set r
3fe0: 65 74 76 61 6c 20 5b 6c 69 73 74 20 74 79 70 65  etval [list type
3ff0: 20 64 69 72 65 63 74 6f 72 79 20 63 68 69 6c 64   directory child
4000: 63 6f 75 6e 74 20 32 5d 0a 09 09 09 09 09 09 7d  count 2].......}
4010: 0a 0a 09 09 09 09 09 09 3a 3a 61 70 70 66 73 3a  ........::appfs:
4020: 3a 64 62 20 65 76 61 6c 20 7b 53 45 4c 45 43 54  :db eval {SELECT
4030: 20 74 79 70 65 2c 20 74 69 6d 65 2c 20 73 6f 75   type, time, sou
4040: 72 63 65 2c 20 73 69 7a 65 2c 20 70 65 72 6d 73  rce, size, perms
4050: 20 46 52 4f 4d 20 66 69 6c 65 73 20 57 48 45 52   FROM files WHER
4060: 45 20 70 61 63 6b 61 67 65 5f 73 68 61 31 20 3d  E package_sha1 =
4070: 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63 6b 61   $pathinfo(packa
4080: 67 65 5f 73 68 61 31 29 20 41 4e 44 20 66 69 6c  ge_sha1) AND fil
4090: 65 5f 64 69 72 65 63 74 6f 72 79 20 3d 20 24 64  e_directory = $d
40a0: 69 72 65 63 74 6f 72 79 20 41 4e 44 20 66 69 6c  irectory AND fil
40b0: 65 5f 6e 61 6d 65 20 3d 20 24 66 69 6c 65 3b 7d  e_name = $file;}
40c0: 20 72 65 74 76 61 6c 20 7b 7d 0a 09 09 09 09 09   retval {}......
40d0: 09 75 6e 73 65 74 20 2d 6e 6f 63 6f 6d 70 6c 61  .unset -nocompla
40e0: 69 6e 20 72 65 74 76 61 6c 28 2a 29 0a 09 09 09  in retval(*)....
40f0: 09 09 7d 0a 09 09 09 09 7d 0a 0a 09 09 09 7d 0a  ..}.....}.....}.
4100: 09 09 7d 0a 0a 09 09 69 66 20 7b 21 5b 69 6e 66  ..}....if {![inf
4110: 6f 20 65 78 69 73 74 73 20 72 65 74 76 61 6c 28  o exists retval(
4120: 74 79 70 65 29 5d 7d 20 7b 0a 09 09 09 72 65 74  type)]} {....ret
4130: 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20  urn -code error 
4140: 22 4e 6f 20 73 75 63 68 20 66 69 6c 65 20 6f 72  "No such file or
4150: 20 64 69 72 65 63 74 6f 72 79 22 0a 09 09 7d 0a   directory"...}.
4160: 0a 09 09 72 65 74 75 72 6e 20 5b 61 72 72 61 79  ...return [array
4170: 20 67 65 74 20 72 65 74 76 61 6c 5d 0a 09 7d 0a   get retval]..}.
4180: 0a 09 70 72 6f 63 20 6f 70 65 6e 70 61 74 68 20  ..proc openpath 
4190: 7b 70 61 74 68 20 6d 6f 64 65 7d 20 7b 0a 09 09  {path mode} {...
41a0: 61 72 72 61 79 20 73 65 74 20 70 61 74 68 69 6e  array set pathin
41b0: 66 6f 20 5b 5f 70 61 72 73 65 70 61 74 68 20 24  fo [_parsepath $
41c0: 70 61 74 68 5d 0a 0a 09 09 69 66 20 7b 24 70 61  path]....if {$pa
41d0: 74 68 69 6e 66 6f 28 5f 74 79 70 65 29 20 21 3d  thinfo(_type) !=
41e0: 20 22 66 69 6c 65 73 22 7d 20 7b 0a 09 09 09 72   "files"} {....r
41f0: 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f  eturn -code erro
4200: 72 20 22 69 6e 76 61 6c 69 64 20 74 79 70 65 22  r "invalid type"
4210: 0a 09 09 7d 0a 0a 09 09 73 65 74 20 6c 6f 63 61  ...}....set loca
4220: 6c 70 61 74 68 20 5b 5f 6c 6f 63 61 6c 70 61 74  lpath [_localpat
4230: 68 20 24 70 61 74 68 69 6e 66 6f 28 70 61 63 6b  h $pathinfo(pack
4240: 61 67 65 29 20 24 70 61 74 68 69 6e 66 6f 28 68  age) $pathinfo(h
4250: 6f 73 74 6e 61 6d 65 29 20 24 70 61 74 68 69 6e  ostname) $pathin
4260: 66 6f 28 66 69 6c 65 29 5d 0a 0a 09 09 69 66 20  fo(file)]....if 
4270: 7b 24 6d 6f 64 65 20 3d 3d 20 22 63 72 65 61 74  {$mode == "creat
4280: 65 22 7d 20 7b 0a 09 09 09 72 65 74 75 72 6e 20  e"} {....return 
4290: 24 6c 6f 63 61 6c 70 61 74 68 0a 09 09 7d 0a 0a  $localpath...}..
42a0: 09 09 69 66 20 7b 5b 66 69 6c 65 20 65 78 69 73  ..if {[file exis
42b0: 74 73 20 24 6c 6f 63 61 6c 70 61 74 68 5d 7d 20  ts $localpath]} 
42c0: 7b 0a 09 09 09 72 65 74 75 72 6e 20 24 6c 6f 63  {....return $loc
42d0: 61 6c 70 61 74 68 0a 09 09 7d 0a 0a 09 09 73 65  alpath...}....se
42e0: 74 20 77 6f 72 6b 20 5b 73 70 6c 69 74 20 24 70  t work [split $p
42f0: 61 74 68 69 6e 66 6f 28 66 69 6c 65 29 20 22 2f  athinfo(file) "/
4300: 22 5d 0a 09 09 73 65 74 20 64 69 72 65 63 74 6f  "]...set directo
4310: 72 79 20 5b 6a 6f 69 6e 20 5b 6c 72 61 6e 67 65  ry [join [lrange
4320: 20 24 77 6f 72 6b 20 30 20 65 6e 64 2d 31 5d 20   $work 0 end-1] 
4330: 22 2f 22 5d 0a 09 09 73 65 74 20 66 69 6c 65 20  "/"]...set file 
4340: 5b 6c 69 6e 64 65 78 20 24 77 6f 72 6b 20 65 6e  [lindex $work en
4350: 64 5d 0a 09 09 3a 3a 61 70 70 66 73 3a 3a 64 62  d]...::appfs::db
4360: 20 65 76 61 6c 20 7b 53 45 4c 45 43 54 20 66 69   eval {SELECT fi
4370: 6c 65 5f 73 68 61 31 2c 20 70 65 72 6d 73 20 46  le_sha1, perms F
4380: 52 4f 4d 20 66 69 6c 65 73 20 57 48 45 52 45 20  ROM files WHERE 
4390: 70 61 63 6b 61 67 65 5f 73 68 61 31 20 3d 20 24  package_sha1 = $
43a0: 70 61 74 68 69 6e 66 6f 28 70 61 63 6b 61 67 65  pathinfo(package
43b0: 5f 73 68 61 31 29 20 41 4e 44 20 66 69 6c 65 5f  _sha1) AND file_
43c0: 6e 61 6d 65 20 3d 20 24 66 69 6c 65 20 41 4e 44  name = $file AND
43d0: 20 66 69 6c 65 5f 64 69 72 65 63 74 6f 72 79 20   file_directory 
43e0: 3d 20 24 64 69 72 65 63 74 6f 72 79 3b 7d 20 70  = $directory;} p
43f0: 6b 67 70 61 74 68 69 6e 66 6f 20 7b 7d 0a 0a 09  kgpathinfo {}...
4400: 09 69 66 20 7b 24 70 6b 67 70 61 74 68 69 6e 66  .if {$pkgpathinf
4410: 6f 28 66 69 6c 65 5f 73 68 61 31 29 20 3d 3d 20  o(file_sha1) == 
4420: 22 22 7d 20 7b 0a 09 09 09 72 65 74 75 72 6e 20  ""} {....return 
4430: 2d 63 6f 64 65 20 65 72 72 6f 72 20 22 4e 6f 20  -code error "No 
4440: 73 75 63 68 20 66 69 6c 65 20 6f 72 20 64 69 72  such file or dir
4450: 65 63 74 6f 72 79 22 0a 09 09 7d 0a 0a 09 09 73  ectory"...}....s
4460: 65 74 20 6c 6f 63 61 6c 63 61 63 68 65 66 69 6c  et localcachefil
4470: 65 20 5b 64 6f 77 6e 6c 6f 61 64 20 24 70 61 74  e [download $pat
4480: 68 69 6e 66 6f 28 68 6f 73 74 6e 61 6d 65 29 20  hinfo(hostname) 
4490: 24 70 6b 67 70 61 74 68 69 6e 66 6f 28 66 69 6c  $pkgpathinfo(fil
44a0: 65 5f 73 68 61 31 29 5d 0a 0a 09 09 69 66 20 7b  e_sha1)]....if {
44b0: 24 6d 6f 64 65 20 3d 3d 20 22 77 72 69 74 65 22  $mode == "write"
44c0: 7d 20 7b 0a 09 09 09 73 65 74 20 74 6d 70 6c 6f  } {....set tmplo
44d0: 63 61 6c 70 61 74 68 20 22 24 7b 6c 6f 63 61 6c  calpath "${local
44e0: 70 61 74 68 7d 2e 5b 65 78 70 72 20 72 61 6e 64  path}.[expr rand
44f0: 28 29 5d 5b 63 6c 6f 63 6b 20 63 6c 69 63 6b 73  ()][clock clicks
4500: 5d 22 0a 0a 09 09 09 73 65 74 20 66 61 69 6c 65  ]".....set faile
4510: 64 20 30 0a 09 09 09 69 66 20 7b 5b 63 61 74 63  d 0....if {[catc
4520: 68 20 7b 0a 09 09 09 09 66 69 6c 65 20 6d 6b 64  h {.....file mkd
4530: 69 72 20 5b 66 69 6c 65 20 64 69 72 6e 61 6d 65  ir [file dirname
4540: 20 24 6c 6f 63 61 6c 70 61 74 68 5d 0a 09 09 09   $localpath]....
4550: 09 66 69 6c 65 20 63 6f 70 79 20 2d 66 6f 72 63  .file copy -forc
4560: 65 20 2d 2d 20 24 6c 6f 63 61 6c 63 61 63 68 65  e -- $localcache
4570: 66 69 6c 65 20 24 74 6d 70 6c 6f 63 61 6c 70 61  file $tmplocalpa
4580: 74 68 0a 0a 09 09 09 09 69 66 20 7b 24 70 6b 67  th......if {$pkg
4590: 70 61 74 68 69 6e 66 6f 28 70 65 72 6d 73 29 20  pathinfo(perms) 
45a0: 3d 3d 20 22 78 22 7d 20 7b 0a 09 09 09 09 09 66  == "x"} {......f
45b0: 69 6c 65 20 61 74 74 72 69 62 75 74 65 73 20 24  ile attributes $
45c0: 74 6d 70 6c 6f 63 61 6c 70 61 74 68 20 2d 70 65  tmplocalpath -pe
45d0: 72 6d 69 73 73 69 6f 6e 73 20 2b 78 0a 09 09 09  rmissions +x....
45e0: 09 7d 0a 0a 09 09 09 09 66 69 6c 65 20 72 65 6e  .}......file ren
45f0: 61 6d 65 20 2d 66 6f 72 63 65 20 2d 2d 20 24 74  ame -force -- $t
4600: 6d 70 6c 6f 63 61 6c 70 61 74 68 20 24 6c 6f 63  mplocalpath $loc
4610: 61 6c 70 61 74 68 0a 09 09 09 7d 20 65 72 72 5d  alpath....} err]
4620: 7d 20 7b 0a 09 09 09 09 73 65 74 20 66 61 69 6c  } {.....set fail
4630: 65 64 20 31 0a 09 09 09 7d 0a 09 09 09 63 61 74  ed 1....}....cat
4640: 63 68 20 7b 0a 09 09 09 09 66 69 6c 65 20 64 65  ch {.....file de
4650: 6c 65 74 65 20 2d 66 6f 72 63 65 20 2d 2d 20 24  lete -force -- $
4660: 74 6d 70 6c 6f 63 61 6c 70 61 74 68 0a 09 09 09  tmplocalpath....
4670: 7d 0a 0a 09 09 09 69 66 20 7b 24 66 61 69 6c 65  }.....if {$faile
4680: 64 7d 20 7b 0a 09 09 09 09 72 65 74 75 72 6e 20  d} {.....return 
4690: 2d 63 6f 64 65 20 65 72 72 6f 72 20 24 65 72 72  -code error $err
46a0: 0a 09 09 09 7d 0a 0a 09 09 09 72 65 74 75 72 6e  ....}.....return
46b0: 20 24 6c 6f 63 61 6c 70 61 74 68 0a 09 09 7d 0a   $localpath...}.
46c0: 0a 09 09 72 65 74 75 72 6e 20 24 6c 6f 63 61 6c  ...return $local
46d0: 63 61 63 68 65 66 69 6c 65 0a 09 7d 0a 0a 09 70  cachefile..}...p
46e0: 72 6f 63 20 6c 6f 63 61 6c 70 61 74 68 20 7b 70  roc localpath {p
46f0: 61 74 68 7d 20 7b 0a 09 09 61 72 72 61 79 20 73  ath} {...array s
4700: 65 74 20 70 61 74 68 69 6e 66 6f 20 5b 5f 70 61  et pathinfo [_pa
4710: 72 73 65 70 61 74 68 20 24 70 61 74 68 5d 0a 0a  rsepath $path]..
4720: 09 09 69 66 20 7b 24 70 61 74 68 69 6e 66 6f 28  ..if {$pathinfo(
4730: 5f 74 79 70 65 29 20 21 3d 20 22 66 69 6c 65 73  _type) != "files
4740: 22 7d 20 7b 0a 09 09 09 72 65 74 75 72 6e 20 2d  "} {....return -
4750: 63 6f 64 65 20 65 72 72 6f 72 20 22 69 6e 76 61  code error "inva
4760: 6c 69 64 20 74 79 70 65 22 0a 09 09 7d 0a 0a 09  lid type"...}...
4770: 09 73 65 74 20 6c 6f 63 61 6c 70 61 74 68 20 5b  .set localpath [
4780: 5f 6c 6f 63 61 6c 70 61 74 68 20 24 70 61 74 68  _localpath $path
4790: 69 6e 66 6f 28 70 61 63 6b 61 67 65 29 20 24 70  info(package) $p
47a0: 61 74 68 69 6e 66 6f 28 68 6f 73 74 6e 61 6d 65  athinfo(hostname
47b0: 29 20 24 70 61 74 68 69 6e 66 6f 28 66 69 6c 65  ) $pathinfo(file
47c0: 29 5d 0a 0a 09 09 72 65 74 75 72 6e 20 24 6c 6f  )]....return $lo
47d0: 63 61 6c 70 61 74 68 0a 09 7d 0a 0a 09 70 72 6f  calpath..}...pro
47e0: 63 20 65 78 69 73 74 73 20 7b 70 61 74 68 7d 20  c exists {path} 
47f0: 7b 0a 09 09 63 61 74 63 68 20 7b 0a 09 09 09 73  {...catch {....s
4800: 65 74 20 69 6e 66 6f 20 5b 67 65 74 61 74 74 72  et info [getattr
4810: 20 24 70 61 74 68 5d 0a 09 09 7d 20 65 72 72 0a   $path]...} err.
4820: 0a 09 09 69 66 20 7b 21 5b 69 6e 66 6f 20 65 78  ...if {![info ex
4830: 69 73 74 73 20 69 6e 66 6f 5d 7d 20 7b 0a 09 09  ists info]} {...
4840: 09 69 66 20 7b 24 65 72 72 20 3d 3d 20 22 4e 6f  .if {$err == "No
4850: 20 73 75 63 68 20 66 69 6c 65 20 6f 72 20 64 69   such file or di
4860: 72 65 63 74 6f 72 79 22 7d 20 7b 0a 09 09 09 09  rectory"} {.....
4870: 72 65 74 75 72 6e 20 5b 6c 69 73 74 5d 0a 09 09  return [list]...
4880: 09 7d 20 65 6c 73 65 20 7b 0a 09 09 09 09 72 65  .} else {.....re
4890: 74 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72  turn -code error
48a0: 20 24 65 72 72 0a 09 09 09 7d 0a 09 09 7d 0a 0a   $err....}...}..
48b0: 09 09 72 65 74 75 72 6e 20 24 69 6e 66 6f 0a 09  ..return $info..
48c0: 7d 0a 0a 09 70 72 6f 63 20 70 72 65 70 61 72 65  }...proc prepare
48d0: 5f 74 6f 5f 63 72 65 61 74 65 20 7b 70 61 74 68  _to_create {path
48e0: 20 7b 6d 75 73 74 5f 6e 6f 74 5f 65 78 69 73 74   {must_not_exist
48f0: 20 31 7d 7d 20 7b 0a 09 09 69 66 20 7b 24 6d 75   1}} {...if {$mu
4900: 73 74 5f 6e 6f 74 5f 65 78 69 73 74 7d 20 7b 0a  st_not_exist} {.
4910: 09 09 09 69 66 20 7b 5b 65 78 69 73 74 73 20 24  ...if {[exists $
4920: 70 61 74 68 5d 20 21 3d 20 22 22 7d 20 7b 0a 09  path] != ""} {..
4930: 09 09 09 72 65 74 75 72 6e 20 2d 63 6f 64 65 20  ...return -code 
4940: 65 72 72 6f 72 20 22 46 69 6c 65 20 61 6c 72 65  error "File alre
4950: 61 64 79 20 65 78 69 73 74 73 22 0a 09 09 09 7d  ady exists"....}
4960: 0a 09 09 7d 0a 0a 09 09 73 65 74 20 66 69 6c 65  ...}....set file
4970: 6e 61 6d 65 20 5b 6c 6f 63 61 6c 70 61 74 68 20  name [localpath 
4980: 24 70 61 74 68 5d 0a 0a 09 09 73 65 74 20 64 69  $path]....set di
4990: 72 6e 61 6d 65 20 5b 66 69 6c 65 20 64 69 72 6e  rname [file dirn
49a0: 61 6d 65 20 24 66 69 6c 65 6e 61 6d 65 5d 0a 0a  ame $filename]..
49b0: 09 09 66 69 6c 65 20 6d 6b 64 69 72 20 24 64 69  ..file mkdir $di
49c0: 72 6e 61 6d 65 0a 0a 09 09 72 65 74 75 72 6e 20  rname....return 
49d0: 24 66 69 6c 65 6e 61 6d 65 0a 09 7d 0a 0a 09 70  $filename..}...p
49e0: 72 6f 63 20 75 6e 6c 69 6e 6b 70 61 74 68 20 7b  roc unlinkpath {
49f0: 70 61 74 68 7d 20 7b 0a 09 09 61 72 72 61 79 20  path} {...array 
4a00: 73 65 74 20 70 61 74 68 61 74 74 72 73 20 5b 65  set pathattrs [e
4a10: 78 69 73 74 73 20 24 70 61 74 68 5d 0a 0a 09 09  xists $path]....
4a20: 69 66 20 7b 21 5b 69 6e 66 6f 20 65 78 69 73 74  if {![info exist
4a30: 73 20 70 61 74 68 61 74 74 72 73 28 70 61 63 6b  s pathattrs(pack
4a40: 61 67 65 64 29 5d 7d 20 7b 0a 09 09 09 72 65 74  aged)]} {....ret
4a50: 75 72 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20  urn -code error 
4a60: 22 69 6e 76 61 6c 69 64 20 74 79 70 65 22 0a 09  "invalid type"..
4a70: 09 7d 0a 0a 09 09 73 65 74 20 6c 6f 63 61 6c 70  .}....set localp
4a80: 61 74 68 20 24 70 61 74 68 61 74 74 72 73 28 6c  ath $pathattrs(l
4a90: 6f 63 61 6c 70 61 74 68 29 0a 0a 09 09 69 66 20  ocalpath)....if 
4aa0: 7b 5b 69 6e 66 6f 20 65 78 69 73 74 73 20 70 61  {[info exists pa
4ab0: 74 68 61 74 74 72 73 28 69 73 5f 6c 6f 63 61 6c  thattrs(is_local
4ac0: 66 69 6c 65 29 5d 7d 20 7b 0a 09 09 09 69 66 20  file)]} {....if 
4ad0: 7b 5b 66 69 6c 65 20 69 73 64 69 72 65 63 74 6f  {[file isdirecto
4ae0: 72 79 20 24 6c 6f 63 61 6c 70 61 74 68 5d 7d 20  ry $localpath]} 
4af0: 7b 0a 09 09 09 09 73 65 74 20 63 68 69 6c 64 72  {.....set childr
4b00: 65 6e 20 5b 67 65 74 63 68 69 6c 64 72 65 6e 20  en [getchildren 
4b10: 24 70 61 74 68 5d 0a 0a 09 09 09 09 69 66 20 7b  $path]......if {
4b20: 5b 6c 6c 65 6e 67 74 68 20 24 63 68 69 6c 64 72  [llength $childr
4b30: 65 6e 5d 20 21 3d 20 30 7d 20 7b 0a 09 09 09 09  en] != 0} {.....
4b40: 09 72 65 74 75 72 6e 20 2d 63 6f 64 65 20 65 72  .return -code er
4b50: 72 6f 72 20 22 41 73 6b 65 64 20 74 6f 20 64 65  ror "Asked to de
4b60: 6c 65 74 65 20 6e 6f 6e 2d 65 6d 70 74 79 20 64  lete non-empty d
4b70: 69 72 65 63 74 6f 72 79 22 0a 09 09 09 09 7d 0a  irectory".....}.
4b80: 09 09 09 7d 0a 0a 09 09 09 66 69 6c 65 20 64 65  ...}.....file de
4b90: 6c 65 74 65 20 2d 66 6f 72 63 65 20 2d 2d 20 24  lete -force -- $
4ba0: 6c 6f 63 61 6c 70 61 74 68 0a 09 09 7d 20 65 6c  localpath...} el
4bb0: 73 65 69 66 20 7b 5b 69 6e 66 6f 20 65 78 69 73  seif {[info exis
4bc0: 74 73 20 70 61 74 68 61 74 74 72 73 28 69 73 5f  ts pathattrs(is_
4bd0: 72 65 6d 6f 74 65 66 69 6c 65 29 5d 7d 20 7b 0a  remotefile)]} {.
4be0: 09 09 09 69 66 20 7b 24 70 61 74 68 61 74 74 72  ...if {$pathattr
4bf0: 73 28 74 79 70 65 29 20 3d 3d 20 22 64 69 72 65  s(type) == "dire
4c00: 63 74 6f 72 79 22 7d 20 7b 0a 09 09 09 09 73 65  ctory"} {.....se
4c10: 74 20 63 68 69 6c 64 72 65 6e 20 5b 67 65 74 63  t children [getc
4c20: 68 69 6c 64 72 65 6e 20 24 70 61 74 68 5d 0a 0a  hildren $path]..
4c30: 09 09 09 09 69 66 20 7b 5b 6c 6c 65 6e 67 74 68  ....if {[llength
4c40: 20 24 63 68 69 6c 64 72 65 6e 5d 20 21 3d 20 30   $children] != 0
4c50: 7d 20 7b 0a 09 09 09 09 09 72 65 74 75 72 6e 20  } {......return 
4c60: 2d 63 6f 64 65 20 65 72 72 6f 72 20 22 41 73 6b  -code error "Ask
4c70: 65 64 20 74 6f 20 64 65 6c 65 74 65 20 6e 6f 6e  ed to delete non
4c80: 2d 65 6d 70 74 79 20 64 69 72 65 63 74 6f 72 79  -empty directory
4c90: 22 0a 09 09 09 09 7d 0a 09 09 09 7d 0a 09 09 7d  ".....}....}...}
4ca0: 20 65 6c 73 65 20 7b 0a 09 09 09 72 65 74 75 72   else {....retur
4cb0: 6e 20 2d 63 6f 64 65 20 65 72 72 6f 72 20 22 55  n -code error "U
4cc0: 6e 6b 6e 6f 77 6e 20 69 66 20 66 69 6c 65 20 69  nknown if file i
4cd0: 73 20 72 65 6d 6f 74 65 20 6f 72 20 6c 6f 63 61  s remote or loca
4ce0: 6c 20 21 3f 22 0a 09 09 7d 0a 0a 09 09 73 65 74  l !?"...}....set
4cf0: 20 77 68 69 74 65 6f 75 74 66 69 6c 65 20 24 70   whiteoutfile $p
4d00: 61 74 68 61 74 74 72 73 28 77 68 69 74 65 6f 75  athattrs(whiteou
4d10: 74 70 61 74 68 29 0a 09 09 73 65 74 20 77 68 69  tpath)...set whi
4d20: 74 65 6f 75 74 64 69 72 20 5b 66 69 6c 65 20 64  teoutdir [file d
4d30: 69 72 6e 61 6d 65 20 24 77 68 69 74 65 6f 75 74  irname $whiteout
4d40: 66 69 6c 65 5d 0a 09 09 66 69 6c 65 20 6d 6b 64  file]...file mkd
4d50: 69 72 20 24 77 68 69 74 65 6f 75 74 64 69 72 0a  ir $whiteoutdir.
4d60: 09 09 63 6c 6f 73 65 20 5b 6f 70 65 6e 20 24 77  ..close [open $w
4d70: 68 69 74 65 6f 75 74 66 69 6c 65 20 77 5d 0a 09  hiteoutfile w]..
4d80: 7d 0a 7d 0a                                      }.}.