summaryrefslogtreecommitdiffstats
path: root/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs_subr.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs_subr.c')
-rw-r--r--contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs_subr.c358
1 files changed, 358 insertions, 0 deletions
diff --git a/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs_subr.c b/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs_subr.c
new file mode 100644
index 0000000..fcb8176
--- /dev/null
+++ b/contrib/netbsd-tests/fs/puffs/h_dtfs/dtfs_subr.c
@@ -0,0 +1,358 @@
+/* $NetBSD: dtfs_subr.c,v 1.4 2013/10/19 17:45:00 christos Exp $ */
+
+/*
+ * Copyright (c) 2006 Antti Kantee. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <puffs.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <util.h>
+
+#include "dtfs.h"
+
+void
+dtfs_baseattrs(struct vattr *vap, enum vtype type, ino_t id)
+{
+ struct timeval tv;
+ struct timespec ts;
+
+ gettimeofday(&tv, NULL);
+ TIMEVAL_TO_TIMESPEC(&tv, &ts);
+
+ vap->va_type = type;
+ if (type == VDIR) {
+ vap->va_mode = 0777;
+ vap->va_nlink = 1; /* n + 1 after adding dent */
+ } else {
+ vap->va_mode = 0666;
+ vap->va_nlink = 0; /* n + 1 */
+ }
+ vap->va_uid = 0;
+ vap->va_gid = 0;
+ vap->va_fileid = id;
+ vap->va_size = 0;
+ vap->va_blocksize = getpagesize();
+ vap->va_gen = random();
+ vap->va_flags = 0;
+ vap->va_rdev = PUFFS_VNOVAL;
+ vap->va_bytes = 0;
+ vap->va_filerev = 1;
+ vap->va_vaflags = 0;
+
+ vap->va_atime = vap->va_mtime = vap->va_ctime = vap->va_birthtime = ts;
+}
+
+/*
+ * Well, as you can probably see, this interface has the slight problem
+ * of assuming file creation will always be succesful, or at least not
+ * giving a reason for the failure. Be sure to do better when you
+ * implement your own fs.
+ */
+struct puffs_node *
+dtfs_genfile(struct puffs_node *dir, const struct puffs_cn *pcn,
+ enum vtype type)
+{
+ struct dtfs_file *dff;
+ struct dtfs_dirent *dfd;
+ struct dtfs_mount *dtm;
+ struct puffs_node *newpn;
+ uid_t uid;
+ int rv;
+
+ assert(dir->pn_va.va_type == VDIR);
+ assert(dir->pn_mnt != NULL);
+
+ uid = 0;
+ rv = puffs_cred_getuid(pcn->pcn_cred, &uid);
+ assert(rv == 0);
+
+ if (type == VDIR) {
+ dff = dtfs_newdir();
+ dff->df_dotdot = dir;
+ } else
+ dff = dtfs_newfile();
+
+ dtm = puffs_pn_getmntspecific(dir);
+ newpn = puffs_pn_new(dir->pn_mnt, dff);
+ if (newpn == NULL)
+ errx(1, "getnewpnode");
+ dtfs_baseattrs(&newpn->pn_va, type, dtm->dtm_nextfileid++);
+
+ dfd = emalloc(sizeof(struct dtfs_dirent));
+ dfd->dfd_node = newpn;
+ dfd->dfd_name = estrndup(pcn->pcn_name, pcn->pcn_namelen);
+ dfd->dfd_namelen = strlen(dfd->dfd_name);
+ dfd->dfd_parent = dir;
+ dtfs_adddent(dir, dfd);
+
+ newpn->pn_va.va_uid = uid;
+ newpn->pn_va.va_gid = dir->pn_va.va_gid;
+
+ return newpn;
+}
+
+struct dtfs_file *
+dtfs_newdir()
+{
+ struct dtfs_file *dff;
+
+ dff = emalloc(sizeof(struct dtfs_file));
+ memset(dff, 0, sizeof(struct dtfs_file));
+ LIST_INIT(&dff->df_dirents);
+
+ return dff;
+}
+
+struct dtfs_file *
+dtfs_newfile()
+{
+ struct dtfs_file *dff;
+
+ dff = emalloc(sizeof(struct dtfs_file));
+ memset(dff, 0, sizeof(struct dtfs_file));
+
+ return dff;
+}
+
+struct dtfs_dirent *
+dtfs_dirgetnth(struct dtfs_file *searchdir, int n)
+{
+ struct dtfs_dirent *dirent;
+ int i;
+
+ i = 0;
+ LIST_FOREACH(dirent, &searchdir->df_dirents, dfd_entries) {
+ if (i == n)
+ return dirent;
+ i++;
+ }
+
+ return NULL;
+}
+
+struct dtfs_dirent *
+dtfs_dirgetbyname(struct dtfs_file *searchdir, const char *fname, size_t fnlen)
+{
+ struct dtfs_dirent *dirent;
+
+ LIST_FOREACH(dirent, &searchdir->df_dirents, dfd_entries)
+ if (dirent->dfd_namelen == fnlen
+ && strncmp(dirent->dfd_name, fname, fnlen) == 0)
+ return dirent;
+
+ return NULL;
+}
+
+/*
+ * common nuke, kill dirent from parent node
+ */
+void
+dtfs_nukenode(struct puffs_node *nukeme, struct puffs_node *pn_parent,
+ const char *fname, size_t fnlen)
+{
+ struct dtfs_dirent *dfd;
+ struct dtfs_mount *dtm;
+
+ assert(pn_parent->pn_va.va_type == VDIR);
+
+ dfd = dtfs_dirgetbyname(DTFS_PTOF(pn_parent), fname, fnlen);
+ assert(dfd);
+
+ dtm = puffs_pn_getmntspecific(nukeme);
+ dtm->dtm_nfiles--;
+ assert(dtm->dtm_nfiles >= 1);
+
+ dtfs_removedent(pn_parent, dfd);
+ free(dfd);
+}
+
+/* free lingering information */
+void
+dtfs_freenode(struct puffs_node *pn)
+{
+ struct dtfs_file *df = DTFS_PTOF(pn);
+ struct dtfs_mount *dtm;
+ int i;
+
+ assert(pn->pn_va.va_nlink == 0);
+ dtm = puffs_pn_getmntspecific(pn);
+
+ switch (pn->pn_va.va_type) {
+ case VREG:
+ assert(dtm->dtm_fsizes >= pn->pn_va.va_size);
+ dtm->dtm_fsizes -= pn->pn_va.va_size;
+ for (i = 0; i < BLOCKNUM(df->df_datalen, DTFS_BLOCKSHIFT); i++)
+ free(df->df_blocks[i]);
+ if (df->df_datalen > i << DTFS_BLOCKSHIFT)
+ free(df->df_blocks[i]);
+ break;
+ case VLNK:
+ free(df->df_linktarget);
+ break;
+ case VCHR:
+ case VBLK:
+ case VDIR:
+ case VSOCK:
+ case VFIFO:
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ free(df);
+ puffs_pn_put(pn);
+}
+
+void
+dtfs_setsize(struct puffs_node *pn, off_t newsize)
+{
+ struct dtfs_file *df = DTFS_PTOF(pn);
+ struct dtfs_mount *dtm;
+ size_t newblocks;
+ int needalloc, shrinks;
+ int i;
+
+ needalloc = newsize > ROUNDUP(df->df_datalen, DTFS_BLOCKSIZE);
+ shrinks = newsize < pn->pn_va.va_size;
+
+ if (needalloc || shrinks) {
+ newblocks = BLOCKNUM(newsize, DTFS_BLOCKSHIFT) + 1;
+
+ if (shrinks)
+ for (i = newblocks; i < df->df_numblocks; i++)
+ free(df->df_blocks[i]);
+
+ df->df_blocks = erealloc(df->df_blocks,
+ newblocks * sizeof(uint8_t *));
+ /*
+ * if extended, set storage to zero
+ * to match correct behaviour
+ */
+ if (!shrinks) {
+ for (i = df->df_numblocks; i < newblocks; i++) {
+ df->df_blocks[i] = emalloc(DTFS_BLOCKSIZE);
+ memset(df->df_blocks[i], 0, DTFS_BLOCKSIZE);
+ }
+ }
+
+ df->df_datalen = newsize;
+ df->df_numblocks = newblocks;
+ }
+
+ dtm = puffs_pn_getmntspecific(pn);
+ if (!shrinks) {
+ dtm->dtm_fsizes += newsize - pn->pn_va.va_size;
+ } else {
+ dtm->dtm_fsizes -= pn->pn_va.va_size - newsize;
+ }
+
+ pn->pn_va.va_size = newsize;
+ pn->pn_va.va_bytes = BLOCKNUM(newsize,DTFS_BLOCKSHIFT)>>DTFS_BLOCKSHIFT;
+}
+
+/* add & bump link count */
+void
+dtfs_adddent(struct puffs_node *pn_dir, struct dtfs_dirent *dent)
+{
+ struct dtfs_file *dir = DTFS_PTOF(pn_dir);
+ struct puffs_node *pn_file = dent->dfd_node;
+ struct dtfs_file *file = DTFS_PTOF(pn_file);
+ struct dtfs_mount *dtm;
+
+ assert(pn_dir->pn_va.va_type == VDIR);
+ LIST_INSERT_HEAD(&dir->df_dirents, dent, dfd_entries);
+ pn_file->pn_va.va_nlink++;
+
+ dtm = puffs_pn_getmntspecific(pn_file);
+ dtm->dtm_nfiles++;
+
+ dent->dfd_parent = pn_dir;
+ if (dent->dfd_node->pn_va.va_type == VDIR) {
+ file->df_dotdot = pn_dir;
+ pn_dir->pn_va.va_nlink++;
+ }
+
+ dtfs_updatetimes(pn_dir, 0, 1, 1);
+}
+
+/* remove & lower link count */
+void
+dtfs_removedent(struct puffs_node *pn_dir, struct dtfs_dirent *dent)
+{
+ struct puffs_node *pn_file = dent->dfd_node;
+
+ assert(pn_dir->pn_va.va_type == VDIR);
+ LIST_REMOVE(dent, dfd_entries);
+ if (pn_file->pn_va.va_type == VDIR) {
+ struct dtfs_file *df = DTFS_PTOF(pn_file);
+
+ pn_dir->pn_va.va_nlink--;
+ df->df_dotdot = NULL;
+ }
+ pn_file->pn_va.va_nlink--;
+ assert(pn_dir->pn_va.va_nlink >= 2);
+
+ dtfs_updatetimes(pn_dir, 0, 1, 1);
+}
+
+void
+dtfs_updatetimes(struct puffs_node *pn, int doatime, int doctime, int domtime)
+{
+ struct timeval tv;
+ struct timespec ts;
+
+ gettimeofday(&tv, NULL);
+ TIMEVAL_TO_TIMESPEC(&tv, &ts);
+
+ if (doatime)
+ pn->pn_va.va_atime = ts;
+ if (doctime)
+ pn->pn_va.va_ctime = ts;
+ if (domtime)
+ pn->pn_va.va_mtime = ts;
+}
+
+bool
+dtfs_isunder(struct puffs_node *pn, struct puffs_node *pn_parent)
+{
+ struct dtfs_file *df;
+
+ while (pn) {
+ if (pn == pn_parent)
+ return true;
+ df = DTFS_CTOF(pn);
+ pn = df->df_dotdot;
+ }
+
+ return false;
+}
OpenPOWER on IntegriCloud