commit c26ca5332605a4fb9d201a79fc1fdb8b1e6385d0
parent ba7b99c16f3b734f1d1cb4facb194b57aececd20
Author: glenda <glenda@kobeni>
Date: Sun, 18 Feb 2024 18:40:52 +0000
fs: implement fcut trunc
Diffstat:
M | fs.c | | | 65 | +++++++++++++++++++++++++++++++++++++++-------------------------- |
M | pages.c | | | 26 | ++++++++++++++++++++++++++ |
M | pages.h | | | 1 | + |
3 files changed, 66 insertions(+), 26 deletions(-)
diff --git a/fs.c b/fs.c
@@ -22,6 +22,7 @@ void fs_open(Req *r);
void fs_read(Req *r);
void fs_write(Req *r);
+void fcut_open(Req *r);
void fcut_write(Req *r);
void normalize_sel(void);
@@ -73,14 +74,12 @@ fs_open(Req *r)
char *rstr = nil;
File *file = r->fid->file;
uchar mode = r->ifcall.mode;
- if ((mode & OTRUNC) == 0) goto end;
- if (file == fctl) goto end;
if (file == fcut) {
- // if needed split pages at 'min' and 'max' in two
- // remove pages from min to max
- rstr = "trunc not implemented yet";
+ fcut_open(r);
goto end;
}
+ if ((mode & OTRUNC) == 0) goto end;
+ if (file == fctl) goto end;
if (file == fdata) {
pg.length = 0;
fdata->length = 0;
@@ -162,37 +161,51 @@ fs_write(Req *r)
}
void
+fcut_open(Req *r)
+{
+ vlong min, max;
+ min = sel.min * FrameSize;
+ max = sel.max * FrameSize;
+
+ if ((r->ifcall.mode & OTRUNC) != 0) {
+ Page *maxpg = splitpage(&pg, max);
+ Page *minpg = splitpage(&pg, min);
+ assert(minpg != nil);
+ assert(maxpg != nil);
+ if (minpg->prev != nil) {
+ minpg->prev->next = maxpg;
+ maxpg->prev = minpg->prev;
+ } else {
+ pg.start = maxpg;
+ maxpg->prev = nil;
+ }
+ while (minpg != maxpg) {
+ Page *fp = minpg;
+ fp->as->len = 0;
+ minpg = fp->next;
+ freepage(fp);
+ }
+ pg.length -= max - min;
+ fdata->length = pg.length;
+ fcut->length = 0;
+ sel.max = sel.min;
+ normalize_sel();
+ }
+}
+
+void
fcut_write(Req *r)
{
Page *maxpage;
vlong min, max, offset;
- long count, d;
+ long count;
min = sel.min * FrameSize;
max = sel.max * FrameSize;
- // find page that 'max' lands on
- offset = 0;
- maxpage = pg.start;
- while ((maxpage != nil) && (offset + maxpage->as->len < max)) {
- offset += maxpage->as->len;
- maxpage = maxpage->next;
- }
+ maxpage = splitpage(&pg, max);
if (maxpage == nil) {
maxpage = addpage(&pg);
}
- d = max - offset;
- if (d > 0) {
- // split page in two
- Page *s = duppage(maxpage);
- s->as->len = d;
- s->next = maxpage;
- if (s->prev != nil) s->prev->next = s;
- else pg.start = s;
- maxpage->as->len -= d;
- maxpage->as->cap -= d;
- maxpage->as->p += d;
- maxpage->prev = s;
- }
// insert more pages as needed
offset = r->ifcall.offset + min;
count = r->ifcall.count;
diff --git a/pages.c b/pages.c
@@ -151,3 +151,29 @@ addpage(PBuf *pb)
pb->size += new->as->len;
return new;
}
+
+Page *
+splitpage(PBuf *pb, vlong offset)
+{
+ vlong d, count = 0;
+ Page *sp = pb->start;
+ // find page at offset
+ while ((sp != nil) && (count + sp->as->len < offset)) {
+ count += sp->as->len;
+ sp = sp->next;
+ }
+ if (sp == nil) return nil;
+ d = offset - count;
+ if (d > 0) {
+ Page *np = duppage(sp);
+ np->as->len = d;
+ np->next = sp;
+ if (np->prev != nil) np->prev->next = np;
+ else pb->start = np;
+ sp->as->len -= d;
+ sp->as->cap -= d;
+ sp->as->p += d;
+ sp->prev = np;
+ }
+ return sp;
+}
diff --git a/pages.h b/pages.h
@@ -52,3 +52,4 @@ Page * allocpage(void);
Page * duppage(Page *);
void freepage(Page *);
Page * addpage(PBuf *pb);
+Page * splitpage(PBuf *pb, vlong offset);