socsvn commit: r238811 - soc2012/gpf/pefs_kmod/sbin/pefs
gpf at FreeBSD.org
gpf at FreeBSD.org
Mon Jul 2 15:23:03 UTC 2012
Author: gpf
Date: Mon Jul 2 15:23:00 2012
New Revision: 238811
URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=238811
Log:
- make pefs verify work for unmounted fs or fs without key
- use a flags variable in all major functions due to different semantics or
code that should be used according to whether fs is mounted and has a key
or not.
code is a little crude at some points and requires comments, more testing
and handling of a few todos that can be seen in xxx comment headers.
Modified:
soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c
soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c
soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h
soc2012/gpf/pefs_kmod/sbin/pefs/pefs_subr.c
Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c
==============================================================================
--- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c Mon Jul 2 15:19:56 2012 (r238810)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_checksum.c Mon Jul 2 15:23:00 2012 (r238811)
@@ -187,34 +187,43 @@
static int
pefs_compute_symlink_checksum(struct file_header *fhp, const EVP_MD *md,
- uint8_t hash_len)
+ uint8_t hash_len, int flags)
{
struct pefs_xslink_ctext xsl;
EVP_MD_CTX mdctx;
+ char *buf;
int error, i, md_len;
+ size_t buf_len;
struct checksum *csp;
TAILQ_INIT(&(fhp->checksums));
fhp->nhashes = 0;
- /* feed parent directory to ioctl() */
- strlcpy(xsl.pxsl_filename, fhp->filename, sizeof(xsl.pxsl_filename));
- xsl.pxsl_namelen = strnlen(xsl.pxsl_filename, sizeof(xsl.pxsl_filename));
-
- error = ioctl(fhp->pfd, PEFS_GETSLINKCTEXT, &xsl);
- if (error != 0) {
- pefs_warn("error retrieving symlink's ciphertext of %s", fhp->path);
- return (PEFS_ERR_IO);
+ if ((flags & PEFS_UNMOUNTED) != 0 || (flags & PEFS_NOKEY) != 0) {
+ buf = fhp->target_path;
+ buf_len = strnlen(fhp->target_path, MAXPATHLEN + 1);
+ }
+ else {
+ /* feed parent directory to ioctl() */
+ strlcpy(xsl.pxsl_filename, fhp->filename, sizeof(xsl.pxsl_filename));
+ xsl.pxsl_namelen = strnlen(xsl.pxsl_filename, sizeof(xsl.pxsl_filename));
+
+ error = ioctl(fhp->pfd, PEFS_GETSLINKCTEXT, &xsl);
+ if (error != 0) {
+ pefs_warn("error retrieving symlink's ciphertext of %s", fhp->path);
+ return (PEFS_ERR_IO);
+ }
+
+ dprintf(("read %d bytes from kernel\n\n", xsl.pxsl_slink_len));
+ dprintf(("printing contents of buf:"));
+ for (i=0; i < (int)xsl.pxsl_slink_len; i++) dprintf(("%c", xsl.pxsl_slink[i]));
+ dprintf(("!\n"));
+ buf = xsl.pxsl_slink;
+ buf_len = xsl.pxsl_slink_len;
}
-
- dprintf(("read %d bytes from kernel\n\n", xsl.pxsl_slink_len));
- dprintf(("printing contents of buf:"));
- for (i=0; i < (int)xsl.pxsl_slink_len; i++) dprintf(("%c", xsl.pxsl_slink[i]));
- dprintf(("!\n"));
-
EVP_MD_CTX_init(&mdctx);
EVP_DigestInit_ex(&mdctx, md, NULL);
- EVP_DigestUpdate(&mdctx, xsl.pxsl_slink, xsl.pxsl_slink_len);
+ EVP_DigestUpdate(&mdctx, buf, buf_len);
csp = malloc(sizeof(struct checksum));
if (csp == NULL) {
@@ -243,18 +252,22 @@
static int
pefs_compute_file_checksums(struct file_header *fhp, const EVP_MD *md,
- uint8_t hash_len)
+ uint8_t hash_len, int flags)
{
struct pefs_xsector_ctext xsct;
+ char sector_buf[PEFS_SECTOR_SIZE];
EVP_MD_CTX mdctx;
struct stat sb;
- off_t resid;
+ off_t offset, resid;
+ FILE * fp;
+ char *buf;
uint32_t bytes_to_read;
+ size_t buf_len;
int error, i, md_len;
struct checksum *csp;
if (fhp->target_path != NULL)
- return (pefs_compute_symlink_checksum(fhp, md, hash_len));
+ return (pefs_compute_symlink_checksum(fhp, md, hash_len, flags));
TAILQ_INIT(&(fhp->checksums));
@@ -267,34 +280,58 @@
resid = sb.st_size;
if (resid == 0) {
pefs_warn("empty files are not allowed: %s", fhp->path);
- return (PEFS_ERR_INVALID);
+ return (PEFS_ERR_GENERIC);
+ }
+
+ fp = NULL;
+ if ((flags & PEFS_UNMOUNTED) != 0 || (flags & PEFS_NOKEY) != 0) {
+ fp = fdopen(fhp->fd, "r");
+ if (fp == NULL) {
+ pefs_warn("could not open file for reading: %s", fhp->path);
+ return (PEFS_ERR_IO);
+ }
}
fhp->nhashes = 0;
+ offset = 0;
xsct.pxsct_offset = 0;
while (resid > 0) {
if (resid > PEFS_SECTOR_SIZE)
bytes_to_read = PEFS_SECTOR_SIZE;
else
bytes_to_read = resid;
-
- resid-=bytes_to_read;
- xsct.pxsct_ctext_len = bytes_to_read;
- error = ioctl(fhp->fd, PEFS_GETSECTORCTEXT, &xsct);
- if (error != 0) {
- pefs_warn("error retrieving ciphertext of %s", fhp->path);
- return (PEFS_ERR_IO);
+
+ if ((flags & PEFS_UNMOUNTED) != 0 || (flags & PEFS_NOKEY) != 0) {
+ fread(sector_buf, bytes_to_read, sizeof(char), fp);
+ if (ferror(fp)) {
+ pefs_warn("error reading from file: %s", fhp->path);
+ return (PEFS_ERR_IO);
+ }
+ buf = sector_buf;
+ buf_len = bytes_to_read;
+ resid-=bytes_to_read;
+ }
+ else {
+ resid-=bytes_to_read;
+ xsct.pxsct_ctext_len = bytes_to_read;
+ error = ioctl(fhp->fd, PEFS_GETSECTORCTEXT, &xsct);
+ if (error != 0) {
+ pefs_warn("error retrieving ciphertext of %s", fhp->path);
+ return (PEFS_ERR_IO);
+ }
+ xsct.pxsct_offset+= xsct.pxsct_ctext_len;
+ buf = xsct.pxsct_ctext;
+ buf_len = xsct.pxsct_ctext_len;
}
- xsct.pxsct_offset+= xsct.pxsct_ctext_len;
EVP_MD_CTX_init(&mdctx);
EVP_DigestInit_ex(&mdctx, md, NULL);
- EVP_DigestUpdate(&mdctx, xsct.pxsct_ctext, xsct.pxsct_ctext_len);
+ EVP_DigestUpdate(&mdctx, buf, buf_len);
- dprintf(("read %d bytes from kernel\n\n", bytes_to_read));
- dprintf(("printing contents of buffer:"));
- for (i=0; i < (int)bytes_to_read; i++) dprintf(("%c", xsct.pxsct_ctext[i]));
- dprintf(("!\n"));
+ //dprintf(("read %d bytes\n\n", buf_len));
+ //dprintf(("printing contents of buffer:"));
+ //for (i=0; i < (int)buf_len; i++) dprintf(("%c", buf[i]));
+ //dprintf(("!\n"));
csp = malloc(sizeof(struct checksum));
if (csp == NULL) {
@@ -320,6 +357,15 @@
fhp->nhashes++;
}
+ /*
+ * XXXgpf: [TODO] better move the fp into file_header struct and deal with
+ * closing it during pefs_file_close.
+ */
+ if (fp != NULL) {
+ fclose(fp);
+ fhp->fd = -1;
+ }
+
return (0);
}
@@ -333,11 +379,11 @@
}
static int
-pefs_allocate_hash_table(struct cuckoo_hash_table *chtp, uint32_t nelements, int flags)
+pefs_allocate_hash_table(struct cuckoo_hash_table *chtp, uint32_t nelements, int alloc_flag)
{
uint32_t i;
- if (flags == PEFS_EXTEND) {
+ if (alloc_flag == PEFS_EXTEND) {
/*
* spending 15% more space for each table lowers the chance to fall into an
* infinite loop during cuckoo insertion to about 1.5%.
@@ -349,12 +395,12 @@
return (PEFS_ERR_GENERIC);
}
}
- else if (flags == PEFS_NOEXTEND) {
+ else if (alloc_flag == PEFS_NOEXTEND) {
chtp->size = nelements;
chtp->nelements = nelements;
}
/* reallocate the hash tables in case of infinite loop during cuckoo insert */
- else if (flags == PEFS_REALLOC) {
+ else if (alloc_flag == PEFS_REALLOC) {
chtp->size = pefs_next_prime(chtp->size + 1);
if (chtp->size < chtp->nelements) {
pefs_warn("numeric overflow while computing new hash table size");
@@ -582,11 +628,40 @@
* file id used is checksum = VMAC(E(tweak || filename))
*/
static int
-pefs_get_file_id(struct file_header *fhp)
+pefs_get_file_id(struct file_header *fhp, int flags)
{
struct pefs_xnamecsum xncs;
uint64_t temp;
- int error;
+ char *enc, *buf;
+ int error, r;
+ size_t buf_len, enc_len;
+
+ if ((flags & PEFS_NOKEY) != 0 || (flags & PEFS_UNMOUNTED) != 0) {
+ enc = fhp->filename;
+ enc_len = strnlen(fhp->filename, sizeof(fhp->filename));
+ enc++;
+ enc_len--;
+ buf_len = MAXNAMLEN + 1;
+ buf = malloc(buf_len);
+ if (buf == NULL) {
+ pefs_warn("memory allocation error");
+ return (PEFS_ERR_SYS);
+ }
+
+ r = pefs_name_pton(enc, enc_len, buf, buf_len);
+ if (r <= 0) {
+ pefs_warn("failed to extract file id from encrypted filename: %s", fhp->filename);
+ error = PEFS_ERR_GENERIC;
+ }
+ else {
+ memcpy(&temp, buf, sizeof(temp));
+ fhp->file_id = be64toh(temp);
+ error = 0;
+ }
+
+ free(buf);
+ return (error);
+ }
strlcpy(xncs.pxnc_filename, fhp->filename, sizeof(xncs.pxnc_filename));
xncs.pxnc_namelen = strnlen(xncs.pxnc_filename, sizeof(xncs.pxnc_filename));
@@ -600,7 +675,7 @@
fhp->file_id = be64toh(temp);
}
else
- pefs_warn("failed to fetch file id from kernel");
+ pefs_warn("failed to fetch file id from kernel for filename: %s", fhp->filename);
return (error);
}
@@ -662,7 +737,7 @@
continue;
}
- error = pefs_get_file_id(&targetfh);
+ error = pefs_get_file_id(&targetfh, 0);
if (error == 0) {
res = pefs_cuckoo_lookup(chtp, &targetfh);
if (res == NULL)
@@ -753,7 +828,7 @@
}
static int
-pefs_open_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, int flags)
{
char dirbuf[MAXPATHLEN + 1], namebuf[MAXNAMLEN + 1];
char sbuf[MAXPATHLEN + 1];
@@ -840,9 +915,15 @@
* symlink.
* e.g. a directory
*/
- if (lstat(fhp->target_path, &sb) != 0) {
- warn("cannot stat symlink's target file %s", fhp->target_path);
- return (PEFS_ERR_SYS);
+ if ((flags & PEFS_NOKEY) == 0 && (flags & PEFS_UNMOUNTED) == 0) {
+ /*
+ * If target_path is encrypted due to no key or unmounted fs,
+ * lstat will always fail.
+ */
+ if (lstat(fhp->target_path, &sb) != 0) {
+ warn("cannot stat symlink's target file %s", fhp->target_path);
+ return (PEFS_ERR_SYS);
+ }
}
/*
@@ -880,16 +961,18 @@
return (PEFS_ERR_INVALID);
}
- if (fstatfs(fhp->fd, &this_fs) == -1) {
- pefs_warn("statfs failed: %s: %s", fhp->path, strerror(errno));
- return (PEFS_ERR_SYS);
- }
+ if ((flags & PEFS_UNMOUNTED) == 0) {
+ if (fstatfs(fhp->fd, &this_fs) == -1) {
+ pefs_warn("statfs failed: %s: %s", fhp->path, strerror(errno));
+ return (PEFS_ERR_SYS);
+ }
- if ((fsp->f_fsid.val[0] != this_fs.f_fsid.val[0]) ||
- (fsp->f_fsid.val[1] != this_fs.f_fsid.val[1])) {
- pefs_warn("filename: %s does not reside in filesystem %s",
- fhp->path, fsp->f_mntonname);
- return (PEFS_ERR_INVALID);
+ if ((fsp->f_fsid.val[0] != this_fs.f_fsid.val[0]) ||
+ (fsp->f_fsid.val[1] != this_fs.f_fsid.val[1])) {
+ pefs_warn("filename: %s does not reside in filesystem %s",
+ fhp->path, fsp->f_mntonname);
+ return (PEFS_ERR_INVALID);
+ }
}
/* Keep all hardlink file headers in a rb tree */
@@ -977,19 +1060,19 @@
TAILQ_INIT(&fh_head);
RB_INIT(&hlc_head);
while((fhp = pefs_next_file(fpin, &error, &nfiles)) != NULL) {
- error = pefs_open_semantic_checks(fhp, &fs, &hlc_head);
+ error = pefs_open_semantic_checks(fhp, &fs, &hlc_head, 0);
if (error != 0) {
pefs_close_file(fhp);
return (error);
}
- error = pefs_get_file_id(fhp);
+ error = pefs_get_file_id(fhp, 0);
if (error != 0) {
pefs_close_file(fhp);
return (error);
}
- error = pefs_compute_file_checksums(fhp, md, hash_len);
+ error = pefs_compute_file_checksums(fhp, md, hash_len, 0);
if (error != 0) {
pefs_close_file(fhp);
return (error);
@@ -1602,7 +1685,8 @@
*/
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 *path, struct statfs *fsp, struct hardlink_head *hlc_headp, struct file_header_head *fh_headp,
+ int flags)
{
char tmpath[MAXPATHLEN];
struct stat sb;
@@ -1614,6 +1698,7 @@
while (dirp) {
sdp = readdir(dirp);
if (sdp != NULL) {
+ /* XXXgpf: Need to pay special attention to these files */
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)
@@ -1629,7 +1714,7 @@
closedir(dirp);
return (PEFS_ERR_SYS);
}
- error = pefs_traverse_fs(chtp, md, hash_len, dirtmp, tmpath, fsp, hlc_headp, fh_headp);
+ error = pefs_traverse_fs(chtp, md, hash_len, dirtmp, tmpath, fsp, hlc_headp, fh_headp, flags);
if (error != 0) {
closedir(dirp);
return (PEFS_ERR_SYS);
@@ -1652,14 +1737,15 @@
return (PEFS_ERR_SYS);
}
strlcpy(fhp->path, tmpath, sizeof(fhp->path));
- error = pefs_open_semantic_checks(fhp, fsp, NULL);
+
+ error = pefs_open_semantic_checks(fhp, fsp, NULL, flags);
if (error != 0) {
closedir(dirp);
free(fhp);
return (error);
}
- error = pefs_get_file_id(fhp);
+ error = pefs_get_file_id(fhp, flags);
if (error != 0) {
pefs_close_file(fhp);
free(fhp);
@@ -1674,13 +1760,14 @@
}
indexfhp->found = 1;
- error = pefs_compute_file_checksums(fhp, md, hash_len);
+ error = pefs_compute_file_checksums(fhp, md, hash_len, flags);
if (error != 0) {
pefs_close_file(fhp);
free(fhp);
return (error);
}
+ /* get sb for pefs_rb_insert */
error = lstat(fhp->path, &sb);
if (error != 0) {
warn("cannot stat file %s", fhp->path);
@@ -1695,17 +1782,13 @@
free(fhp);
return (error);
}
-
+
/*
- * 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?
- */
+ * XXXgpf: [TODO] if error encountered during
+ * pefs_compare_cehcksums, then store this information
+ * but keep on traversing the fs to find other errors
+ * as well.
+ */
error = pefs_compare_checksums(fhp, indexfhp, hash_len);
//if (error != 0) {
//pefs_close_file(fhp);
@@ -1730,6 +1813,7 @@
return (PEFS_ERR_SYS);
}
+/* XXXgpf: probably turn this to int */
static void
pefs_found_all_entries(struct cuckoo_hash_table *chtp)
{
@@ -1757,7 +1841,7 @@
* XXXgpf: [TODO] comments
*/
int
-pefs_verify_checksum(int fdin, char *fsroot)
+pefs_verify_checksum(int fdin, char *fsroot, int flags)
{
struct statfs fs;
struct checksum_file_header cfh;
@@ -1797,25 +1881,27 @@
//pefs_print_hash_tables(&cht, hash_len);
+ RB_INIT(&hlc_head);
+ TAILQ_INIT(&fh_head);
+
dirp = opendir(fsroot);
if (dirp == NULL) {
pefs_warn("failed to open dir %s", fsroot);
return (PEFS_ERR_SYS);
}
- RB_INIT(&hlc_head);
- TAILQ_INIT(&fh_head);
-
- error = pefs_traverse_fs(&cht, md, hash_len, dirp, fsroot, &fs, &hlc_head, &fh_head);
+ error = pefs_traverse_fs(&cht, md, hash_len, dirp, fsroot, &fs, &hlc_head, &fh_head, flags);
if (error != 0)
return (error);
//pefs_rb_print(&hlc_head);
pefs_rb_warn(&hlc_head);
- pefs_symlink_warn(&cht, &fh_head);
+ if ((flags & PEFS_UNMOUNTED) == 0 && (flags & PEFS_NOKEY) == 0)
+ pefs_symlink_warn(&cht, &fh_head);
pefs_found_all_entries(&cht);
/* XXXgpf: [TODO] free mem in the end and when error occurs */
+ /* XXXgpf: [TODO] verify action should also use a signature to verify .pefs.checksum */
return (0);
}
Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c
==============================================================================
--- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c Mon Jul 2 15:19:56 2012 (r238810)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.c Mon Jul 2 15:23:00 2012 (r238811)
@@ -1102,7 +1102,7 @@
/*
* XXXgpf: Instead of a man page entry:
*
- * pefs verify checksumpath filesystem
+ * pefs verify [-u/-n] checksumpath filesystem
*
* $command ...
*
@@ -1112,12 +1112,27 @@
static int
pefs_verify(int argc, char *argv[])
{
+ struct stat sb;
char fsroot[MAXPATHLEN];
- int error, fdin, i;
+ int error, fdin, flags, i;
- while ((i = getopt(argc, argv, "a:i:p:")) != -1)
+ flags = 0;
+ while ((i = getopt(argc, argv, "nu")) != -1)
switch(i) {
- /* XXXgpf: Should I add an option to tell if it's a mounted or unmounted fs ? */
+ case 'n':
+ flags|= PEFS_NOKEY;
+ if ((flags & PEFS_UNMOUNTED) != 0) {
+ pefs_warn("flags -u and -n are mutually exclusive");
+ return (PEFS_ERR_INVALID);
+ }
+ break;
+ case 'u':
+ flags|= PEFS_UNMOUNTED;
+ if ((flags & PEFS_NOKEY) != 0) {
+ pefs_warn("flags -u and -n are mutually exclusive");
+ return (PEFS_ERR_INVALID);
+ }
+ break;
default:
pefs_usage();
}
@@ -1140,15 +1155,28 @@
argc -=1;
argv +=1;
- /* XXXgpf: For now, assume that verify works only with a mounted pefs fs */
- initfsroot(argc, argv, 0, fsroot, sizeof(fsroot));
+ if ((flags & PEFS_UNMOUNTED) == 0)
+ initfsroot(argc, argv, 0, fsroot, sizeof(fsroot));
+ else {
+ strlcpy(fsroot, argv[0], sizeof(fsroot));
+ if (stat(fsroot, &sb) != 0) {
+ warn("cannot stat fs root: %s", fsroot);
+ return (PEFS_ERR_NOENT);
+ }
- error = pefs_verify_checksum(fdin, fsroot);
+ if (S_ISDIR(sb.st_mode) == 0) {
+ pefs_warn("fs root is not a directory: %s", fsroot);
+ return (PEFS_ERR_SYS);
+ }
+ }
+
+ error = pefs_verify_checksum(fdin, fsroot, flags);
if (error == 0)
printf("everything's ok!\n");
close(fdin);
return (error);
+
}
static void
@@ -1177,7 +1205,7 @@
" pefs showchains [-fp] [-i iterations] [-k keyfile] filesystem\n"
" pefs showalgs\n"
" pefs addchecksum [-a algo] [-i inputfile] [-p checksumpath] filesystem\n"
-" pefs verify [checksumpath filesystem]\n"
+" pefs verify [-n/u] [checksumpath filesystem]\n"
);
exit(PEFS_ERR_USAGE);
}
Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h
==============================================================================
--- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h Mon Jul 2 15:19:56 2012 (r238810)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_ctl.h Mon Jul 2 15:23:00 2012 (r238811)
@@ -44,6 +44,9 @@
#define PEFS_FILE_KEYCONF ".pefs.conf"
#define PEFS_FILE_CHECKSUM ".pefs.checksum"
+#define PEFS_NOKEY 0x0001
+#define PEFS_UNMOUNTED 0x0002
+
#define PEFS_KEYCONF_ALG_IND 0
#define PEFS_KEYCONF_ITERATIONS_IND 1
@@ -95,7 +98,9 @@
const struct pefs_xkey *xk_parent);
uintmax_t pefs_keyid_as_int(char *keyid);
int pefs_create_checksum_file(FILE *fpin, char *fsroot, char *csm_path, const char *algo);
-int pefs_verify_checksum(int fdin, char *fsroot);
+int pefs_verify_checksum(int fdin, char *fsroot, int flags);
+
+int pefs_name_pton(char const *src, size_t srclen, u_char *target, size_t targsize);
const char * pefs_alg_name(struct pefs_xkey *xk);
void pefs_alg_list(FILE *stream);
Modified: soc2012/gpf/pefs_kmod/sbin/pefs/pefs_subr.c
==============================================================================
--- soc2012/gpf/pefs_kmod/sbin/pefs/pefs_subr.c Mon Jul 2 15:19:56 2012 (r238810)
+++ soc2012/gpf/pefs_kmod/sbin/pefs/pefs_subr.c Mon Jul 2 15:23:00 2012 (r238811)
@@ -74,3 +74,72 @@
return (0);
}
+#define Assert(Cond) (void)0
+
+/*
+ * Algorithm is standard base64 with few exceptions:
+ * - file system friendly alphabet
+ * - no paddings and whitespace skip
+ */
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_";
+int
+pefs_name_pton(char const *src, size_t srclen, u_char *target, size_t targsize)
+{
+ int tarindex, state, ch;
+ char *pos;
+
+ state = 0;
+ tarindex = 0;
+
+ while ((ch = *src++) != '\0' && srclen-- > 0) {
+ if (target && (size_t)tarindex >= targsize)
+ return (-1);
+
+ pos = strchr(Base64, ch);
+ if (pos == 0) /* A non-base64 character. */
+ return (-1);
+
+ switch (state) {
+ case 0:
+ if (target) {
+ target[tarindex] = (pos - Base64) << 2;
+ }
+ state = 1;
+ break;
+ case 1:
+ if (target) {
+ target[tarindex] |= (pos - Base64) >> 4;
+ if ((size_t)tarindex + 1 < targsize)
+ target[tarindex+1] =
+ ((pos - Base64) & 0x0f) << 4 ;
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ target[tarindex] |= (pos - Base64) >> 2;
+ if ((size_t)tarindex + 1 < targsize)
+ target[tarindex+1] =
+ ((pos - Base64) & 0x03) << 6;
+ }
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if (target) {
+ target[tarindex] |= (pos - Base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ return (-1);
+ }
+ }
+
+ if (tarindex == 0)
+ return (-1);
+ return (tarindex);
+}
More information about the svn-soc-all
mailing list