Merge branch 'next/vere' into jo/khan-c3

This commit is contained in:
Jōshin 2022-03-18 16:50:16 -06:00
commit 50de7b45b0
No known key found for this signature in database
GPG Key ID: A8BE5A9A521639D0
69 changed files with 36917 additions and 14622 deletions

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
16.14.0

View File

@ -159,6 +159,42 @@ so that I can type e.g. `git mu origin/foo 1337`.
If you're making a Vere release, just play it safe and update all the pills.
To produce multi pills, you will need to set up an environment with the
appropriate desks with the appropriate contents, doing something like the
following (where `> ` denotes an urbit command and `% ` denotes a unix shell
command):
```console
> |merge %garden our %base
> |merge %landscape our %base
> |merge %bitcoin our %base
> |merge %webterm our %base
> |mount %
> |mount %garden
> |mount %landscape
> |mount %bitcoin
> |mount %webterm
% rsync -avL --delete pkg/arvo/ zod/base/
% for desk in garden landscape bitcoin webterm; do \
rsync -avL --delete pkg/$desk/ zod/$desk/ \
done
> |commit %base
> |commit %garden
> |commit %landscape
> |commit %bitcoin
> |commit %webterm
> .multi/pill +solid %base %garden %landscape %bitcoin %webterm
> .brass-multi/pill +brass %base %garden %landscape %bitcoin %webterm
```
And then of course:
```console
> .solid/pill +solid
> .brass/pill +brass
> .ivory/pill +ivory
```
For an Urbit OS release, after all the merge commits, make a release with the
commit message "release: urbit-os-v1.0.xx". This commit should have up-to-date
artifacts from pkg/interface and a new version number in the desk.docket-0 of

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9a56f675d2a6c5dafa92a9e2d55040d994f3d3d27a1ed827bd87d1158b1e69d0
size 3749183
oid sha256:ae4a7a69fe81c5f2114d7b7360c05602f614fe66b96d1db4c3dc0c2a2a5d856e
size 7536000

View File

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:843387cce113f18b403f76b6ba97ddf1746a5436b107d087d1f33b38db6f8c1a
size 26237959
oid sha256:bcab0698de6efda1bbac54b0833da5e853bca058919110aa5668aa63fb40626e
size 9392699

View File

@ -1,6 +1,9 @@
{
"name": "root",
"private": true,
"engines": {
"node": "16.14.0"
},
"devDependencies": {
"eslint": "^7.29.0",
"husky": "^6.0.0",

View File

@ -60,18 +60,31 @@
::
++ poke-rekey :: rotate private keys
|= des=@t
=/ sed=(unit seed:jael)
=/ fud=(unit feed:jael)
%+ biff
(bind (slaw %uw des) cue)
(soft seed:jael)
(soft feed:jael)
=< abet
?~ sed
?~ fud
~& %invalid-private-key
this
?. =(our.bowl who.u.sed)
~& [%wrong-private-key-ship who.u.sed]
=/ fed (need fud)
?@ -.fed
?. =(our.bowl who.fed)
~& [%wrong-private-key-ship who.fed]
this
(emit %pass / %arvo %j %rekey lyf.fed key.fed)
?. =(our.bowl who.fed)
~& [%wrong-private-key-ship who.fed]
this
(emit %pass / %arvo %j %rekey lyf.u.sed key.u.sed)
=| caz=(list card)
%- emil
|-
?~ kyz.fed (flop caz)
%= $
kyz.fed t.kyz.fed
caz [[%pass / %arvo %j %rekey i.kyz.fed] caz]
==
::
++ ames-secret
^- @t

View File

@ -2235,6 +2235,112 @@
=/ pub (from.j qj)
?< =([0 0] pub)
pub
++ schnorr
~% %schnorr ..schnorr ~
=> |%
++ tagged-hash
|= [tag=@ [l=@ x=@]]
=+ hat=(sha-256:sha (swp 3 tag))
%- sha-256l:sha
:- (add 64 l)
(can 3 ~[[l x] [32 hat] [32 hat]])
++ lift-x
|= x=@I
^- (unit point)
=/ c curve
?. (lth x p.domain.c)
~
=/ fop field-p.c
=+ [fadd fpow]=[sum.fop exp.fop]
=/ cp (fadd (fpow 3 x) 7)
=/ y (fpow (rsh [0 2] +(p.domain.c)) cp)
?. =(cp (fpow 2 y))
~
%- some :- x
?: =(0 (mod y 2))
y
(sub p.domain.c y)
--
|%
::
++ sign :: schnorr signature
~/ %sosi
|= [sk=@I m=@I a=@I]
^- @J
?> (gte 32 (met 3 m))
?> (gte 32 (met 3 a))
=/ c curve
:: implies (gte 32 (met 3 sk))
::
?< |(=(0 sk) (gte sk n.domain.c))
=/ pp
(mul-point-scalar g.domain.c sk)
=/ d
?: =(0 (mod y.pp 2))
sk
(sub n.domain.c sk)
=/ t
%+ mix d
(tagged-hash 'BIP0340/aux' [32 a])
=/ rand
%+ tagged-hash 'BIP0340/nonce'
:- 96
(rep 8 ~[m x.pp t])
=/ kp (mod rand n.domain.c)
?< =(0 kp)
=/ rr (mul-point-scalar g.domain.c kp)
=/ k
?: =(0 (mod y.rr 2))
kp
(sub n.domain.c kp)
=/ e
%- mod
:_ n.domain.c
%+ tagged-hash 'BIP0340/challenge'
:- 96
(rep 8 ~[m x.pp x.rr])
=/ sig
%^ cat 8
(mod (add k (mul e d)) n.domain.c)
x.rr
?> (verify x.pp m sig)
sig
::
++ verify :: schnorr verify
~/ %sove
|= [pk=@I m=@I sig=@J]
^- ?
?> (gte 32 (met 3 pk))
?> (gte 32 (met 3 m))
?> (gte 64 (met 3 sig))
=/ c curve
=/ pup (lift-x pk)
?~ pup
%.n
=/ pp u.pup
=/ r (cut 8 [1 1] sig)
?: (gte r p.domain.c)
%.n
=/ s (end 8 sig)
?: (gte s n.domain.c)
%.n
=/ e
%- mod
:_ n.domain.c
%+ tagged-hash 'BIP0340/challenge'
:- 96
(rep 8 ~[m x.pp r])
=/ aa
(mul-point-scalar g.domain.c s)
=/ bb
(mul-point-scalar pp (sub n.domain.c e))
?: &(=(x.aa x.bb) !=(y.aa y.bb)) :: infinite?
%.n
=/ rr (add-points aa bb)
?. =(0 (mod y.rr 2))
%.n
=(r x.rr)
--
--
--
::

View File

@ -0,0 +1,21 @@
:: Test that these hints do not crash the runtime
:: there is no need to include the hints for dynamic %bout
:: since all hoon tests exersize dynamic %bout
|%
:: these test that the hilt-trace hints
:: are safe to run or ignore
++ test-hela-hilt
~> %hela
~
++ test-nara-hilt
~> %nara
~
:: these test that the hint-trace hints
:: are safe to run or ignore
++ test-hela-hint
~> %hela.[1 leaf+"test-hela-trace-hint"]
~
++ test-nara-hint
~> %nara.[1 leaf+"test-nara-trace-hint"]
~
--

View File

@ -116,4 +116,237 @@
3d07.03a9.9925.0581.
f7de.cd5e.f0f4.f809
==
++ test-schnorr
=> |%
+$ case-sec
$: sec=@
pub=@
aux=@
mes=@
sig=@
==
+$ case-pub
$: pub=@
mes=@
sig=@
res=?
==
--
=< %+ category "bip-0340 vectors"
(zing :(weld t1 t2 t3))
=/ cases-sec=(list case-sec)
:~
:* 0x3
0xf930.8a01.9258.c310.4934.4f85.f89d.5229.
b531.c845.836f.99b0.8601.f113.bce0.36f9
0
0
0xe907.831f.8084.8d10.69a5.371b.4024.1036.
4bdf.1c5f.8307.b008.4c55.f1ce.2dca.8215.
25f6.6a4a.85ea.8b71.e482.a74f.382d.2ce5.
ebee.e8fd.b217.2f47.7df4.900d.3105.36c0
==
:* 0xb7e1.5162.8aed.2a6a.bf71.5880.9cf4.f3c7.
62e7.160f.38b4.da56.a784.d904.5190.cfef
0xdff1.d77f.2a67.1c5f.3618.3726.db23.41be.
58fe.ae1d.a2de.ced8.4324.0f7b.502b.a659
1
0x243f.6a88.85a3.08d3.1319.8a2e.0370.7344.
a409.3822.299f.31d0.082e.fa98.ec4e.6c89
0x6896.bd60.eeae.296d.b48a.229f.f71d.fe07.
1bde.413e.6d43.f917.dc8d.cf8c.78de.3341.
8906.d11a.c976.abcc.b20b.0912.92bf.f4ea.
897e.fcb6.39ea.871c.fa95.f6de.339e.4b0a
==
:* 0xc90f.daa2.2168.c234.c4c6.628b.80dc.1cd1.
2902.4e08.8a67.cc74.020b.bea6.3b14.e5c9
0xdd30.8afe.c577.7e13.121f.a72b.9cc1.b7cc.
0139.7153.09b0.86c9.60e1.8fd9.6977.4eb8
0xc87a.a538.24b4.d7ae.2eb0.35a2.b5bb.bccc.
080e.76cd.c6d1.692c.4b0b.62d7.98e6.d906
0x7e2d.58d8.b3bc.df1a.bade.c782.9054.f90d.
da98.05aa.b56c.7733.3024.b9d0.a508.b75c
0x5831.aaee.d7b4.4bb7.4e5e.ab94.ba9d.4294.
c49b.cf2a.6072.8d8b.4c20.0f50.dd31.3c1b.
ab74.5879.a5ad.954a.72c4.5a91.c3a5.1d3c.
7ade.a98d.82f8.481e.0e1e.0367.4a6f.3fb7
==
:* 0xb43.2b26.7793.7381.aef0.5bb0.2a66.ecd0.
1277.3062.cf3f.a254.9e44.f58e.d240.1710
0x25d1.dff9.5105.f525.3c40.22f6.28a9.96ad.
3a0d.95fb.f21d.468a.1b33.f8c1.60d8.f517
0xffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff.
ffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff
0xffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff.
ffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff
0x7eb0.5097.57e2.46f1.9449.8856.5161.1cb9.
65ec.c1a1.87dd.51b6.4fda.1edc.9637.d5ec.
9758.2b9c.b13d.b393.3705.b32b.a982.af5a.
f25f.d788.81eb.b327.71fc.5922.efc6.6ea3
==
==
=/ t1
%+ turn cases-sec
|= case-sec
^- tang
%+ expect-eq
!> sig
!> (sign:schnorr:ecc sec mes aux)
=/ t2
%+ turn cases-sec
|= case-sec
^- tang
%- expect
!> (verify:schnorr:ecc pub mes sig)
=/ cases-pub=(list case-pub)
:~
:* 0xd69c.3509.bb99.e412.e68b.0fe8.544e.7283.
7dfa.3074.6d8b.e2aa.6597.5f29.d22d.c7b9
0x4df3.c3f6.8fcc.83b2.7e9d.42c9.0431.a724.
99f1.7875.c81a.599b.566c.9889.b969.6703
0x3b.78ce.563f.89a0.ed94.14f5.aa28.ad0d.
96d6.795f.9c63.76af.b154.8af6.03b3.eb45.
c9f8.207d.ee10.60cb.71c0.4e80.f593.060b.
07d2.8308.d7f4
%.y
==
:* 0xeefd.ea4c.db67.7750.a420.fee8.07ea.cf21.
eb98.98ae.79b9.7687.66e4.faa0.4a2d.4a34
0x243f.6a88.85a3.08d3.1319.8a2e.0370.7344.
a409.3822.299f.31d0.082e.fa98.ec4e.6c89
0x6cff.5c3b.a86c.69ea.4b73.76f3.1a9b.cb4f.
74c1.9760.89b2.d996.3da2.e554.3e17.7769.
69e8.9b4c.5564.d003.4910.6b84.9778.5dd7.
d1d7.13a8.ae82.b32f.a79d.5f7f.c407.d39b
%.n
==
:* 0xdff1.d77f.2a67.1c5f.3618.3726.db23.41be.
58fe.ae1d.a2de.ced8.4324.0f7b.502b.a659
0x243f.6a88.85a3.08d3.1319.8a2e.0370.7344.
a409.3822.299f.31d0.082e.fa98.ec4e.6c89
0xfff9.7bd5.755e.eea4.2045.3a14.3552.35d3.
82f6.472f.8568.a18b.2f05.7a14.6029.7556.
3cc2.7944.640a.c607.cd10.7ae1.0923.d9ef.
7a73.c643.e166.be5e.beaf.a34b.1ac5.53e2
%.n
==
:* 0xdff1.d77f.2a67.1c5f.3618.3726.db23.41be.
58fe.ae1d.a2de.ced8.4324.0f7b.502b.a659
0x243f.6a88.85a3.08d3.1319.8a2e.0370.7344.
a409.3822.299f.31d0.082e.fa98.ec4e.6c89
0x1fa6.2e33.1edb.c21c.3947.92d2.ab11.00a7.
b432.b013.df3f.6ff4.f99f.cb33.e0e1.515f.
2889.0b3e.db6e.7189.b630.448b.515c.e4f8.
622a.954c.fe54.5735.aaea.5134.fccd.b2bd
%.n
==
:* 0xdff1.d77f.2a67.1c5f.3618.3726.db23.41be.
58fe.ae1d.a2de.ced8.4324.0f7b.502b.a659
0x243f.6a88.85a3.08d3.1319.8a2e.0370.7344.
a409.3822.299f.31d0.082e.fa98.ec4e.6c89
0x6cff.5c3b.a86c.69ea.4b73.76f3.1a9b.cb4f.
74c1.9760.89b2.d996.3da2.e554.3e17.7769.
9617.64b3.aa9b.2ffc.b6ef.947b.6887.a226.
e8d7.c93e.00c5.ed0c.1834.ff0d.0c2e.6da6
%.n
==
:* 0xdff1.d77f.2a67.1c5f.3618.3726.db23.41be.
58fe.ae1d.a2de.ced8.4324.0f7b.502b.a659
0x243f.6a88.85a3.08d3.1319.8a2e.0370.7344.
a409.3822.299f.31d0.082e.fa98.ec4e.6c89
0x123d.da83.28af.9c23.a94c.1fee.cfd1.23ba.
4fb7.3476.f0d5.94dc.b65c.6425.bd18.6051
%.n
==
:* 0xdff1.d77f.2a67.1c5f.3618.3726.db23.41be.
58fe.ae1d.a2de.ced8.4324.0f7b.502b.a659
0x243f.6a88.85a3.08d3.1319.8a2e.0370.7344.
a409.3822.299f.31d0.082e.fa98.ec4e.6c89
0x1.7615.fbaf.5ae2.8864.013c.0997.42de.
adb4.dba8.7f11.ac67.54f9.3780.d5a1.837c.
f197
%.n
==
:* 0xdff1.d77f.2a67.1c5f.3618.3726.db23.41be.
58fe.ae1d.a2de.ced8.4324.0f7b.502b.a659
0x243f.6a88.85a3.08d3.1319.8a2e.0370.7344.
a409.3822.299f.31d0.082e.fa98.ec4e.6c89
0x4a29.8dac.ae57.395a.15d0.795d.dbfd.1dcb.
564d.a82b.0f26.9bc7.0a74.f822.0429.ba1d.
69e8.9b4c.5564.d003.4910.6b84.9778.5dd7.
d1d7.13a8.ae82.b32f.a79d.5f7f.c407.d39b
%.n
==
:* 0xdff1.d77f.2a67.1c5f.3618.3726.db23.41be.
58fe.ae1d.a2de.ced8.4324.0f7b.502b.a659
0x243f.6a88.85a3.08d3.1319.8a2e.0370.7344.
a409.3822.299f.31d0.082e.fa98.ec4e.6c89
0xffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff.
ffff.ffff.ffff.ffff.ffff.fffe.ffff.fc2f.
69e8.9b4c.5564.d003.4910.6b84.9778.5dd7.
d1d7.13a8.ae82.b32f.a79d.5f7f.c407.d39b
%.n
==
:* 0xdff1.d77f.2a67.1c5f.3618.3726.db23.41be.
58fe.ae1d.a2de.ced8.4324.0f7b.502b.a659
0x243f.6a88.85a3.08d3.1319.8a2e.0370.7344.
a409.3822.299f.31d0.082e.fa98.ec4e.6c89
0x6cff.5c3b.a86c.69ea.4b73.76f3.1a9b.cb4f.
74c1.9760.89b2.d996.3da2.e554.3e17.7769.
ffff.ffff.ffff.ffff.ffff.ffff.ffff.fffe.
baae.dce6.af48.a03b.bfd2.5e8c.d036.4141
%.n
==
:* 0xffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff.
ffff.ffff.ffff.ffff.ffff.fffe.ffff.fc30
0x243f.6a88.85a3.08d3.1319.8a2e.0370.7344.
a409.3822.299f.31d0.082e.fa98.ec4e.6c89
0x6cff.5c3b.a86c.69ea.4b73.76f3.1a9b.cb4f.
74c1.9760.89b2.d996.3da2.e554.3e17.7769.
69e8.9b4c.5564.d003.4910.6b84.9778.5dd7.
d1d7.13a8.ae82.b32f.a79d.5f7f.c407.d39b
%.n
==
==
:_ .
^= t3
%+ turn cases-pub
|= case-pub
^- tang
%+ expect-eq
!> res
!> (verify:schnorr:ecc pub mes sig)
++ test-schnorr-bounds
=> |% +$ case [sec=@ pub=@ aux=@ mes=@ sig=@] --
=< %+ category "bounds"
(zing (weld t1 t2))
=/ too-big
0xff.ffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff.
ffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff
=/ big-sig
0xff.ffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff.
ffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff.
ffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff.
ffff.ffff.ffff.ffff.ffff.ffff.ffff.ffff
=/ cases-big-sec=(list case)
:~ [too-big 0 0 0 0]
[1 0 too-big 0 0]
[1 0 0 too-big 0]
==
=/ cases-big-pub=(list case)
:~ [0 too-big 0 0 0]
[0 0 0 too-big 0]
[0 0 0 0 big-sig]
==
=/ t1
%+ turn cases-big-sec
|= case
%- expect-fail
|. (sign:schnorr:ecc sec mes aux)
:_ .
^= t2
%+ turn cases-big-pub
|= case
%- expect-fail
|. (verify:schnorr:ecc pub mes sig)
--

View File

@ -1,10 +1,10 @@
:~ title+'System'
info+'An app launcher for Urbit.'
color+0xee.5432
glob-http+['https://bootstrap.urbit.org/glob-0v5.1o2c9.g1btf.nandl.703oh.40up1.glob' 0v5.1o2c9.g1btf.nandl.703oh.40up1]
glob-http+['https://bootstrap.urbit.org/glob-0vcggb9.v4sgp.jbo30.t34mk.58i52.glob' 0vcggb9.v4sgp.jbo30.t34mk.58i52]
::glob-ames+~zod^0v0
base+'grid'
version+[1 0 3]
version+[1 1 0]
website+'https://tlon.io'
license+'MIT'
==

48997
pkg/grid/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -15,8 +15,10 @@
"tsc": "tsc --noEmit"
},
"dependencies": {
"@radix-ui/react-checkbox": "^0.1.5",
"@radix-ui/react-dialog": "^0.0.20",
"@radix-ui/react-dropdown-menu": "^0.0.23",
"@radix-ui/react-icons": "^1.1.0",
"@radix-ui/react-polymorphic": "^0.0.13",
"@radix-ui/react-portal": "^0.0.15",
"@radix-ui/react-toggle": "^0.0.10",
@ -36,6 +38,9 @@
"postcss-import": "^14.0.2",
"query-string": "^7.0.1",
"react": "^17.0.2",
"react-dnd": "^15.1.1",
"react-dnd-html5-backend": "^15.1.2",
"react-dnd-touch-backend": "^15.1.1",
"react-dom": "^17.0.2",
"react-error-boundary": "^3.1.3",
"react-router-dom": "^5.2.0",

View File

@ -0,0 +1,35 @@
import React, { useState } from 'react';
import classNames from 'classnames';
import * as RadixCheckbox from '@radix-ui/react-checkbox';
import { CheckIcon } from '@radix-ui/react-icons';
export const Checkbox: React.FC<RadixCheckbox.CheckboxProps> = ({
defaultChecked,
checked,
onCheckedChange,
disabled,
className,
children
}) => {
const [on, setOn] = useState(defaultChecked);
const isControlled = !!onCheckedChange;
const proxyChecked = isControlled ? checked : on;
const proxyOnCheckedChange = isControlled ? onCheckedChange : setOn;
return (
<div className="flex content-center space-x-2">
<RadixCheckbox.Root
className={classNames('default-ring rounded-lg bg-white h-7 w-7', className)}
checked={proxyChecked}
onCheckedChange={proxyOnCheckedChange}
disabled={disabled}
id="checkbox"
>
<RadixCheckbox.Indicator className="flex justify-center">
<CheckIcon className="text-black" />
</RadixCheckbox.Indicator>
</RadixCheckbox.Root>
<label htmlFor="checkbox">{children}</label>
</div>
);
};

View File

@ -0,0 +1,20 @@
import React from 'react';
export const Lock = (props: React.SVGProps<SVGSVGElement>) => (
<svg
width="10"
height="12"
viewBox="-11 -8 32 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8 5H9C9.55228 5 10 5.44772 10 6V11C10 11.5523 9.55229 12 9 12H1C0.447716 12 0 11.5523 0 11V6C0 5.44772 0.447715 5 1 5H2V3C2 1.34315 3.34315 0 5 0C6.65685 0 8 1.34315 8 3V5ZM7 5V3C7 1.89543 6.10457 1 5 1C3.89543 1 3 1.89543 3 3V5H7ZM3 6H9V11H1V6H2H3Z"
className="fill-current"
strokeMiterlimit="10"
/>
</svg>
);

View File

@ -5,6 +5,7 @@ import classNames from 'classnames';
import { NotificationPrefs } from './preferences/NotificationPrefs';
import { SystemUpdatePrefs } from './preferences/SystemUpdatePrefs';
import { InterfacePrefs } from './preferences/InterfacePrefs';
import { SecurityPrefs } from './preferences/SecurityPrefs';
import { useCharges } from '../state/docket';
import { AppPrefs } from './preferences/AppPrefs';
import { DocketImage } from '../components/DocketImage';
@ -14,6 +15,7 @@ import { LeftArrow } from '../components/icons/LeftArrow';
import { System } from '../components/icons/System';
import { Interface } from '../components/icons/Interface';
import { Notifications } from '../components/icons/Notifications';
import { Lock } from '../components/icons/Lock';
import { getAppName } from '../state/util';
interface SystemPreferencesSectionProps {
@ -77,11 +79,11 @@ export const SystemPreferences = (props: RouteComponentProps<{ submenu: string }
FallbackComponent={ErrorAlert}
onReset={() => history.push('/leap/system-preferences')}
>
<div className="sm:flex h-full overflow-y-auto">
<div className="h-full overflow-y-auto sm:flex">
<Route exact={isMobile} path={match.url}>
<aside className="flex-none self-start w-full sm:w-auto min-w-60 py-4 sm:py-8 font-semibold text-black sm:text-gray-600 border-r-2 border-gray-50">
<aside className="self-start flex-none w-full py-4 font-semibold text-black border-r-2 sm:w-auto min-w-60 sm:py-8 sm:text-gray-600 border-gray-50">
<nav className="px-2 sm:px-6">
<h2 className="sm:hidden h3 mb-4 px-2">System Preferences</h2>
<h2 className="px-2 mb-4 sm:hidden h3">System Preferences</h2>
<ul className="space-y-1">
<SystemPreferencesSection
url={subUrl('notifications')}
@ -101,6 +103,10 @@ export const SystemPreferences = (props: RouteComponentProps<{ submenu: string }
<Interface className="w-8 h-8 mr-3 bg-gray-100 rounded-md" />
Interface Settings
</SystemPreferencesSection>
<SystemPreferencesSection url={subUrl('security')} active={matchSub('security')}>
<Lock className="w-8 h-8 mr-3 bg-gray-100 rounded-md" />
Security
</SystemPreferencesSection>
</ul>
</nav>
<hr className="my-4 border-t-2 border-gray-50" />
@ -126,6 +132,7 @@ export const SystemPreferences = (props: RouteComponentProps<{ submenu: string }
<Route path={`${match.url}/apps/:desk`} component={AppPrefs} />
<Route path={`${match.url}/system-updates`} component={SystemUpdatePrefs} />
<Route path={`${match.url}/interface`} component={InterfacePrefs} />
<Route path={`${match.url}/security`} component={SecurityPrefs} />
<Route
path={[`${match.url}/notifications`, match.url]}
component={NotificationPrefs}
@ -133,7 +140,7 @@ export const SystemPreferences = (props: RouteComponentProps<{ submenu: string }
</Switch>
<Link
to={match.url}
className="inline-flex sm:hidden items-center sm:none mt-auto pt-4 h4 text-gray-400"
className="inline-flex items-center pt-4 mt-auto text-gray-400 sm:hidden sm:none h4"
>
<LeftArrow className="w-3 h-3 mr-2" /> Back
</Link>

View File

@ -0,0 +1,32 @@
import React, { useState } from 'react';
import classNames from 'classnames';
import { Button } from '../../components/Button';
import { Checkbox } from '../../components/Checkbox';
export const SecurityPrefs = () => {
const [allSessions, setAllSessions] = useState(false);
return (
<>
<h2 className="h3 mb-7">Security</h2>
<div className="space-y-3">
<section className={classNames('inner-section')}>
<h3 className="flex items-center mb-2 h4">Logout</h3>
<div className="flex flex-col justify-center flex-1 space-y-6">
<Checkbox
defaultChecked={false}
checked={allSessions}
onCheckedChange={() => setAllSessions((prev) => !prev)}
>
Log out of all sessions.
</Checkbox>
<form method="post" action="/~/logout">
{allSessions && <input type="hidden" name="all" />}
<Button>Logout</Button>
</form>
</div>
</section>
</div>
</>
);
};

View File

@ -1,46 +1,43 @@
import { map, omit } from 'lodash';
import React, { FunctionComponent, useEffect } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { Route, RouteComponentProps, useHistory, useParams } from 'react-router-dom';
import { Route, useHistory, useParams } from 'react-router-dom';
import { ErrorAlert } from '../components/ErrorAlert';
import { MenuState, Nav } from '../nav/Nav';
import { useCharges } from '../state/docket';
import useKilnState from '../state/kiln';
import { RemoveApp } from '../tiles/RemoveApp';
import { SuspendApp } from '../tiles/SuspendApp';
import { Tile } from '../tiles/Tile';
import { TileGrid } from '../tiles/TileGrid';
import { TileInfo } from '../tiles/TileInfo';
interface RouteProps {
menu?: MenuState;
}
export const Grid: FunctionComponent<{}> = () => {
const charges = useCharges();
export const Grid: FunctionComponent = () => {
const { push } = useHistory();
const { menu } = useParams<RouteProps>();
const chargesLoaded = Object.keys(charges).length > 0;
useEffect(() => {
// TOOD: rework
// Heuristically detect reload completion and redirect
async function attempt(count = 0) {
if(count > 5) {
if (count > 5) {
window.location.reload();
}
const start = performance.now();
await useKilnState.getState().fetchVats();
await useKilnState.getState().fetchVats();
if((performance.now() - start) > 5000) {
attempt(count+1);
if (performance.now() - start > 5000) {
attempt(count + 1);
} else {
push('/');
}
}
if(menu === 'upgrading') {
if (menu === 'upgrading') {
attempt();
}
}, [menu])
}, [menu]);
return (
<div className="flex flex-col">
@ -49,15 +46,7 @@ export const Grid: FunctionComponent<{}> = () => {
</header>
<main className="h-full w-full flex justify-center pt-4 md:pt-16 pb-32 relative z-0">
{!chargesLoaded && <span>Loading...</span>}
{chargesLoaded && (
<div className="grid justify-center grid-cols-2 sm:grid-cols-[repeat(auto-fit,minmax(auto,250px))] gap-4 px-4 md:px-8 w-full max-w-6xl">
{charges &&
map(omit(charges, window.desk), (charge, desk) => (
<Tile key={desk} charge={charge} desk={desk} disabled={menu === 'upgrading'} />
))}
</div>
)}
<TileGrid menu={menu} />
<ErrorBoundary FallbackComponent={ErrorAlert} onReset={() => push('/')}>
<Route exact path="/app/:desk">
<TileInfo />

View File

@ -4,7 +4,7 @@ import { compose } from 'lodash/fp';
import _ from 'lodash';
import create, { GetState, SetState, UseStore } from 'zustand';
import { persist } from 'zustand/middleware';
import Urbit, { SubscriptionRequestInterface } from '@urbit/http-api';
import Urbit, { FatalError, SubscriptionRequestInterface } from '@urbit/http-api';
import { Poke } from '@urbit/api';
import api from './api';
import { clearStorageMigration, createStorageKey, storageVersion, useMockData } from './util';
@ -107,7 +107,9 @@ export function createSubscription(
path,
event: e,
err: () => {},
quit: () => {}
quit: () => {
throw new FatalError("subscription clogged");
}
};
// TODO: err, quit handling (resubscribe?)
return request;

View File

@ -21,6 +21,9 @@ interface BaseSettingsState {
theme: 'light' | 'dark' | 'auto';
doNotDisturb: boolean;
};
tiles: {
order: string[];
};
putEntry: (bucket: string, key: string, value: Value) => Promise<void>;
[ref: string]: unknown;
}
@ -71,6 +74,9 @@ export const useSettingsState = createState<BaseSettingsState>(
theme: 'auto',
doNotDisturb: true
},
tiles: {
order: []
},
loaded: false,
putEntry: async (bucket, key, val) => {
const poke = doPutEntry(window.desk, bucket, key, val);

View File

@ -1,5 +1,6 @@
import classNames from 'classnames';
import React, { FunctionComponent } from 'react';
import { useDrag } from 'react-dnd';
import { chadIsRunning } from '@urbit/api';
import { TileMenu } from './TileMenu';
import { Spinner } from '../components/Spinner';
@ -9,6 +10,7 @@ import { ChargeWithDesk } from '../state/docket';
import { useTileColor } from './useTileColor';
import { useVat } from '../state/kiln';
import { Bullet } from '../components/icons/Bullet';
import { dragTypes } from './TileGrid';
type TileProps = {
charge: ChargeWithDesk;
@ -28,13 +30,23 @@ export const Tile: FunctionComponent<TileProps> = ({ charge, desk, disabled = fa
const link = getAppHref(href);
const backgroundColor = suspended ? suspendColor : active ? tileColor || 'purple' : suspendColor;
const [{ isDragging }, drag] = useDrag(() => ({
type: dragTypes.TILE,
item: { desk },
collect: (monitor) => ({
isDragging: !!monitor.isDragging()
})
}));
return (
<a
ref={drag}
href={active ? link : undefined}
target="_blank"
rel="noreferrer"
className={classNames(
'group relative font-semibold aspect-w-1 aspect-h-1 rounded-3xl default-ring focus-visible:ring-4 overflow-hidden',
'group absolute font-semibold w-full h-full rounded-3xl default-ring focus-visible:ring-4 overflow-hidden',
isDragging && 'opacity-0',
lightText && active && !loading ? 'text-gray-200' : 'text-gray-800',
!active && 'cursor-default'
)}
@ -48,7 +60,7 @@ export const Tile: FunctionComponent<TileProps> = ({ charge, desk, disabled = fa
<>
{loading && <Spinner className="h-6 w-6 mr-2" />}
<span className="text-gray-500">
{suspended ? 'Suspended' : loading ? 'Installing' : hung ? 'Errored' : null }
{suspended ? 'Suspended' : loading ? 'Installing' : hung ? 'Errored' : null}
</span>
</>
)}

View File

@ -0,0 +1,56 @@
import classNames from 'classnames';
import { uniq, without } from 'lodash';
import React, { FunctionComponent } from 'react';
import { useDrop } from 'react-dnd';
import { useSettingsState } from '../state/settings';
import { dragTypes, selTiles } from './TileGrid';
interface TileContainerProps {
desk: string;
}
export const TileContainer: FunctionComponent<TileContainerProps> = ({ desk, children }) => {
const { order } = useSettingsState(selTiles);
const [{ isOver }, drop] = useDrop<{ desk: string }, undefined, { isOver: boolean }>(
() => ({
accept: dragTypes.TILE,
drop: ({ desk: itemDesk }) => {
if (!itemDesk || itemDesk === desk) {
return undefined;
}
// [1, 2, 3, 4] 1 -> 3
// [2, 3, 4]
const beforeSlot = order.indexOf(itemDesk) < order.indexOf(desk);
const orderWithoutOriginal = without(order, itemDesk);
const slicePoint = orderWithoutOriginal.indexOf(desk);
// [2, 3] [4]
const left = orderWithoutOriginal.slice(0, beforeSlot ? slicePoint + 1 : slicePoint);
const right = orderWithoutOriginal.slice(slicePoint);
// concat([2, 3], [1], [4])
const newOrder = uniq(left.concat([itemDesk], right));
// [2, 3, 1, 4]
console.log({ order, left, right, slicePoint, newOrder });
useSettingsState.getState().putEntry('tiles', 'order', newOrder);
return undefined;
},
collect: (monitor) => ({
isOver: !!monitor.isOver()
})
}),
[desk, order]
);
return (
<div
ref={drop}
className={classNames(
'relative aspect-w-1 aspect-h-1 rounded-3xl ring-4',
isOver && 'ring-blue-500',
!isOver && 'ring-transparent'
)}
>
{children}
</div>
);
};

View File

@ -0,0 +1,77 @@
import React, { useEffect } from 'react';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { TouchBackend } from 'react-dnd-touch-backend';
import { uniq } from 'lodash';
import { ChargeWithDesk, useCharges } from '../state/docket';
import { Tile } from './Tile';
import { MenuState } from '../nav/Nav';
import { SettingsState, useSettingsState } from '../state/settings';
import { TileContainer } from './TileContainer';
import { useMedia } from '../logic/useMedia';
export interface TileData {
desk: string;
charge: ChargeWithDesk;
position: number;
dragging: boolean;
}
interface TileGridProps {
menu?: MenuState;
}
export const dragTypes = {
TILE: 'tile'
};
export const selTiles = (s: SettingsState) => s.tiles;
export const TileGrid = ({ menu }: TileGridProps) => {
const charges = useCharges();
const chargesLoaded = Object.keys(charges).length > 0;
const { order } = useSettingsState(selTiles);
const isMobile = useMedia('(pointer: coarse)');
useEffect(() => {
const hasKeys = order && !!order.length;
const chargeKeys = Object.keys(charges);
if (!hasKeys) {
useSettingsState.getState().putEntry('tiles', 'order', chargeKeys);
} else if (order.length < chargeKeys.length) {
useSettingsState.getState().putEntry('tiles', 'order', uniq(order.concat(chargeKeys)));
}
}, [charges, order]);
if (!chargesLoaded) {
return <span>Loading...</span>;
}
return (
<DndProvider
backend={isMobile ? TouchBackend : HTML5Backend}
options={
isMobile
? {
delay: 50,
scrollAngleRanges: [
{ start: 30, end: 150 },
{ start: 210, end: 330 }
]
}
: undefined
}
>
<div className="grid justify-center grid-cols-2 sm:grid-cols-[repeat(auto-fit,minmax(auto,250px))] gap-4 px-4 md:px-8 w-full max-w-6xl">
{order
.filter((d) => d !== window.desk)
.map((desk) => (
<TileContainer desk={desk}>
<Tile key={desk} charge={charges[desk]} desk={desk} disabled={menu === 'upgrading'} />
</TileContainer>
))}
</div>
</DndProvider>
);
};

1
pkg/interface/.nvmrc Normal file
View File

@ -0,0 +1 @@
16.14.0

View File

@ -4,6 +4,9 @@
"description": "",
"main": "index.js",
"private": true,
"engines": {
"node": "16.14.0"
},
"dependencies": {
"@babel/runtime": "^7.12.5",
"@radix-ui/react-dialog": "^0.1.0",

View File

@ -7,7 +7,6 @@
content="width=device-width, initial-scale=1, shrink-to-fit=no,maximum-scale=1"/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-touch-fullscreen" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<link rel="manifest"
href='data:application/manifest+json,{
"name": "Groups",
@ -16,6 +15,9 @@
"display": "standalone",
"background_color": "%23FFFFFF",
"theme_color": "%23000000"}' />
<meta name="theme-color" content="#FFFFFF" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#1A1A1A" media="(prefers-color-scheme: dark)">
<meta name="theme-color" content="#FFFFFF">
<script src="/apps/landscape/desk.js"></script>
<script src="/session.js"></script>
</head>

View File

@ -229,6 +229,18 @@ export function deSig(ship: string): string {
return ship.replace('~', '');
}
export function preSig(ship: string): string {
if (!ship) {
return '';
}
if (ship.trim().startsWith('~')) {
return ship.trim();
}
return '~'.concat(ship.trim());
}
export function uxToHex(ux: string) {
if (ux.length > 2 && ux.substr(0, 2) === '0x') {
const value = ux.substr(2).replace('.', '').padStart(6, '0');

View File

@ -143,6 +143,8 @@ function PendingGroup(props: PendingGroupProps) {
<Box>
{!joining ? (
<Text color="blue">Invited</Text>
) : joining === 'no-perms' || joining == 'strange' ? (
<Text color="red">Join Failed</Text>
) : joining !== "done" ? (
<Text gray>Joining...</Text>
) : (

View File

@ -8,7 +8,7 @@ import {
} from '@urbit/api';
import { BigInteger } from 'big-integer';
import React, { useCallback } from 'react';
import { useHovering } from '~/logic/lib/util';
import { deSig, useHovering } from '~/logic/lib/util';
import useLocalState from '~/logic/state/local';
import { StatelessAsyncAction } from '~/views/components/StatelessAsyncAction';
import { SwipeMenu } from '~/views/components/SwipeMenu';
@ -38,7 +38,7 @@ const NotificationText = ({ contents, ...rest }: NotificationTextProps) => {
return (
<Mention
key={idx}
ship={content.ship}
ship={deSig(content.ship)}
first={idx === 0}
{...rest}
/>

View File

@ -1,54 +0,0 @@
import {
Button,
Col,
StatelessCheckboxField, Text
} from '@tlon/indigo-react';
import React, { useState } from 'react';
import { BackButton } from './BackButton';
export default function SecuritySettings() {
const [allSessions, setAllSessions] = useState(false);
return (
<>
<BackButton />
<Col gapY={5} p={5} pt={4}>
<Col gapY={1} mt={0}>
<Text fontSize={2} fontWeight="medium">
Security Preferences
</Text>
<Text gray>
Manage sessions, login credentials and web access
</Text>
</Col>
<Col gapY={1}>
<Text color="black">
Log out of this session
</Text>
<Text mb={3} gray>
{allSessions
? 'You will be logged out of all browsers that have currently logged into your Urbit.'
: 'You will be logged out of your Urbit on this browser.'}
</Text>
<StatelessCheckboxField
mb={3}
selected={allSessions}
onChange={() => setAllSessions(s => !s)}
>
<Text>Log out of all sessions</Text>
</StatelessCheckboxField>
<form method="post" action="/~/logout">
{allSessions && <input type="hidden" name="all" />}
<Button
primary
destructive
border={1}
style={{ cursor: 'pointer' }}
>
Logout
</Button>
</form>
</Col>
</Col>
</>
);
}

View File

@ -11,7 +11,6 @@ import DisplayForm from './components/lib/DisplayForm';
import { LeapSettings } from './components/lib/LeapSettings';
import { NotificationPreferences } from './components/lib/NotificationPref';
import S3Form from './components/lib/S3Form';
import SecuritySettings from './components/lib/Security';
import { DmSettings } from './components/lib/DmSettings';
import ShortcutSettings from './components/lib/ShortcutSettings';
@ -117,11 +116,6 @@ return;
<SidebarItem icon='Messages' text='Direct Messages' hash='dm' />
<SidebarItem icon='Node' text='CalmEngine' hash='calm' />
<SidebarItem icon='EastCarat' text='Shortcuts' hash='shortcuts' />
<SidebarItem
icon='Locked'
text='Devices + Security'
hash='security'
/>
</Col>
</Col>
<Col flexGrow={1} overflowY='auto'>
@ -138,7 +132,6 @@ return;
{hash === 's3' && <S3Form />}
{hash === 'leap' && <LeapSettings />}
{hash === 'calm' && <CalmPrefs />}
{hash === 'security' && <SecuritySettings />}
{hash === 'debug' && <DebugPane />}
</SettingsItem>
</Col>

View File

@ -40,8 +40,9 @@ export function MentionText(props: MentionTextProps) {
export function Mention(props: {
ship: string;
first?: boolean;
emphasis?: 'bold' | 'italic';
} & PropFunc<typeof Text>) {
const { ship, first = false, ...rest } = props;
const { ship, first = false, emphasis, ...rest } = props;
const contact = useContact(`~${deSig(ship)}`);
const showNickname = useShowNickname(contact);
const name = showNickname ? contact?.nickname : cite(ship);
@ -51,8 +52,10 @@ export function Mention(props: {
marginLeft={first? 0 : 1}
marginRight={1}
px={1}
bold={emphasis === 'bold' ? true : false}
bg='washedBlue'
color='blue'
fontStyle={emphasis === 'italic' ? 'italic' : undefined}
fontSize={showNickname ? 1 : 0}
mono={!showNickname}
title={showNickname ? cite(ship) : contact?.nickname}

View File

@ -34,11 +34,14 @@ const FixedOverlay = styled(Col)`
transition: all 0.1s ease-out;
`;
type ProfileOverlayProps = BoxProps & {
ship: string;
children?: ReactNode;
color?: string;
};
interface ProfileOverlayProps extends BoxProps {
/**
* A valid patp (without sig)
*/
ship: string,
children?: ReactNode,
color?: string,
}
const selSettings = (s: SettingsState) => [s.calm.hideAvatars, s.calm.hideNicknames];

View File

@ -167,9 +167,11 @@ export function ShipSearch<I extends string, V extends Value<I>>(
name={id}
render={(arrayHelpers) => {
const onAdd = (ship: string) => {
setFieldValue(name(), ship);
inputIdx.current += 1;
arrayHelpers.push('');
if (!pills.includes(ship)) {
setFieldValue(name(), ship);
inputIdx.current += 1;
arrayHelpers.push('');
}
};
const onRemove = (idx: number) => {

View File

@ -34,6 +34,72 @@ interface GraphMentionNode {
ship: string;
}
const addEmphasisToMention = (contents: Content[], content: Content, index: number) => {
const prevContent = contents[index - 1];
const nextContent = contents[index + 1];
if (
'text' in content &&
(content.text.trim() === '**' || content.text.trim() === '*' )
) {
return {
text: ''
};
}
if(
'text' in content &&
content.text.endsWith('*') &&
!content.text.startsWith('*') &&
nextContent !== undefined &&
'mention' in nextContent
) {
if (content.text.charAt((content.text.length - 2)) === '*') {
return { text: content.text.slice(0, content.text.length - 2) };
}
return { text: content.text.slice(0, content.text.length - 1) };
}
if (
'text' in content &&
content.text.startsWith('*') &&
!content.text.endsWith('*') &&
prevContent !== undefined &&
'mention' in contents[index - 1]
) {
if (content.text.charAt(1) === '*') {
return { text: content.text.slice(2, content.text.length) };
}
return { text: content.text.slice(1, content.text.length) };
}
if (
'mention' in content &&
prevContent !== undefined &&
'text' in prevContent &&
// @ts-ignore type guard above covers this.
prevContent.text.endsWith('*') &&
nextContent !== undefined &&
'text' in contents[index + 1] &&
// @ts-ignore type guard above covers this.
nextContent.text.startsWith('*')
) {
if (
// @ts-ignore covered by typeguard in conditions
prevContent.text.charAt(prevContent.text.length - 2) === '*' &&
// @ts-ignore covered by typeguard in conditions
nextContent.text.charAt(nextContent.text[1]) === '*'
) {
return {
mention: content.mention,
emphasis: 'bold'
};
}
return {
mention: content.mention,
emphasis: 'italic'
};
}
return content;
};
const codeToMdAst = (content: CodeContent) => {
return {
type: 'root',
@ -100,7 +166,8 @@ const contentToMdAst = (tall: boolean) => (
children: [
{
type: 'graph-mention',
ship: content.mention
ship: content.mention,
emphasis: content.emphasis
}
]
}
@ -343,7 +410,9 @@ const renderers = {
list: ({ depth, ordered, children }) => {
return ordered ? <Ol>{children}</Ol> : <Ul>{children}</Ul>;
},
'graph-mention': ({ ship }) => <Mention ship={ship} />,
'graph-mention': (obj) => {
return <Mention ship={obj.ship} emphasis={obj.emphasis} />;
},
image: ({ url, tall }) => (
<Box mt="1" mb="2" flexShrink={0}>
<RemoteContent key={url} url={url} tall={tall} />
@ -439,7 +508,10 @@ export const GraphContent = React.memo((
transcluded = 0,
...rest
} = props;
const [, ast] = stitchAsts(contents.map(contentToMdAst(tall)));
const [, ast] = stitchAsts(
contents
.map((content, index) => addEmphasisToMention(contents, content, index))
.map(contentToMdAst(tall)));
return (
<Box {...rest}>
<Graphdown transcluded={transcluded} ast={ast} tall={tall} />

View File

@ -6,7 +6,7 @@ import {
Button,
ManagedTextInputField,
ManagedCheckboxField,
ContinuousProgressBar,
ContinuousProgressBar
} from '@tlon/indigo-react';
import { Formik, Form } from 'formik';
import React, { useEffect, useState } from 'react';
@ -20,6 +20,7 @@ import airlock from '~/logic/api';
import { joinError, joinLoad, JoinProgress } from '@urbit/api';
import { useQuery } from '~/logic/lib/useQuery';
import { JoinKind, JoinDesc, JoinSkeleton } from './Skeleton';
import { preSig } from '~/logic/lib/util';
interface InviteWithUid extends Invite {
uid: string;
@ -32,7 +33,7 @@ interface FormSchema {
const initialValues = {
autojoin: false,
shareContact: false,
shareContact: false
};
function JoinForm(props: {
@ -150,22 +151,37 @@ function JoinError(props: {
desc: JoinDesc;
request: JoinRequest;
modal: boolean;
dismiss: () => void;
}) {
const { desc, request, modal } = props;
const { dismiss, desc, request, modal } = props;
const { preview } = usePreview(desc.group);
const group = preview?.metadata?.title ?? desc.group;
const title = `Joining ${group} failed`;
const explanation =
request.progress === 'no-perms'
? 'You do not have the correct permissions'
: 'An unexpected error occurred';
: 'An unexpected error occurred';
const onRetry = () => {
useGroupState.getState().abortJoin(desc.group);
const [,,ship,name] = group.split('/');
airlock.poke(
join(ship, name, desc.kind, false, false)
);
};
const onAbort = () => {
useGroupState.getState().abortJoin(desc.group);
dismiss();
};
return (
<JoinSkeleton modal={modal} title={title} desc={desc}>
<Col p='4' gapY='4'>
<Text fontWeight='medium'>{explanation}</Text>
<Row>
<Button>Dismiss</Button>
<Row gapX="2">
<Button onClick={onRetry} primary>Retry</Button>
<Button onClick={onAbort} destructive>Abort</Button>
</Row>
</Col>
</JoinSkeleton>
@ -233,7 +249,7 @@ export function Join(props: JoinProps) {
finished={finishedPath}
/>
) : isErrored ? (
<JoinError modal={modal} desc={desc} request={openedRequest} />
<JoinError dismiss={dismiss} modal={modal} desc={desc} request={openedRequest} />
) : (
<JoinInitial modal={modal} dismiss={dismiss} desc={desc} invite={invite} />
);
@ -256,7 +272,7 @@ export function JoinPrompt(props: JoinPromptProps) {
};
const onSubmit = async ({ link }: PromptFormSchema) => {
const path = `/ship/${link}`;
const path = `/ship/${preSig(link)}`;
history.push({
search: appendQuery({ 'join-path': path })
});

View File

@ -622,6 +622,9 @@
[%x %keys ~]
:- ~ :- ~ :- mar
!>(`update:store`[now.bowl [%keys ~(key by graphs)]])
[%x %archived-keys ~]
:- ~ :- ~ :- mar
!>(`update:store`[now.bowl [%keys ~(key by archive)]])
::
[%x %tag-queries *]
:- ~ :- ~ :- mar
@ -636,7 +639,7 @@
=/ =ship (slav %p i.t.t.path)
=/ =term i.t.t.t.path
=/ marked-graph=(unit marked-graph:store)
(~(get by graphs) [ship term])
(~(get by archive) [ship term])
?~ marked-graph [~ ~]
=* graph p.u.marked-graph
=* mark q.u.marked-graph

View File

@ -295,12 +295,14 @@
::
++ rollback
|^
=/ =request:view (~(got by joining) rid)
=/ =request:view (~(got by joining) rid)
?+ progress.request ~|(cannot-rollback/progress.request !!)
%start start
%added added
%metadata metadata
%start start
%added added
%metadata metadata
?(%no-perms %strange %abort) error
==
++ error jn-core
++ start jn-core
++ added (emit del-us:pass)
++ metadata (emit:added remove-pull-groups:pass)

View File

@ -471,6 +471,7 @@
^+ post-core
?. should-notify post-core
=/ title=(list content:store)
?: =(title (crip "{(scow %p our.bowl)}/dm-inbox")) title.kind
?. is-mention title.kind
~[text/(rap 3 'You were mentioned in ' title ~)]
=/ link=path

View File

@ -22,6 +22,7 @@
[%4 observers=(map serial observer:sur)]
[%5 observers=(map serial observer:sur) warm-cache=_|]
[%6 state-0]
[%7 state-0]
==
::
+$ serial @uv
@ -35,7 +36,7 @@
--
::
%- agent:dbug
=| [%6 state-0]
=| [%7 state-0]
=* state -
::
^- agent:gall
@ -117,8 +118,10 @@
=| cards=(list card)
|-
?- -.old-state
%6
%7
[cards this(state old-state)]
%6
$(-.old-state %7, cards :_(cards (act %warm-cache-all ~)))
::
%5
=. cards

View File

@ -1,10 +1,10 @@
:~ title+'Groups'
info+'A suite of applications to communicate on Urbit'
color+0xee.5432
glob-http+['https://bootstrap.urbit.org/glob-0v2.2tc97.h3e0k.7b26d.a0ma8.em5ce.glob' 0v2.2tc97.h3e0k.7b26d.a0ma8.em5ce]
glob-http+['https://bootstrap.urbit.org/glob-0v1r2v6.v94vo.0v3ei.0ukff.upuui.glob' 0v1r2v6.v94vo.0v3ei.0ukff.upuui]
base+'landscape'
version+[1 0 6]
version+[1 0 9]
website+'https://tlon.io'
license+'MIT'
==

View File

@ -41,6 +41,7 @@ export interface AppReference {
export interface MentionContent {
mention: string;
emphasis?: 'bold' | 'italic';
}
export type Content =
| TextContent

View File

@ -350,8 +350,9 @@ intmax_t mdb_get_filesize(HANDLE han_u)
char *realpath(const char *path, char *resolved_path)
{
// TODO
return strdup(path);
// XX MAX_PATH
//
return _fullpath(resolved_path, path, MAX_PATH);
}
long sysconf(int name)

View File

@ -10,7 +10,7 @@ _dup_std_handle(HANDLE* new_u, DWORD typ_u)
HANDLE han_u = GetStdHandle(typ_u);
BOOL con_u = GetConsoleMode(han_u, &dum_u);
if ( con_u ) {
han_u = (HANDLE)_get_osfhandle(open(c3_dev_null, O_RDWR, 0));
han_u = (HANDLE)_get_osfhandle(c3_open(c3_dev_null, O_RDWR, 0));
}
if ( !DuplicateHandle(GetCurrentProcess(), han_u, GetCurrentProcess(), new_u, 0, TRUE, DUPLICATE_SAME_ACCESS) ) {

View File

@ -55,6 +55,44 @@ _main_presig(c3_c* txt_c)
return new_c;
}
/* _main_repath(): canonicalize path, using dirname if needed.
*/
c3_c*
_main_repath(c3_c* pax_c)
{
c3_c* rel_c;
c3_c* fas_c;
c3_c* dir_c;
c3_w len_w;
c3_i wit_i;
c3_assert(pax_c);
if ( 0 != (rel_c = realpath(pax_c, 0)) ) {
return rel_c;
}
fas_c = strrchr(pax_c, '/');
if ( !fas_c ) {
c3_c rec_c[2048];
wit_i = snprintf(rec_c, sizeof(rec_c), "./%s", pax_c);
c3_assert(sizeof(rec_c) > wit_i);
return _main_repath(rec_c);
}
c3_assert(u3_unix_cane(fas_c + 1));
*fas_c = 0;
dir_c = realpath(pax_c, 0);
*fas_c = '/';
if ( 0 == dir_c ) {
return 0;
}
len_w = strlen(dir_c) + strlen(fas_c) + 1;
rel_c = c3_malloc(len_w);
wit_i = snprintf(rel_c, len_w, "%s%s", dir_c, fas_c);
c3_assert(len_w == wit_i + 1);
c3_free(dir_c);
return rel_c;
}
/* _main_getopt(): extract option map from command line.
*/
static u3_noun
@ -139,7 +177,7 @@ _main_getopt(c3_i argc, c3_c** argv)
break;
}
case 'Y': {
u3_Host.ops_u.puk_c = strdup(optarg);
u3_Host.ops_u.puk_c = _main_repath(optarg);
break;
}
case 'Z': {
@ -147,11 +185,11 @@ _main_getopt(c3_i argc, c3_c** argv)
break;
}
case 'J': {
u3_Host.ops_u.lit_c = strdup(optarg);
u3_Host.ops_u.lit_c = _main_repath(optarg);
break;
}
case 'B': {
u3_Host.ops_u.pil_c = strdup(optarg);
u3_Host.ops_u.pil_c = _main_repath(optarg);
break;
}
case 'b': {
@ -163,7 +201,7 @@ _main_getopt(c3_i argc, c3_c** argv)
break;
}
case 'A': {
u3_Host.ops_u.arv_c = strdup(optarg);
u3_Host.ops_u.arv_c = _main_repath(optarg);
break;
}
case 'H': {
@ -171,7 +209,7 @@ _main_getopt(c3_i argc, c3_c** argv)
break;
}
case 'I': {
u3_Host.ops_u.jin_c = strdup(optarg);
u3_Host.ops_u.jin_c = _main_repath(optarg);
break;
}
case 'C': {
@ -209,7 +247,7 @@ _main_getopt(c3_i argc, c3_c** argv)
break;
}
case 'k': {
u3_Host.ops_u.key_c = strdup(optarg);
u3_Host.ops_u.key_c = _main_repath(optarg);
break;
}
case 'n': {
@ -231,7 +269,7 @@ _main_getopt(c3_i argc, c3_c** argv)
break;
}
case 'i': {
u3_Host.ops_u.imp_c = strdup(optarg);
u3_Host.ops_u.imp_c = _main_repath(optarg);
break;
}
case 'L': { u3_Host.ops_u.net = c3n; break; }
@ -291,7 +329,7 @@ _main_getopt(c3_i argc, c3_c** argv)
}
}
u3_Host.dir_c = strdup(argv[optind]);
u3_Host.dir_c = _main_repath(argv[optind]);
}
// daemon mode (-d) implies disabling terminal assumptions (-t)
@ -705,31 +743,7 @@ main(c3_i argc,
printf("~\n");
// printf("welcome.\n");
printf("urbit %s\n", URBIT_VERSION);
// prints the absolute path of the pier
//
c3_c* abs_c = realpath(u3_Host.dir_c, 0);
// if the ship is being booted, we use realpath(). Otherwise, we use getcwd()
// with a memory-allocation loop
//
if (abs_c == NULL) {
c3_i mprint_i = 1000;
abs_c = c3_malloc(mprint_i);
// allocates more memory as needed if the path is too large
//
while ( abs_c != getcwd(abs_c, mprint_i) ) {
c3_free(abs_c);
mprint_i *= 2;
abs_c = c3_malloc(mprint_i);
}
printf("boot: home is %s/%s\n", abs_c, u3_Host.dir_c);
c3_free(abs_c);
} else {
printf("boot: home is %s\n", abs_c);
c3_free(abs_c);
}
printf("boot: home is %s\n", u3_Host.dir_c);
// printf("vere: hostname is %s\n", u3_Host.ops_u.nam_c);
if ( c3y == u3_Host.ops_u.dem ) {

View File

@ -122,4 +122,35 @@
} \
rut;})
/* Asserting unix fs wrappers.
**
** these all crash the process if passed a non-canonical
** path (i.e., one containing '.', '..', or the empty path
** component), so make sure you don't pass them one. if you
** find yourself fighting with them, then please delete them
** and do a sed search-and-replace to remove the `c3_` from
** their call sites; their goal is to decrease maintenance
** burden, not increase it.
*/
// defined in vere/io/unix.c.
c3_t u3_unix_cane(const c3_c* pax_c);
# define c3_open(a, ...) ({ \
c3_assert(u3_unix_cane(a)); \
open(a, __VA_ARGS__);})
# define c3_opendir(a) ({ \
c3_assert(u3_unix_cane(a)); \
opendir(a);})
# define c3_mkdir(a, b) ({ \
c3_assert(u3_unix_cane(a)); \
mkdir(a, b);})
# define c3_rmdir(a) ({ \
c3_assert(u3_unix_cane(a)); \
rmdir(a);})
# define c3_unlink(a) ({ \
c3_assert(u3_unix_cane(a)); \
unlink(a);})
# define c3_fopen(a, b) ({ \
c3_assert(u3_unix_cane(a)); \
fopen(a, b);})
#endif /* ifndef C3_DEFS_H */

View File

@ -36,18 +36,16 @@
# define c3__bac c3_s3('b','a','c')
# define c3__bach c3_s4('b','a','c','h')
# define c3__bag c3_s3('b','a','g')
# define c3__bar c3_s3('b','a','r')
# define c3__bail c3_s4('b','a','i','l')
# define c3__ball c3_s4('b','a','l','l')
# define c3__band c3_s4('b','a','n','d')
# define c3__bank c3_s4('b','a','n','k')
# define c3__bar c3_s3('b','a','r')
# define c3__bark c3_s4('b','a','r','k')
# define c3__barn c3_s4('b','a','r','n')
# define c3__base c3_s4('b','a','s','e')
# define c3__bask c3_s4('b','a','s','k')
# define c3__basp c3_s4('b','a','s','p')
# define c3__bee c3_s3('b','e','e')
# define c3__bel c3_s3('b','e','l')
# define c3__bbye c3_s4('b','b','y','e')
# define c3__bcbn c3_s4('b','c','b','n')
# define c3__bcbr c3_s4('b','c','b','r')
@ -68,7 +66,9 @@
# define c3__bean c3_s4('b','e','a','n')
# define c3__bear c3_s4('b','e','a','r')
# define c3__bede c3_s4('b','e','d','e')
# define c3__bee c3_s3('b','e','e')
# define c3__behn c3_s4('b','e','h','n')
# define c3__bel c3_s3('b','e','l')
# define c3__belt c3_s4('b','e','l','t')
# define c3__bend c3_s4('b','e','n','d')
# define c3__ber c3_s3('b','e','r')
@ -101,6 +101,7 @@
# define c3__bnpd c3_s4('b','n','p','d')
# define c3__bnps c3_s4('b','n','p','s')
# define c3__bnsp c3_s4('b','n','s','p')
# define c3__boat c3_s4('b','o','a','t')
# define c3__boce c3_s4('b','o','c','e')
# define c3__boil c3_s4('b','o','i','l')
# define c3__boin c3_s4('b','o','i','n')
@ -110,7 +111,6 @@
# define c3__bong c3_s4('b','o','n','g')
# define c3__book c3_s4('b','o','o','k')
# define c3__bool c3_s4('b','o','o','l')
# define c3__boat c3_s4('b','o','a','t')
# define c3__boot c3_s4('b','o','o','t')
# define c3__born c3_s4('b','o','r','n')
# define c3__both c3_s4('b','o','t','h')
@ -121,16 +121,16 @@
# define c3__brax c3_s4('b','r','a','x')
# define c3__brbn c3_s4('b','r','b','n')
# define c3__brcb c3_s4('b','r','c','b')
# define c3__brcl c3_s4('b','r','c','l')
# define c3__brcn c3_s4('b','r','c','n')
# define c3__brcs c3_s4('b','r','c','s')
# define c3__brdg c3_s4('b','r','d','g')
# define c3__brdl c3_s4('b','r','d','l')
# define c3__brdp c3_s4('b','r','d','p')
# define c3__brdt c3_s4('b','r','d','t')
# define c3__brkt c3_s4('b','r','k','t')
# define c3__brhp c3_s4('b','r','h','p')
# define c3__brip c3_s4('b','r','i','p')
# define c3__brcl c3_s4('b','r','c','l')
# define c3__brkt c3_s4('b','r','k','t')
# define c3__brlc c3_s4('b','r','l','c')
# define c3__brld c3_s4('b','r','l','d')
# define c3__brls c3_s4('b','r','l','s')
@ -212,9 +212,9 @@
# define c3__clkt c3_s4('c','l','k','t')
# define c3__clls c3_s4('c','l','l','s')
# define c3__clms c3_s4('c','l','m','s')
# define c3__clr c3_s3('c','l','r')
# define c3__clsg c3_s4('c','l','s','g')
# define c3__clsp c3_s4('c','l','s','p')
# define c3__clr c3_s3('c','l','r')
# define c3__cltr c3_s4('c','l','t','r')
# define c3__cnbc c3_s4('c','n','b','c')
# define c3__cnbr c3_s4('c','n','b','r')
@ -248,9 +248,9 @@
# define c3__cook c3_s4('c','o','o','k')
# define c3__cool c3_s4('c','o','o','l')
# define c3__core c3_s4('c','o','r','e')
# define c3__corp c3_s4('c','o','r','p')
# define c3__corm c3_s4('c','o','r','m')
# define c3__corp c3_s4('c','o','r','p')
# define c3__corp c3_s4('c','o','r','p')
# define c3__cow c3_s3('c','o','w')
# define c3__cpu c3_s3('c','p','u')
# define c3__crad c3_s4('c','r','a','d')
@ -281,11 +281,11 @@
# define c3__cstg c3_s4('c','s','t','g')
# define c3__cstr c3_s4('c','s','t','r')
# define c3__cszp c3_s4('c','s','z','p')
# define c3__ctl c3_s3('c','t','l')
# define c3__cttp c3_s4('c','t','t','p')
# define c3__cube c3_s4('c','u','b','e')
# define c3__cull c3_s4('c','u','l','l')
# define c3__curd c3_s4('c','u','r','d')
# define c3__ctl c3_s3('c','t','l')
# define c3__cut c3_s3('c','u','t')
# define c3__cyl c3_s3('c','y','l')
# define c3__czar c3_s4('c','z','a','r')
@ -365,13 +365,13 @@
# define c3__dtwt c3_s4('d','t','w','t')
# define c3__dtzy c3_s4('d','t','z','y')
# define c3__dtzz c3_s4('d','t','z','z')
# define c3__dxkt c3_s4('d','x','k','t')
# define c3__dub c3_s3('d','u','b')
# define c3__duct c3_s4('d','u','c','t')
# define c3__duke c3_s4('d','u','k','e')
# define c3__dumb c3_s4('d','u','m','b')
# define c3__dump c3_s4('d','u','m','p')
# define c3__dust c3_s4('d','u','s','t')
# define c3__dxkt c3_s4('d','x','k','t')
# define c3__e c3_s1('e')
# define c3__earl c3_s4('e','a','r','l')
# define c3__east c3_s4('e','a','s','t')
@ -383,10 +383,10 @@
# define c3__emph c3_s4('e','m','p','h')
# define c3__end c3_s3('e','n','d')
# define c3__eq c3_s2('e','q')
# define c3__ex c3_s2('e','x')
# define c3__esh c3_s3('e','s','h')
# define c3__ergo c3_s4('e','r','g','o')
# define c3__esh c3_s3('e','s','h')
# define c3__etch c3_s4('e','t','c','h')
# define c3__ex c3_s2('e','x')
# define c3__exit c3_s4('e','x','i','t')
# define c3__eyre c3_s4('e','y','r','e')
# define c3__f c3_s1('f')
@ -444,13 +444,13 @@
# define c3__free c3_s4('f','r','e','e')
# define c3__frez c3_s4('f','r','e','z')
# define c3__frit c3_s4('f','r','i','t')
# define c3__from c3_s4('f','r','o','m')
# define c3__frog c3_s4('f','r','o','g')
# define c3__from c3_s4('f','r','o','m')
# define c3__fron c3_s4('f','r','o','n')
# define c3__fry c3_s3('f','r','y')
# define c3__fuge c3_s4('f','u','g','e')
# define c3__fume c3_s4('f','u','m','e')
# define c3__full c3_s4('f','u','l','l')
# define c3__fume c3_s4('f','u','m','e')
# define c3__fun c3_s3('f','u','n')
# define c3__fund c3_s4('f','u','n','d')
# define c3__fung c3_s4('f','u','n','g')
@ -527,6 +527,7 @@
# define c3__head c3_s4('h','e','a','d')
# define c3__heal c3_s4('h','e','a','l')
# define c3__hear c3_s4('h','e','a','r')
# define c3__hela c3_s4('h','e','l','a')
# define c3__helm c3_s4('h','e','l','m')
# define c3__helo c3_s4('h','e','l','o')
# define c3__help c3_s4('h','e','l','p')
@ -544,8 +545,8 @@
# define c3__hit c3_s3('h','i','t')
# define c3__hmal c3_s4('h','m','a','l')
# define c3__hold c3_s4('h','o','l','d')
# define c3__holt c3_s4('h','o','l','t')
# define c3__hole c3_s4('h','o','l','e')
# define c3__holt c3_s4('h','o','l','t')
# define c3__home c3_s4('h','o','m','e')
# define c3__homp c3_s4('h','o','m','p')
# define c3__hook c3_s4('h','o','o','k')
@ -573,10 +574,10 @@
# define c3__http c3_s4('h','t','t','p')
# define c3__hume c3_s4('h','u','m','e')
# define c3__hunk c3_s4('h','u','n','k')
# define c3__hxtr c3_s4('h','x','t','r')
# define c3__hxts c3_s4('h','x','t','s')
# define c3__hxgl c3_s4('h','x','g','l')
# define c3__hxgr c3_s4('h','x','g','r')
# define c3__hxtr c3_s4('h','x','t','r')
# define c3__hxts c3_s4('h','x','t','s')
# define c3__i c3_s1('i')
# define c3__ic c3_s2('i','c')
# define c3__ice c3_s3('i','c','e')
@ -706,8 +707,8 @@
# define c3__lt c3_s2('l','t')
# define c3__lull c3_s4('l','u','l','l')
# define c3__lunt c3_s4('l','u','n','t')
# define c3__mack c3_s4('m','a','c','k')
# define c3__mach c3_s4('m','a','c','h')
# define c3__mack c3_s4('m','a','c','k')
# define c3__main c3_s4('m','a','i','n')
# define c3__make c3_s4('m','a','k','e')
# define c3__malg c3_s4('m','a','l','g')
@ -717,9 +718,9 @@
# define c3__map c3_s3('m','a','p')
# define c3__marg c3_s4('m','a','r','g')
# define c3__mark c3_s4('m','a','r','k')
# define c3__mass c3_s4('m','a','s','s')
# define c3__marn c3_s4('m','a','r','n')
# define c3__mash c3_s4('m','a','s','h')
# define c3__mass c3_s4('m','a','s','s')
# define c3__mast c3_s4('m','a','s','t')
# define c3__mate c3_s4('m','a','t','e')
# define c3__mave c3_s4('m','a','v','e')
@ -741,8 +742,8 @@
# define c3__mirt c3_s4('m','i','r','t')
# define c3__miss c3_s4('m','i','s','s')
# define c3__mix c3_s3('m','i','x')
# define c3__mod c3_s3('m','o','d')
# define c3__moat c3_s4('m','o','a','t')
# define c3__mod c3_s3('m','o','d')
# define c3__mold c3_s4('m','o','l','d')
# define c3__mong c3_s4('m','o','n','g')
# define c3__mono c3_s4('m','o','n','o')
@ -775,6 +776,7 @@
# define c3__nail c3_s4('n','a','i','l')
# define c3__name c3_s4('n','a','m','e')
# define c3__nap c3_s3('n','a','p')
# define c3__nara c3_s4('n','a','r','a')
# define c3__narv c3_s4('n','a','r','v')
# define c3__ne c3_s2('n','e')
# define c3__need c3_s4('n','e','e','d')
@ -793,8 +795,8 @@
# define c3__noah c3_s4('n','o','a','h')
# define c3__nock c3_s4('n','o','c','k')
# define c3__none c3_s4('n','o','n','e')
# define c3__nop c3_s3('n','o','p')
# define c3__noop c3_s4('n','o','o','p')
# define c3__nop c3_s3('n','o','p')
# define c3__norm c3_s4('n','o','r','m')
# define c3__nost c3_s4('n','o','s','t')
# define c3__not c3_s3('n','o','t')
@ -873,7 +875,6 @@
# define c3__plet c3_s4('p','l','e','t')
# define c3__plic c3_s4('p','l','i','c')
# define c3__plin c3_s4('p','l','i','n')
# define c3__plol c3_s4('p','l','o','m')
# define c3__plom c3_s4('p','l','o','m')
# define c3__plov c3_s4('p','l','o','v')
# define c3__plug c3_s4('p','l','u','g')
@ -943,14 +944,14 @@
# define c3__ramp c3_s4('r','a','m','p')
# define c3__rasp c3_s4('r','a','s','p')
# define c3__raw c3_s3('r','a','w')
# define c3__ret c3_s3('r','e','t')
# define c3__rez c3_s3('r','e','z')
# define c3__read c3_s4('r','e','a','d')
# define c3__reck c3_s4('r','e','c','k')
# define c3__reef c3_s4('r','e','e','f')
# define c3__resd c3_s4('r','e','s','d')
# define c3__rest c3_s4('r','e','s','t')
# define c3__ret c3_s3('r','e','t')
# define c3__revo c3_s4('r','e','v','o')
# define c3__rez c3_s3('r','e','z')
# define c3__rin c3_s3('r','i','n')
# define c3__ring c3_s4('r','i','n','g')
# define c3__ripe c3_s4('r','i','p','e')
@ -1113,11 +1114,6 @@
# define c3__term c3_s4('t','e','r','m')
# define c3__test c3_s4('t','e','s','t')
# define c3__text c3_s4('t','e','x','t')
# define c3__that c3_s4('t','h','a','t')
# define c3__this c3_s4('t','h','i','s')
# define c3__thin c3_s4('t','h','i','n')
# define c3__thud c3_s4('t','h','u','d')
# define c3__time c3_s4('t','i','m','e')
# define c3__tgbn c3_s4('t','g','b','n')
# define c3__tgbr c3_s4('t','g','b','r')
# define c3__tgdg c3_s4('t','g','d','g')
@ -1132,13 +1128,18 @@
# define c3__tgpm c3_s4('t','g','p','m')
# define c3__tgps c3_s4('t','g','p','s')
# define c3__tgsp c3_s4('t','g','s','p')
# define c3__that c3_s4('t','h','a','t')
# define c3__thee c3_s4('t','h','e','e')
# define c3__then c3_s4('t','h','e','n')
# define c3__they c3_s4('t','h','e','y')
# define c3__tick c3_s4('t','i','c','k')
# define c3__thin c3_s4('t','h','i','n')
# define c3__this c3_s4('t','h','i','s')
# define c3__thou c3_s4('t','h','o','u')
# define c3__thud c3_s4('t','h','u','d')
# define c3__thuo c3_s4('t','h','u','o')
# define c3__thus c3_s4('t','h','u','s')
# define c3__tick c3_s4('t','i','c','k')
# define c3__time c3_s4('t','i','m','e')
# define c3__tip c3_s3('t','i','p')
# define c3__tmbn c3_s4('t','m','b','n')
# define c3__tmdg c3_s4('t','m','d','g')
@ -1217,8 +1218,8 @@
# define c3__vamp c3_s4('v','a','m','p')
# define c3__vane c3_s4('v','a','n','e')
# define c3__var c3_s3('v','a','r')
# define c3__veb c3_s3('v','e','b')
# define c3__veal c3_s4('v','e','a','l')
# define c3__veb c3_s3('v','e','b')
# define c3__veck c3_s4('v','e','c','k')
# define c3__veer c3_s4('v','e','e','r')
# define c3__vega c3_s4('v','e','g','a')
@ -1231,7 +1232,6 @@
# define c3__vint c3_s4('v','i','n','t')
# define c3__void c3_s4('v','o','i','d')
# define c3__vorp c3_s4('v','o','r','p')
# define c3__way c3_s3('w','a','y')
# define c3__wack c3_s4('w','a','c','k')
# define c3__wail c3_s4('w','a','i','l')
# define c3__wake c3_s4('w','a','k','e')
@ -1243,19 +1243,20 @@
# define c3__warx c3_s4('w','a','r','x')
# define c3__wash c3_s4('w','a','s','h')
# define c3__watt c3_s4('w','a','t','t')
# define c3__way c3_s3('w','a','y')
# define c3__weak c3_s4('w','e','a','k')
# define c3__web c3_s3('w','e','b')
# define c3__wet c3_s3('w','e','t')
# define c3__wend c3_s4('w','e','n','d')
# define c3__werp c3_s4('w','e','r','p')
# define c3__west c3_s4('w','e','s','t')
# define c3__wet c3_s3('w','e','t')
# define c3__what c3_s4('w','h','a','t')
# define c3__whey c3_s4('w','h','e','y')
# define c3__who c3_s3('w','h','o')
# define c3__whom c3_s4('w','h','o','m')
# define c3__wing c3_s4('w','i','n','g')
# define c3__wild c3_s4('w','i','l','d')
# define c3__win c3_s3('w','i','n')
# define c3__wing c3_s4('w','i','n','g')
# define c3__wipe c3_s4('w','i','p','e')
# define c3__wise c3_s4('w','i','s','e')
# define c3__wish c3_s4('w','i','s','h')
@ -1285,10 +1286,9 @@
# define c3__wtts c3_s4('w','t','t','s')
# define c3__wtzp c3_s4('w','t','z','p')
# define c3__wyrd c3_s4('w','y','r','d')
# define c3__yew c3_s3('y','a','w')
# define c3__yell c3_s4('y','e','l','l')
# define c3__z c3_s1('z')
# define c3__yelp c3_s4('y','e','l','p')
# define c3__z c3_s1('z')
# define c3__zact c3_s4('z','a','c','t')
# define c3__zalt c3_s4('z','a','l','t')
# define c3__zarb c3_s4('z','a','r','b')
@ -1309,7 +1309,6 @@
# define c3__zpdx c3_s4('z','p','d','x')
# define c3__zpfs c3_s4('z','p','f','s')
# define c3__zpgr c3_s4('z','p','g','r')
# define c3__zphs c3_s4('z','p','h','x')
# define c3__zphx c3_s4('z','p','h','x')
# define c3__zplc c3_s4('z','p','l','c')
# define c3__zpmc c3_s4('z','p','m','c')

View File

@ -127,12 +127,12 @@
/* u3i_string(): Produce an LSB-first atom from the C string [a].
*/
u3_noun
u3_atom
u3i_string(const c3_c* a_c);
/* u3i_tape(): from a C string, to a list of bytes.
*/
u3_atom
u3_noun
u3i_tape(const c3_c* txt_c);
/* u3i_list(): list from `u3_none`-terminated varargs.

View File

@ -129,6 +129,30 @@
void
u3t_boot(void);
/* u3t_slog_cap(): slog a tank with a caption with
** a given priority c3_l (assumed 0-3).
*/
void
u3t_slog_cap(c3_l pri_l, u3_noun cap, u3_noun tan);
/* u3t_slog_trace(): given a c3_l priority pri and a raw stack tax
** flop the order into start-to-end, render, and slog each item
** until done.
*/
void
u3t_slog_trace(c3_l pri_l, u3_noun tax);
/* u3t_slog_nara(): slog only the deepest road's trace with
** c3_l priority pri
*/
void
u3t_slog_nara(c3_l pri_l);
/* u3t_slog_hela(): join all roads' traces together into one tax
** and pass it to slog_trace along with the given c3_l priority pri_l
*/
void
u3t_slog_hela(c3_l pri_l);
/** Globals.
**/

View File

@ -328,7 +328,7 @@
void (*bot_f)(); // call when chis is up
} u3_host; // host == computer == process
/** New pier system.
/** Pier system.
**/
/* u3_ovum_news: u3_ovum lifecycle events
*/
@ -756,7 +756,7 @@
c3_d
u3_time_gap_ms(u3_noun now, u3_noun wen);
/** ward: common structure lifecycle
/** Common structure lifecycle.
**/
/* u3_dent_init(): initialize file record.
*/
@ -841,7 +841,7 @@
c3_w
u3_mcut_host(c3_c* buf_c, c3_w len_w, u3_noun hot);
/** New vere
/** IO drivers.
**/
/* u3_auto_init(): initialize all drivers.
*/
@ -1050,41 +1050,14 @@
void
u3_lord_peek(u3_lord* god_u, u3_pico* pic_u);
/** Filesystem (new api).
**/
/* u3_walk_load(): load file or bail.
*/
u3_noun
u3_walk_load(c3_c* pas_c);
/* u3_walk_safe(): load file or 0.
*/
u3_noun
u3_walk_safe(c3_c* pas_c);
/* u3_walk_save(): save file or bail.
*/
void
u3_walk_save(c3_c* pas_c, u3_noun tim, u3_atom pad, c3_c* bas_c, u3_noun pax);
/* u3_walk(): traverse `dir_c` to produce an arch, updating `old`.
*/
u3_noun
u3_walk(const c3_c* dir_c, u3_noun old);
/* u3_path(): C unix path in computer for file or directory.
*/
c3_c*
u3_path(c3_o fyl, u3_noun pax);
/** Filesystem (async)
/** Filesystem (async).
**/
/* u3_foil_folder(): load directory, blockingly. create if nonexistent.
*/
u3_dire*
u3_foil_folder(const c3_c* pax_c); // directory object, or 0
/** Terminal, new style.
/** Terminal.
**/
/* u3_term_start_spinner(): prepare spinner state. RETAIN.
*/
@ -1182,8 +1155,18 @@
u3_save_io_exit(u3_pier *pir_u);
/** Storage, new school.
/** Storage.
**/
/* u3_unix_save(): save file undir .../.urb/put or bail.
*/
void
u3_unix_save(c3_c* pax_c, u3_atom pad);
/* u3_unix_cane(): true iff (unix) path is canonical.
*/
c3_t
u3_unix_cane(const c3_c* pax_c);
/* u3_unix_initial_into_card(): create initial filesystem sync card.
*/
u3_noun
@ -1222,14 +1205,14 @@
u3_auto*
u3_conn_io_init(u3_pier* pir_u);
/** fore, first events
/** fore, first events.
**/
/* u3_hind_io_init(): initialize fore
*/
u3_auto*
u3_fore_io_init(u3_pier* pir_u);
/** hind, defaults
/** hind, defaults.
**/
/* u3_hind_io_init(): initialize hint
*/
@ -1342,7 +1325,7 @@
void
u3_pier_slog(u3_pier* pir_u);
/* u3_pier_boot(): start the new pier system.
/* u3_pier_boot(): start the pier.
*/
u3_pier*
u3_pier_boot(c3_w wag_w, // config flags
@ -1352,7 +1335,7 @@
u3_noun pax, // path to pier
u3_weak fed); // extra private keys
/* u3_pier_stay(): restart the new pier system.
/* u3_pier_stay(): restart the pier.
*/
u3_pier*
u3_pier_stay(c3_w wag_w, u3_noun pax);

View File

@ -31,20 +31,17 @@ u3_noun get_syllable(c3_c** cur_ptr, c3_c* one, c3_c* two, c3_c* three) {
}
}
static
u3_noun combine(u3_noun p, u3_noun q)
static u3_noun
combine(u3_noun p, u3_noun q)
{
if (_(u3a_is_atom(p))) {
if ( (c3y == u3a_is_atom(p)) || (c3y == u3a_is_atom(q)) ) {
return 0;
}
if (_(u3a_is_atom(q))) {
return 0;
}
u3_noun ret = u3nc(0, u3qa_add(u3t(p), u3qa_mul(256, u3t(q))));
u3z(p);
u3z(q);
u3_noun lef = u3qa_mul(256, u3t(q));
u3_noun ret = u3nc(0, u3qa_add(u3t(p), lef));
u3z(lef);
u3z(p); u3z(q);
return ret;
}

View File

@ -239,17 +239,17 @@ _ce_image_open(u3e_image* img_u)
c3_c ful_c[8193];
snprintf(ful_c, 8192, "%s", u3P.dir_c);
mkdir(ful_c, 0700);
c3_mkdir(ful_c, 0700);
snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c);
mkdir(ful_c, 0700);
c3_mkdir(ful_c, 0700);
snprintf(ful_c, 8192, "%s/.urb/chk", u3P.dir_c);
mkdir(ful_c, 0700);
c3_mkdir(ful_c, 0700);
snprintf(ful_c, 8192, "%s/.urb/chk/%s.bin", u3P.dir_c, img_u->nam_c);
if ( -1 == (img_u->fid_i = open(ful_c, mod_i, 0666)) ) {
fprintf(stderr, "loom: open %s: %s\r\n", ful_c, strerror(errno));
if ( -1 == (img_u->fid_i = c3_open(ful_c, mod_i, 0666)) ) {
fprintf(stderr, "loom: c3_open %s: %s\r\n", ful_c, strerror(errno));
return c3n;
}
else {
@ -333,20 +333,20 @@ _ce_patch_create(u3_ce_patch* pat_u)
c3_c ful_c[8193];
snprintf(ful_c, 8192, "%s", u3P.dir_c);
mkdir(ful_c, 0700);
c3_mkdir(ful_c, 0700);
snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c);
mkdir(ful_c, 0700);
c3_mkdir(ful_c, 0700);
snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c);
if ( -1 == (pat_u->ctl_i = open(ful_c, O_RDWR | O_CREAT | O_EXCL, 0600)) ) {
fprintf(stderr, "loom: patch open control.bin: %s\r\n", strerror(errno));
if ( -1 == (pat_u->ctl_i = c3_open(ful_c, O_RDWR | O_CREAT | O_EXCL, 0600)) ) {
fprintf(stderr, "loom: patch c3_open control.bin: %s\r\n", strerror(errno));
c3_assert(0);
}
snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c);
if ( -1 == (pat_u->mem_i = open(ful_c, O_RDWR | O_CREAT | O_EXCL, 0600)) ) {
fprintf(stderr, "loom: patch open memory.bin: %s\r\n", strerror(errno));
if ( -1 == (pat_u->mem_i = c3_open(ful_c, O_RDWR | O_CREAT | O_EXCL, 0600)) ) {
fprintf(stderr, "loom: patch c3_open memory.bin: %s\r\n", strerror(errno));
c3_assert(0);
}
}
@ -359,10 +359,10 @@ _ce_patch_delete(void)
c3_c ful_c[8193];
snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c);
unlink(ful_c);
c3_unlink(ful_c);
snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c);
unlink(ful_c);
c3_unlink(ful_c);
}
/* _ce_patch_verify(): check patch data mug.
@ -431,18 +431,18 @@ _ce_patch_open(void)
c3_i ctl_i, mem_i;
snprintf(ful_c, 8192, "%s", u3P.dir_c);
mkdir(ful_c, 0700);
c3_mkdir(ful_c, 0700);
snprintf(ful_c, 8192, "%s/.urb", u3P.dir_c);
mkdir(ful_c, 0700);
c3_mkdir(ful_c, 0700);
snprintf(ful_c, 8192, "%s/.urb/chk/control.bin", u3P.dir_c);
if ( -1 == (ctl_i = open(ful_c, O_RDWR)) ) {
if ( -1 == (ctl_i = c3_open(ful_c, O_RDWR)) ) {
return 0;
}
snprintf(ful_c, 8192, "%s/.urb/chk/memory.bin", u3P.dir_c);
if ( -1 == (mem_i = open(ful_c, O_RDWR)) ) {
if ( -1 == (mem_i = c3_open(ful_c, O_RDWR)) ) {
close(ctl_i);
_ce_patch_delete();
@ -838,7 +838,7 @@ _ce_backup(void)
snprintf(ful_c, 8192, "%s/.urb/bhk", u3P.dir_c);
if ( mkdir(ful_c, 0700) ) {
if ( c3_mkdir(ful_c, 0700) ) {
if ( EEXIST != errno ) {
fprintf(stderr, "loom: image backup: %s\r\n", strerror(errno));
}
@ -847,15 +847,15 @@ _ce_backup(void)
snprintf(ful_c, 8192, "%s/.urb/bhk/%s.bin", u3P.dir_c, nop_u.nam_c);
if ( -1 == (nop_u.fid_i = open(ful_c, mod_i, 0666)) ) {
fprintf(stderr, "loom: open %s: %s\r\n", ful_c, strerror(errno));
if ( -1 == (nop_u.fid_i = c3_open(ful_c, mod_i, 0666)) ) {
fprintf(stderr, "loom: c3_open %s: %s\r\n", ful_c, strerror(errno));
return;
}
snprintf(ful_c, 8192, "%s/.urb/bhk/%s.bin", u3P.dir_c, sop_u.nam_c);
if ( -1 == (sop_u.fid_i = open(ful_c, mod_i, 0666)) ) {
fprintf(stderr, "loom: open %s: %s\r\n", ful_c, strerror(errno));
if ( -1 == (sop_u.fid_i = c3_open(ful_c, mod_i, 0666)) ) {
fprintf(stderr, "loom: c3_open %s: %s\r\n", ful_c, strerror(errno));
return;
}
@ -863,11 +863,11 @@ _ce_backup(void)
|| (c3n == _ce_image_copy(&u3P.sou_u, &sop_u)) )
{
unlink(ful_c);
c3_unlink(ful_c);
snprintf(ful_c, 8192, "%s/.urb/bhk/%s.bin", u3P.dir_c, nop_u.nam_c);
unlink(ful_c);
c3_unlink(ful_c);
snprintf(ful_c, 8192, "%s/.urb/bhk", u3P.dir_c);
rmdir(ful_c);
c3_rmdir(ful_c);
}
close(nop_u.fid_i);

View File

@ -541,7 +541,7 @@ u3i_qual(u3_noun a, u3_noun b, u3_noun c, u3_noun d)
/* u3i_string(): Produce an LSB-first atom from the C string [a].
*/
u3_noun
u3_atom
u3i_string(const c3_c* a_c)
{
return u3i_bytes(strlen(a_c), (c3_y *)a_c);
@ -549,7 +549,7 @@ u3i_string(const c3_c* a_c)
/* u3i_tape(): from a C string, to a list of bytes.
*/
u3_atom
u3_noun
u3i_tape(const c3_c* txt_c)
{
if ( !*txt_c ) {

View File

@ -432,7 +432,7 @@ u3_noun
u3m_file(c3_c* pas_c)
{
struct stat buf_b;
c3_i fid_i = open(pas_c, O_RDONLY, 0644);
c3_i fid_i = c3_open(pas_c, O_RDONLY, 0644);
c3_w fln_w, red_w;
c3_y* pad_y;

View File

@ -453,7 +453,7 @@ _n_nock_on(u3_noun bus, u3_noun fol)
#define KICS 54
#define TICB 55
#define TICS 56
// nock 11
// nock 12
#define WILS 57
#define WISH 58
// hint processing
@ -1020,7 +1020,8 @@ _n_bint(u3_noun* ops, u3_noun hif, u3_noun nef, c3_o los_o, c3_o tel_o)
default: {
return _n_comp(ops, nef, los_o, tel_o);
}
case c3__nara:
case c3__hela:
case c3__bout: {
u3_noun fen = u3_nul;
c3_w nef_w = _n_comp(&fen, nef, los_o, c3n);
@ -1055,7 +1056,8 @@ _n_bint(u3_noun* ops, u3_noun hif, u3_noun nef, c3_o los_o, c3_o tel_o)
++tot_w; _n_emit(ops, TOSS);
tot_w += _n_comp(ops, nef, los_o, tel_o);
} break;
case c3__nara:
case c3__hela:
case c3__bout: {
u3_noun fen = u3_nul;
c3_w nef_w = _n_comp(&fen, nef, los_o, c3n);
@ -1696,12 +1698,28 @@ u3n_find(u3_noun key, u3_noun fol)
static c3_o
_n_hilt_fore(u3_noun hin, u3_noun bus, u3_noun* out)
{
if ( c3__bout == u3h(hin) ) {
u3_atom now = u3i_chub(u3t_trace_time());
*out = u3i_cell(u3h(hin), now);
}
else {
*out = u3_nul;
u3_noun tag, fol;
u3x_cell(hin, &tag, &fol);
switch ( tag ) {
case c3__bout: {
u3_atom now = u3i_chub(u3t_trace_time());
*out = u3i_cell(tag, now);
} break;
case c3__nara : {
u3t_slog_nara(0);
*out = u3_nul;
} break;
case c3__hela : {
u3t_slog_hela(0);
*out = u3_nul;
} break;
default: {
*out = u3_nul;
} break;
}
u3z(hin);
@ -1742,13 +1760,41 @@ _n_hilt_hind(u3_noun tok, u3_noun pro)
static c3_o
_n_hint_fore(u3_cell hin, u3_noun bus, u3_noun* clu)
{
if ( c3__bout == u3h(hin) ) {
u3_atom now = u3i_chub(u3t_trace_time());
*clu = u3i_trel(u3h(hin), *clu, now);
}
else {
u3z(*clu);
*clu = u3_nul;
u3_noun tag, fol;
u3x_cell(hin, &tag, &fol);
switch ( tag ) {
case c3__bout: {
u3_atom now = u3i_chub(u3t_trace_time());
*clu = u3nt(u3k(tag), *clu, now);
} break;
case c3__nara: {
u3_noun pri, tan;
if ( c3y == u3r_cell(*clu, &pri, &tan) ) {
c3_l pri_l = c3y == u3a_is_cat(pri) ? pri : 0;
u3t_slog_cap(pri_l, u3i_string("trace of"), u3k(tan));
u3t_slog_nara(pri_l);
}
u3z(*clu);
*clu = u3_nul;
} break;
case c3__hela: {
u3_noun pri, tan;
if ( c3y == u3r_cell(*clu, &pri, &tan) ) {
c3_l pri_l = c3y == u3a_is_cat(pri) ? pri : 0;
u3t_slog_cap(pri_l, u3i_string("trace of"), u3k(tan));
u3t_slog_hela(pri_l);
}
u3z(*clu);
*clu = u3_nul;
} break;
default: {
u3z(*clu);
*clu = u3_nul;
} break;
}
u3z(hin);
@ -1763,9 +1809,7 @@ static void
_n_hint_hind(u3_noun tok, u3_noun pro)
{
u3_noun p_tok, q_tok, r_tok;
if ( (c3y == u3r_trel(tok, &p_tok, &q_tok, &r_tok))
&& (c3__bout == p_tok) )
{
if ( (c3y == u3r_trel(tok, &p_tok, &q_tok, &r_tok)) && (c3__bout == p_tok) ) {
// get the microseconds elapsed
u3_atom delta = u3ka_sub(u3i_chub(u3t_trace_time()), u3k(r_tok));
@ -1782,17 +1826,8 @@ _n_hint_hind(u3_noun tok, u3_noun pro)
// "q_q_tok: report"
// prepend the priority to form a cell of the same shape q_tok
// send this to ut3_slog so that it can be logged out
u3t_slog(
u3nc(
u3k(p_q_tok),
u3nt(
c3__rose,
u3nt(u3nt(':', ' ', u3_nul), u3_nul, u3_nul),
u3nt(u3k(q_q_tok), u3i_string(str_c), u3_nul)
)
)
);
c3_l pri_l = c3y == u3a_is_cat(p_q_tok) ? p_q_tok : 0;
u3t_slog_cap(pri_l, u3k(q_q_tok), u3i_string(str_c));
u3z(delta);
}
else {

View File

@ -282,13 +282,13 @@ u3t_trace_open(c3_c* dir_c)
struct stat st;
if ( -1 == stat(fil_c, &st) ) {
mkdir(fil_c, 0700);
c3_mkdir(fil_c, 0700);
}
c3_c lif_c[2056];
snprintf(lif_c, 2056, "%s/%d.json", fil_c, u3_Host.tra_u.fun_w);
u3_Host.tra_u.fil_u = fopen(lif_c, "w");
u3_Host.tra_u.fil_u = c3_fopen(lif_c, "w");
u3_Host.tra_u.nid_w = (int)getpid();
fprintf(u3_Host.tra_u.fil_u, "[ ");
@ -589,3 +589,87 @@ u3t_boff(void)
#endif
}
}
/* u3t_slog_cap(): slog a tank with a caption with
** a given priority c3_l (assumed 0-3).
*/
void
u3t_slog_cap(c3_l pri_l, u3_noun cap, u3_noun tan)
{
u3t_slog(
u3nc(
pri_l,
u3nt(
c3__rose,
u3nt(u3nt(':', ' ', u3_nul), u3_nul, u3_nul),
u3nt(cap, tan, u3_nul)
)
)
);
}
/* u3t_slog_trace(): given a c3_l priority pri and a raw stack tax
** flop the order into start-to-end, render, and slog each item
** until done.
*/
void
u3t_slog_trace(c3_l pri_l, u3_noun tax)
{
// render the stack
// Note: ton is a reference to a data struct
// we have just allocated
// lit is a used as a moving cursor pointer through
// that allocated struct
// once we finish lit will be null, but ton will still
// point to the whole valid allocated data structure
// and thus we can free it safely at the end of the func
// to clean up after ourselves.
// Note: flop reverses the stack trace list 'tax'
u3_noun ton = u3dc("mook", 2, u3kb_flop(tax));
u3_noun lit = u3t(ton);
// print the stack one stack item at a time
while ( u3_nul != lit ) {
u3t_slog(u3nc(pri_l, u3k(u3h(lit)) ));
lit = u3t(lit);
}
u3z(ton);
}
/* u3t_slog_nara(): slog only the deepest road's trace with
** c3_l priority pri
*/
void
u3t_slog_nara(c3_l pri_l)
{
u3_noun tax = u3k(u3R->bug.tax);
u3t_slog_trace(pri_l, tax);
}
/* u3t_slog_hela(): join all roads' traces together into one tax
** and pass it to slog_trace along with the given c3_l priority pri_l
*/
void
u3t_slog_hela(c3_l pri_l)
{
// rod_u protects us from mutating the global state
u3_road* rod_u = u3R;
// inits to the the current road's trace
u3_noun tax = u3k(rod_u->bug.tax);
// while there is a parent road ref ...
while ( &(u3H->rod_u) != rod_u ) {
// ... point at the next road and append its stack to tax
rod_u = u3tn(u3_road, rod_u->par_p);
tax = u3kb_weld(tax, u3k(rod_u->bug.tax));
}
u3t_slog_trace(pri_l, tax);
}

View File

@ -509,7 +509,7 @@ _cu_rock_path_make(c3_c* dir_c, c3_d eve_d, c3_c** out_c)
return c3n;
}
if ( mkdir(nam_c, 0700)
if ( c3_mkdir(nam_c, 0700)
&& (EEXIST != errno) )
{
fprintf(stderr, "rock: directory create failed (%s, %" PRIu64 "): %s\r\n",
@ -552,8 +552,8 @@ _cu_rock_save(c3_c* dir_c, c3_d eve_d, c3_d len_d, c3_y* byt_y)
return c3n;
}
if ( -1 == (fid_i = open(nam_c, O_RDWR | O_CREAT | O_TRUNC, 0644)) ) {
fprintf(stderr, "rock: open failed (%s, %" PRIu64 "): %s\r\n",
if ( -1 == (fid_i = c3_open(nam_c, O_RDWR | O_CREAT | O_TRUNC, 0644)) ) {
fprintf(stderr, "rock: c3_open failed (%s, %" PRIu64 "): %s\r\n",
dir_c, eve_d, strerror(errno));
c3_free(nam_c);
return c3n;
@ -691,8 +691,8 @@ u3u_mmap_read(c3_c* cap_c, c3_c* pat_c, c3_d* out_d, c3_y** out_y)
// open file
//
if ( -1 == (fid_i = open(pat_c, O_RDONLY, 0644)) ) {
fprintf(stderr, "%s: open failed (%s): %s\r\n",
if ( -1 == (fid_i = c3_open(pat_c, O_RDONLY, 0644)) ) {
fprintf(stderr, "%s: c3_open failed (%s): %s\r\n",
cap_c, pat_c, strerror(errno));
return c3n;
}
@ -744,8 +744,8 @@ u3u_mmap(c3_c* cap_c, c3_c* pat_c, c3_d len_d, c3_y** out_y)
// open file
//
if ( -1 == (fid_i = open(pat_c, O_RDWR | O_CREAT | O_TRUNC, 0644)) ) {
fprintf(stderr, "%s: open failed (%s): %s\r\n",
if ( -1 == (fid_i = c3_open(pat_c, O_RDWR | O_CREAT | O_TRUNC, 0644)) ) {
fprintf(stderr, "%s: c3_open failed (%s): %s\r\n",
cap_c, pat_c, strerror(errno));
return c3n;
}
@ -895,7 +895,7 @@ u3u_uncram(c3_c* dir_c, c3_d eve_d)
// leave rocks on disk
//
// if ( 0 != unlink(nam_c) ) {
// if ( 0 != c3_unlink(nam_c) ) {
// fprintf(stderr, "uncram: failed to delete rock (%s, %" PRIu64 "): %s\r\n",
// dir_c, eve_d, strerror(errno));
// c3_free(nam_c);

View File

@ -0,0 +1,65 @@
#include "all.h"
#include "vere/vere.h"
/* _setup(): prepare for tests.
*/
static void
_setup(void)
{
}
/* _test_safe():
*/
static c3_i
_test_safe()
{
c3_i ret_i = 1;
if ( !u3_unix_cane("/") ||
!u3_unix_cane("~.") ||
!u3_unix_cane("a") ||
!u3_unix_cane("a/b") ||
!u3_unix_cane("a/b/c/defg/h/ijklmnop") )
{
fprintf(stderr, "_safe fail 1\n");
ret_i = 0;
}
if ( u3_unix_cane("") ||
u3_unix_cane(".") ||
u3_unix_cane("..") ||
u3_unix_cane("/.") ||
u3_unix_cane("a/b/c//") ||
u3_unix_cane("a/b/.") ||
u3_unix_cane("/././../.") ||
u3_unix_cane("/../etc") )
{
fprintf(stderr, "_safe fail 2\r\n");
ret_i = 0;
}
if ( !u3_unix_cane(".a") ||
!u3_unix_cane("/.a.b.c/..c") )
{
fprintf(stderr, "_safe fail 3\r\n");
ret_i = 0;
}
return ret_i;
}
/* main(): run all test cases.
*/
int
main(int argc, char* argv[])
{
_setup();
if ( !_test_safe() ) {
fprintf(stderr, "test unix: failed\r\n");
exit(1);
}
fprintf(stderr, "test unix: ok\r\n");
return 0;
}

View File

@ -462,7 +462,7 @@ _dawn_come(u3_noun stars)
c3_c pat_c[64];
snprintf(pat_c, 64, "%s.key", who_c + 1);
FILE* fil_u = fopen(pat_c, "w");
FILE* fil_u = c3_fopen(pat_c, "w");
fprintf(fil_u, "%s\n", key_c);
fclose(fil_u);
}

View File

@ -42,6 +42,8 @@ u3_lmdb_init(const c3_c* pax_c, size_t siz_i)
MDB_env* env_u;
c3_w ret_w;
c3_assert(u3_unix_cane(pax_c));
if ( (ret_w = mdb_env_create(&env_u)) ) {
mdb_logerror(stderr, ret_w, "lmdb: init fail");
return 0;

View File

@ -585,6 +585,94 @@ u3_disk_read_meta(u3_disk* log_u,
return c3y;
}
/* _disk_lock(): lockfile path.
*/
static c3_c*
_disk_lock(c3_c* pax_c)
{
c3_w len_w = strlen(pax_c) + sizeof("/.vere.lock");
c3_c* paf_c = c3_malloc(len_w);
c3_i wit_i;
wit_i = snprintf(paf_c, len_w, "%s/.vere.lock", pax_c);
c3_assert(wit_i + 1 == len_w);
return paf_c;
}
/* u3_disk_acquire(): acquire a lockfile, killing anything that holds it.
*/
static void
u3_disk_acquire(c3_c* pax_c)
{
c3_c* paf_c = _disk_lock(pax_c);
c3_w pid_w;
FILE* loq_u;
if ( NULL != (loq_u = c3_fopen(paf_c, "r")) ) {
if ( 1 != fscanf(loq_u, "%" SCNu32, &pid_w) ) {
u3l_log("lockfile %s is corrupt!\n", paf_c);
kill(getpid(), SIGTERM);
sleep(1); c3_assert(0);
}
else if (pid_w != getpid()) {
c3_w i_w;
if ( -1 != kill(pid_w, SIGTERM) ) {
u3l_log("disk: stopping process %d, live in %s...\n",
pid_w, pax_c);
for ( i_w = 0; i_w < 16; i_w++ ) {
sleep(1);
if ( -1 == kill(pid_w, SIGTERM) ) {
break;
}
}
if ( 16 == i_w ) {
for ( i_w = 0; i_w < 16; i_w++ ) {
if ( -1 == kill(pid_w, SIGKILL) ) {
break;
}
sleep(1);
}
}
if ( 16 == i_w ) {
u3l_log("disk: process %d seems unkillable!\n", pid_w);
c3_assert(0);
}
u3l_log("disk: stopped old process %u\n", pid_w);
}
}
fclose(loq_u);
c3_unlink(paf_c);
}
if ( NULL == (loq_u = c3_fopen(paf_c, "w")) ) {
u3l_log("disk: unable to open %s\n", paf_c);
c3_assert(0);
}
fprintf(loq_u, "%u\n", getpid());
{
c3_i fid_i = fileno(loq_u);
c3_sync(fid_i);
}
fclose(loq_u);
c3_free(paf_c);
}
/* u3_disk_release(): release a lockfile.
*/
static void
u3_disk_release(c3_c* pax_c)
{
c3_c* paf_c = _disk_lock(pax_c);
c3_unlink(paf_c);
c3_free(paf_c);
}
/* u3_disk_exit(): close the log.
*/
void
@ -633,6 +721,8 @@ u3_disk_exit(u3_disk* log_u)
}
}
u3_disk_release(log_u->dir_u->pax_c);
u3_dire_free(log_u->dir_u);
u3_dire_free(log_u->urb_u);
u3_dire_free(log_u->com_u);
@ -734,6 +824,10 @@ u3_disk_init(c3_c* pax_c, u3_disk_cb cb_u)
}
}
// acquire lockfile.
//
u3_disk_acquire(pax_c);
// create/load $pier/.urb
//
{
@ -758,11 +852,11 @@ u3_disk_init(c3_c* pax_c, u3_disk_cb cb_u)
strcpy(dir_c, pax_c);
strcat(dir_c, "/.urb/put");
mkdir(dir_c, 0700);
c3_mkdir(dir_c, 0700);
strcpy(dir_c, pax_c);
strcat(dir_c, "/.urb/get");
mkdir(dir_c, 0700);
c3_mkdir(dir_c, 0700);
c3_free(dir_c);
}

View File

@ -84,6 +84,8 @@ u3_foil_folder(const c3_c* pax_c)
uv_dirent_t den_u;
c3_i err_i;
c3_assert(u3_unix_cane(pax_c));
/* open directory, synchronously
*/
{

View File

@ -1608,7 +1608,7 @@ _http_write_ports_file(u3_httd* htd_u, c3_c *pax_c)
c3_c* paf_c = c3_malloc(len_w);
snprintf(paf_c, len_w, "%s/%s", pax_c, nam_c);
c3_i por_i = open(paf_c, O_WRONLY | O_CREAT | O_TRUNC, 0666);
c3_i por_i = c3_open(paf_c, O_WRONLY | O_CREAT | O_TRUNC, 0666);
c3_free(paf_c);
u3_http* htp_u = htd_u->htp_u;
@ -1651,7 +1651,7 @@ _http_release_ports_file(c3_c *pax_c)
c3_assert(wit_i > 0);
c3_assert(len_w == (c3_w)wit_i + 1);
unlink(paf_c);
c3_unlink(paf_c);
c3_free(paf_c);
}

View File

@ -549,14 +549,13 @@ _term_it_show_more(u3_utty* uty_u)
/* _term_it_path(): path for console file.
*/
static c3_c*
_term_it_path(c3_o fyl, u3_noun pax)
_term_it_path(u3_noun pax)
{
c3_w len_w;
c3_w len_w = 0;
c3_c *pas_c;
// measure
//
len_w = strlen(u3_Host.dir_c);
{
u3_noun wiz = pax;
@ -569,7 +568,6 @@ _term_it_path(c3_o fyl, u3_noun pax)
// cut
//
pas_c = c3_malloc(len_w + 1);
strncpy(pas_c, u3_Host.dir_c, len_w);
pas_c[len_w] = '\0';
{
u3_noun wiz = pax;
@ -578,7 +576,7 @@ _term_it_path(c3_o fyl, u3_noun pax)
while ( u3_nul != wiz ) {
c3_w tis_w = u3r_met(3, u3h(wiz));
if ( (c3y == fyl) && (u3_nul == u3t(wiz)) ) {
if ( (u3_nul == u3t(wiz)) ) {
*waq_c++ = '.';
} else *waq_c++ = '/';
@ -598,27 +596,10 @@ _term_it_path(c3_o fyl, u3_noun pax)
static void
_term_it_save(u3_noun pax, u3_noun pad)
{
c3_c* pax_c;
c3_c* bas_c = 0;
c3_w xap_w = u3kb_lent(u3k(pax));
u3_noun xap = u3_nul;
u3_noun urb = c3_s4('.','u','r','b');
u3_noun put = c3_s3('p','u','t');
// directory base and relative path
if ( 2 < xap_w ) {
u3_noun bas = u3nt(urb, put, u3_nul);
bas_c = _term_it_path(c3n, bas);
xap = u3qb_scag(xap_w - 2, pax);
}
pax = u3nt(urb, put, pax);
pax_c = _term_it_path(c3y, pax);
u3_walk_save(pax_c, 0, pad, bas_c, xap);
c3_c* pax_c = _term_it_path(pax);
u3_unix_save(pax_c, pad);
c3_free(pax_c);
c3_free(bas_c);
}
/* _term_ovum_plan(): plan term ovums, configuring spinner.

View File

@ -1,5 +1,36 @@
/* vere/unix.c
**
** this file is responsible for maintaining a bidirectional
** mapping between the contents of a clay desk and a directory
** in a unix filesystem.
**
** TODO this driver is crufty and overdue for a rewrite.
** aspirationally, the rewrite should do sanity checking and
** transformations at the noun level to convert messages from
** arvo into sets of fs operations on trusted inputs, and
** inverse transformations and checks for fs contents to arvo
** messages.
**
** the two relevant transformations to apply are:
**
** 1. bidirectionally map file contents to atoms
** 2. bidirectionally map arvo $path <-> unix relative paths
**
** the first transform is trivial. the second poses some
** challenges: an arvo $path is a list of $knot, and the $knot
** space intersects with invalid unix paths in the three cases
** of: %$ (the empty knot), '.', and '..'. we escape these by
** prepending a '!' to the filename corresponding to the $knot,
** yielding unix files named '!', '!.', and '!..'.
**
** there is also the case of the empty path. we elide empty
** paths from this wrapper, which always uses the last path
** component as the file extension/mime-type.
**
** these transforms are implemented, but they ought to be
** implemented in one place, prior to any fs calls; as-is, they
** are sprinkled throughout the file updating code.
**
*/
#include "all.h"
#include <ftw.h>
@ -58,6 +89,7 @@ struct _u3_ufil;
c3_c* pax_c; // pier directory
c3_o alm; // timer set
c3_o dyr; // ready to update
u3_noun sat; // (sane %ta) handle
#ifdef SYNCLOG
c3_w lot_w; // sync-slot
struct _u3_sylo {
@ -72,6 +104,50 @@ struct _u3_ufil;
void
u3_unix_ef_look(u3_unix* unx_u, u3_noun mon, u3_noun all);
/* u3_unix_cane(): true iff (unix) path is canonical.
*/
c3_t
u3_unix_cane(const c3_c* pax_c)
{
if ( 0 == pax_c ) {
return 0;
}
// allow absolute paths.
//
if ( '/' == *pax_c ) {
pax_c++;
// allow root.
//
if ( 0 == *pax_c ) {
return 1;
}
}
do {
if ( 0 == *pax_c
|| 0 == strcmp(".", pax_c)
|| 0 == strcmp("..", pax_c)
|| 0 == strncmp("/", pax_c, 1)
|| 0 == strncmp("./", pax_c, 2)
|| 0 == strncmp("../", pax_c, 3) )
{
return 0;
}
pax_c = strchr(pax_c, '/');
} while ( 0 != pax_c++ );
return 1;
}
/* _unix_sane_ta(): true iff pat is a valid @ta
**
** %ta is parsed by:
** (star ;~(pose nud low hep dot sig cab))
*/
static c3_t
_unix_sane_ta(u3_unix* unx_u, u3_atom pat)
{
return _(u3n_slam_on(u3k(unx_u->sat), pat));
}
/* u3_readdir_r():
*/
c3_w
@ -91,6 +167,56 @@ u3_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
return(0);
}
/* _unix_string_to_knot(): convert c unix path component to $knot
*/
static u3_atom
_unix_string_to_knot(c3_c* pax_c)
{
c3_assert(pax_c);
// XX this can happen if we encounter a file without an extension.
//
// c3_assert(*pax_c);
c3_assert(!strchr(pax_c, '/'));
// XX horrible
//
# ifdef _WIN32
c3_assert(!strchr(pax_c, '\\'));
# endif
if ( '!' == *pax_c ) {
pax_c++;
}
return u3i_string(pax_c);
}
/* _unix_knot_to_string(): convert $knot to c unix path component. RETAIN.
*/
static c3_c*
_unix_knot_to_string(u3_atom pon)
{
c3_c* ret_c;
if ( u3_nul != pon
&& c3_s1('.') != pon
&& c3_s2('.','.') != pon
&& '!' != u3r_byte(0, pon) )
{
ret_c = u3r_string(pon);
}
else {
c3_w met_w = u3r_met(3, pon);
ret_c = c3_malloc(met_w + 2);
*ret_c = '!';
u3r_bytes(0, met_w, (c3_y*)ret_c + 1, pon);
ret_c[met_w + 1] = 0;
}
c3_assert(!strchr(ret_c, '/'));
# ifdef _WIN32
c3_assert(!strchr(ret_c, '\\'));
# endif
return ret_c;
}
/* _unix_down(): descend path.
*/
static c3_c*
@ -108,29 +234,34 @@ _unix_down(c3_c* pax_c, c3_c* sub_c)
return don_c;
}
/* _unix_string_to_path(): convert c string to u3_noun path
*
* c string must begin with the pier path plus mountpoint
/* _unix_string_to_path(): convert c string to u3_noun $path
**
** c string must begin with the pier path plus mountpoint
*/
static u3_noun
_unix_string_to_path_helper(c3_c* pax_c)
{
u3_noun not;
c3_assert(pax_c[-1] == '/');
c3_c* end_w = strchr(pax_c, '/');
if ( !end_w ) {
end_w = strrchr(pax_c, '.');
if ( !end_w ) {
return u3nc(u3i_string(pax_c), u3_nul);
c3_c* end_c = strchr(pax_c, '/');
if ( !end_c ) {
end_c = strrchr(pax_c, '.');
if ( !end_c ) {
return u3nc(_unix_string_to_knot(pax_c), u3_nul);
}
else {
return u3nt(u3i_bytes(end_w - pax_c, (c3_y*) pax_c),
u3i_string(end_w + 1),
u3_nul);
*end_c = 0;
not = _unix_string_to_knot(pax_c);
*end_c = '.';
return u3nt(not, _unix_string_to_knot(end_c + 1), u3_nul);
}
}
else {
return u3nc(u3i_bytes(end_w - pax_c, (c3_y*) pax_c),
_unix_string_to_path_helper(end_w + 1));
*end_c = 0;
not = _unix_string_to_knot(pax_c);
*end_c = '/';
return u3nc(not, _unix_string_to_path_helper(end_c + 1));
}
}
static u3_noun
@ -144,7 +275,7 @@ _unix_string_to_path(u3_unix* unx_u, c3_c* pax_c)
return u3_nul;
}
else {
return u3nc(u3i_string(pox_c + 1), u3_nul);
return u3nc(_unix_string_to_knot(pox_c + 1), u3_nul);
}
}
else {
@ -152,6 +283,77 @@ _unix_string_to_path(u3_unix* unx_u, c3_c* pax_c)
}
}
/* _unix_mkdirp(): recursive mkdir of dirname of pax_c.
*/
static void
_unix_mkdirp(c3_c* pax_c)
{
c3_c* fas_c = strchr(pax_c + 1, '/');
while ( fas_c ) {
*fas_c = 0;
if ( 0 != mkdir(pax_c, 0777) && EEXIST != errno ) {
u3l_log("unix: mkdir %s: %s\n", pax_c, strerror(errno));
u3m_bail(c3__fail);
}
*fas_c++ = '/';
fas_c = strchr(fas_c, '/');
}
}
/* u3_unix_save(): save file under .../.urb/put or bail.
**
** XX this is quite bad, and doesn't share much in common with
** the rest of unix.c. a refactor would probably share common
** logic with _unix_sync_change, perhaps using openat, making
** unx_u optional, and/or having a flag to not track the file
** for future changes.
*/
void
u3_unix_save(c3_c* pax_c, u3_atom pad)
{
c3_i fid_i;
c3_w lod_w, len_w, fln_w, rit_w;
c3_y* pad_y;
c3_c* ful_c;
if ( !u3_unix_cane(pax_c) ) {
u3l_log("%s: non-canonical path\n", pax_c);
u3z(pad); u3m_bail(c3__fail);
}
if ( '/' == *pax_c) {
pax_c++;
}
lod_w = strlen(u3_Host.dir_c);
len_w = lod_w + sizeof("/.urb/put/") + strlen(pax_c);
ful_c = c3_malloc(len_w);
rit_w = snprintf(ful_c, len_w, "%s/.urb/put/%s", u3_Host.dir_c, pax_c);
c3_assert(len_w == rit_w + 1);
_unix_mkdirp(ful_c);
fid_i = c3_open(ful_c, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if ( fid_i < 0 ) {
u3l_log("%s: %s\n", ful_c, strerror(errno));
c3_free(ful_c);
u3z(pad); u3m_bail(c3__fail);
}
fln_w = u3r_met(3, pad);
pad_y = c3_malloc(fln_w);
u3r_bytes(0, fln_w, pad_y, pad);
u3z(pad);
rit_w = write(fid_i, pad_y, fln_w);
close(fid_i);
c3_free(pad_y);
if ( rit_w != fln_w ) {
u3l_log("%s: %s\n", ful_c, strerror(errno));
c3_free(ful_c);
u3m_bail(c3__fail);
}
c3_free(ful_c);
}
/* _unix_rm_r_cb(): callback to delete individual files/directories
*/
static c3_i
@ -165,7 +367,7 @@ _unix_rm_r_cb(const c3_c* pax_c,
u3l_log("bad file type in rm_r: %s\r\n", pax_c);
break;
case FTW_F:
if ( 0 != unlink(pax_c) && ENOENT != errno ) {
if ( 0 != c3_unlink(pax_c) && ENOENT != errno ) {
u3l_log("error unlinking (in rm_r) %s: %s\n",
pax_c, strerror(errno));
c3_assert(0);
@ -181,7 +383,7 @@ _unix_rm_r_cb(const c3_c* pax_c,
u3l_log("couldn't stat path: %s\r\n", pax_c);
break;
case FTW_DP:
if ( 0 != rmdir(pax_c) && ENOENT != errno ) {
if ( 0 != c3_rmdir(pax_c) && ENOENT != errno ) {
u3l_log("error rmdiring %s: %s\n", pax_c, strerror(errno));
c3_assert(0);
}
@ -213,7 +415,7 @@ _unix_rm_r(c3_c* pax_c)
static void
_unix_mkdir(c3_c* pax_c)
{
if ( 0 != mkdir(pax_c, 0755) && EEXIST != errno) {
if ( 0 != c3_mkdir(pax_c, 0755) && EEXIST != errno) {
u3l_log("error mkdiring %s: %s\n", pax_c, strerror(errno));
c3_assert(0);
}
@ -224,7 +426,7 @@ _unix_mkdir(c3_c* pax_c)
static c3_w
_unix_write_file_hard(c3_c* pax_c, u3_noun mim)
{
c3_i fid_i = open(pax_c, O_WRONLY | O_CREAT | O_TRUNC, 0666);
c3_i fid_i = c3_open(pax_c, O_WRONLY | O_CREAT | O_TRUNC, 0666);
c3_w len_w, rit_w, siz_w, mug_w = 0;
c3_y* dat_y;
@ -267,7 +469,7 @@ static void
_unix_write_file_soft(u3_ufil* fil_u, u3_noun mim)
{
struct stat buf_u;
c3_i fid_i = open(fil_u->pax_c, O_RDONLY, 0644);
c3_i fid_i = c3_open(fil_u->pax_c, O_RDONLY, 0644);
c3_ws len_ws, red_ws;
c3_w old_w;
c3_y* old_y;
@ -339,7 +541,7 @@ _unix_get_mount_point(u3_unix* unx_u, u3_noun mon)
return NULL;
}
c3_c* nam_c = u3r_string(mon);
c3_c* nam_c = _unix_knot_to_string(mon);
u3_umon* mon_u;
for ( mon_u = unx_u->mon_u;
@ -374,7 +576,7 @@ _unix_get_mount_point(u3_unix* unx_u, u3_noun mon)
static void
_unix_scan_mount_point(u3_unix* unx_u, u3_umon* mon_u)
{
DIR* rid_u = opendir(mon_u->dir_u.pax_c);
DIR* rid_u = c3_opendir(mon_u->dir_u.pax_c);
if ( !rid_u ) {
u3l_log("error opening pier directory: %s: %s\r\n",
mon_u->dir_u.pax_c, strerror(errno));
@ -425,12 +627,11 @@ _unix_scan_mount_point(u3_unix* unx_u, u3_umon* mon_u)
}
}
else {
if ( '.' != out_u->d_name[len_w]
|| '\0' == out_u->d_name[len_w + 1]
|| '~' == out_u->d_name[strlen(out_u->d_name) - 1]
|| ('#' == out_u->d_name[0] &&
'#' == out_u->d_name[strlen(out_u->d_name) - 1])
) {
if ( '.' != out_u->d_name[len_w]
|| '\0' == out_u->d_name[len_w + 1]
|| '~' == out_u->d_name[strlen(out_u->d_name) - 1]
|| !_unix_sane_ta(unx_u, _unix_string_to_knot(out_u->d_name)) )
{
c3_free(pax_c);
continue;
}
@ -452,7 +653,7 @@ static u3_noun _unix_free_node(u3_unix* unx_u, u3_unod* nod_u);
static void
_unix_free_file(u3_ufil *fil_u)
{
if ( 0 != unlink(fil_u->pax_c) && ENOENT != errno ) {
if ( 0 != c3_unlink(fil_u->pax_c) && ENOENT != errno ) {
u3l_log("error unlinking %s: %s\n", fil_u->pax_c, strerror(errno));
c3_assert(0);
}
@ -482,8 +683,8 @@ _unix_free_dir(u3_udir *dir_u)
}
/* _unix_free_node(): free node, deleting everything within
*
* also deletes from parent list if in it
**
** also deletes from parent list if in it
*/
static u3_noun
_unix_free_node(u3_unix* unx_u, u3_unod* nod_u)
@ -526,12 +727,12 @@ _unix_free_node(u3_unix* unx_u, u3_unod* nod_u)
}
/* _unix_free_mount_point(): free mount point
*
* this process needs to happen in a very careful order. in particular,
* we must recurse before we get to the callback, so that libuv does all
* the child directories before it does us.
*
* tread carefully
**
** this process needs to happen in a very careful order. in
** particular, we must recurse before we get to the callback, so
** that libuv does all the child directories before it does us.
**
** tread carefully
*/
static void
_unix_free_mount_point(u3_unix* unx_u, u3_umon* mon_u)
@ -559,7 +760,7 @@ _unix_delete_mount_point(u3_unix* unx_u, u3_noun mon)
return;
}
c3_c* nam_c = u3r_string(mon);
c3_c* nam_c = _unix_knot_to_string(mon);
u3_umon* mon_u;
u3_umon* tem_u;
@ -651,7 +852,7 @@ _unix_watch_dir(u3_udir* dir_u, u3_udir* par_u, c3_c* pax_c)
static void
_unix_create_dir(u3_udir* dir_u, u3_udir* par_u, u3_noun nam)
{
c3_c* nam_c = u3r_string(nam);
c3_c* nam_c = _unix_knot_to_string(nam);
c3_w nam_w = strlen(nam_c);
c3_w pax_w = strlen(par_u->pax_c);
c3_c* pax_c = c3_malloc(pax_w + 1 + nam_w + 1);
@ -671,12 +872,13 @@ _unix_create_dir(u3_udir* dir_u, u3_udir* par_u, u3_noun nam)
static u3_noun _unix_update_node(u3_unix* unx_u, u3_unod* nod_u);
/* _unix_update_file(): update file, producing list of changes
*
* when scanning through files, if dry, do nothing. otherwise, mark as
* dry, then check if file exists. if not, remove self from node list
* and add path plus sig to %into event. otherwise, read the file and
* get a mug checksum. if same as gum_w, move on. otherwise, overwrite
* add path plus data to %into event.
**
** when scanning through files, if dry, do nothing. otherwise,
** mark as dry, then check if file exists. if not, remove
** self from node list and add path plus sig to %into event.
** otherwise, read the file and get a mug checksum. if same as
** gum_w, move on. otherwise, overwrite add path plus data to
** %into event.
*/
static u3_noun
_unix_update_file(u3_unix* unx_u, u3_ufil* fil_u)
@ -690,7 +892,7 @@ _unix_update_file(u3_unix* unx_u, u3_ufil* fil_u)
fil_u->dry = c3n;
struct stat buf_u;
c3_i fid_i = open(fil_u->pax_c, O_RDONLY, 0644);
c3_i fid_i = c3_open(fil_u->pax_c, O_RDONLY, 0644);
c3_ws len_ws, red_ws;
c3_y* dat_y;
@ -745,9 +947,9 @@ _unix_update_file(u3_unix* unx_u, u3_ufil* fil_u)
}
/* _unix_update_dir(): update directory, producing list of changes
*
* when changing this, consider whether to also change
* _unix_initial_update_dir()
**
** when changing this, consider whether to also change
** _unix_initial_update_dir()
*/
static u3_noun
_unix_update_dir(u3_unix* unx_u, u3_udir* dir_u)
@ -773,7 +975,7 @@ _unix_update_dir(u3_unix* unx_u, u3_udir* dir_u)
}
else {
if ( c3y == nod_u->dir ) {
DIR* red_u = opendir(nod_u->pax_c);
DIR* red_u = c3_opendir(nod_u->pax_c);
if ( 0 == red_u ) {
u3_unod* nex_u = nod_u->nex_u;
can = u3kb_weld(_unix_free_node(unx_u, nod_u), can);
@ -786,7 +988,7 @@ _unix_update_dir(u3_unix* unx_u, u3_udir* dir_u)
}
else {
struct stat buf_u;
c3_i fid_i = open(nod_u->pax_c, O_RDONLY, 0644);
c3_i fid_i = c3_open(nod_u->pax_c, O_RDONLY, 0644);
if ( (fid_i < 0) || (fstat(fid_i, &buf_u) < 0) ) {
if ( ENOENT != errno ) {
@ -813,7 +1015,7 @@ _unix_update_dir(u3_unix* unx_u, u3_udir* dir_u)
// Check for new nodes
DIR* rid_u = opendir(dir_u->pax_c);
DIR* rid_u = c3_opendir(dir_u->pax_c);
if ( !rid_u ) {
u3l_log("error opening directory %s: %s\r\n",
dir_u->pax_c, strerror(errno));
@ -869,11 +1071,10 @@ _unix_update_dir(u3_unix* unx_u, u3_udir* dir_u)
if ( !nod_u ) {
if ( !S_ISDIR(buf_u.st_mode) ) {
if ( !strchr(out_u->d_name,'.')
|| '~' == out_u->d_name[strlen(out_u->d_name) - 1]
|| ('#' == out_u->d_name[0] &&
'#' == out_u->d_name[strlen(out_u->d_name) - 1])
) {
if ( !strchr(out_u->d_name,'.')
|| '~' == out_u->d_name[strlen(out_u->d_name) - 1]
|| !_unix_sane_ta(unx_u, _unix_string_to_knot(out_u->d_name)) )
{
c3_free(pax_c);
continue;
}
@ -942,7 +1143,8 @@ _unix_update_mount(u3_unix* unx_u, u3_umon* mon_u, u3_noun all)
u3_noun wir = u3nt(c3__sync,
u3dc("scot", c3__uv, unx_u->sev_l),
u3_nul);
u3_noun cad = u3nq(c3__into, u3i_string(mon_u->nam_c), all, can);
u3_noun cad = u3nq(c3__into, _unix_string_to_knot(mon_u->nam_c), all,
can);
u3_auto_plan(&unx_u->car_u, u3_ovum_init(0, c3__c, wir, cad));
}
@ -950,13 +1152,13 @@ _unix_update_mount(u3_unix* unx_u, u3_umon* mon_u, u3_noun all)
}
/* _unix_initial_update_file(): read file, but don't watch
** XX deduplicate with _unix_update_file()
** XX deduplicate with _unix_update_file()
*/
static u3_noun
_unix_initial_update_file(c3_c* pax_c, c3_c* bas_c)
{
struct stat buf_u;
c3_i fid_i = open(pax_c, O_RDONLY, 0644);
c3_i fid_i = c3_open(pax_c, O_RDONLY, 0644);
c3_ws len_ws, red_ws;
c3_y* dat_y;
@ -1006,14 +1208,14 @@ _unix_initial_update_file(c3_c* pax_c, c3_c* bas_c)
}
/* _unix_initial_update_dir(): read directory, but don't watch
** XX deduplicate with _unix_update_dir()
** XX deduplicate with _unix_update_dir()
*/
static u3_noun
_unix_initial_update_dir(c3_c* pax_c, c3_c* bas_c)
{
u3_noun can = u3_nul;
DIR* rid_u = opendir(pax_c);
DIR* rid_u = c3_opendir(pax_c);
if ( !rid_u ) {
u3l_log("error opening initial directory: %s: %s\r\n",
pax_c, strerror(errno));
@ -1089,8 +1291,8 @@ _unix_sync_file(u3_unix* unx_u, u3_udir* par_u, u3_noun nam, u3_noun ext, u3_nou
// form file path
c3_c* nam_c = u3r_string(nam);
c3_c* ext_c = u3r_string(ext);
c3_c* nam_c = _unix_knot_to_string(nam);
c3_c* ext_c = _unix_knot_to_string(ext);
c3_w par_w = strlen(par_u->pax_c);
c3_w nam_w = strlen(nam_c);
c3_w ext_w = strlen(ext_c);
@ -1174,7 +1376,7 @@ _unix_sync_change(u3_unix* unx_u, u3_udir* dir_u, u3_noun pax, u3_noun mim)
_unix_sync_file(unx_u, dir_u, u3k(i_pax), u3k(it_pax), mim);
}
else {
c3_c* nam_c = u3r_string(i_pax);
c3_c* nam_c = _unix_knot_to_string(i_pax);
c3_w pax_w = strlen(dir_u->pax_c);
u3_unod* nod_u;
@ -1207,7 +1409,7 @@ static void
_unix_sync_ergo(u3_unix* unx_u, u3_umon* mon_u, u3_noun can)
{
u3_noun nac = can;
u3_noun nam = u3i_string(mon_u->nam_c);
u3_noun nam = _unix_string_to_knot(mon_u->nam_c);
while ( u3_nul != nac) {
_unix_sync_change(unx_u, &mon_u->dir_u,
@ -1263,98 +1465,24 @@ u3_unix_ef_hill(u3_unix* unx_u, u3_noun hil)
u3z(hil);
}
/* u3_unix_acquire(): acquire a lockfile, killing anything that holds it.
*/
static void
u3_unix_acquire(c3_c* pax_c)
{
c3_c* paf_c = _unix_down(pax_c, ".vere.lock");
c3_w pid_w;
FILE* loq_u;
if ( NULL != (loq_u = fopen(paf_c, "r")) ) {
if ( 1 != fscanf(loq_u, "%" SCNu32, &pid_w) ) {
u3l_log("lockfile %s is corrupt!\n", paf_c);
kill(getpid(), SIGTERM);
sleep(1); c3_assert(0);
}
else if (pid_w != getpid()) {
c3_w i_w;
if ( -1 != kill(pid_w, SIGTERM) ) {
u3l_log("unix: stopping process %d, live in %s...\n",
pid_w, pax_c);
for ( i_w = 0; i_w < 16; i_w++ ) {
sleep(1);
if ( -1 == kill(pid_w, SIGTERM) ) {
break;
}
}
if ( 16 == i_w ) {
for ( i_w = 0; i_w < 16; i_w++ ) {
if ( -1 == kill(pid_w, SIGKILL) ) {
break;
}
sleep(1);
}
}
if ( 16 == i_w ) {
u3l_log("unix: process %d seems unkillable!\n", pid_w);
c3_assert(0);
}
u3l_log("unix: stopped old process %u\n", pid_w);
}
}
fclose(loq_u);
unlink(paf_c);
}
if ( NULL == (loq_u = fopen(paf_c, "w")) ) {
u3l_log("unix: unable to open %s\n", paf_c);
c3_assert(0);
}
fprintf(loq_u, "%u\n", getpid());
{
c3_i fid_i = fileno(loq_u);
c3_sync(fid_i);
}
fclose(loq_u);
c3_free(paf_c);
}
/* u3_unix_release(): release a lockfile.
*/
static void
u3_unix_release(c3_c* pax_c)
{
c3_c* paf_c = _unix_down(pax_c, ".vere.lock");
unlink(paf_c);
c3_free(paf_c);
}
/* u3_unix_ef_look(): update the root of a specific mount point.
*/
void
u3_unix_ef_look(u3_unix* unx_u, u3_noun mon, u3_noun all)
{
if ( c3y == unx_u->dyr ) {
c3_c* nam_c = _unix_knot_to_string(mon);
unx_u->dyr = c3n;
u3_umon* mon_u = unx_u->mon_u;
while ( mon_u && ( c3n == u3r_sing_c(mon_u->nam_c, mon) ) ) {
while ( mon_u && 0 != strcmp(nam_c, mon_u->nam_c) ) {
mon_u = mon_u->nex_u;
}
c3_free(nam_c);
if ( mon_u ) {
_unix_update_mount(unx_u, mon_u, all);
}
}
u3z(mon);
}
@ -1431,10 +1559,7 @@ _unix_io_exit(u3_auto* car_u)
{
u3_unix* unx_u = (u3_unix*)car_u;
// XX move to disk.c?
//
u3_unix_release(unx_u->pax_c);
u3z(unx_u->sat);
c3_free(unx_u->pax_c);
c3_free(unx_u);
}
@ -1449,10 +1574,7 @@ u3_unix_io_init(u3_pier* pir_u)
unx_u->pax_c = strdup(pir_u->pax_c);
unx_u->alm = c3n;
unx_u->dyr = c3n;
// XX move to disk.c?
//
u3_unix_acquire(unx_u->pax_c);
unx_u->sat = u3do("sane", c3__ta);
u3_auto* car_u = &unx_u->car_u;
car_u->nam_m = c3__unix;

View File

@ -923,13 +923,13 @@ u3_king_grab(void* vod_p)
struct stat st;
if ( -1 == stat(nam_c, &st) ) {
mkdir(nam_c, 0700);
c3_mkdir(nam_c, 0700);
}
c3_c man_c[2048];
snprintf(man_c, 2048, "%s/%s-daemon.txt", nam_c, wen_c);
fil_u = fopen(man_c, "w");
fil_u = c3_fopen(man_c, "w");
fprintf(fil_u, "%s\r\n", wen_c);
c3_free(wen_c);

View File

@ -526,12 +526,11 @@ _pier_on_scry_done(void* ptr_v, u3_noun nun)
// if serialization and export path succeeded, write to disk
//
if ( (u3_none != out) && (u3_none != pad) ) {
c3_c fil_c[2048];
snprintf(fil_c, 2048, "%s/.urb/put/%s.%s",
pir_u->pax_c, pac_c+1, ext_c);
c3_c fil_c[256];
snprintf(fil_c, 256, "%s.%s", pac_c + 1, ext_c);
u3_walk_save(fil_c, 0, out, pir_u->pax_c, pad);
u3l_log("pier: scry result in %s\n", fil_c);
u3_unix_save(fil_c, pad);
u3l_log("pier: scry result in %s/.urb/put/%s\n", u3_Host.dir_c, fil_c);
}
}

View File

@ -1,326 +0,0 @@
/* vere/walk.c
**
*/
#include "all.h"
#include "vere/vere.h"
/* |%
** ++ arch :: fs node
** $% [& p=@uvI q=*] :: file, hash/data
** [| p=(map ,@ta arch)] :: directory
** == ::
** --
*/
#if 0
static u3_noun
_walk_ok(u3_noun nod)
{
u3_noun don = u3n_mung(u3k(u2A->toy.arch), u3k(nod));
if ( c3n == u3_sing(nod, don) ) {
c3_assert(0);
}
u3z(don);
return nod;
}
#endif
/* u3_walk_safe(): load file or 0.
*/
u3_noun
u3_walk_safe(c3_c* pas_c)
{
struct stat buf_b;
c3_i fid_i = open(pas_c, O_RDONLY, 0644);
c3_w fln_w, red_w;
c3_y* pad_y;
if ( (fid_i < 0) || (fstat(fid_i, &buf_b) < 0) ) {
// u3l_log("%s: %s\n", pas_c, strerror(errno));
return 0;
}
fln_w = buf_b.st_size;
pad_y = c3_malloc(buf_b.st_size);
red_w = read(fid_i, pad_y, fln_w);
close(fid_i);
if ( fln_w != red_w ) {
c3_free(pad_y);
return 0;
}
else {
u3_noun pad = u3i_bytes(fln_w, (c3_y *)pad_y);
c3_free(pad_y);
return pad;
}
}
/* u3_walk_load(): load file or bail.
*/
u3_noun
u3_walk_load(c3_c* pas_c)
{
struct stat buf_b;
c3_i fid_i = open(pas_c, O_RDONLY, 0644);
c3_w fln_w, red_w;
c3_y* pad_y;
if ( (fid_i < 0) || (fstat(fid_i, &buf_b) < 0) ) {
u3l_log("%s: %s\n", pas_c, strerror(errno));
return u3m_bail(c3__fail);
}
fln_w = buf_b.st_size;
pad_y = c3_malloc(buf_b.st_size);
red_w = read(fid_i, pad_y, fln_w);
close(fid_i);
if ( fln_w != red_w ) {
c3_free(pad_y);
u3l_log("u3_walk_load failed");
return u3m_bail(c3__fail);
}
else {
u3_noun pad = u3i_bytes(fln_w, (c3_y *)pad_y);
c3_free(pad_y);
return pad;
}
}
/* _walk_mkdirp(): recursively make directories in pax at bas_c (RETAIN)
*/
static void
_walk_mkdirp(c3_c* bas_c, u3_noun pax)
{
c3_c* pax_c;
c3_y* waq_y;
c3_w pax_w, fas_w, len_w;
if ( u3_nul == pax ) {
return;
}
pax_w = u3r_met(3, u3h(pax));
fas_w = strlen(bas_c);
len_w = 1 + fas_w + pax_w;
pax_c = c3_malloc(1 + len_w);
strcpy(pax_c, bas_c);
pax_c[fas_w] = '/';
waq_y = (void*)(1 + pax_c + fas_w);
u3r_bytes(0, pax_w, waq_y, u3h(pax));
pax_c[len_w] = '\0';
if ( 0 != mkdir(pax_c, 0755) && EEXIST != errno ) {
u3l_log("error mkdiring %s: %s\n", pax_c, strerror(errno));
u3m_bail(c3__fail);
}
_walk_mkdirp(pax_c, u3t(pax));
c3_free(pax_c);
}
/* u3_walk_save(): save file or bail.
*/
void
u3_walk_save(c3_c* pas_c, u3_noun tim, u3_atom pad, c3_c* bas_c, u3_noun pax)
{
c3_i fid_i = open(pas_c, O_WRONLY | O_CREAT | O_TRUNC, 0666);
c3_w fln_w, rit_w;
c3_y* pad_y;
if ( fid_i < 0 ) {
if ( ENOENT == errno && u3_nul != pax ) {
_walk_mkdirp(bas_c, pax);
return u3_walk_save(pas_c, tim, pad, 0, u3_nul);
}
u3l_log("%s: %s\n", pas_c, strerror(errno));
u3m_bail(c3__fail);
}
fln_w = u3r_met(3, pad);
pad_y = c3_malloc(fln_w);
u3r_bytes(0, fln_w, pad_y, pad);
u3z(pad);
u3z(pax);
rit_w = write(fid_i, pad_y, fln_w);
close(fid_i);
c3_free(pad_y);
if ( rit_w != fln_w ) {
u3l_log("%s: %s\n", pas_c, strerror(errno));
u3m_bail(c3__fail);
}
if ( 0 != tim ) {
struct timeval tim_tv[2];
u3_time_out_tv(&tim_tv[0], u3k(tim));
u3_time_out_tv(&tim_tv[1], tim);
utimes(pas_c, tim_tv);
}
}
/* _walk_in(): inner loop of _walk(), producing map.
*/
static u3_noun
_walk_in(const c3_c* dir_c, c3_w len_w)
{
DIR* dir_d = opendir(dir_c);
u3_noun map = u3_nul;
if ( !dir_d ) {
return u3_nul;
}
else while ( 1 ) {
struct dirent ent_n;
struct dirent* out_n;
if ( u3_readdir_r(dir_d, &ent_n, &out_n) != 0 ) {
u3l_log("%s: %s\n", dir_c, strerror(errno));
break;
}
else if ( !out_n ) {
break;
}
else if ( !strcmp(out_n->d_name, ".") ||
!strcmp(out_n->d_name, "..") ||
('~' == out_n->d_name[0]) ||
('.' == out_n->d_name[0]) ) // XX restricts some spans
{
continue;
}
else {
c3_c* fil_c = out_n->d_name;
c3_w lef_w = len_w + 1 + strlen(fil_c);
c3_c* pat_c = c3_malloc(lef_w + 1);
struct stat buf_b;
strncpy(pat_c, dir_c, lef_w);
pat_c[len_w] = '/';
strncpy(pat_c + len_w + 1, fil_c, lef_w);
pat_c[lef_w] = '\0';
if ( 0 != stat(pat_c, &buf_b) ) {
c3_free(pat_c);
} else {
u3_noun tim = c3_stat_mtime(&buf_b);
if ( !S_ISDIR(buf_b.st_mode) ) {
c3_c* dot_c = strrchr(fil_c, '.');
c3_c* nam_c = strdup(fil_c);
c3_c* ext_c = strdup(dot_c + 1);
nam_c[dot_c - fil_c] = 0;
{
u3_noun nam = u3i_string(nam_c);
u3_noun ext = u3i_string(ext_c);
u3_noun get = u3kdb_get(u3k(map), u3k(nam));
u3_noun dat = u3_walk_load(pat_c);
u3_noun hax;
if ( !strcmp("noun", ext_c) ) {
dat = u3ke_cue(dat);
}
hax = u3do("sham", u3k(dat));
if ( u3_none == get ) { get = u3_nul; }
get = u3kdb_put(get, ext, u3nt(c3y, hax, dat));
map = u3kdb_put(map, nam, u3nc(c3n, get));
}
c3_free(nam_c);
c3_free(ext_c);
}
else {
u3_noun dir = _walk_in(pat_c, lef_w);
if ( u3_nul != dir ) {
map = u3kdb_put
(map, u3i_string(fil_c), u3nc(c3n, dir));
}
else u3z(tim);
}
c3_free(pat_c);
}
}
}
closedir(dir_d);
return map;
}
/* u3_walk(): traverse `dir_c` to produce an arch, updating `old`.
*/
u3_noun
u3_walk(const c3_c* dir_c, u3_noun old)
{
// XX - obviously, cheaper to update old data.
u3z(old);
{
struct stat buf_b;
if ( 0 != stat(dir_c, &buf_b) ) {
u3l_log("can't stat %s\n", dir_c);
// return u3m_bail(c3__fail);
c3_assert(0);
}
else {
return u3nc(c3n,
_walk_in(dir_c, strlen(dir_c)));
}
}
}
/* u3_path(): C unix path in computer for file or directory.
*/
c3_c*
u3_path(c3_o fyl, u3_noun pax)
{
c3_w len_w;
c3_c *pas_c;
// measure
//
len_w = strlen(u3_Local);
{
u3_noun wiz = pax;
while ( u3_nul != wiz ) {
len_w += (1 + u3r_met(3, u3h(wiz)));
wiz = u3t(wiz);
}
}
// cut
//
pas_c = c3_malloc(len_w + 1);
strncpy(pas_c, u3_Local, len_w);
pas_c[len_w] = '\0';
{
u3_noun wiz = pax;
c3_c* waq_c = (pas_c + strlen(pas_c));
while ( u3_nul != wiz ) {
c3_w tis_w = u3r_met(3, u3h(wiz));
if ( (c3y == fyl) && (u3_nul == u3t(wiz)) ) {
*waq_c++ = '.';
} else *waq_c++ = '/';
u3r_bytes(0, tis_w, (c3_y*)waq_c, u3h(wiz));
waq_c += tis_w;
wiz = u3t(wiz);
}
*waq_c = 0;
}
u3z(pax);
return pas_c;
}

View File

@ -131,7 +131,7 @@ _cw_serf_stdio(c3_i* inn_i, c3_i* out_i)
// we replace [FD 0] (stdin) with a fd pointing to /dev/null
// we replace [FD 1] (stdout) with a dup of [FD 2] (stderr)
//
c3_i nul_i = open(c3_dev_null, O_RDWR, 0);
c3_i nul_i = c3_open(c3_dev_null, O_RDWR, 0);
*inn_i = dup(0);
*out_i = dup(1);

View File

@ -204,13 +204,13 @@ _serf_grab(u3_noun sac)
struct stat st;
if ( -1 == stat(nam_c, &st) ) {
mkdir(nam_c, 0700);
c3_mkdir(nam_c, 0700);
}
c3_c man_c[2054];
snprintf(man_c, 2053, "%s/%s-serf.txt", nam_c, wen_c);
fil_u = fopen(man_c, "w");
fil_u = c3_fopen(man_c, "w");
fprintf(fil_u, "%s\r\n", wen_c);
c3_free(wen_c);
@ -835,13 +835,13 @@ _serf_writ_live_exit(u3_serf* sef_u, c3_w cod_w)
struct stat st;
if ( -1 == stat(nam_c, &st) ) {
mkdir(nam_c, 0700);
c3_mkdir(nam_c, 0700);
}
c3_c man_c[2054];
snprintf(man_c, 2053, "%s/%s.txt", nam_c, wen_c);
fil_u = fopen(man_c, "w");
fil_u = c3_fopen(man_c, "w");
c3_free(wen_c);
u3z(wen);