socsvn commit: r238413 - soc2012/gpf/pefs_kmod/sbin/pefs
gpf at FreeBSD.org
gpf at FreeBSD.org
Wed Jun 27 19:02:36 UTC 2012
Author: gpf
Date: Wed Jun 27 19:02:33 2012
New Revision: 238413
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=238413
Log:
pefs verify
for each slnk/reg file:
- look it up in index tables and compare total number of checksums as
well as checksum values.
- generate warning for hardlinks and symlinks just like addchecksum command
does.
- make sure that all files in .pefs.checksum are found in pefs filesystem
for the moment, verify works with a mounted pefs fs. will probably expand
and make it work with an unmouted filesystem.
Modified:
soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c
Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c
==============================================================================
--- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c Wed Jun 27 18:44:36 2012 (r238412)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c Wed Jun 27 19:02:33 2012 (r238413)
@@ -107,15 +107,19 @@
/* XXXgpf: [TODO] turns offsets to uint64_t? */
struct file_header {
- uint32_t nhashes;
- uint64_t file_id;
- uint32_t offset_to_checksums;
- char path[MAXPATHLEN + 1];
- char dirpath[MAXPATHLEN + 1];
- char filename[MAXNAMLEN + 1];
- char *target_path;
- int fd, pfd;
- struct checksum_head checksums;
+ /* on disk information */
+ uint32_t nhashes; /* the number of hashes for the file */
+ uint64_t file_id; /* id is MAC tweak from filename (first 64 bits) */
+ uint32_t offset_to_checksums; /* in file offset to start of checksums */
+
+ /* in memory information */
+ char path[MAXPATHLEN + 1]; /* fullpath for this file */
+ char dirpath[MAXPATHLEN + 1]; /* fullpath for this file's parent dir */
+ char filename[MAXNAMLEN + 1]; /* filename */
+ char *target_path; /*fullpath to this symlink's immediate next target */
+ int fd, pfd; /* file descriptors for the file and its parent dir */
+ int found; /* mark that this entry was found during "verify" action */
+ struct checksum_head checksums; /* this file's checksums */
TAILQ_ENTRY(file_header) file_header_entries;
TAILQ_ENTRY(file_header) fh_hardlink_entries;
};
@@ -889,7 +893,7 @@
}
/* Keep all hardlink file headers in a rb tree */
- if (sb.st_nlink > 1)
+ if (sb.st_nlink > 1 && hlc_headp != NULL)
return (pefs_rb_insert(hlc_headp, fhp, &sb));
return (0);
@@ -995,7 +999,7 @@
pefs_close_file(fhp);
}
- /* checking I/O error with pefs_next_file()*/
+ /* checking I/O error from pefs_next_file() */
if (error != 0)
return (error);
@@ -1476,6 +1480,9 @@
TAILQ_INSERT_TAIL(&(fhp->checksums), csp, checksum_entries);
}
+/*
+ * XXXgpf: [TODO] comments
+ */
static int
pefs_read_checksum_file(int fdin, struct checksum_file_header *cfhp, struct cuckoo_hash_table *chtp)
{
@@ -1498,6 +1505,7 @@
if (fhp != NULL) {
TAILQ_INIT(&(fhp->checksums));
hashes_offset = fhp->offset_to_checksums;
+ fhp->found = 0;
for (k = 0; k < fhp->nhashes; k++) {
csp = malloc(sizeof(struct checksum));
@@ -1530,6 +1538,7 @@
if (fhp != NULL) {
TAILQ_INIT(&(fhp->checksums));
hashes_offset = fhp->offset_to_checksums;
+ fhp->found = 0;
for (k = 0; k < fhp->nhashes; k++) {
csp = malloc(sizeof(struct checksum));
@@ -1556,49 +1565,159 @@
}
static int
-pefs_traverse_fs(struct cuckoo_hash_table *cht, const EVP_MD *md, uint8_t hash_len, DIR *dirp, char *path)
+pefs_compare_checksums(struct file_header *fhp, struct file_header *indexfhp, uint8_t hash_len)
+{
+ struct checksum *csp1, *csp2;
+ uint32_t i;
+ int error;
+
+ dprintf(("comparing hashes for file with fid: %llu\t%llu\n", fhp->file_id, indexfhp->file_id));
+
+ if (fhp->nhashes != indexfhp->nhashes) {
+ pefs_warn("number of hashes differ between on disk file and stored values for file %s: %u vs %u",
+ fhp->path, fhp->nhashes, indexfhp->nhashes);
+ return (1);
+ }
+
+ csp1 = TAILQ_FIRST(&fhp->checksums);
+ csp2 = TAILQ_FIRST(&indexfhp->checksums);
+ i = 1;
+ while (csp1 != NULL && csp2 != NULL) {
+ error = memcmp(csp1->hash, csp2->hash, hash_len);
+ if (error != 0) {
+ pefs_warn("checksum no: %u differs between on disk file and stored values for file %s",
+ i, fhp->path);
+ return (1);
+ }
+ csp1 = TAILQ_NEXT(csp1, checksum_entries);
+ csp2 = TAILQ_NEXT(csp2, checksum_entries);
+ i++;
+ }
+
+ return (0);
+}
+
+/*
+ * XXXgpf: [TODO] comments
+ */
+static int
+pefs_traverse_fs(struct cuckoo_hash_table *chtp, const EVP_MD *md, uint8_t hash_len, DIR *dirp,
+ char *path, struct statfs *fsp, struct hardlink_head *hlc_headp, struct file_header_head *fh_headp)
{
char tmpath[MAXPATHLEN];
+ struct stat sb;
DIR *dirtmp;
struct dirent *sdp;
+ struct file_header *fhp, *indexfhp;
int error;
while (dirp) {
sdp = readdir(dirp);
if (sdp != NULL) {
- if (strcmp(sdp->d_name, "..") != 0 && strcmp(sdp->d_name, ".") != 0) {
- dprintf(("dirent: %s\n", sdp->d_name));
- snprintf(tmpath, sizeof(tmpath), "%s/%s", path, sdp->d_name);
- switch (sdp->d_type) {
- case DT_DIR:
- dirtmp = opendir(tmpath);
- if (dirtmp == NULL) {
- pefs_warn("failed to open dir: %s", tmpath);
- closedir(dirp);
- return (PEFS_ERR_SYS);
- }
- error = pefs_traverse_fs(cht, md, hash_len, dirtmp, tmpath);
- if (error != 0) {
- closedir(dirp);
- return (PEFS_ERR_SYS);
- }
+ if (strcmp(sdp->d_name, "..") == 0 || strcmp(sdp->d_name, ".") == 0 ||
+ strcmp(sdp->d_name, ".pefs.db") == 0 || strcmp(sdp->d_name, ".pefs.conf") == 0 ||
+ strcmp(sdp->d_name, ".pefs.checksum") == 0)
+ continue;
+
+ //dprintf(("dirent: %s\n", sdp->d_name));
+ snprintf(tmpath, sizeof(tmpath), "%s/%s", path, sdp->d_name);
+ switch (sdp->d_type) {
+ case DT_DIR:
+ dirtmp = opendir(tmpath);
+ if (dirtmp == NULL) {
+ pefs_warn("failed to open dir: %s", tmpath);
+ closedir(dirp);
+ return (PEFS_ERR_SYS);
+ }
+ error = pefs_traverse_fs(chtp, md, hash_len, dirtmp, tmpath, fsp, hlc_headp, fh_headp);
+ if (error != 0) {
+ closedir(dirp);
+ return (PEFS_ERR_SYS);
+ }
+ break;
+ /*
+ * Look up the file and verify its checksums.
+ * Total number of checksums should be the same and checksums should match.
+ * Also, take notice of hardlinks & symlink warnings.
+ * After the traversal is done, we must have found all of our entries in the
+ * checksum file.
+ */
+ /* FALLTHROUGH */
+ case DT_REG:
+ case DT_LNK:
+ fhp = malloc(sizeof(struct file_header));
+ if (fhp == NULL) {
+ warn("memory allocation error");
+ closedir(dirp);
+ return (PEFS_ERR_SYS);
+ }
+ strlcpy(fhp->path, tmpath, sizeof(fhp->path));
+ error = pefs_open_semantic_checks(fhp, fsp, NULL);
+ if (error != 0) {
+ closedir(dirp);
+ free(fhp);
+ return (error);
+ }
+
+ error = pefs_get_file_id(fhp);
+ if (error != 0) {
+ pefs_close_file(fhp);
+ free(fhp);
+ return (error);
+ }
+
+ indexfhp = pefs_cuckoo_lookup(chtp, fhp);
+ if (indexfhp == NULL) {
+ pefs_close_file(fhp);
+ free(fhp);
break;
+ }
+ indexfhp->found = 1;
+
+ error = pefs_compute_file_checksums(fhp, md, hash_len);
+ if (error != 0) {
+ pefs_close_file(fhp);
+ free(fhp);
+ return (error);
+ }
+
+ error = lstat(fhp->path, &sb);
+ if (error != 0) {
+ warn("cannot stat file %s", fhp->path);
+ pefs_close_file(fhp);
+ free(fhp);
+ return (PEFS_ERR_SYS);
+ }
+
+ error = pefs_rb_insert(hlc_headp, fhp, &sb);
+ if (error != 0) {
+ pefs_close_file(fhp);
+ free(fhp);
+ return (error);
+ }
+
/*
- * XXXgpf: Look up the file and verify its checksums.
- * Total number of checksums should be the same and checksums should match.
- * Also, take notice of hardlinks & symlink warnings.
- * After the traversal is done, we must have found all of our entries in the
- * checksum file.
+ * XXXgpf: there's a chance of a false positive here.
+ * When creating .pefs.checksum we only check if there's a file id
+ * collision between files that need integrity checking, not against
+ * the entire filesystem. So there's a possibility we will have a
+ * false positive in case there are 2 files with the same file id
+ * now that we traverse the entire fs.
+ *
+ * So should exit and treat a checksum comparison as an error?
*/
- case DT_REG:
- dprintf(("reg file\n"));
- break;
- case DT_LNK:
- dprintf(("smlnk file\n"));
- break;
- default:
- break;
- }
+ error = pefs_compare_checksums(fhp, indexfhp, hash_len);
+ //if (error != 0) {
+ //pefs_close_file(fhp);
+ //free(fhp);
+ //break;
+ //}
+
+ TAILQ_INSERT_TAIL(fh_headp, fhp, file_header_entries);
+ pefs_close_file(fhp);
+ break;
+ default:
+ break;
}
}
else {
@@ -1611,19 +1730,50 @@
return (PEFS_ERR_SYS);
}
+static void
+pefs_found_all_entries(struct cuckoo_hash_table *chtp)
+{
+ struct file_header *fhp;
+ uint32_t i;
+
+ for (i = 0; i < chtp->size; i++) {
+ fhp = chtp->buckets1[i].fhp;
+ if (fhp != NULL)
+ if (fhp->found != 1)
+ pefs_warn("file with file id %llu was not found in filesystem but exists in checksum file",
+ fhp->file_id);
+ }
+
+ for (i = 0; i < chtp->size; i++) {
+ fhp = chtp->buckets2[i].fhp;
+ if (fhp != NULL)
+ if (fhp->found != 1)
+ pefs_warn("file with file id %llu was not found in filesystem but exists in checksum file",
+ fhp->file_id);
+ }
+}
+
/*
* XXXgpf: [TODO] comments
*/
int
pefs_verify_checksum(int fdin, char *fsroot)
{
+ struct statfs fs;
struct checksum_file_header cfh;
struct cuckoo_hash_table cht;
+ struct file_header_head fh_head;
+ struct hardlink_head hlc_head;
const EVP_MD *md;
DIR *dirp;
int error;
uint8_t hash_len;
+ if (statfs(fsroot, &fs) == -1) {
+ pefs_warn("statfs failed: %s: %s", fsroot, strerror(errno));
+ return (PEFS_ERR_SYS);
+ }
+
error = pefs_read_checksum_file_header(fdin, &cfh);
if (error != 0)
return (error);
@@ -1645,17 +1795,26 @@
if (error != 0)
return (error);
- pefs_print_hash_tables(&cht, hash_len);
+ //pefs_print_hash_tables(&cht, hash_len);
dirp = opendir(fsroot);
if (dirp == NULL) {
pefs_warn("failed to open dir %s", fsroot);
return (PEFS_ERR_SYS);
}
- error = pefs_traverse_fs(&cht, md, hash_len, dirp, fsroot);
+
+ RB_INIT(&hlc_head);
+ TAILQ_INIT(&fh_head);
+
+ error = pefs_traverse_fs(&cht, md, hash_len, dirp, fsroot, &fs, &hlc_head, &fh_head);
if (error != 0)
return (error);
+ //pefs_rb_print(&hlc_head);
+ pefs_rb_warn(&hlc_head);
+ pefs_symlink_warn(&cht, &fh_head);
+ pefs_found_all_entries(&cht);
+
/* XXXgpf: [TODO] free mem in the end and when error occurs */
return (0);
}
More information about the svn-soc-all
mailing list