ref: 28f0259d48be125dd16b74ae81d0a23dc430a08a
parent: 246e05a5735206e309d4f3ce221c6460e5562878
author: qwx <qwx@sciops.net>
date: Wed Jan 19 17:46:13 EST 2022
page-del: allow popping/removing subentries, required for dirs + misc checks and sanitization
--- a/page-del
+++ b/page-del
@@ -1,4 +1,4 @@
-diff c4e30bede2f79c42dacb8c91713abf4a4d91c45c uncommitted
+diff aa14ba62fd02ffd0e7053c23b2918e7aa46bcb86 uncommitted
--- a//sys/src/cmd/page.c
+++ b//sys/src/cmd/page.c
@@ -74,7 +74,10 @@
@@ -35,96 +35,102 @@
}
}
-+/* page entries are never freed, there's no point
-+ * and would break everything */
++/* doesn't actually free the page entry or touch links to avoid breakage */
+Page*
-+poppage(Page *p)
++freepage(Page *p, Page *prev)
+{
-+ Page *t, *q;
++ Page *next, *up;
+
-+ if(p == nil)
-+ return nil;
-+ if(p->up != root)
-+ return p;
-+ qlock(&pagelock);
-+ for(t = p->down; t != nil && t->up != root; t = q){
-+ qlock(t);
-+ drawlock(0);
-+ unloadpage(t);
-+ drawlock(1);
-+ free(t->name);
-+ free(t->data);
-+ t->name = t->data = nil;
-+ q = nextpage(t);
-+ qunlock(t);
-+ }
+ drawlock(0);
+ unloadpage(p);
+ drawlock(1);
++ if(p->fd >= 0)
++ close(p->fd);
++ p->fd = -1;
+ free(p->name);
+ free(p->data);
-+ p->name = p->data = nil;
-+ t = prevpage(p);
-+ if(root->tail == p)
-+ root->tail = t;
-+ if(root->down == p || t == nil)
-+ root->down = p->next;
-+ else
-+ t->next = p->next;
-+ qunlock(&pagelock);
-+ qunlock(p);
-+ if(p->next != nil){
-+ forward = 1;
-+ return p->next;
-+ }
-+ forward = -1;
-+ return t;
++ p->name = p->data = p->open = nil;
++ next = nextpage(p);
++ up = p->up;
++ if(up->down == p){
++ if(up->tail != p)
++ up->down = next;
++ else
++ up->down = nil;
++ }else if(up->tail == p){
++ up->tail = prev;
++ prev->next = nil;
++ }else
++ prev->next = next;
++ return next;
+}
+
+Page*
-+delpage(Page *p)
++poppage(Page *p, int del)
+{
++ Page *t, *prev, *next;
++
+ if(p == nil)
+ return nil;
-+ /* to remove(2) subpages in documents makes no sense, and just
-+ * removing a subentry doesn't seem like a feature worth the bother */
-+ if(p->up != root)
++ if(p == root)
+ return p;
-+ if(p->fd >= 0)
-+ close(p->fd);
-+ p->fd = -1;
-+ if(remove(p->name) < 0){
-+ fprint(2, "remove %s: %r", p->name);
-+ return p;
++ if(del){
++ if(!(access(p->name, OREAD) == 0 && remove(p->name) == 0
++ || p->data != nil && access(p->data, OREAD) == 0 && remove(p->data) == 0)){
++ fprint(2, "remove %s: %r", p->name);
++ return p;
++ }
+ }
-+ return poppage(p);
++ qlock(&pagelock);
++ for(t = p->down, prev = p; t != nil && t->up != p->up; prev = t, t = next){
++ qlock(t);
++ next = freepage(t, prev);
++ qunlock(t);
++ }
++ p->down = nil;
++ prev = prevpage(p);
++ next = freepage(p, prev);
++ qunlock(&pagelock);
++ qunlock(p);
++ if(next != nil){
++ forward = 1;
++ return next;
++ }
++ forward = -1;
++ return prev;
+}
+
/*
* A draw operation that touches only the area contained in bot but not in top.
* mp and sp get aligned with bot.min.
-@@ -1461,6 +1533,7 @@
+@@ -1460,8 +1532,10 @@
+ {
char buf[NPATH], *s;
Point o;
- int fd;
+- int fd;
++ int fd, del;
+ Page *p;
++ del = 0;
switch(i){
case Corigsize:
-@@ -1546,6 +1619,32 @@
+ pos = ZP;
+@@ -1545,6 +1619,25 @@
+ break;
case Csnarf:
writeaddr(current, "/dev/snarf");
- break;
++ break;
++ case Cdelete:
++ del = 1;
++ /* wet floor */
+ case Cpop:
+ if(current == nil || !canqlock(current))
+ break;
-+ if((p = poppage(current)) == current){
++ if((p = poppage(current, del)) == current){
+ qunlock(current);
+ break;
+ }
-+ Reset:
-+ current = p;
-+ if(current == nil){
++ if((current = p) == nil){
+ drawlock(0);
+ draw(screen, screen->r, paper, nil, ZP);
+ drawframe(screen->r);
@@ -132,15 +138,6 @@
+ break;
+ }
+ showpage(current);
-+ break;
-+ case Cdelete:
-+ if(current == nil || !canqlock(current))
-+ break;
-+ if((p = delpage(current)) == current){
-+ qunlock(current);
-+ break;
-+ }
-+ goto Reset;
+ break;
case Cnext:
forward = 1;
- showpage(nextpage(current));