summaryrefslogtreecommitdiff
path: root/src/metaentry.c
diff options
context:
space:
mode:
authorAdam Spragg <adam@spra.gg>2022-05-17 17:31:48 +0100
committerAdam Spragg <adam@spra.gg>2022-05-18 17:19:47 +0100
commit260fc47f01ef64368721ec93de4cbd988357b32b (patch)
tree551213a3f0ecdff66f525cf4b0a59c349ee898dd /src/metaentry.c
parentb3c08670f56d7c5ee85dffa1a2faa5e03d2df5a1 (diff)
Add ability to read Format 1 metadata files
Diffstat (limited to 'src/metaentry.c')
-rw-r--r--src/metaentry.c128
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;