pages.c (3327B)
1 #include <u.h> 2 #include <libc.h> 3 4 #include "pages.h" 5 6 Array * 7 allocarray(long len) 8 { 9 Array *new = malloc(sizeof(ArHeader) + len); 10 assert(new != nil); 11 new->len = len; 12 new->ref = 0; 13 return new; 14 } 15 16 ArSlice * 17 allocarslice(Array *ar, long start, long len) 18 { 19 ArSlice *new = malloc(sizeof(ArSlice)); 20 new->ar = ar; 21 new->p = ar->p + start; 22 new->len = len; 23 new->cap = ar->len - start; 24 assert(start + len <= ar->len); 25 return new; 26 } 27 28 Page * 29 allocpage(void) 30 { 31 Array *ar = allocarray(PageSize); 32 memset(ar->p, '?', PageSize); 33 ArSlice *as = allocarslice(ar, 0, PageSize); 34 ar->ref++; 35 Page *new = malloc(sizeof(Page)); 36 new->as = as; 37 new->prev = nil; 38 new->next = nil; 39 return new; 40 } 41 42 Page * 43 duppage(Page *old) 44 { 45 Page *new = malloc(sizeof(Page)); 46 ArSlice *as = malloc(sizeof(ArSlice)); 47 new->as = as; 48 new->prev = old->prev; 49 new->next = old->next; 50 as->ar = old->as->ar; 51 as->p = old->as->p; 52 as->len = old->as->len; 53 as->cap = old->as->cap; 54 as->ar->ref++; 55 return new; 56 } 57 58 void 59 freepage(Page *pg) 60 { 61 pg->as->ar->ref--; 62 if (pg->as->ar->ref <= 0) { 63 free(pg->as->ar); 64 } 65 free(pg->as); 66 free(pg); 67 } 68 69 long 70 pbwrite(PBuf *pb, void *buf, long nbytes, vlong offset) 71 { 72 Page *pgpt; 73 long n, nwritten = 0; 74 75 // TODO: move this section to fs.c/fwrite/fdata 76 // or create separate pbgrow() function 77 // also, last page's len should be shortened accordingly 78 // [[[ 79 while (offset + nbytes > pb->size) { 80 addpage(pb); 81 } 82 if (pb->length < offset + nbytes) pb->length = offset + nbytes; 83 // ]]] 84 85 pgpt = pb->start; 86 if (offset >= pb->length) nbytes = 0; 87 if (offset + nbytes >= pb->length) { 88 nbytes = (pb->length - offset); 89 } 90 while (nbytes > 0) { 91 if (pgpt == nil) { 92 break; 93 } 94 if (offset >= pgpt->as->len) { 95 offset -= pgpt->as->len; 96 pgpt = pgpt->next; 97 continue; 98 } 99 n = nbytes; 100 if (pgpt->as->len - offset < n) n = pgpt->as->len - offset; 101 memcpy(pgpt->as->p + offset, buf, n); 102 nwritten += n; 103 buf = (char *)buf + n; 104 offset += n; 105 nbytes -= n; 106 } 107 return nwritten; 108 } 109 110 long 111 pbread(PBuf *pb, void *buf, long nbytes, vlong offset) 112 { 113 Page *pgpt = pb->start; 114 long n, nread = 0; 115 if (offset >= pb->length) nbytes = 0; 116 if (offset + nbytes >= pb->length) { 117 nbytes = (pb->length - offset); 118 } 119 while (nbytes > 0) { 120 if (pgpt == nil) { 121 break; 122 } 123 if (offset >= pgpt->as->len) { 124 offset -= pgpt->as->len; 125 pgpt = pgpt->next; 126 continue; 127 } 128 n = nbytes; 129 if (pgpt->as->len - offset < n) n = pgpt->as->len - offset; 130 memcpy(buf, pgpt->as->p + offset, n); 131 nread += n; 132 buf = (char *)buf + n; 133 offset += n; 134 nbytes -= n; 135 } 136 return nread; 137 } 138 139 Page * 140 addpage(PBuf *pb) 141 { 142 Page *new = allocpage(); 143 if ((pb->start == nil) || (pb->end == nil)) { 144 pb->start = new; 145 pb->end = new; 146 } else { 147 new->prev = pb->end; 148 pb->end->next = new; 149 pb->end = new; 150 } 151 pb->size += new->as->len; 152 return new; 153 } 154 155 Page * 156 splitpage(PBuf *pb, vlong offset) 157 { 158 vlong d, count = 0; 159 Page *sp = pb->start; 160 // find page at offset 161 while ((sp != nil) && (count + sp->as->len < offset)) { 162 count += sp->as->len; 163 sp = sp->next; 164 } 165 if (sp == nil) return nil; 166 d = offset - count; 167 if (d > 0) { 168 Page *np = duppage(sp); 169 np->as->len = d; 170 np->next = sp; 171 if (np->prev != nil) np->prev->next = np; 172 else pb->start = np; 173 sp->as->len -= d; 174 sp->as->cap -= d; 175 sp->as->p += d; 176 sp->prev = np; 177 } 178 return sp; 179 }