socsvn commit: r237264 - soc2012/gpf/pefs_kmod/sbin/pefs
gpf at FreeBSD.org
gpf at FreeBSD.org
Thu Jun 7 15:08:07 UTC 2012
Author: gpf
Date: Thu Jun 7 15:08:05 2012
New Revision: 237264
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=237264
Log:
- use dirname/basename instead of homegrown solution
- open(2) fhp->path as well as fhp->dirpath of parent dir so as to eliminate
most race conditions. file descriptors are kept in struct file_header.
This is done alongside semantic checks for each file in the now renamed
pefs_open_semantic_check().
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 Thu Jun 7 14:38:43 2012 (r237263)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c Thu Jun 7 15:08:05 2012 (r237264)
@@ -28,6 +28,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/dirent.h>
#include <sys/endian.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
@@ -40,6 +41,7 @@
#include <ctype.h>
#include <dirent.h>
#include <inttypes.h>
+#include <libgen.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
@@ -84,8 +86,6 @@
RB_ENTRY(hardlink_counter) hardlink_entries;
};
-/* XXXgpf: [TODO] check pathname string lengths. Some are MAXPATHLEN + 1, some MAXPATHLEN */
-
/* XXXgpf: unions for on disk structs and move to a different header? */
struct checksum_file_header {
uint8_t version;
@@ -105,9 +105,12 @@
struct file_header {
uint32_t nhashes;
uint64_t file_id;
- char path[MAXPATHLEN];
+ char path[MAXPATHLEN + 1];
+ char dirpath[MAXPATHLEN + 1];
+ char filename[MAXNAMLEN + 1];
char *target_path;
uint32_t offset_to_checksums;
+ int fd, pfd;
struct checksum_head checksums;
TAILQ_ENTRY(file_header) file_header_entries;
TAILQ_ENTRY(file_header) fh_hardlink_entries;
@@ -165,41 +168,34 @@
return 0;
}
+static void
+pefs_close_file(struct file_header *fhp)
+{
+ if (fhp->fd >= 0)
+ close(fhp->fd);
+ if (fhp->pfd >= 0)
+ close(fhp->pfd);
+}
+
static int
pefs_compute_symlink_checksum(struct file_header *fhp, const EVP_MD *md,
uint8_t hash_len)
{
struct pefs_xslink_ctext xsl;
- char parent_dir[MAXPATHLEN];
EVP_MD_CTX mdctx;
- int error, i, fd, md_len;
+ int error, i, md_len;
struct checksum *csp;
- char *pch;
+ TAILQ_INIT(&(fhp->checksums));
fhp->nhashes = 0;
/* feed parent directory to ioctl() */
- strlcpy(parent_dir, fhp->path, sizeof(parent_dir));
- pch = strrchr(parent_dir, '/');
- if (pch == NULL) {
- pefs_warn("error retrieving parent dir of %s", fhp->path);
- return (PEFS_ERR_NOENT);
- }
- *pch = '\0';
-
- strlcpy(xsl.pxsl_filename, pch + 1, sizeof(xsl.pxsl_filename));
+ strlcpy(xsl.pxsl_filename, fhp->filename, sizeof(xsl.pxsl_filename));
xsl.pxsl_namelen = strnlen(xsl.pxsl_filename, sizeof(xsl.pxsl_filename));
- fd = open(parent_dir, O_RDONLY);
- if (fd < 0) {
- warn("failed to open file: %s", parent_dir);
- return (PEFS_ERR_IO);
- }
-
- error = ioctl(fd, PEFS_GETSLINKCTEXT, &xsl);
+ error = ioctl(fhp->pfd, PEFS_GETSLINKCTEXT, &xsl);
if (error != 0) {
pefs_warn("error retrieving symlink's ciphertext of %s", fhp->path);
- close(fd);
return (PEFS_ERR_IO);
}
@@ -215,14 +211,12 @@
csp = malloc(sizeof(struct checksum));
if (csp == NULL) {
pefs_warn("memory allocation error");
- close(fd);
return (PEFS_ERR_SYS);
}
csp->hash = malloc(hash_len);
if (csp->hash == NULL) {
pefs_warn("memory allocation error");
free(csp);
- close(fd);
return (PEFS_ERR_SYS);
}
@@ -236,7 +230,6 @@
TAILQ_INSERT_TAIL(&(fhp->checksums), csp, checksum_entries);
fhp->nhashes++;
- close(fd);
return (0);
}
@@ -249,32 +242,26 @@
struct stat sb;
off_t resid;
uint32_t bytes_to_read;
- int error, i, fd, md_len;
+ int error, i, md_len;
struct checksum *csp;
+ if (fhp->target_path != NULL)
+ return (pefs_compute_symlink_checksum(fhp, md, hash_len));
+
TAILQ_INIT(&(fhp->checksums));
/* XXXgpf: what happens if file size > 2^64? */
- if (lstat(fhp->path, &sb) != 0) {
+ if (fstat(fhp->fd, &sb) != 0) {
warn("cannot stat file %s", fhp->path);
return (PEFS_ERR_SYS);
}
- if (S_ISLNK(sb.st_mode) != 0)
- return (pefs_compute_symlink_checksum(fhp, md, hash_len));
-
resid = sb.st_size;
if (resid == 0) {
pefs_warn("empty files are not allowed: %s", fhp->path);
return (PEFS_ERR_INVALID);
}
- fd = open(fhp->path, O_RDONLY | O_NOFOLLOW);
- if (fd < 0) {
- warn("failed to open file: %s", fhp->path);
- return (PEFS_ERR_IO);
- }
-
fhp->nhashes = 0;
xsct.pxsct_offset = 0;
while (resid > 0) {
@@ -285,10 +272,9 @@
resid-=bytes_to_read;
xsct.pxsct_ctext_len = bytes_to_read;
- error = ioctl(fd, PEFS_GETSECTORCTEXT, &xsct);
+ error = ioctl(fhp->fd, PEFS_GETSECTORCTEXT, &xsct);
if (error != 0) {
pefs_warn("error retrieving ciphertext of %s", fhp->path);
- close(fd);
return (PEFS_ERR_IO);
}
xsct.pxsct_offset+= xsct.pxsct_ctext_len;
@@ -305,14 +291,12 @@
csp = malloc(sizeof(struct checksum));
if (csp == NULL) {
pefs_warn("memory allocation error");
- close(fd);
return (PEFS_ERR_SYS);
}
csp->hash = malloc(hash_len);
if (csp->hash == NULL) {
pefs_warn("memory allocation error");
free(csp);
- close(fd);
return (PEFS_ERR_SYS);
}
@@ -328,7 +312,6 @@
fhp->nhashes++;
}
- close(fd);
return (0);
}
@@ -586,33 +569,15 @@
static int
pefs_get_file_id(struct file_header *fhp)
{
- char parent_dir[MAXPATHLEN];
struct pefs_xnamecsum xncs;
- char *pch;
uint64_t temp;
- int error, fd;
-
- /* feed parent directory to ioctl() */
- strlcpy(parent_dir, fhp->path, sizeof(parent_dir));
- pch = strrchr(parent_dir, '/');
- if (pch == NULL) {
- pefs_warn("error retrieving parent dir of %s", fhp->path);
- return (PEFS_ERR_NOENT);
- }
- *pch = '\0';
-
- fd = open(parent_dir, O_RDONLY);
- if (fd < 0) {
- warn("unable to open file %s", parent_dir);
- return (PEFS_ERR_SYS);
- }
+ int error;
- pch = strrchr(fhp->path, '/');
- pch++;
- strlcpy(xncs.pxnc_filename, pch, sizeof(xncs.pxnc_filename));
+ strlcpy(xncs.pxnc_filename, fhp->filename, sizeof(xncs.pxnc_filename));
xncs.pxnc_namelen = strnlen(xncs.pxnc_filename, sizeof(xncs.pxnc_filename));
- error = ioctl(fd, PEFS_GETNAMECSUM, &xncs);
+ /* feed parent directory to ioctl() */
+ error = ioctl(fhp->pfd, PEFS_GETNAMECSUM, &xncs);
if (error == 0) {
/* XXXgpf: Is this correct? */
@@ -622,7 +587,6 @@
else
pefs_warn("failed to fetch file id from kernel");
- close(fd);
return (error);
}
@@ -631,7 +595,9 @@
{
struct stat sb;
struct file_header targetfh;
+ char dirbuf[MAXPATHLEN + 1], namebuf[MAXNAMLEN + 1];
struct file_header *fhp, *res;
+ char *dirnamep, *namep;
int error;
TAILQ_FOREACH(fhp, fhhp, file_header_entries) {
@@ -655,7 +621,32 @@
if (S_ISLNK(sb.st_mode) == 0 && S_ISREG(sb.st_mode) == 0)
continue;
+ /* retrieve dirpath & filaname */
strlcpy(targetfh.path, fhp->target_path, sizeof(targetfh.path));
+ strlcpy(dirbuf, targetfh.path, sizeof(dirbuf));
+ strlcpy(namebuf, targetfh.path, sizeof(namebuf));
+
+ dirnamep = dirname(dirbuf);
+ if (dirnamep == NULL) {
+ pefs_warn("failed to extract dirname of %s", targetfh.path);
+ continue;
+ }
+ strlcpy(targetfh.dirpath, dirnamep, sizeof(targetfh.dirpath));
+
+ namep = basename(namebuf);
+ if (namep == NULL) {
+ pefs_warn("failed to extract filename of %s", targetfh.path);
+ continue;
+ }
+ strlcpy(targetfh.filename, namep, sizeof(targetfh.filename));
+
+ targetfh.pfd = -1;
+ targetfh.pfd = open(targetfh.dirpath, O_RDONLY);
+ if (targetfh.pfd < 0) {
+ warn("cannot open %s", targetfh.dirpath);
+ continue;
+ }
+
error = pefs_get_file_id(&targetfh);
if (error == 0) {
res = pefs_cuckoo_lookup(chtp, &targetfh);
@@ -663,6 +654,7 @@
pefs_warn("target file %s of symlink %s was not found in inputlist",
targetfh.path, fhp->path);
}
+ pefs_close_file(&targetfh);
}
}
}
@@ -746,16 +738,41 @@
}
static int
-pefs_file_semantic_checks(struct file_header *fhp, struct statfs *fsp, struct hardlink_head *hlc_headp)
+pefs_open_semantic_checks(struct file_header *fhp, struct statfs *fsp, struct hardlink_head *hlc_headp)
{
- char parent_dir[MAXPATHLEN];
- char sbuf[MAXPATHLEN];
+ char dirbuf[MAXPATHLEN + 1], namebuf[MAXNAMLEN + 1];
+ char sbuf[MAXPATHLEN + 1];
struct stat sb;
struct statfs this_fs;
- char *pch;
+ char *dirnamep, *namep;
size_t target_path_size;
int nchars;
+ /* initialize file descriptors in case error occurs */
+ fhp->fd = -1;
+ fhp->pfd = -1;
+
+ /* retrieve dirpath & filename */
+ strlcpy(dirbuf, fhp->path, sizeof(dirbuf));
+ strlcpy(namebuf, fhp->path, sizeof(namebuf));
+
+ dirnamep = dirname(dirbuf);
+ if (dirnamep == NULL) {
+ pefs_warn("failed to extract dirname of %s", fhp->path);
+ return (PEFS_ERR_GENERIC);
+ }
+ strlcpy(fhp->dirpath, dirnamep, sizeof(fhp->dirpath));
+
+
+ namep = basename(namebuf);
+ if (namep == NULL) {
+ pefs_warn("failed to extract filename of %s", fhp->path);
+ return (PEFS_ERR_GENERIC);
+ }
+ strlcpy(fhp->filename, namep, sizeof(fhp->filename));
+
+ dprintf(("path = %s!\ndirname = %s!\nbasename =%s!\n", fhp->path, fhp->dirpath, fhp->filename));
+
if (lstat(fhp->path, &sb) != 0) {
warn("cannot stat file %s", fhp->path);
return (PEFS_ERR_SYS);
@@ -764,6 +781,12 @@
if (S_ISLNK(sb.st_mode) != 0) {
fhp->target_path = NULL;
+ fhp->pfd = open(fhp->dirpath, O_RDONLY);
+ if (fhp->pfd < 0) {
+ warn("cannot open %s", fhp->dirpath);
+ return (PEFS_ERR_IO);
+ }
+
nchars = readlink(fhp->path, sbuf, sizeof(sbuf));
if (nchars == -1) {
warn("readlink failed: %s", fhp->path);
@@ -780,25 +803,17 @@
* Target referes to the file immediately pointed to by our symlink, not
* the final target of a possible symlink chain.
*/
- target_path_size = MAXPATHLEN;
+ target_path_size = MAXPATHLEN + 1;
fhp->target_path = malloc(target_path_size);
if (fhp->target_path == NULL) {
warn("memory allocation error");
return (PEFS_ERR_SYS);
}
-
sbuf[nchars] = '\0';
- /* turn relative paths to absolute paths which are needed for ioctl() */
- if (sbuf[0] != '/') {
- strlcpy(parent_dir, fhp->path, sizeof(parent_dir));
- pch = strrchr(parent_dir, '/');
- if (pch == NULL) {
- pefs_warn("error retrieving parent dir of %s", fhp->path);
- return (PEFS_ERR_NOENT);
- }
- *pch = '\0';
- snprintf(fhp->target_path, target_path_size, "%s/%s", parent_dir, sbuf);
- }
+
+ /* turn relative paths to absolute paths */
+ if (sbuf[0] != '/')
+ snprintf(fhp->target_path, target_path_size, "%s/%s", fhp->dirpath, sbuf);
else
strlcpy(fhp->target_path, sbuf, target_path_size);
@@ -828,12 +843,29 @@
else
fhp->target_path = NULL;
+ fhp->fd = open(fhp->path, O_RDONLY | O_NOFOLLOW);
+ if (fhp->fd < 0) {
+ warn("cannot open %s", fhp->path);
+ return (PEFS_ERR_IO);
+ }
+
+ fhp->pfd = open(fhp->dirpath, O_RDONLY);
+ if (fhp->pfd < 0) {
+ warn("cannot open %s", fhp->dirpath);
+ return (PEFS_ERR_IO);
+ }
+
+ if (fstat(fhp->fd, &sb) != 0) {
+ warn("cannot stat file %s", fhp->path);
+ return (PEFS_ERR_SYS);
+ }
+
if (S_ISREG(sb.st_mode) == 0) {
pefs_warn("filename: %s is not a regular file", fhp->path);
return (PEFS_ERR_INVALID);
}
- if (statfs(fhp->path, &this_fs) == -1) {
+ if (fstatfs(fhp->fd, &this_fs) == -1) {
pefs_warn("statfs failed: %s: %s", fhp->path, strerror(errno));
return (PEFS_ERR_SYS);
}
@@ -888,19 +920,20 @@
/*
* This function creates the in memory database that will be later written to
* the checksum file.
- * A) The total sum of entries is gathered so that the hash tables are allocated.
- * B) For each file entry:
- * B1) semantic checks:
- * B1a) file should reside in pefs filesystem & file should be regular file.
- * B1b) if symlink, acquire and save the absolute path of the symlink's
+ * A) For each file entry:
+ * A1) semantic checks:
+ * A1a) file should reside in pefs filesystem & file should be regular file.
+ * A1b) if symlink, acquire and save the absolute path of the symlink's
* target. Try to stat() the target but don't do anything else.
- * B1c) If hardlink, save a reference to this file entry in our rb tree.
+ * A1c) If hardlink, save a reference to this file entry in our rb tree.
* rb-tree uses inodes as keys and is used in part C to print warnings.
- * B2) the file_id is retrieved.
- * B3) list of checksums is computed for the file's 4k blocks.
- * B4) file entry is added to universal fh_head.
- * C) Print warnings for hardlinks if the number of links found in inputlist isn't
+ * A1d) Open and store file descriptors to file & parent_directory.
+ * A2) the file_id is retrieved.
+ * A3) list of checksums is computed for the file's 4k blocks.
+ * A4) file entry is added to universal fh_head.
+ * B) Print warnings for hardlinks if the number of links found in inputlist isn't
* equal to the number of total inode links.
+ * C) Hash tables are allocated.
* D) Cuckoo insertion:
* We try to populate our hash tables using the cuckoo algorithm. Should we fall
* into an infinite loop during insertion, we re-allocate larger hash tables
@@ -929,19 +962,26 @@
TAILQ_INIT(&fh_head);
RB_INIT(&hlc_head);
while((fhp = pefs_next_file(fpin, &error, &nfiles)) != NULL) {
- error = pefs_file_semantic_checks(fhp, &fs, &hlc_head);
- if (error != 0)
+ error = pefs_open_semantic_checks(fhp, &fs, &hlc_head);
+ if (error != 0) {
+ pefs_close_file(fhp);
return (error);
+ }
error = pefs_get_file_id(fhp);
- if (error != 0)
+ if (error != 0) {
+ pefs_close_file(fhp);
return (error);
+ }
error = pefs_compute_file_checksums(fhp, md, hash_len);
- if (error != 0)
+ if (error != 0) {
+ pefs_close_file(fhp);
return (error);
+ }
TAILQ_INSERT_TAIL(&fh_head, fhp, file_header_entries);
+ pefs_close_file(fhp);
}
/* checking I/O error with pefs_next_file()*/
More information about the svn-soc-all
mailing list