static void *ileaf_resize(struct btree *btree, tuxkey_t inum, vleaf *base, unsigned newsize) { assert(ileaf_sniff(btree, base)); struct ileaf *leaf = base; assert(inum >= ibase(leaf)); be_u16 *dict = base + btree->sb->blocksize; unsigned at = inum - ibase(leaf); if (at >= btree->entries_per_leaf) return NULL; unsigned extend_empty = at < icount(leaf) ? 0 : at - icount(leaf) + 1; unsigned offset = at && icount(leaf) ? from_be_u16(*(dict - (at < icount(leaf) ? at : icount(leaf)))) : 0; unsigned size = at < icount(leaf) ? from_be_u16(*(dict - at - 1)) - offset : 0; int more = newsize - size; if (more > 0 && sizeof(*dict) * extend_empty + more > ileaf_free(btree, leaf)) return NULL; for (; extend_empty--; leaf->count = to_be_u16(from_be_u16(leaf->count) + 1)) *(dict - icount(leaf) - 1) = to_be_u16(atdict(dict, icount(leaf))); assert(icount(leaf)); unsigned itop = from_be_u16(*(dict - icount(leaf))); void *attrs = leaf->table + offset; printf("resize inum 0x%Lx at 0x%x from %x to %x\n", (L)inum, offset, size, newsize); assert(itop >= offset + size); memmove(attrs + newsize, attrs + size, itop - offset - size); for (int i = at + 1; i <= icount(leaf); i++) add_idict(dict - i, more); return attrs; }
static void ileaf_trim(struct btree *btree, struct ileaf *leaf) { be_u16 *dict = (void *)leaf + btree->sb->blocksize; while (icount(leaf) > 1 && *(dict - icount(leaf)) == *(dict - icount(leaf) + 1)) leaf->count = to_be_u16(from_be_u16(leaf->count) - 1); if (icount(leaf) == 1 && !*(dict - 1)) leaf->count = 0; }
static void ileaf_dump(struct btree *btree, vleaf *vleaf) { struct sb *sb = btree->sb; struct ileaf *leaf = vleaf; inum_t inum = ibase(leaf); be_u16 *dict = vleaf + sb->blocksize; unsigned offset = 0; printf("inode table block 0x%Lx/%i (%x bytes free)\n", (L)ibase(leaf), icount(leaf), ileaf_free(btree, leaf)); //hexdump(dict - icount(leaf), icount(leaf) * 2); for (int i = -1; -i <= icount(leaf); i--, inum++) { int limit = from_be_u16(dict[i]), size = limit - offset; if (!size) continue; printf(" 0x%Lx: ", (L)inum); //printf("[%x] ", offset); if (size < 0) printf("<corrupt>\n"); else if (!size) printf("<empty>\n"); else { /* FIXME: this doesn't work in kernel */ struct inode inode = { .i_sb = vfs_sb(btree->sb) }; unsigned xsize = decode_xsize(&inode, leaf->table + offset, size); tux_inode(&inode)->xcache = xsize ? new_xcache(xsize) : NULL; decode_attrs(&inode, leaf->table + offset, size); dump_attrs(&inode); xcache_dump(&inode); free(tux_inode(&inode)->xcache); } offset = limit; } } void *ileaf_lookup(struct btree *btree, inum_t inum, struct ileaf *leaf, unsigned *result) { assert(inum >= ibase(leaf)); assert(inum < ibase(leaf) + btree->entries_per_leaf); unsigned at = inum - ibase(leaf), size = 0; void *attrs = NULL; printf("lookup inode 0x%Lx, %Lx + %x\n", (L)inum, (L)ibase(leaf), at); if (at < icount(leaf)) { be_u16 *dict = (void *)leaf + btree->sb->blocksize; unsigned offset = atdict(dict, at); if ((size = from_be_u16(*(dict - at - 1)) - offset)) attrs = leaf->table + offset; } *result = size; return attrs; }
inum_t find_empty_inode(struct btree *btree, struct ileaf *leaf, inum_t goal) { assert(goal >= ibase(leaf)); goal -= ibase(leaf); //printf("find empty inode starting at %Lx, base %Lx\n", (L)goal, (L)ibase(leaf)); be_u16 *dict = (void *)leaf + btree->sb->blocksize; unsigned i, offset = goal && goal < icount(leaf) ? from_be_u16(*(dict - goal)) : 0; for (i = goal; i < icount(leaf); i++) { unsigned limit = from_be_u16(*(dict - i - 1)); if (offset == limit) break; offset = limit; } return i + ibase(leaf); }
/* * Chop inums * return value: * < 0 - error * 1 - modified * 0 - not modified */ static int ileaf_chop(struct btree *btree, tuxkey_t start, u64 len, void *leaf) { struct ileaf *ileaf = leaf; __be16 *dict = ileaf_dict(btree, leaf); tuxkey_t base = ibase(ileaf); unsigned count = icount(ileaf); tuxkey_t at = start - base; void *startp, *endp, *tailp; unsigned size; if (at + 1 > count) return 0; len = min_t(u64, len, count - at); startp = ileaf->table + atdict(dict, at); endp = ileaf->table + atdict(dict, at + len); if (startp == endp) return 0; /* Remove data */ tailp = ileaf->table + atdict(dict, count); memmove(startp, endp, tailp - endp); /* Adjust dict */ size = endp - startp; while (at < count) { at++; add_idict(dict - at, -size); } ileaf_trim(btree, leaf); return 1; }
/* * Find free inum * (callback for btree_traverse()) * * return value: * 1 - found * 0 - not found */ int ileaf_find_free(struct btree *btree, tuxkey_t key_bottom, tuxkey_t key_limit, void *leaf, tuxkey_t key, u64 len, void *data) { tuxkey_t at = key - ibase(leaf); unsigned count = icount(leaf); key_limit = min(key_limit, key + len); if (at < count) { __be16 *dict = ileaf_dict(btree, leaf); unsigned limit, offset = atdict(dict, at); while (at < count) { at++; limit = __atdict(dict, at); if (offset == limit) { at--; break; } offset = limit; } } if (ibase(leaf) + at < key_limit) { *(inum_t *)data = ibase(leaf) + at; return 1; } return 0; }
/* vorbis_info is for range checking */ vorbis_info_residue *res0_unpack(vorbis_info *vi,oggpack_buffer *opb){ int j,acc=0; vorbis_info_residue0 *info=(vorbis_info_residue0 *)_ogg_calloc(1,sizeof(*info)); codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; info->begin=oggpack_read(opb,24); info->end=oggpack_read(opb,24); info->grouping=oggpack_read(opb,24)+1; info->partitions=oggpack_read(opb,6)+1; info->groupbook=oggpack_read(opb,8); for(j=0;j<info->partitions;j++){ int cascade=oggpack_read(opb,3); if(oggpack_read(opb,1)) cascade|=(oggpack_read(opb,5)<<3); info->secondstages[j]=cascade; acc+=icount(cascade); } for(j=0;j<acc;j++) info->booklist[j]=oggpack_read(opb,8); if(info->groupbook>=ci->books)goto errout; for(j=0;j<acc;j++) if(info->booklist[j]>=ci->books)goto errout; return(info); errout: res0_free_info(info); return(NULL); }
static int isinorder(struct btree *btree, struct ileaf *leaf) { be_u16 *dict = (void *)leaf + btree->sb->blocksize; for (int i = 0, offset = 0, limit; --i >= -icount(leaf); offset = limit) if ((limit = from_be_u16(dict[i])) < offset) return 0; return 1; }
static int ileaf_merge(struct btree *btree, void *vinto, void *vfrom) { struct ileaf *into = vinto, *from = vfrom; unsigned fromcount = icount(from); /* If "from" is empty, does nothing */ if (!fromcount) return 1; assert(ibase(from) > ibase(into)); tuxkey_t fromibase = ibase(from); unsigned count = icount(into); int hole = fromibase - ibase(into) + count; __be16 *dict = ileaf_dict(btree, into); __be16 *fromdict = ileaf_dict(btree, from); int need_size = hole * sizeof(*dict) + ileaf_need(btree, from); if (ileaf_free(btree, into) < need_size) return 0; /* Fill hole of dict until from_ibase */ unsigned limit = atdict(dict, count); __be16 __limit = cpu_to_be16(limit); while (hole--) { count++; *(dict - count) = __limit; } /* Copy data from "from" */ unsigned fromlimit = atdict(fromdict, fromcount); memcpy(into->table + limit, from->table, fromlimit); /* Adjust copying fromdict */ if (limit) { int i; for (i = 1; i <= fromcount; i++) add_idict(dict - i, limit); } veccopy(dict - count - fromcount, fromdict - fromcount, fromcount); into->count = cpu_to_be16(count + fromcount); return 1; }
static int isinorder(struct btree *btree, struct ileaf *leaf) { __be16 *dict = ileaf_dict(btree, leaf); for (int i = 0, offset = 0, limit; i < icount(leaf); i++, offset = limit) if ((limit = __atdict(dict, i + 1)) < offset) return 0; return 1; }
int ileaf_purge(struct btree *btree, inum_t inum, struct ileaf *leaf) { if (inum < ibase(leaf) || inum - ibase(leaf) >= btree->entries_per_leaf) return -EINVAL; be_u16 *dict = (void *)leaf + btree->sb->blocksize; unsigned at = inum - ibase(leaf); unsigned offset = atdict(dict, at); unsigned size = from_be_u16(*(dict - at - 1)) - offset; printf("delete inode %Lx from %p[%x/%x]\n", (L)inum, leaf, at, size); if (!size) return -ENOENT; unsigned free = from_be_u16(*(dict - icount(leaf))), tail = free - offset - size; assert(offset + size + tail <= free); memmove(leaf->table + offset, leaf->table + offset + size, tail); for (int i = at + 1; i <= icount(leaf); i++) add_idict(dict - i, -size); ileaf_trim(btree, leaf); return 0; }
static void ileaf_trim(struct btree *btree, struct ileaf *leaf) { __be16 *dict = ileaf_dict(btree, leaf); unsigned count = icount(leaf); while (count > 1 && *(dict - count) == *(dict - count + 1)) count--; if (count == 1 && !*(dict - 1)) count = 0; leaf->count = cpu_to_be16(count); }
/* userland only */ void ileaf_merge(struct btree *btree, struct ileaf *leaf, struct ileaf *from) { if (!icount(from)) return; be_u16 *dict = (void *)leaf + btree->sb->blocksize; be_u16 *fromdict = (void *)from + btree->sb->blocksize; unsigned at = icount(leaf), free = atdict(dict, at), size = atdict(fromdict, icount(from)); printf("copy in %i bytes\n", size); memcpy(leaf->table + free, from->table, size); leaf->count = to_be_u16(from_be_u16(leaf->count) + icount(from)); veccopy(dict - icount(leaf), fromdict - icount(from), icount(from)); for (int i = at + 1; at && i <= at + icount(from); i++) add_idict(dict - i, from_be_u16(*(dict - at))); }
static void ileaf_dump(struct btree *btree, void *vleaf) { if (!tux3_trace) return; struct ileaf_attr_ops *attr_ops = btree->ops->private_ops; struct ileaf *leaf = vleaf; inum_t inum = ibase(leaf); __be16 *dict = ileaf_dict(btree, leaf); unsigned offset = 0; trace_on("inode table block 0x%Lx/%i (%x bytes free)", ibase(leaf), icount(leaf), ileaf_free(btree, leaf)); for (int i = 0; i < icount(leaf); i++, inum++) { int limit = __atdict(dict, i + 1), size = limit - offset; if (!size) continue; if (size < 0) trace_on(" 0x%Lx: <corrupt>\n", inum); else if (!size) trace_on(" 0x%Lx: <empty>\n", inum); else if (attr_ops == &iattr_ops) { /* FIXME: this doesn't work in kernel */ struct tux3_inode tuxnode = {}; struct inode *inode = &tuxnode.vfs_inode; void *attrs = leaf->table + offset; inode->i_sb = vfs_sb(btree->sb), attr_ops->decode(btree, inode, attrs, size); free_xcache(inode); } offset = limit; } }
static tuxkey_t ileaf_split_hint(struct btree *btree, struct ileaf *ileaf, tuxkey_t key, int size) { /* * FIXME: make sure there is space for size. * FIXME: better split position? */ tuxkey_t base = ibase(ileaf); unsigned count = icount(ileaf); if (key >= base + count) return key & ~(btree->entries_per_leaf - 1); return base + count / 2; }
void *ileaf_lookup(struct btree *btree, inum_t inum, struct ileaf *leaf, unsigned *result) { assert(inum >= ibase(leaf)); tuxkey_t at = inum - ibase(leaf), size = 0; void *attrs = NULL; trace("lookup inode 0x%Lx, %Lx + %Lx", inum, ibase(leaf), at); if (at < icount(leaf)) { __be16 *dict = ileaf_dict(btree, leaf); unsigned offset = atdict(dict, at); if ((size = __atdict(dict, at + 1) - offset)) attrs = leaf->table + offset; } *result = size; return attrs; }
static int ileaf_init(struct btree *btree, void *leaf) { struct ileaf_attr_ops *attr_ops = btree->ops->private_ops; trace("initialize inode leaf %p", leaf); *(struct ileaf *)leaf = (struct ileaf){ .magic = attr_ops->magic, }; return 0; } static int ileaf_need(struct btree *btree, struct ileaf *ileaf) { __be16 *dict = ileaf_dict(btree, ileaf); unsigned count = icount(ileaf); return atdict(dict, count) + count * sizeof(*dict); }
static int ileaf_init(struct btree *btree, vleaf *leaf) { printf("initialize inode leaf %p\n", leaf); *(struct ileaf *)leaf = (struct ileaf){ to_be_u16(0x90de) }; return 0; } static int ileaf_sniff(struct btree *btree, vleaf *leaf) { return ((struct ileaf *)leaf)->magic == to_be_u16(0x90de); } static unsigned ileaf_need(struct btree *btree, vleaf *vleaf) { be_u16 *dict = vleaf + btree->sb->blocksize; unsigned count = icount(to_ileaf(vleaf)); return atdict(dict, count) + count * sizeof(*dict); }
/* * Enumerate inum * (callback for btree_traverse()) */ int ileaf_enumerate(struct btree *btree, tuxkey_t key_bottom, tuxkey_t key_limit, void *leaf, tuxkey_t key, u64 len, void *data) { struct ileaf *ileaf = leaf; __be16 *dict = ileaf_dict(btree, ileaf); struct ileaf_enumrate_cb *cb = data; tuxkey_t at, base = ibase(ileaf); unsigned count; at = key - base; count = min_t(u64, key + len - base, icount(ileaf)); if (at < count) { unsigned offset = atdict(dict, at); for (; at < count; at++) { unsigned size, limit; inum_t inum; void *attrs; int err; limit = __atdict(dict, at + 1); if (limit <= offset) continue; attrs = ileaf->table + offset; size = limit - offset; inum = base + at; err = cb->callback(btree, inum, attrs, size, cb->data); if (err) return err; offset = limit; } } return 0; }
static vorbis_info_residue0 *_012_unpack(vorbis_info *vi,oggpack_buffer *opb) { int j,acc=0; vorbis_info_residue0 *info=_ogg_calloc(1,sizeof(*info)); codec_setup_info *ci=vi->codec_setup; info->begin=oggpack_read24(opb,24); info->len=oggpack_read24(opb,24)-info->begin; info->samples_per_partition=oggpack_read24(opb,24)+1; info->partitions=oggpack_read24(opb,6)+1; info->groupbook=oggpack_read24(opb,8); if(info->groupbook>=ci->books) goto errout; for(j=0;j<info->partitions;j++){ int cascade=oggpack_read24(opb,3); if(oggpack_read1(opb)) cascade|=(oggpack_read24(opb,5)<<3); info->secondstages[j]=cascade; acc+=icount(cascade); } for(j=0;j<acc;j++){ int list=oggpack_read24(opb,8); if(list>=ci->books) goto errout; info->booklist[j]=list; } return(info); errout: res012_free_info(info); return(NULL); }
static int ileaf_can_free(struct btree *btree, void *leaf) { struct ileaf *ileaf = leaf; return icount(ileaf) == 0; }
static tuxkey_t ileaf_split(struct btree *btree, tuxkey_t inum, vleaf *from, vleaf *into) { assert(ileaf_sniff(btree, from)); struct ileaf *leaf = from, *dest = into; be_u16 *dict = from + btree->sb->blocksize, *destdict = into + btree->sb->blocksize; #ifdef SPLIT_AT_INUM printf("split at inum 0x%Lx\n", (L)inum); assert(inum >= ibase(leaf)); unsigned at = inum - ibase(leaf) < icount(leaf) ? inum - ibase(leaf) : icount(leaf); #else /* binsearch inum starting nearest middle of block */ unsigned at = 1, hi = icount(leaf); while (at < hi) { int mid = (at + hi) / 2; if (*(dict - mid) < (btree->sb->blocksize / 2)) at = mid + 1; else hi = mid; } #endif /* should trim leading empty inodes on copy */ unsigned split = atdict(dict, at), free = from_be_u16(*(dict - icount(leaf))); printf("split at %x of %x\n", at, icount(leaf)); printf("copy out %x bytes at %x\n", free - split, split); assert(free >= split); memcpy(dest->table, leaf->table + split, free - split); dest->count = to_be_u16(icount(leaf) - at); veccopy(destdict - icount(dest), dict - icount(leaf), icount(dest)); for (int i = 1; i <= icount(dest); i++) add_idict(destdict - i, -split); #ifdef SPLIT_AT_INUM /* round down to multiple of 64 above ibase */ inum_t round = inum & ~(inum_t)(btree->entries_per_leaf - 1); dest->ibase = to_be_u64(round > ibase(leaf) + icount(leaf) ? round : inum); #else dest->ibase = to_be_u64(ibase(leaf) + at); #endif leaf->count = to_be_u16(at); memset(leaf->table + split, 0, (char *)(dict - icount(leaf)) - (leaf->table + split)); ileaf_trim(btree, leaf); return ibase(dest); }
static void *ileaf_resize(struct btree *btree, tuxkey_t inum, void *vleaf, int newsize) { struct ileaf *ileaf = vleaf; __be16 *dict = ileaf_dict(btree, ileaf); unsigned count = icount(ileaf); tuxkey_t at = inum - ibase(ileaf); int extend_dict, offset, size; assert(inum >= ibase(ileaf)); /* Get existent attributes, and calculate expand/shrink size */ if (at + 1 > count) { /* Check size roughly to avoid overflow int */ if ((at + 1) * sizeof(*dict) >= btree->sb->blocksize) goto overflow; /* Need to extend dict */ extend_dict = (at + 1 - count) * sizeof(*dict); offset = atdict(dict, count); size = 0; } else { /* "at" is in dict, so get attr size */ extend_dict = 0; offset = atdict(dict, at); size = __atdict(dict, at + 1) - offset; } if (ileaf_free(btree, ileaf) < newsize - size + extend_dict) { overflow: return NULL; } /* Extend dict */ if (extend_dict) { __be16 limit = cpu_to_be16(atdict(dict, count)); while (count < at + 1) { count++; *(dict - count) = limit; } ileaf->count = cpu_to_be16(count); } void *attrs = ileaf->table + offset; if (newsize != size) { /* Expand/Shrink attr space */ unsigned limit = __atdict(dict, count); assert(limit >= offset + size); memmove(attrs + newsize, attrs + size, limit - offset - size); /* Adjust dict */ int diff = newsize - size; at++; while (at <= count) { add_idict(dict - at, diff); at++; } } return attrs; }
/* vorbis_info is for range checking */ vorbis_info_residue *res0_unpack(vorbis_info *vi,oggpack_buffer *opb){ int j,acc=0; vorbis_info_residue0 *info=(vorbis_info_residue0 *)_ogg_calloc(1,sizeof(*info)); codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; info->begin=oggpack_read(opb,24); info->end=oggpack_read(opb,24); info->grouping=oggpack_read(opb,24)+1; info->partitions=oggpack_read(opb,6)+1; info->groupbook=oggpack_read(opb,8); /* check for premature EOP */ if(info->groupbook<0)goto errout; for(j=0;j<info->partitions;j++){ int cascade=oggpack_read(opb,3); int cflag=oggpack_read(opb,1); if(cflag<0) goto errout; if(cflag){ int c=oggpack_read(opb,5); if(c<0) goto errout; cascade|=(c<<3); } info->secondstages[j]=cascade; acc+=icount(cascade); } for(j=0;j<acc;j++){ int book=oggpack_read(opb,8); if(book<0) goto errout; info->booklist[j]=book; } if(info->groupbook>=ci->books)goto errout; for(j=0;j<acc;j++){ if(info->booklist[j]>=ci->books)goto errout; if(ci->book_param[info->booklist[j]]->maptype==0)goto errout; } /* verify the phrasebook is not specifying an impossible or inconsistent partitioning scheme. */ /* modify the phrasebook ranging check from r16327; an early beta encoder had a bug where it used an oversized phrasebook by accident. These files should continue to be playable, but don't allow an exploit */ { int entries = ci->book_param[info->groupbook]->entries; int dim = ci->book_param[info->groupbook]->dim; int partvals = 1; if (dim<1) goto errout; while(dim>0){ partvals *= info->partitions; if(partvals > entries) goto errout; dim--; } info->partvals = partvals; } return(info); errout: res0_free_info(info); return(NULL); }
void io_stream_t::conn_proc(int fd, netaddr_t *netaddr) const { fd_guard_t fd_guard(fd); class netaddr_guard_t { netaddr_t *netaddr; public: inline netaddr_guard_t(netaddr_t *_netaddr) throw() : netaddr(_netaddr) { } inline ~netaddr_guard_t() throw() { delete netaddr; } } netaddr_guard(netaddr); bq_fd_setup(fd); bq_conn_t *conn = transport.new_connect(fd, ctl(), remote_errors); class conn_guard_t { bq_conn_t *conn; io_stream::mmconns_t &mmconns; public: inline conn_guard_t(bq_conn_t *_conn, stat_t &stat) throw() : conn(_conn), mmconns(stat.mmconns()) { ++mmconns; } inline ~conn_guard_t() throw() { --mmconns; delete conn; } } conn_guard(conn, stat); conn->setup_accept(); netaddr_t const &local_addr = bind_addr(); bq_in_t in(*conn, ibuf_size, &stat.icount()); for(bool work = true; work;) { { char obuf[obuf_size]; bq_out_t out(*conn, obuf, sizeof(obuf), &stat.ocount()); in_t::ptr_t ptr(in); do { in.timeout_set(timeout); out.timeout_set(timeout); work = proto.request_proc(ptr, out, local_addr, *netaddr); ++stat.reqs(); if(!work) break; } while(in.truncate(ptr)); } if(work) { short int events = POLLIN; interval_t _keepalive = keepalive; if(bq_poll(fd, events, &_keepalive) < 0) break; } } conn->shutdown(); }
static tuxkey_t ileaf_split(struct btree *btree, tuxkey_t hint, void *from, void *into) { assert(ileaf_sniff(btree, from)); struct ileaf *leaf = from, *dest = into; __be16 *dict = ileaf_dict(btree, from); __be16 *destdict = ileaf_dict(btree, into); #ifdef SPLIT_AT_INUM /* * This is to prevent to have same ibase on both of from and into * FIXME: we would want to split at better position. */ if (hint == ibase(leaf)) hint++; trace("split at inum 0x%Lx", hint); unsigned at = min_t(tuxkey_t, hint - ibase(leaf), icount(leaf)); #else /* binsearch inum starting nearest middle of block */ unsigned at = 1, hi = icount(leaf); while (at < hi) { int mid = (at + hi) / 2; if (*(dict - mid) < (btree->sb->blocksize / 2)) at = mid + 1; else hi = mid; } #endif /* should trim leading empty inodes on copy */ unsigned split = atdict(dict, at), free = atdict(dict, icount(leaf)); trace("split at %x of %x", at, icount(leaf)); trace("copy out %x bytes at %x", free - split, split); assert(free >= split); memcpy(dest->table, leaf->table + split, free - split); dest->count = cpu_to_be16(icount(leaf) - at); veccopy(destdict - icount(dest), dict - icount(leaf), icount(dest)); for (int i = 1; i <= icount(dest); i++) add_idict(destdict - i, -split); #ifdef SPLIT_AT_INUM /* round down to multiple of 64 above ibase */ inum_t round = hint & ~(inum_t)(btree->entries_per_leaf - 1); dest->ibase = cpu_to_be64(round > ibase(leaf) + icount(leaf) ? round : hint); #else dest->ibase = cpu_to_be64(ibase(leaf) + at); #endif leaf->count = cpu_to_be16(at); memset(leaf->table + split, 0, (char *)(dict - icount(leaf)) - (leaf->table + split)); ileaf_trim(btree, leaf); return ibase(dest); }