diff options
Diffstat (limited to 'src/metaentry.c')
-rw-r--r-- | src/metaentry.c | 128 |
1 files changed, 124 insertions, 4 deletions
diff --git a/src/metaentry.c b/src/metaentry.c index 6e27f11..ed0e23d 100644 --- a/src/metaentry.c +++ b/src/metaentry.c @@ -555,6 +555,123 @@ mentries_fromfile_v0(struct metahash **mhash, const char *ptr, const char *max) return 0; } +/* Creates a metaentry list from a Format 1 file buffer */ +static int +mentries_fromfile_v1(struct metahash **mhash, const char *ptr, const char *max) +{ + struct metaentry *mentry; + int i; + char *mtime = NULL, *nsec, *tz; + struct tm tm; + + if (read_char(&ptr, max) != '\n') + return -1; + + while (ptr < max) { + mentry = mentry_alloc(); + + if ((mentry->path = read_string_url(&ptr, max)) == NULL) + goto err; + mentry->pathlen = strlen(mentry->path); + + if (read_char(&ptr, max) != '\t') + goto err; + mentry->owner = read_string_url(&ptr, max); + + if (read_char(&ptr, max) != '\t') + goto err; + mentry->group = read_string_url(&ptr, max); + + if (read_char(&ptr, max) != '\t') + goto err; + mentry->mode = read_int_string(&ptr, max, 8); + + /* Read the whole mtime string into `mtime`. */ + if (read_char(&ptr, max) != '\t') + goto err; + if ((mtime = read_string_url(&ptr, max)) == NULL) + goto err; + + /* Get the time_t part of `mtime` into mentry->mtime */ + if ((nsec = strptime(mtime, "%Y-%m-%dT%H:%M:%S", &tm)) == NULL) + goto err; + tm.tm_isdst = 0; + mentry->mtime = timegm(&tm); + + /* Check if there's a nanosecond portion of `mtime` */ + if (*nsec == '.') { + /* There is a decimal point in mtime. Get nanoseconds. */ + ++nsec; + mentry->mtimensec = strtol(nsec, &tz, 10); + i = tz - nsec; + while (i < 9) { + /* Too few digits for nanosecond precision. + * e.g. "...T10:15:23.5", which we've parsed as + * 5 nanoseconds, but is actually half a second + * or 500000000 nanoseconds. + * Scale to correct value. + */ + mentry->mtimensec *= 10; + ++i; + } + while (i > 9) { + /* Too many digits for nanosecond precision. + * Scale to correct value + */ + mentry->mtimensec /= 10; + --i; + } + } + else { + /* No decimal point. Set nanoseconds to zero */ + mentry->mtimensec = 0; + tz = nsec; + } + + /* Check for a 'Z' (Zulu/UTC) timesone specifier in `mtime`. */ + if (*tz == 'Z') + ++tz; + + /* Check that we've reached the end of `mtime` */ + if (*tz != '\0') + goto err; + free(mtime); + mtime = NULL; + + mentry->xattrs = 0; + mentry->xattr_names = NULL; + mentry->xattr_lvalues = NULL; + mentry->xattr_values = NULL; + while ((i = read_char(&ptr, max)) == '\t') { + mentry->xattr_names = xrealloc(mentry->xattr_names, + (mentry->xattrs + 1) * sizeof(char *)); + mentry->xattr_lvalues = xrealloc(mentry->xattr_lvalues, + (mentry->xattrs + 1) * sizeof(ssize_t)); + mentry->xattr_values = xrealloc(mentry->xattr_values, + (mentry->xattrs + 1) * sizeof(char *)); + + mentry->xattr_names[mentry->xattrs] = read_string_url(&ptr, max); + read_char(&ptr, max); + mentry->xattr_values[mentry->xattrs] = read_binary_url(&ptr, max, + &mentry->xattr_lvalues[mentry->xattrs]); + + ++mentry->xattrs; + } + if (i != '\n') + goto err; + + mentry_insert(mentry, *mhash); + } + + return 0; + +err: + if (mtime) + free(mtime); + mentry_free(mentry); + return -1; +} + /* Creates a metaentry list from a file */ void mentries_fromfile(struct metahash **mhash, const char *path) @@ -603,13 +720,16 @@ mentries_fromfile(struct metahash **mhash, const char *path) } ptr += SIGNATURELEN; - if (strncmp(ptr, VERSION_0, VERSIONLEN)) { + if (strncmp(ptr, VERSION_0, VERSIONLEN) == 0) { + i = mentries_fromfile_v0(mhash, ptr + VERSIONLEN, max); + } + else if (strncmp(ptr, VERSION_1, VERSIONLEN) == 0) { + i = mentries_fromfile_v1(mhash, ptr + VERSIONLEN, max); + } + else { msg(MSG_CRITICAL, "Invalid version of file %s\n", path); goto out; } - ptr += VERSIONLEN; - - i = mentries_fromfile_v0(mhash, ptr, max); if (i != 0) { msg(MSG_CRITICAL, "Invalid characters in file %s\n", path); goto out; |