Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
pkgdb: track mtime in pkgdb
strssndktn committed 7 months ago
commit 08bf9b3d79b127b127ecf597286ba14c016af8c4
parent 699f92e
18 files changed +126 -41
modified docs/pkg-query.8
@@ -223,7 +223,7 @@ for the package origin, and
for the package version.
.It Cm \&%C
Expands to the list of categories the matched package belongs to.
-
.It Cm \&%F Ns Op psugmft
+
.It Cm \&%F Ns Op psugmftl
Expands to the list of files of the matched package, where
.Cm p
stands for path,
@@ -236,7 +236,9 @@ for group,
.Cm m
for mode (permissions),
.Cm f
-
for file flags, and
+
for file flags,
+
.Cm l
+
for last modification time, and
.Cm t
for the symlink target (or empty string if no symlink).
.It Cm \&%D
modified docs/pkg_printf.3
@@ -512,6 +512,9 @@ File flags [string]
.It Cm %Fg
File ownership: group name [string]
.Vt struct pkg_file *
+
.It Cm %Fl
+
File last modification time [epoch]
+
.Vt struct pkg_file *
.It Cm %\^Fn
File path name [string]
.Vt struct pkg_file *
modified libpkg/pkg.c
@@ -493,12 +493,13 @@ pkg_addrdep(struct pkg *pkg, const char *name, const char *origin, const char *v
int
pkg_addfile(struct pkg *pkg, const char *path, const char *sum, bool check_duplicates)
{
-
	return (pkg_addfile_attr(pkg, path, sum, NULL, NULL, 0, 0, NULL, check_duplicates));
+
	return (pkg_addfile_attr(pkg, path, sum, NULL, NULL, 0, 0, 0, NULL, check_duplicates));
}

int
pkg_addfile_attr(struct pkg *pkg, const char *path, const char *sum,
-
		 const char *uname, const char *gname, mode_t perm, u_long fflags,
+
		 const char *uname, const char *gname, mode_t perm,
+
		 u_long fflags, time_t mtime,
		 const char *symlink_target, bool check_duplicates)
{
	struct pkg_file *f = NULL;
@@ -541,6 +542,9 @@ pkg_addfile_attr(struct pkg *pkg, const char *path, const char *sum,
	if (symlink_target != NULL)
		strlcpy(f->symlink_target, symlink_target, sizeof(f->symlink_target));

+
	if (mtime > 0)
+
		f->time[1].tv_sec = mtime;
+

	pkghash_safe_add(pkg->filehash, f->path, f, NULL);
	DL_APPEND(pkg->files, f);

modified libpkg/pkg_add.c
@@ -374,15 +374,15 @@ fill_timespec_buf(const struct stat *aest, struct timespec tspec[2])
{
#ifdef HAVE_STRUCT_STAT_ST_MTIM
	tspec[0].tv_sec = aest->st_atim.tv_sec;
-
	tspec[0].tv_nsec = aest->st_atim.tv_nsec;
+
	tspec[0].tv_nsec = 0;
	tspec[1].tv_sec = aest->st_mtim.tv_sec;
-
	tspec[1].tv_nsec = aest->st_mtim.tv_nsec;
+
	tspec[1].tv_nsec = 0;
#else
# if defined(_DARWIN_C_SOURCE) || defined(__APPLE__)
	tspec[0].tv_sec = aest->st_atimespec.tv_sec;
-
	tspec[0].tv_nsec = aest->st_atimespec.tv_nsec;
+
	tspec[0].tv_nsec = 0;
	tspec[1].tv_sec = aest->st_mtimespec.tv_sec;
-
	tspec[1].tv_nsec = aest->st_mtimespec.tv_nsec;
+
	tspec[1].tv_nsec = 0;
# else
	/* Portable unix version */
	tspec[0].tv_sec = aest->st_atime;
modified libpkg/pkg_create.c
@@ -132,6 +132,9 @@ pkg_create_from_dir(struct pkg *pkg, const char *root,
				}
				file->symlink_target[linklen] = '\0';
			}
+

+
			file->time[0] = st.st_atim;
+
			file->time[1] = st.st_mtim;
		}

		counter_count();
modified libpkg/pkg_manifest.c
@@ -580,6 +580,7 @@ pkg_set_files_from_object(struct pkg *pkg, const ucl_object_t *obj)
	u_long fflags = 0;
	char *fname = NULL;
	const char *key, *okey;
+
	time_t mtime = 0;

	okey = ucl_object_key(obj);
	if (okey == NULL)
@@ -618,6 +619,15 @@ pkg_set_files_from_object(struct pkg *pkg, const ucl_object_t *obj)
#endif
		} else if (STRIEQ(key, "symlink_target") && cur->type == UCL_STRING) {
			symlink_target = ucl_object_tostring(cur);
+
		} else if (STRIEQ(key, "mtime") &&
+
			   (cur->type == UCL_STRING || cur->type == UCL_INT)) {
+
			errno = 0;
+
			mtime = strtoll(ucl_object_tostring_forced(cur), NULL, 10);
+
			if (mtime == 0 && errno != 0) {
+
				pkg_emit_errno("strtoll: invalid epoch value",
+
					       ucl_object_tostring_forced(cur));
+
				continue;
+
			}
		} else {
			dbg(1, "Skipping unknown key for file(%s): %s",
			    fname, key);
@@ -625,7 +635,7 @@ pkg_set_files_from_object(struct pkg *pkg, const ucl_object_t *obj)
	}

	pkg_addfile_attr(pkg, fname, sum, uname, gname, perm, fflags,
-
			 symlink_target, false);
+
			 mtime, symlink_target, false);
	free(fname);

	return (EPKG_OK);
@@ -1177,6 +1187,11 @@ pkg_emit_object(struct pkg *pkg, short flags)
							      ucl_object_fromstring(file->symlink_target),
							      "symlink_target", 0, false);
				}
+
				if (file->time[1].tv_sec > 0) {
+
					ucl_object_insert_key(file_attrs,
+
							      ucl_object_fromint(file->time[1].tv_sec),
+
							      "mtime", 0, false);
+
				}

				urlencode(dp, &tmpsbuf);
				if (map == NULL)
modified libpkg/pkg_ports.c
@@ -407,12 +407,12 @@ meta_file(struct plist *p, char *line, struct file_attr *a, bool is_config)
				       a->owner ? a->owner : p->uname,
				       a->group ? a->group : p->gname,
				       a->mode ? a->mode : p->perm,
-
				       a->fflags,
+
				       a->fflags, st.st_mtim.tv_sec,
				       linklen > 0 ? symlink_target : NULL,
				       true);
	} else {
		ret = pkg_addfile_attr(p->pkg, path, buf, p->uname,
-
				       p->gname, p->perm, 0,
+
				       p->gname, p->perm, 0, st.st_mtim.tv_sec,
				       linklen > 0 ? symlink_target : NULL,
				       true);
	}
modified libpkg/pkg_printf.c
@@ -76,6 +76,7 @@
 * Ff pkg_file     File flags of file
 * Fg pkg_file     Group owner of file
 * Fk pkg_file     Keep flag
+
 * Fl pkg_file     File modification time
 * Fn pkg_file     File path name
 * Fp pkg_file     File permissions
 * Fs pkg_file     File SHA256 checksum
@@ -320,6 +321,15 @@ static const struct pkg_printf_fmt fmt[] = {
		PP_PKG|PP_F,
		&format_file_group,
	},
+
	[PP_PKG_FILE_MTIME] =
+
	{
+
		'F',
+
		'l',
+
		false,
+
		false,
+
		PP_PKG|PP_F,
+
		&format_file_mtime,
+
	},
	[PP_PKG_FILE_PATH] =
	{
		'F',
@@ -885,6 +895,24 @@ format_fflags(xstring *buf, u_long fflags, struct percent_esc *p)
	return (ret);
}

+
static xstring *
+
format_time_t(xstring *buf, time_t timestamp, struct percent_esc *p)
+
{
+
	fflush(p->item_fmt->fp);
+
	if (strlen(p->item_fmt->buf) == 0)
+
		return (int_val(buf, timestamp, p));
+
	else {
+
		char	 buffer[1024];
+
		time_t	 tsv;
+

+
		tsv = timestamp;
+
		strftime(buffer, sizeof(buffer), p->item_fmt->buf,
+
			 localtime(&tsv));
+
		fprintf(buf->fp, "%s", buffer);
+
	}
+
	return (buf);
+
}
+

/*
 * Note: List values -- special behaviour with ? and # modifiers.
 * Affects %A %B %C %D %F %G %L %O %U %b %d %r
@@ -1168,6 +1196,17 @@ format_files(xstring *buf, const void *data, struct percent_esc *p)
}

/*
+
 * %Fm -- File modification time.
+
 */
+
xstring *
+
format_file_mtime(xstring *buf, const void *data, struct percent_esc *p)
+
{
+
	const struct pkg_file *file = data;
+

+
	return (format_time_t(buf, file->time[1].tv_sec, p));
+
}
+

+
/*
 * %Fg -- File group.
 */
xstring *
@@ -1930,19 +1969,7 @@ format_install_tstamp(xstring *buf, const void *data, struct percent_esc *p)
{
	const struct pkg	*pkg = data;

-
	fflush(p->item_fmt->fp);
-
	if (strlen(p->item_fmt->buf) == 0)
-
		return (int_val(buf, pkg->timestamp, p));
-
	else {
-
		char	 buffer[1024];
-
		time_t	 tsv;
-

-
		tsv = (time_t)pkg->timestamp;
-
		strftime(buffer, sizeof(buffer), p->item_fmt->buf,
-
			 localtime(&tsv));
-
		fprintf(buf->fp, "%s", buffer);
-
	}
-
	return (buf);
+
	return (format_time_t(buf, pkg->timestamp, p));
}

/*
modified libpkg/pkgdb.c
@@ -420,6 +420,7 @@ pkgdb_init(sqlite3 *sdb)
		"gname TEXT,"
		"perm INTEGER,"
		"fflags INTEGER,"
+
		"mtime INTEGER,"
		"symlink_target TEXT,"
		"package_id INTEGER REFERENCES packages(id) ON DELETE CASCADE"
			" ON UPDATE CASCADE"
@@ -1366,22 +1367,22 @@ static sql_prstmt sql_prepared_statements[PRSTMT_LAST] = {
	[FILES] = {
		NULL,
		"INSERT INTO files (path, sha256, uname, gname, "
-
		"perm, fflags, symlink_target, package_id) "
-
		"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)",
-
		"TTTTIITI",
+
		"perm, fflags, symlink_target, mtime, package_id) "
+
		"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)",
+
		"TTTTIITII",
	},
	[FILES_REPLACE] = {
		NULL,
		"INSERT OR REPLACE INTO files (path, sha256, uname, gname, "
-
		"perm, fflags, symlink_target, package_id) "
-
		"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)",
-
		"TTTTIITI",
+
		"perm, fflags, symlink_target, mtime, package_id) "
+
		"VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)",
+
		"TTTTIITII",
	},
	[DIRS1] = {
		NULL,
		"INSERT OR IGNORE INTO directories(path, uname, gname, perm, fflags) "
		"VALUES(?1,?2,?3,?4,?5)",
-
		"TTTII",
+
		"TTTIII",
	},
	[DIRS2] = {
		NULL,
@@ -1770,6 +1771,7 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg, int forced,
				 _pkgdb_empty_str_null(file->gname),
				 file->perm, file->fflags,
				 _pkgdb_empty_str_null(file->symlink_target),
+
				 file->time[1].tv_sec,
				 package_id);
		if (ret == SQLITE_DONE)
			continue;
@@ -1792,6 +1794,7 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg, int forced,
					 _pkgdb_empty_str_null(file->gname),
					 file->perm, file->fflags,
					 _pkgdb_empty_str_null(file->symlink_target),
+
					 file->time[1].tv_sec,
					 package_id);
			pkgdb_it_free(it);
			if (ret == SQLITE_DONE)
@@ -1851,7 +1854,8 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg, int forced,
	while (pkg_dirs(pkg, &dir) == EPKG_OK) {
		if (run_prstmt(DIRS1, dir->path, _pkgdb_empty_str_null(dir->uname),
			       _pkgdb_empty_str_null(dir->gname),
-
			       dir->perm, dir->fflags) != SQLITE_DONE) {
+
			       dir->perm, dir->fflags,
+
			       dir->time[1].tv_sec) != SQLITE_DONE) {
			ERROR_STMT_SQLITE(s, STMT(DIRS1));
			goto cleanup;
		}
modified libpkg/pkgdb_iterator.c
@@ -388,7 +388,7 @@ pkgdb_load_files(sqlite3 *sqlite, struct pkg *pkg)
	sqlite3_stmt	*stmt = NULL;
	int		 ret;
	const char	 sql[] = ""
-
		"SELECT path, sha256, uname, gname, perm, fflags, symlink_target "
+
		"SELECT path, sha256, uname, gname, perm, fflags, mtime, symlink_target "
		"  FROM files"
		"  WHERE package_id = ?1"
		"  ORDER BY PATH ASC";
@@ -418,9 +418,10 @@ pkgdb_load_files(sqlite3 *sqlite, struct pkg *pkg)
		const char *gname = sqlite3_column_text(stmt, 3);
		mode_t perm = sqlite3_column_int64(stmt, 4);
		u_long fflags = sqlite3_column_int64(stmt, 5);
-
		const char *symlink_target = sqlite3_column_text(stmt, 6);
+
		time_t mtime = sqlite3_column_int64(stmt, 6);
+
		const char *symlink_target = sqlite3_column_text(stmt, 7);
		pkg_addfile_attr(pkg, path, sum, uname, gname, perm, fflags,
-
				 symlink_target, false);
+
				 mtime, symlink_target, false);
	}
	sqlite3_finalize(stmt);

modified libpkg/private/db_upgrades.h
@@ -733,6 +733,7 @@ static struct db_upgrades {
	"ALTER TABLE files ADD COLUMN gname TEXT; "
	"ALTER TABLE files ADD COLUMN perm INTEGER; "
	"ALTER TABLE files ADD COLUMN fflags INTEGER; "
+
	"ALTER TABLE files ADD COLUMN mtime INTEGER; "
	"ALTER TABLE files ADD COLUMN symlink_target TEXT; "
	"ALTER TABLE directories ADD COLUMN uname TEXT; "
	"ALTER TABLE directories ADD COLUMN gname TEXT; "
modified libpkg/private/pkg.h
@@ -792,7 +792,7 @@ int pkg_addfile(struct pkg *pkg, const char *path, const char *sha256,
    bool check_duplicates);
int pkg_addfile_attr(struct pkg *pkg, const char *path, const char *sha256,
    const char *uname, const char *gname, mode_t perm, u_long fflags,
-
    const char *symlink_target, bool check_duplicates);
+
    time_t mtime, const char *symlink_target, bool check_duplicates);

int pkg_adddir(struct pkg *pkg, const char *path, bool check_duplicates);
int pkg_adddir_attr(struct pkg *pkg, const char *path, const char *uname,
modified libpkg/private/pkg_printf.h
@@ -93,6 +93,7 @@ typedef enum _fmt_code_t {
	PP_PKG_DIRECTORIES,
	PP_PKG_FILE_FFLAGS,
	PP_PKG_FILE_GROUP,
+
	PP_PKG_FILE_MTIME,
	PP_PKG_FILE_PATH,
	PP_PKG_FILE_PERMS,
	PP_PKG_FILE_SHA256,
@@ -185,6 +186,7 @@ _static xstring *format_directory_path(xstring *, const void *, struct percent_e
_static xstring *format_directory_perms(xstring *, const void *, struct percent_esc *);
_static xstring *format_directory_user(xstring *, const void *, struct percent_esc *);
_static xstring *format_files(xstring *, const void *, struct percent_esc *);
+
_static xstring *format_file_mtime(xstring *, const void *, struct percent_esc *);
_static xstring *format_file_group(xstring *, const void *, struct percent_esc *);
_static xstring *format_file_path(xstring *, const void *, struct percent_esc *);
_static xstring *format_file_perms(xstring *, const void *, struct percent_esc *);
modified src/query.c
@@ -45,7 +45,7 @@ static const struct query_flags accepted_query_flags[] = {
	{ 'd', "nov",		1, PKG_LOAD_DEPS },
	{ 'r', "nov",		1, PKG_LOAD_RDEPS },
	{ 'C', "",		1, PKG_LOAD_CATEGORIES },
-
	{ 'F', "psugmft",	1, PKG_LOAD_FILES },
+
	{ 'F', "psugmftl",	1, PKG_LOAD_FILES },
	{ 'O', "kvdD",		1, PKG_LOAD_OPTIONS },
	{ 'D', "",		1, PKG_LOAD_DIRS },
	{ 'S', "pugmf",		1, PKG_LOAD_DIRS }, /* sub directories - directory with options */
@@ -265,6 +265,8 @@ format_str(struct pkg *pkg, xstring *dest, const char *qstr, const void *data)
					pkg_fprintf(dest->fp, "%Ff", data);
				else if (qstr[0] == 't')
					pkg_fprintf(dest->fp, "%Ft", data);
+
				else if (qstr[0] == 'l')
+
					pkg_fprintf(dest->fp, "%Fl", data);
				break;
			case 'O':
				qstr++;
modified tests/frontend/create-parsebin.sh
@@ -23,6 +23,7 @@ genmanifest() {
        local file1_size=$(wc -c < ${file1})
        local file1_sha=$(openssl dgst -sha256 -hex ${file1} | sed -nE 's/.*=[[:space:]]*([[:xdigit:]]+)/\1/p')
        cp -a ${file1} ${TMPDIR}/${file1_base}
+
	file1_mtime=$(q_mtime ${TMPDIR}/${file1_base})

        PKG_FILES="${PKG_FILES}/${file1_base}: {perm: 0644}${NL}"
	PKG_SHA256="${PKG_SHA256}
@@ -32,6 +33,7 @@ genmanifest() {
        gname = \"wheel\";
        perm = \"0644\";
        fflags = 0;
+
        mtime = ${file1_mtime};
    }"

        PKG_FLATSIZE=$((${PKG_FLATSIZE}+${file1_size}))
modified tests/frontend/create.sh
@@ -422,6 +422,7 @@ post-install:
EOF
	touch A
	mkdir B
+
	A_mtime=$(q_mtime A)

	atf_check \
		-o empty \
@@ -457,6 +458,7 @@ files {
        gname = "wheel";
        perm = "0000";
        fflags = 0;
+
        mtime = ${A_mtime};
    }
}
directories {
@@ -482,6 +484,7 @@ EOF
create_from_manifest_and_plist_body() {
	genmanifest
	touch testfile
+
	testfile_mtime=$(q_mtime testfile)
	genplist "testfile"
	atf_check \
		-o empty \
@@ -511,6 +514,7 @@ files {
        gname = "wheel";
        perm = "0000";
        fflags = 0;
+
        mtime = ${testfile_mtime};
    }
}
EOF
@@ -532,6 +536,8 @@ files: {
EOF
	touch testfile
	ln -s sym-target sym-file
+
	test_file_mtime=$(q_mtime testfile)
+
	sym_file_mtime=$(q_mtime sym-file)
	atf_check \
		-o empty \
		-e empty \
@@ -560,6 +566,7 @@ files {
        gname = "wheel";
        perm = "0644";
        fflags = 0;
+
        mtime = ${test_file_mtime};
    }
    /sym-file {
        sum = "1\$a83552cc4e1e92707178239c630b7f05d51124ff2afa7c5595ff4e76cb96cfa4";
@@ -568,6 +575,7 @@ files {
        perm = "0644";
        fflags = 0;
        symlink_target = "sym-target";
+
        mtime = ${sym_file_mtime};
    }
}
EOF
modified tests/frontend/query.sh
@@ -31,12 +31,14 @@ files: {
		"gname": "groot"
		"perm": "777"
		"fflags": "schg,nodump"
+
		"mtime": 2342
	}
	"${TMPDIR}/bla": {
		"sum": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
		"uname": "utoor"
		"gname": "gtoor"
		"perm": "1765"
+
		"mtime": 4223
	}
	"${TMPDIR}/sym": {
		"sum": ""
@@ -44,6 +46,7 @@ files: {
		"gname": "sym-gtoor"
		"perm": "0644"
		"symlink_target": "sym-target"
+
		"mtime": 123432
	}
}
EOF
@@ -164,12 +167,12 @@ EOF

	if [ "${OS}" = "FreeBSD" ]; then
	    atf_check \
-
		-o match:"^${TMPDIR}/bla utoor gtoor 1765 - $" \
-
		-o match:"^${TMPDIR}/plop uroot groot 777 schg,nodump $" \
-
		-o match:"^${TMPDIR}/sym sym-root sym-gtoor 644 - sym-target$" \
+
		-o match:"^${TMPDIR}/bla utoor gtoor 1765 - 4223 $" \
+
		-o match:"^${TMPDIR}/plop uroot groot 777 schg,nodump 2342 $" \
+
		-o match:"^${TMPDIR}/sym sym-root sym-gtoor 644 - 123432 sym-target$" \
		-e empty \
		-s exit:0 \
-
		pkg query "%Fp %Fu %Fg %Fm %Ff %Ft" test
+
		pkg query "%Fp %Fu %Fg %Fm %Ff %Fl %Ft" test

	    atf_check \
		-o inline:"${TMPDIR}/test-dir uroot groot 660 arch,nodump\n" \
modified tests/frontend/test_environment.sh.in
@@ -49,6 +49,14 @@ atf_require() {
}


+
q_mtime() {
+
    if [ "${OS}" = "FreeBSD" ]; then
+
	stat -f "%m" "$1"
+
    else
+
	stat -c "%Y" "$1"
+
    fi
+
}
+

# helper function to obtain expected values for binaries used by the test cases

bin_meta() {