Beispiel #1
0
Datei: null.c Projekt: glk/puffs
/*ARGSUSED*/
int
puffs_null_node_write(struct puffs_usermount *pu, puffs_cookie_t opc,
	uint8_t *buf, off_t offset, size_t *buflen,
	const struct puffs_cred *pcred, int ioflag)
{
	struct puffs_node *pn = opc;
	ssize_t n;
	off_t off;
	int fd, rv;

	rv = 0;
	fd = writeableopen(PNPATH(pn));
	if (fd == -1)
		return errno;

	off = lseek(fd, offset, SEEK_SET);
	if (off == -1) {
		rv = errno;
		goto out;
	}

	n = write(fd, buf, *buflen);
	if (n == -1)
		rv = errno;
	else
		*buflen -= n;

 out:
	close(fd);
	return rv;
}
Beispiel #2
0
Datei: null.c Projekt: glk/puffs
/*ARGSUSED*/
int
puffs_null_fs_statvfs(struct puffs_usermount *pu, struct statfs *svfsb)
{

	if (statfs(PNPATH(puffs_getroot(pu)), svfsb) == -1)
		return errno;

	return 0;
}
Beispiel #3
0
Datei: null.c Projekt: glk/puffs
/*ARGSUSED*/
int
puffs_null_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc,
	struct dirent *de, off_t *off, size_t *reslen,
	const struct puffs_cred *pcred, int *eofflag, off_t *cookies,
	size_t *ncookies)
{
	struct puffs_node *pn = opc;
	struct dirent entry, *result;
	DIR *dp;
	off_t i;
	int rv;

	*ncookies = 0;
	dp = opendir(PNPATH(pn));
	if (dp == NULL)
		return errno;

	rv = 0;
	i = *off;

	/*
	 * XXX: need to do trickery here, telldir/seekdir would be nice, but
	 * then we'd need to keep state, which I'm too lazy to keep
	 */
	while (i--) {
		rv = readdir_r(dp, &entry, &result);
		if (rv || !result)
			goto out;
	}

	for (;;) {
		rv = readdir_r(dp, &entry, &result);
		if (rv != 0)
			goto out;

		if (!result) {
			*eofflag = 1;
			goto out;
		}

		if (_DIRENT_SIZE(result) > *reslen)
			goto out;

		*de = *result;
		*reslen -= _DIRENT_SIZE(result);
		de = _DIRENT_NEXT(de);

		(*off)++;
		PUFFS_STORE_DCOOKIE(cookies, ncookies, *off);
	}

 out:
	closedir(dp);
	return 0;
}
Beispiel #4
0
Datei: null.c Projekt: glk/puffs
/*ARGSUSED*/
int
puffs_null_node_link(struct puffs_usermount *pu, puffs_cookie_t opc,
	puffs_cookie_t targ, const struct puffs_cn *pcn)
{
	struct puffs_node *pn_targ = targ;

	if (link(PNPATH(pn_targ), PCNPATH(pcn)) == -1)
		return errno;

	return 0;
}
Beispiel #5
0
Datei: null.c Projekt: glk/puffs
/*ARGSUSED*/
int
puffs_null_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc,
	puffs_cookie_t targ, const struct puffs_cn *pcn)
{
	struct puffs_node *pn_targ = targ;

	if (rmdir(PNPATH(pn_targ)) == -1)
		return errno;
	puffs_pn_remove(pn_targ);

	return 0;
}
Beispiel #6
0
int
sysctlfs_fs_nodetofh(struct puffs_usermount *pu, void *cookie,
	void *fid, size_t *fidsize)
{
	struct puffs_node *pn = cookie;
	struct sfsfid *sfid;

	sfid = fid;
	sfid->len = PNPLEN(pn);
	memcpy(&sfid->path, PNPATH(pn), sfid->len * sizeof(int));

	return 0;
}
Beispiel #7
0
Datei: null.c Projekt: glk/puffs
/*ARGSUSED*/
int
puffs_null_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc,
	struct vattr *va, const struct puffs_cred *pcred)
{
	struct puffs_node *pn = opc;
	struct stat sb;

	if (lstat(PNPATH(pn), &sb) == -1)
		return errno;
	puffs_stat2vattr(va, &sb);

	return 0;
}
Beispiel #8
0
Datei: null.c Projekt: glk/puffs
/*ARGSUSED*/
int
puffs_null_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc,
	const struct puffs_cred *pcred, char *linkname, size_t *linklen)
{
	struct puffs_node *pn = opc;
	ssize_t rv;

	rv = readlink(PNPATH(pn), linkname, *linklen);
	if (rv == -1)
		return errno;

	*linklen = rv;
	return 0;
}
Beispiel #9
0
Datei: null.c Projekt: glk/puffs
/*ARGSUSED*/
int
puffs_null_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc,
	const struct vattr *va, const struct puffs_cred *pcred)
{
	struct puffs_node *pn = opc;
	int rv;

	rv = processvattr(PNPATH(pn), va, pn->pn_va.va_type == VREG);
	if (rv)
		return rv;

	puffs_setvattr(&pn->pn_va, va);

	return 0;
}
Beispiel #10
0
int
getnodeattr(struct puffs_usermount *pu, struct puffs_node *pn, const char *path)
{
	struct psshfs_ctx *pctx = puffs_getspecific(pu);
	struct psshfs_node *psn = pn->pn_data;
	struct vattr va;
	int rv;

	if (!psn->attrread || REFRESHTIMEOUT(pctx, time(NULL)-psn->attrread)) {
		rv = getpathattr(pu, path ? path : PNPATH(pn), &va);
		if (rv)
			return rv;

		setpnva(pu, pn, &va);
	}

	return 0;
}
Beispiel #11
0
Datei: null.c Projekt: glk/puffs
/*ARGSUSED*/
int
puffs_null_node_fsync(struct puffs_usermount *pu, puffs_cookie_t opc,
	const struct puffs_cred *pcred, int how,
	off_t offlo, off_t offhi)
{
	struct puffs_node *pn = opc;
	int fd, rv;
	int fflags;

	rv = 0;
	fd = writeableopen(PNPATH(pn));
	if (fd == -1)
		return errno;

	if (fsync(fd) == -1)
		rv = errno;

	close(fd);

	return rv;
}
Beispiel #12
0
/*
 * called from nodewalk, checks for exact match
 */
void *
puffs_path_walkcmp(struct puffs_usermount *pu, struct puffs_node *pn, void *arg)
{
	struct puffs_pathobj *po = arg;
	struct puffs_pathobj po2;

	if (po->po_len != PNPLEN(pn))
		return NULL;

	/*
	 * If hashing and the hash doesn't match, we know this is
	 * definitely not a match.  Otherwise check for collisions.
	 */
	if (pu->pu_flags & PUFFS_FLAG_HASHPATH)
		if (pn->pn_po.po_hash != po->po_hash)
			return NULL;

	po2.po_path = PNPATH(pn);
	po2.po_len = PNPLEN(pn);

	if (pu->pu_pathcmp(pu, po, &po2, PNPLEN(pn), 0) == 0)
		return pn;
	return NULL;
}
Beispiel #13
0
Datei: null.c Projekt: glk/puffs
/*ARGSUSED*/
int
puffs_null_fs_nodetofh(struct puffs_usermount *pu, puffs_cookie_t opc,
	void *fid, size_t *fidsize)
{
	struct puffs_node *pn = opc;
	fhandle_t fh;
	int rv;

	if (*fidsize != sizeof(struct fid))
		return EINVAL;

	rv = 0;
	if (getfh(PNPATH(pn), &fh) == -1)
		rv = errno;
	if (rv == 0) {
		*(struct fid *)fid = fh.fh_fid;
		pn->pn_data = malloc(*fidsize);
		if (pn->pn_data == NULL)
			abort(); /* lazy */
		memcpy(pn->pn_data, fid, *fidsize);
	}

	return rv;
}
Beispiel #14
0
int
sysctlfs_node_write(struct puffs_usermount *pu, void *opc, uint8_t *buf,
	off_t offset, size_t *resid, const struct puffs_cred *cred,
	int ioflag)
{
	struct puffs_node *pn = opc;
	struct sfsnode *sfs = pn->pn_data;
	long long ll;
	int i, rv;
	bool b;

	/*
	 * I picked the wrong day to ... um, the wrong place to return errors
	 */

	/* easy to support, but just unavailable now */
	if (rflag)
		return EOPNOTSUPP;

	if (puffs_cred_isjuggernaut(cred) == 0)
		return EACCES;

	if (ISADIR(sfs))
		return EISDIR;

	if (offset != 0)
		return EINVAL;

	if (ioflag & PUFFS_IO_APPEND)
		return EINVAL;

	switch (SYSCTL_TYPE(sfs->sysctl_flags)) {
	case CTLTYPE_BOOL:
		if (strcasestr((const char *)buf, "true"))
			b = true;
		else if (strcasestr((const char *)buf, "false"))
			b = false;
		else
			return EINVAL;
		rv = sysctl(PNPATH(pn), PNPLEN(pn), NULL, NULL,
		    &b, sizeof(b));
		break;
	case CTLTYPE_INT:
		if (sscanf((const char *)buf, "%d", &i) != 1)
			return EINVAL;
		rv = sysctl(PNPATH(pn), PNPLEN(pn), NULL, NULL,
		    &i, sizeof(int));
		break;
	case CTLTYPE_QUAD:
		if (sscanf((const char *)buf, "%lld", &ll) != 1)
			return EINVAL;
		rv =  sysctl(PNPATH(pn), PNPLEN(pn), NULL, NULL,
		    &ll, sizeof(long long));
		break;
	case CTLTYPE_STRING:
		rv = sysctl(PNPATH(pn), PNPLEN(pn), NULL, NULL, buf, *resid);
		break;
	default:
		rv = EINVAL;
		break;
	}

	if (rv)
		return rv;

	*resid = 0;
	return 0;
}
Beispiel #15
0
int
sysctlfs_node_readdir(struct puffs_usermount *pu, void *opc,
	struct dirent *dent, off_t *readoff, size_t *reslen,
	const struct puffs_cred *pcr, int *eofflag,
	off_t *cookies, size_t *ncookies)
{
	struct sysctlnode sn[SFS_NODEPERDIR];
	struct sysctlnode qnode;
	struct puffs_node *pn_dir = opc;
	struct puffs_node *pn_res;
	struct puffs_pathobj po;
	struct sfsnode *sfs_dir = pn_dir->pn_data, *sfs_ent;
	SfsName *sname;
	size_t sl, i;
	enum vtype vt;
	ino_t id;

	*ncookies = 0;

 again:
	if (*readoff == DENT_DOT || *readoff == DENT_DOTDOT) {
		puffs_gendotdent(&dent, sfs_dir->myid, *readoff, reslen);
		(*readoff)++;
		PUFFS_STORE_DCOOKIE(cookies, ncookies, *readoff);
		goto again;
	}

	memset(&qnode, 0, sizeof(qnode));
	sl = SFS_NODEPERDIR * sizeof(struct sysctlnode);
	qnode.sysctl_flags = SYSCTL_VERSION;
	sname = PNPATH(pn_dir);
	(*sname)[PNPLEN(pn_dir)] = CTL_QUERY;

	if (sysctl(*sname, PNPLEN(pn_dir) + 1, sn, &sl,
	    &qnode, sizeof(qnode)) == -1)
		return ENOENT;

	po.po_path = sname;
	po.po_len = PNPLEN(pn_dir)+1;

	for (i = DENT_ADJ(*readoff); i < sl / sizeof(struct sysctlnode); i++) {
		if (SYSCTL_TYPE(sn[i].sysctl_flags) == CTLTYPE_NODE)
			vt = VDIR;
		else
			vt = VREG;

		/*
		 * check if the node exists.  if so, give it the real
		 * inode number.  otherwise just fake it.
		 */
		(*sname)[PNPLEN(pn_dir)] = sn[i].sysctl_num;
		pn_res = puffs_pn_nodewalk(pu, puffs_path_walkcmp, &po);
		if (pn_res) {
			sfs_ent = pn_res->pn_data;
			id = sfs_ent->myid;
		} else {
			id = nextid++;
		}

		if (!puffs_nextdent(&dent, sn[i].sysctl_name, id,
		    puffs_vtype2dt(vt), reslen))
			return 0;

		(*readoff)++;
		PUFFS_STORE_DCOOKIE(cookies, ncookies, *readoff);
	}

	*eofflag = 1;
	return 0;
}
Beispiel #16
0
int
sftp_readdir(struct puffs_usermount *pu, struct psshfs_ctx *pctx,
	struct puffs_node *pn)
{
	struct puffs_cc *pcc = puffs_cc_getcc(pu);
	struct psshfs_node *psn = pn->pn_data;
	struct psshfs_dir *olddir, *testd;
	struct puffs_framebuf *pb;
	uint32_t reqid = NEXTREQ(pctx);
	uint32_t count, dhandlen;
	int tmpval;
	char *dhand = NULL;
	size_t nent;
	char *longname = NULL;
	size_t idx;
	int rv;

	assert(pn->pn_va.va_type == VDIR);
	idx = 0;
	olddir = psn->dir;
	nent = psn->dentnext;

	if (psn->dir && psn->dentread
	    && !REFRESHTIMEOUT(pctx, time(NULL) - psn->dentread))
		return 0;

	if (psn->dentread) {
		if ((rv = puffs_inval_namecache_dir(pu, pn)))
			warn("readdir: dcache inval fail %p", pn);
	}

	pb = psbuf_makeout();
	psbuf_req_str(pb, SSH_FXP_OPENDIR, reqid, PNPATH(pn));
	if (puffs_framev_enqueue_cc(pcc, pctx->sshfd, pb, 0) == -1) {
		rv = errno;
		goto wayout;
	}
	rv = psbuf_expect_handle(pb, &dhand, &dhandlen);
	if (rv)
		goto wayout;

	/*
	 * Well, the following is O(n^2), so feel free to improve if it
	 * gets too taxing on your system.
	 */

	/*
	 * note: for the "getattr in batch" to work, this must be before
	 * the attribute-getting.  Otherwise times for first entries in
	 * large directories might expire before the directory itself and
	 * result in one-by-one attribute fetching.
	 */
	psn->dentread = time(NULL);

	psn->dentnext = 0;
	psn->denttot = 0;
	psn->dir = NULL;

	for (;;) {
		reqid = NEXTREQ(pctx);
		psbuf_recycleout(pb);
		psbuf_req_data(pb, SSH_FXP_READDIR, reqid, dhand, dhandlen);
		GETRESPONSE(pb, pctx->sshfd);

		/* check for EOF */
		if (psbuf_get_type(pb) == SSH_FXP_STATUS) {
			rv = psbuf_expect_status(pb);
			goto out;
		}
		rv = psbuf_expect_name(pb, &count);
		if (rv)
			goto out;

		for (; count--; idx++) {
			if (idx == psn->denttot)
				allocdirs(psn);
			if ((rv = psbuf_get_str(pb,
			    &psn->dir[idx].entryname, NULL)))
				goto out;
			if ((rv = psbuf_get_str(pb, &longname, NULL)) != 0)
				goto out;
			if ((rv = psbuf_get_vattr(pb, &psn->dir[idx].va)) != 0)
				goto out;
			if (sscanf(longname, "%*s%d",
			    &tmpval) != 1) {
				rv = EPROTO;
				goto out;
			}
			psn->dir[idx].va.va_nlink = tmpval;
			free(longname);
			longname = NULL;

			/*
			 * In case of DOT, copy the attributes (mostly
			 * because we want the link count for the root dir).
			 */
			if (strcmp(psn->dir[idx].entryname, ".") == 0) {
				setpnva(pu, pn, &psn->dir[idx].va);
			}

			/*
			 * Check if we already have a psshfs_dir for the
			 * name we are processing.  If so, use the old one.
			 * If not, create a new one
			 */
			testd = lookup(olddir, nent, psn->dir[idx].entryname);
			if (testd) {
				psn->dir[idx].entry = testd->entry;
				/*
				 * Has entry.  Update attributes to what
				 * we just got from the server.
				 */
				if (testd->entry) {
					setpnva(pu, testd->entry,
					    &psn->dir[idx].va);
					psn->dir[idx].va.va_fileid
					    = testd->entry->pn_va.va_fileid;

				/*
				 * No entry.  This can happen in two cases:
				 * 1) the file was created "behind our back"
				 *    on the server
				 * 2) we do two readdirs before we instantiate
				 *    the node (or run with -t 0).
				 *
				 * Cache attributes from the server in
				 * case we want to instantiate this node
				 * soon.  Also preserve the old inode number
				 * which was given when the dirent was created.
				 */
				} else {
					psn->dir[idx].va.va_fileid
					    = testd->va.va_fileid;
					testd->va = psn->dir[idx].va;
				}

			/* No previous entry?  Initialize this one. */
			} else {
				psn->dir[idx].entry = NULL;
				psn->dir[idx].va.va_fileid = pctx->nextino++;
			}
			psn->dir[idx].attrread = psn->dentread;
			psn->dir[idx].valid = 1;
		}
	}

 out:
	/* XXX: rv */
	psn->dentnext = idx;
	freedircache(olddir, nent);

	reqid = NEXTREQ(pctx);
	psbuf_recycleout(pb);
	psbuf_req_data(pb, SSH_FXP_CLOSE, reqid, dhand, dhandlen);
	puffs_framev_enqueue_justsend(pu, pctx->sshfd, pb, 1, 0);
	free(dhand);
	free(longname);

	return rv;

 wayout:
	free(dhand);
	PSSHFSRETURN(rv);
}