Attempting to add weight changes to every rbyd append

This does not work as is due to ambiguity with grows and insertions.

Before, these were disambiguated by seperate grow and attr tags. You
effectively grew the neighboring id before claiming its weight
as yours. But now that the attr itself creates the grow/insertion,
it's ambiguous which one is intended.
This commit is contained in:
Christopher Haster
2023-03-30 01:00:55 -05:00
parent e5cd2904ee
commit 5a1c36f210
5 changed files with 1486 additions and 986 deletions
+193 -102
View File
@@ -449,7 +449,7 @@ static inline lfs_size_t lfs_tag_dsize(lfs_tag_t tag) {
// 16-bit metadata tags
enum lfsr_tag_type {
LFSR_TAG_UNREACHABLE = 0x0002,
LFSR_TAG_UNR = 0x0002,
LFSR_TAG_NAME = 0x1000,
LFSR_TAG_BNAME = 0x1000,
@@ -475,9 +475,10 @@ enum lfsr_tag_type {
LFSR_TAG_FCRC = 0x1004,
// in-device only
LFSR_TAG_GROW = 0x0006,
LFSR_TAG_SHRINK = 0x0016,
LFSR_TAG_FROM = 0x0026,
LFSR_TAG_NOOP = 0x0006,
LFSR_TAG_GROW = 0x0016,
LFSR_TAG_SHRINK = 0x0026,
LFSR_TAG_FROM = 0x0036,
};
#define LFSR_TAG_ALT_(color, dir, key) \
@@ -727,13 +728,60 @@ struct lfs_diskoff {
struct lfsr_attr {
lfsr_tag_t tag;
lfs_ssize_t id;
lfs_ssize_t delta;
lfsr_data_t data;
const struct lfsr_attr *next;
};
#define LFSD_ATTR_(_tag, _id, _delta, _buf, _len, _next) \
(&(const struct lfsr_attr){ \
_tag, _id, _delta, \
LFSR_DATA_BUF(_buf, _len), \
_next})
#define LFSD_ATTR(_type, _id, _delta, _buf, _len, _next) \
LFSD_ATTR_(LFSR_TAG_##_type, _id, _delta, _buf, _len, _next)
#define LFSD_ATTR_DISK_(_tag, _id, _delta, _block, _off, _len, _next) \
(&(const struct lfsr_attr){ \
_tag, _id, _delta, \
LFSR_DATA_DISK(_block, _off, _len), \
_next})
#define LFSD_ATTR_DISK(_type, _id, _delta, _block, _off, _len, _next) \
LFSD_ATTR_DISK_(LFSR_TAG_##_type, _id, _delta, _block, _off, _len, _next)
#define LFSD_ATTR_IF_(_pred, _tag, _id, _delta, _buf, _len, _next) \
LFSD_ATTR_( \
(_pred) ? (_tag) : LFSR_TAG_NOOP, \
_id, \
_delta, \
_buf, \
(_pred) ? (_len) : 0, \
_next)
#define LFSD_ATTR_IF(_pred, _type, _id, _delta, _buf, _len, _next) \
LFSD_ATTR_IF_(_pred, LFSR_TAG_##_type, _id, _delta, _buf, _len, _next)
#define LFSD_ATTR_DISK_IF_(_pred, \
_tag, _id, _delta, _block, _off, _len, _next) \
LFSD_ATTR_DISK_( \
(_pred) ? (_tag) : LFSD_TAG_NOOP, \
_id, \
_delta, \
_block, \
_off, \
(_pred) ? (_len) : 0, \
_next)
#define LFSD_ATTR_DISK_IF(_pred, \
_type, _id, _delta, _block, _off, _len, _next) \
LFSD_ATTR_DISK_IF_(_pred, \
LFSD_TAG_##_type, _id, _delta, _block, _off, _len, _next)
#define LFSR_ATTR_(_tag, _id, _buf, _len, _next) \
(&(const struct lfsr_attr){ \
_tag, _id, \
_tag, _id, 0, \
LFSR_DATA_BUF(_buf, _len), \
_next})
@@ -742,7 +790,7 @@ struct lfsr_attr {
#define LFSR_ATTR_DISK_(_tag, _id, _block, _off, _len, _next) \
(&(const struct lfsr_attr){ \
_tag, _id, \
_tag, _id, 0, \
LFSR_DATA_DISK(_block, _off, _len), \
_next})
@@ -751,7 +799,7 @@ struct lfsr_attr {
#define LFSR_ATTR_IF_(_pred, _tag, _id, _buf, _len, _next) \
LFSR_ATTR_( \
(_pred) ? (_tag) : LFSR_TAG_GROW, \
(_pred) ? (_tag) : LFSR_TAG_NOOP, \
_id, \
_buf, \
(_pred) ? (_len) : 0, \
@@ -762,7 +810,7 @@ struct lfsr_attr {
#define LFSR_ATTR_DISK_IF_(_pred, _tag, _id, _block, _off, _len, _next) \
LFSR_ATTR_DISK_( \
(_pred) ? (_tag) : LFSR_TAG_GROW, \
(_pred) ? (_tag) : LFSR_TAG_NOOP, \
_id, \
_block, \
_off, \
@@ -1882,7 +1930,7 @@ static void lfsr_rbyd_p_red(
p_weights[0] = weight_;
p_jumps[0] = jump_;
} else {
LFS_ASSERT(false);
LFS_UNREACHABLE();
}
}
}
@@ -1890,7 +1938,9 @@ static void lfsr_rbyd_p_red(
// core rbyd algorithm
static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
lfsr_tag_t tag, lfs_ssize_t id, lfsr_data_t data) {
lfsr_tag_t tag, lfs_ssize_t id, lfs_ssize_t delta,
lfsr_data_t data) {
printf("append w=%d id=%d d=%d\n", rbyd->weight, id, delta);
LFS_ASSERT(tag != 0);
// we can't do anything if we're not erased
@@ -1898,6 +1948,12 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
return LFS_ERR_RANGE;
}
// TODO do we really need this?
// ignore noops
if (tag == LFSR_TAG_NOOP) {
return 0;
}
// make sure every rbyd starts with its revision count
if (rbyd->off == 0) {
uint32_t rev;
@@ -1926,51 +1982,26 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
//
// note lfsr_rbyd_commit will throw out this copy of the rbyd if an
// error occurs
lfsr_tag_t tag_;
lfs_ssize_t id_;
lfsr_tag_t other_tag_;
lfs_ssize_t other_id_;
if (tag == LFSR_TAG_GROW) {
// noop?
if (lfsr_data_len(data) == 0) {
return 0;
}
LFS_ASSERT(id <= rbyd->weight);
rbyd->weight += lfsr_data_len(data);
LFS_ASSERT(delta >= -(lfs_ssize_t)rbyd->weight);
LFS_ASSERT(id <= rbyd->weight + delta);
rbyd->weight += delta;
lfs_ssize_t id_ = id-delta - lfs_smax32(-delta, 0);
lfs_ssize_t other_id_ = id-delta;
lfsr_tag_t tag_ = lfsr_tag_isrm(tag) ? tag & ~0x2 : tag;
lfsr_tag_t other_tag_ = lfsr_tag_isrm(tag) ? (tag & ~0x2) + 0x10 : tag;
// TODO need this?
// TODO restructure with above?
if (delta > 0) {
id_ += 1;
other_id_ += 1;
tag_ = 0;
id_ = id;
other_tag_ = tag_;
other_id_ = id_;
} else if (tag == LFSR_TAG_SHRINK) {
// noop?
if (lfsr_data_len(data) == 0) {
return 0;
}
LFS_ASSERT(id < rbyd->weight);
LFS_ASSERT(lfsr_data_len(data) <= rbyd->weight);
rbyd->weight -= lfsr_data_len(data);
tag_ = 0;
id_ = id;
other_tag_ = tag_;
other_id_ = id_ + lfsr_data_len(data);
} else if (lfsr_tag_isrm(tag)) {
LFS_ASSERT(id < rbyd->weight);
tag_ = tag & ~0x2;
id_ = id;
other_tag_ = tag_ + 0x10;
other_id_ = id_;
} else {
LFS_ASSERT(id < rbyd->weight);
tag_ = tag;
id_ = id;
other_tag_ = tag_;
other_id_ = id_;
other_tag_ = 0;
}
printf("ids %d..%d\n", id_, other_id_);
// diverged state in case we are removing a range from the tree
//
// this is a second copy of the search path state, used to keep track
@@ -2012,19 +2043,19 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
lfsr_tag_t alt;
lfs_ssize_t weight;
lfs_off_t jump;
lfs_ssize_t delta = lfsr_rbyd_readtag(lfs,
lfs_ssize_t d = lfsr_rbyd_readtag(lfs,
&lfs->pcache, &lfs->rcache, 0,
rbyd->block, branch, &alt, &weight, &jump, NULL);
if (delta < 0) {
if (d < 0) {
rbyd->erased = false;
return delta;
return d;
}
// found an alt?
if (lfsr_tag_isalt(alt)) {
// make jump absolute
jump = branch - jump;
lfs_off_t branch_ = branch + delta;
lfs_off_t branch_ = branch + d;
// do bounds want to take different paths? begin cutting
if (!diverged
@@ -2036,6 +2067,7 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
p_alts[0], p_weights[0],
lower_id, upper_id,
other_tag_, other_id_)) {
printf("diverged! %x\n", branch);
// first take care of any lingering red alts
if (lfsr_tag_isred(p_alts[0])) {
alt = lfsr_tag_mkblack(p_alts[0]);
@@ -2257,6 +2289,8 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
lower_id = other_lower_id;
}
printf("found %d\n", id_);
// split leaf nodes?
//
// note we bias the weights here so that lfsr_rbyd_lookup
@@ -2266,41 +2300,61 @@ static int lfsr_rbyd_append(lfs_t *lfs, lfsr_rbyd_t *rbyd,
if (lfsr_tag_isrm(tag_)) {
// found an old removed tag, no split needed, just prune the
// removed tag
printf("a %x %x\n", branch, rbyd->off);
} else if (id_ < id
|| (id_ == id && lfsr_tag_key(tag_) < lfsr_tag_key(tag)
&& tag != LFSR_TAG_GROW
&& tag != LFSR_TAG_SHRINK)) {
// split less than
//
// note this is consistent for all appends and only happens when
// appending to the end of the tree
alt = LFSR_TAG_ALT(R, LE, tag_);
weight = id_ - lower_id;
} else if (tag == LFSR_TAG_GROW) {
// decrease weight when growing
alt = LFSR_TAG_ALT(B, LE, 0xfff0);
weight = upper_id - lower_id - 1 + lfsr_data_len(data);
} else if (tag == LFSR_TAG_SHRINK) {
// decrease weight when shrinking
if (upper_id - lower_id - 1 > (lfs_ssize_t)lfsr_data_len(data)) {
} else if (id_ < (delta > 0 ? id : id-lfs_smax32(-delta, 0))
|| (id_ == (delta > 0 ? id : id-lfs_smax32(-delta, 0))
&& lfsr_tag_key(tag_) < lfsr_tag_key(tag))) {
if (lfsr_tag_isrm(tag)) {
printf("b %x %x\n", branch, rbyd->off);
// if removed make our tag unreachable
alt = LFSR_TAG_ALT(B, LE, 0xfff0);
weight = upper_id - lower_id - 1 - lfsr_data_len(data);
weight = upper_id - lower_id - 1 + delta;
} else {
// split less than
printf("c %x %x\n", branch, rbyd->off);
alt = LFSR_TAG_ALT(R, LE, tag_);
weight = id_ - lower_id;
}
} else if (id_ > id
|| (id_ == id && lfsr_tag_key(tag_) > lfsr_tag_key(tag))) {
// // Also note that this handles the case for rms/unreachables,
// // we might pick up an rm/unreachable during lfsr_tag_lookup, but
// // this is unavoidable in the case we've removed everything in a tree.
// // This probably makes "unreachable" a bad tag name, but I can't think
// // of a better one.
// //
//
// } else if (tag == LFSR_TAG_GROW) {
// // decrease weight when growing
// alt = LFSR_TAG_ALT(B, LE, 0xfff0);
// weight = upper_id - lower_id - 1 + lfsr_data_len(data);
//
// } else if (tag == LFSR_TAG_SHRINK) {
// // decrease weight when shrinking
// if (upper_id - lower_id - 1 > (lfs_ssize_t)lfsr_data_len(data)) {
// alt = LFSR_TAG_ALT(B, LE, 0xfff0);
// weight = upper_id - lower_id - 1 - lfsr_data_len(data);
// }
} else if (id_ > id-delta
|| (id_ == id-delta
&& lfsr_tag_key(tag_) > lfsr_tag_key(tag))) {
if (lfsr_tag_isrm(tag)) {
// hide our tag during removes
printf("d %x %x\n", branch, rbyd->off);
// if removed make our tag unreachable
alt = LFSR_TAG_ALT(B, LE, 0xfff0);
weight = upper_id - lower_id - 1;
weight = upper_id - lower_id - 1 + delta;
} else {
printf("e %x %x\n", branch, rbyd->off);
// split greater than
alt = LFSR_TAG_ALT(R, GT, tag);
weight = upper_id - id - 1;
weight = upper_id - id - 1 + delta;
}
// TODO rm me
} else {
printf("g %x %x\n", branch, rbyd->off);
}
if (alt) {
@@ -2331,13 +2385,9 @@ leaf:;
//
// note we always need something after the alts! without something between
// alts we may not be able to find the trunk of our tree
if (tag == LFSR_TAG_GROW || tag == LFSR_TAG_SHRINK) {
tag = LFSR_TAG_UNREACHABLE;
data = LFSR_DATA_NULL;
}
err = lfsr_rbyd_progtag(lfs, rbyd,
tag, id, lfsr_data_len(data), &rbyd->crc);
// TODO WHY OFF BY ONE delta > 0???
tag, id /*+(delta > 0 ? delta-1 : delta)*/, lfsr_data_len(data), &rbyd->crc);
if (err) {
rbyd->erased = false;
return err;
@@ -2353,6 +2403,38 @@ leaf:;
return 0;
}
// TODO remove this wrapper
static int lfsr_rbyd_append_(lfs_t *lfs, lfsr_rbyd_t *rbyd,
lfsr_tag_t tag, lfs_ssize_t id, lfsr_data_t data) {
if (tag == LFSR_TAG_GROW) {
int err = lfsr_rbyd_append(lfs, rbyd,
LFSR_TAG_UNR, id,
+lfsr_data_len(data), LFSR_DATA_NULL);
if (err) {
return err;
}
return 0;
} else if (tag == LFSR_TAG_SHRINK) {
int err = lfsr_rbyd_append(lfs, rbyd,
LFSR_TAG_UNR, id,
-lfsr_data_len(data), LFSR_DATA_NULL);
if (err) {
return err;
}
return 0;
} else {
int err = lfsr_rbyd_append(lfs, rbyd,
tag, id, 0, data);
if (err) {
return err;
}
return 0;
}
}
static int lfsr_rbyd_commit(lfs_t *lfs, lfsr_rbyd_t *rbyd,
const struct lfsr_attr *attrs) {
// we can't do anything if we're not erased
@@ -2378,10 +2460,19 @@ static int lfsr_rbyd_commit(lfs_t *lfs, lfsr_rbyd_t *rbyd,
// append each tag to the tree
for (const struct lfsr_attr *attr = attrs; attr; attr = attr->next) {
int err = lfsr_rbyd_append(lfs, &rbyd_,
attr->tag, attr->id, attr->data);
if (err) {
return err;
// TODO rm this
if (attr->delta == 0) {
int err = lfsr_rbyd_append_(lfs, &rbyd_,
attr->tag, attr->id, attr->data);
if (err) {
return err;
}
} else {
int err = lfsr_rbyd_append(lfs, &rbyd_,
attr->tag, attr->id, attr->delta, attr->data);
if (err) {
return err;
}
}
}
@@ -3037,7 +3128,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
// size, can we combine grows into the tag append in the rbyd
// somehow?
// create grows as necessary
err = lfsr_rbyd_append(lfs, &rbyd_,
err = lfsr_rbyd_append_(lfs, &rbyd_,
LFSR_TAG_GROW,
id - (weight-1),
// TODO also this is a weird way to use lfsr_data_t
@@ -3059,7 +3150,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
}
// append the attr
err = lfsr_rbyd_append(lfs, &rbyd_,
err = lfsr_rbyd_append_(lfs, &rbyd_,
tag, id, LFSR_DATA_DISK(rbyd->block, off, size));
if (err) {
return err;
@@ -3075,7 +3166,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
// append any pending attrs, it's up to upper
// layers to make sure these always fit
for (const struct lfsr_attr *attr = attrs; attr; attr = attr->next) {
err = lfsr_rbyd_append(lfs, &rbyd_,
err = lfsr_rbyd_append_(lfs, &rbyd_,
attr->tag, attr->id, attr->data);
if (err) {
return err;
@@ -3145,7 +3236,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
// TODO does this work if we're removing nothing/oob?
// add an rbyd and btree test?
if ((lfs_size_t)bisect < rbyd_.weight) {
err = lfsr_rbyd_append(lfs, &rbyd_,
err = lfsr_rbyd_append_(lfs, &rbyd_,
LFSR_TAG_SHRINK,
bisect,
LFSR_DATA_BUF(NULL, rbyd_.weight-bisect));
@@ -3161,7 +3252,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
lfs_ssize_t bisect_ = bisect;
for (const struct lfsr_attr *attr = attrs; attr; attr = attr->next) {
if (attr->id < bisect_) {
err = lfsr_rbyd_append(lfs, &rbyd_,
err = lfsr_rbyd_append_(lfs, &rbyd_,
attr->tag, attr->id, attr->data);
if (err) {
return err;
@@ -3213,7 +3304,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
// size, can we combine grows into the tag append in the rbyd
// somehow?
// create grows as necessary
err = lfsr_rbyd_append(lfs, &sibling,
err = lfsr_rbyd_append_(lfs, &sibling,
LFSR_TAG_GROW,
id - bisect - (weight-1),
// TODO also this is a weird way to use lfsr_data_t
@@ -3223,7 +3314,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
}
// append the attr
err = lfsr_rbyd_append(lfs, &sibling,
err = lfsr_rbyd_append_(lfs, &sibling,
tag, id - bisect,
LFSR_DATA_DISK(rbyd->block, off, size));
if (err) {
@@ -3237,7 +3328,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
bisect_ = bisect;
for (const struct lfsr_attr *attr = attrs; attr; attr = attr->next) {
if (attr->id >= bisect_) {
err = lfsr_rbyd_append(lfs, &sibling,
err = lfsr_rbyd_append_(lfs, &sibling,
attr->tag, attr->id-bisect_, attr->data);
if (err) {
return err;
@@ -3452,7 +3543,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
// size, can we combine grows into the tag append in the rbyd
// somehow?
// create grows as necessary
err = lfsr_rbyd_append(lfs, &rbyd_,
err = lfsr_rbyd_append_(lfs, &rbyd_,
LFSR_TAG_GROW,
sdelta + id - (weight-1),
// TODO also this is a weird way to use lfsr_data_t
@@ -3462,7 +3553,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
}
// append the attr
err = lfsr_rbyd_append(lfs, &rbyd_,
err = lfsr_rbyd_append_(lfs, &rbyd_,
tag, sdelta + id, LFSR_DATA_DISK(sibling.block, off, size));
if (err) {
return err;
@@ -3471,7 +3562,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
// if we exceed our compaction threshold our merge has
// failed, clean up ids and merge_abort
if (rbyd_.off > lfs->cfg->block_size/2) {
err = lfsr_rbyd_append(lfs, &rbyd_,
err = lfsr_rbyd_append_(lfs, &rbyd_,
LFSR_TAG_SHRINK,
sdelta,
// TODO also this is a weird way to use lfsr_data_t
@@ -3506,7 +3597,7 @@ static int lfsr_btree_commit(lfs_t *lfs,
return err;
}
err = lfsr_rbyd_append(lfs, &rbyd_,
err = lfsr_rbyd_append_(lfs, &rbyd_,
LFSR_TAG_BNAME, split_id,
LFSR_DATA_DISK(parent.block, split_off, split_size));
if (err) {
+8
View File
@@ -100,6 +100,14 @@ extern "C"
#endif
#endif
#ifndef LFS_UNREACHABLE
#ifndef LFS_NO_ASSERT
#define LFS_UNREACHABLE() __builtin_unreachable()
#else
#define LFS_UNREACHABLE() LFS_ASSERT(false)
#endif
#endif
// Builtin functions, these may be replaced by more efficient
// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
+16 -16
View File
@@ -7,20 +7,20 @@ import os
import struct
TAG_UNREACHABLE = 0x0002
TAG_NAME = 0x1000
TAG_BNAME = 0x1000
TAG_REG = 0x1010
TAG_DIR = 0x1020
TAG_STRUCT = 0x3000
TAG_INLINED = 0x3000
TAG_BLOCK = 0x3100
TAG_BRANCH = 0x3200
TAG_BTREE = 0x3300
TAG_UATTR = 0x4000
TAG_ALT = 0x0008
TAG_CRC = 0x0004
TAG_FCRC = 0x1004
TAG_UNR = 0x0002
TAG_NAME = 0x1000
TAG_BNAME = 0x1000
TAG_REG = 0x1010
TAG_DIR = 0x1020
TAG_STRUCT = 0x3000
TAG_INLINED = 0x3000
TAG_BLOCK = 0x3100
TAG_BRANCH = 0x3200
TAG_BTREE = 0x3300
TAG_UATTR = 0x4000
TAG_ALT = 0x0008
TAG_CRC = 0x0004
TAG_FCRC = 0x1004
def blocklim(s):
if '.' in s:
@@ -83,8 +83,8 @@ def xxd(data, width=16, crc=False):
for b in map(chr, data[i:i+width])))
def tagrepr(tag, id, size, off=None):
if (tag & 0xfffe) == TAG_UNREACHABLE:
return 'unreachable id%d%s' % (
if (tag & 0xfffe) == TAG_UNR:
return 'unr id%d%s' % (
id,
' %d' % size if size else '')
elif (tag & 0xf00c) == TAG_NAME:
+16 -16
View File
@@ -16,20 +16,20 @@ COLORS = [
]
TAG_UNREACHABLE = 0x0002
TAG_NAME = 0x1000
TAG_BNAME = 0x1000
TAG_REG = 0x1010
TAG_DIR = 0x1020
TAG_STRUCT = 0x3000
TAG_INLINED = 0x3000
TAG_BLOCK = 0x3100
TAG_BRANCH = 0x3200
TAG_BTREE = 0x3300
TAG_UATTR = 0x4000
TAG_ALT = 0x0008
TAG_CRC = 0x0004
TAG_FCRC = 0x1004
TAG_UNR = 0x0002
TAG_NAME = 0x1000
TAG_BNAME = 0x1000
TAG_REG = 0x1010
TAG_DIR = 0x1020
TAG_STRUCT = 0x3000
TAG_INLINED = 0x3000
TAG_BLOCK = 0x3100
TAG_BRANCH = 0x3200
TAG_BTREE = 0x3300
TAG_UATTR = 0x4000
TAG_ALT = 0x0008
TAG_CRC = 0x0004
TAG_FCRC = 0x1004
def blocklim(s):
if '.' in s:
@@ -92,8 +92,8 @@ def xxd(data, width=16, crc=False):
for b in map(chr, data[i:i+width])))
def tagrepr(tag, id, size, off=None):
if (tag & 0xfffe) == TAG_UNREACHABLE:
return 'unreachable id%d%s' % (
if (tag & 0xfffe) == TAG_UNR:
return 'unr id%d%s' % (
id,
' %d' % size if size else '')
elif (tag & 0xf00c) == TAG_NAME:
+1253 -852
View File
File diff suppressed because it is too large Load Diff