2007-08-23 19:19:40 +04:00
|
|
|
/* $NetBSD: subr.c,v 1.26 2007/08/23 15:19:40 pooka Exp $ */
|
2006-12-29 18:35:39 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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/cdefs.h>
|
|
|
|
#ifndef lint
|
2007-08-23 19:19:40 +04:00
|
|
|
__RCSID("$NetBSD: subr.c,v 1.26 2007/08/23 15:19:40 pooka Exp $");
|
2006-12-29 18:35:39 +03:00
|
|
|
#endif /* !lint */
|
|
|
|
|
|
|
|
#include <assert.h>
|
2007-06-21 17:53:00 +04:00
|
|
|
#include <err.h>
|
2006-12-29 18:35:39 +03:00
|
|
|
#include <errno.h>
|
|
|
|
#include <puffs.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <util.h>
|
|
|
|
|
|
|
|
#include "psshfs.h"
|
|
|
|
#include "sftp_proto.h"
|
|
|
|
|
|
|
|
static void
|
|
|
|
freedircache(struct psshfs_dir *base, size_t count)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
free(base[i].entryname);
|
|
|
|
base[i].entryname = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(base);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define ENTRYCHUNK 16
|
|
|
|
static void
|
|
|
|
allocdirs(struct psshfs_node *psn)
|
|
|
|
{
|
|
|
|
size_t oldtot = psn->denttot;
|
|
|
|
|
|
|
|
psn->denttot += ENTRYCHUNK;
|
|
|
|
psn->dir = erealloc(psn->dir,
|
|
|
|
psn->denttot * sizeof(struct psshfs_dir));
|
|
|
|
memset(psn->dir + oldtot, 0, ENTRYCHUNK * sizeof(struct psshfs_dir));
|
2007-05-20 21:47:12 +04:00
|
|
|
|
|
|
|
psn->da = erealloc(psn->da, psn->denttot * sizeof(struct delayattr));
|
2006-12-29 18:35:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
struct psshfs_dir *
|
2007-02-15 16:07:29 +03:00
|
|
|
lookup(struct psshfs_dir *bdir, size_t ndir, const char *name)
|
2006-12-29 18:35:39 +03:00
|
|
|
{
|
2007-02-15 16:07:29 +03:00
|
|
|
struct psshfs_dir *test;
|
2006-12-29 18:35:39 +03:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ndir; i++) {
|
2007-02-15 16:07:29 +03:00
|
|
|
test = &bdir[i];
|
|
|
|
if (test->valid != 1)
|
2006-12-29 18:35:39 +03:00
|
|
|
continue;
|
2007-02-15 16:07:29 +03:00
|
|
|
if (strcmp(test->entryname, name) == 0)
|
|
|
|
return test;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct psshfs_dir *
|
|
|
|
lookup_by_entry(struct psshfs_dir *bdir, size_t ndir, struct puffs_node *entry)
|
|
|
|
{
|
|
|
|
struct psshfs_dir *test;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ndir; i++) {
|
|
|
|
test = &bdir[i];
|
|
|
|
if (test->valid != 1)
|
|
|
|
continue;
|
|
|
|
if (test->entry == entry)
|
|
|
|
return test;
|
2006-12-29 18:35:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-02-10 02:36:17 +03:00
|
|
|
struct readdirattr {
|
|
|
|
struct psshfs_node *psn;
|
|
|
|
int idx;
|
|
|
|
char entryname[MAXPATHLEN+1];
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
2007-05-05 19:49:51 +04:00
|
|
|
readdir_getattr_resp(struct puffs_usermount *pu,
|
2007-05-16 14:04:08 +04:00
|
|
|
struct puffs_framebuf *pb, void *arg, int error)
|
2007-02-10 02:36:17 +03:00
|
|
|
{
|
|
|
|
struct readdirattr *rda = arg;
|
|
|
|
struct psshfs_node *psn = rda->psn;
|
2007-05-21 00:27:04 +04:00
|
|
|
struct psshfs_node *psn_targ = NULL;
|
|
|
|
struct psshfs_dir *pdir = NULL;
|
2007-02-10 02:36:17 +03:00
|
|
|
struct vattr va;
|
|
|
|
|
2007-05-21 00:27:04 +04:00
|
|
|
/* XXX: this is not enough */
|
|
|
|
if (psn->stat & PSN_RECLAIMED)
|
|
|
|
goto out;
|
|
|
|
|
2007-05-16 14:04:08 +04:00
|
|
|
if (error)
|
|
|
|
goto out;
|
|
|
|
|
2007-02-10 02:36:17 +03:00
|
|
|
pdir = lookup(psn->dir, psn->denttot, rda->entryname);
|
|
|
|
if (!pdir)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (psbuf_expect_attrs(pb, &va))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (pdir->entry) {
|
|
|
|
psn_targ = pdir->entry->pn_data;
|
|
|
|
|
|
|
|
puffs_setvattr(&pdir->entry->pn_va, &va);
|
|
|
|
psn_targ->attrread = time(NULL);
|
|
|
|
} else {
|
|
|
|
puffs_setvattr(&pdir->va, &va);
|
|
|
|
pdir->attrread = time(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2007-05-21 00:06:23 +04:00
|
|
|
if (psn_targ) {
|
|
|
|
psn_targ->getattr_pb = NULL;
|
|
|
|
assert(pdir->getattr_pb == NULL);
|
2007-05-21 00:27:04 +04:00
|
|
|
} else if (pdir) {
|
2007-05-21 00:06:23 +04:00
|
|
|
pdir->getattr_pb = NULL;
|
|
|
|
}
|
|
|
|
|
2007-02-10 02:36:17 +03:00
|
|
|
free(rda);
|
2007-05-05 19:49:51 +04:00
|
|
|
puffs_framebuf_destroy(pb);
|
2007-02-10 02:36:17 +03:00
|
|
|
}
|
|
|
|
|
2007-05-20 21:47:12 +04:00
|
|
|
static void
|
2007-05-05 19:49:51 +04:00
|
|
|
readdir_getattr(struct puffs_usermount *pu, struct psshfs_node *psn,
|
2007-02-10 02:36:17 +03:00
|
|
|
const char *basepath, int idx)
|
|
|
|
{
|
|
|
|
char path[MAXPATHLEN+1];
|
2007-05-05 19:49:51 +04:00
|
|
|
struct psshfs_ctx *pctx = puffs_getspecific(pu);
|
2007-02-10 02:36:17 +03:00
|
|
|
struct psshfs_dir *pdir = psn->dir;
|
2007-05-05 19:49:51 +04:00
|
|
|
struct puffs_framebuf *pb;
|
2007-02-10 02:36:17 +03:00
|
|
|
struct readdirattr *rda;
|
|
|
|
const char *entryname = pdir[idx].entryname;
|
|
|
|
uint32_t reqid = NEXTREQ(pctx);
|
|
|
|
|
|
|
|
rda = emalloc(sizeof(struct readdirattr));
|
|
|
|
rda->psn = psn;
|
|
|
|
rda->idx = idx;
|
|
|
|
strlcpy(rda->entryname, entryname, sizeof(rda->entryname));
|
|
|
|
|
|
|
|
strcpy(path, basepath);
|
|
|
|
strcat(path, "/");
|
|
|
|
strlcat(path, entryname, sizeof(path));
|
|
|
|
|
2007-05-05 19:49:51 +04:00
|
|
|
pb = psbuf_makeout();
|
2007-02-10 02:36:17 +03:00
|
|
|
psbuf_req_str(pb, SSH_FXP_LSTAT, reqid, path);
|
2007-05-20 21:47:12 +04:00
|
|
|
psn->da[psn->nextda].pufbuf = pb;
|
|
|
|
psn->da[psn->nextda].rda = rda;
|
|
|
|
psn->nextda++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
readdir_getattr_send(struct puffs_usermount *pu, struct psshfs_node *psn)
|
|
|
|
{
|
|
|
|
struct psshfs_ctx *pctx = puffs_getspecific(pu);
|
2007-05-21 00:06:23 +04:00
|
|
|
struct psshfs_dir *pdir = psn->dir;
|
|
|
|
struct psshfs_node *psn_targ;
|
|
|
|
struct readdirattr *rda;
|
2007-05-20 21:47:12 +04:00
|
|
|
size_t i;
|
|
|
|
int rv = 0;
|
|
|
|
|
2007-05-21 00:06:23 +04:00
|
|
|
for (i = 0; i < psn->nextda; i++) {
|
|
|
|
rda = psn->da[i].rda;
|
|
|
|
if (pdir[rda->idx].entry) {
|
|
|
|
psn_targ = pdir[rda->idx].entry->pn_data;
|
|
|
|
psn_targ->getattr_pb = psn->da[i].pufbuf;
|
|
|
|
} else {
|
|
|
|
pdir[rda->idx].getattr_pb = psn->da[i].pufbuf;
|
|
|
|
}
|
|
|
|
SENDCB(psn->da[i].pufbuf, readdir_getattr_resp, rda);
|
|
|
|
}
|
2007-05-15 17:46:47 +04:00
|
|
|
|
|
|
|
out:
|
2007-05-20 21:47:12 +04:00
|
|
|
return;
|
2007-02-10 02:36:17 +03:00
|
|
|
}
|
|
|
|
|
2007-03-22 16:11:00 +03:00
|
|
|
int
|
|
|
|
getpathattr(struct puffs_cc *pcc, const char *path, struct vattr *vap)
|
|
|
|
{
|
|
|
|
PSSHFSAUTOVAR(pcc);
|
|
|
|
|
|
|
|
psbuf_req_str(pb, SSH_FXP_LSTAT, reqid, path);
|
2007-05-11 20:23:00 +04:00
|
|
|
GETRESPONSE(pb);
|
2007-03-22 16:11:00 +03:00
|
|
|
|
|
|
|
rv = psbuf_expect_attrs(pb, vap);
|
|
|
|
|
2007-05-15 17:46:47 +04:00
|
|
|
out:
|
2007-03-22 16:11:00 +03:00
|
|
|
PSSHFSRETURN(rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
getnodeattr(struct puffs_cc *pcc, struct puffs_node *pn)
|
|
|
|
{
|
|
|
|
struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
|
|
|
|
struct psshfs_node *psn = pn->pn_data;
|
|
|
|
struct vattr va;
|
2007-05-21 00:27:04 +04:00
|
|
|
int rv, dohardway;
|
2007-03-22 16:11:00 +03:00
|
|
|
|
|
|
|
if ((time(NULL) - psn->attrread) >= PSSHFS_REFRESHIVAL) {
|
2007-05-21 00:27:04 +04:00
|
|
|
dohardway = 1;
|
2007-05-21 00:06:23 +04:00
|
|
|
if (psn->getattr_pb) {
|
|
|
|
rv=puffs_framev_framebuf_ccpromote(psn->getattr_pb,pcc);
|
2007-05-21 00:27:04 +04:00
|
|
|
if (rv == 0) {
|
|
|
|
rv = psbuf_expect_attrs(psn->getattr_pb, &va);
|
|
|
|
puffs_framebuf_destroy(psn->getattr_pb);
|
|
|
|
psn->getattr_pb = NULL;
|
|
|
|
if (rv == 0)
|
|
|
|
dohardway = 0;
|
|
|
|
}
|
|
|
|
}
|
2007-05-21 00:06:23 +04:00
|
|
|
|
2007-05-21 00:27:04 +04:00
|
|
|
if (dohardway) {
|
2007-05-21 00:06:23 +04:00
|
|
|
rv = getpathattr(pcc, PNPATH(pn), &va);
|
|
|
|
if (rv)
|
|
|
|
return rv;
|
|
|
|
}
|
2007-03-22 16:11:00 +03:00
|
|
|
|
|
|
|
/*
|
2007-05-21 00:06:23 +04:00
|
|
|
* Check if the file was modified from below us.
|
|
|
|
* If so, invalidate page cache. This is the only
|
|
|
|
* sensible place we can do this in.
|
2007-03-22 16:11:00 +03:00
|
|
|
*/
|
|
|
|
if (psn->attrread)
|
|
|
|
if (pn->pn_va.va_mtime.tv_sec != va.va_mtime.tv_sec)
|
|
|
|
puffs_inval_pagecache_node(pu, pn);
|
|
|
|
|
|
|
|
puffs_setvattr(&pn->pn_va, &va);
|
|
|
|
psn->attrread = time(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:35:39 +03:00
|
|
|
int
|
|
|
|
sftp_readdir(struct puffs_cc *pcc, struct psshfs_ctx *pctx,
|
|
|
|
struct puffs_node *pn)
|
|
|
|
{
|
2007-05-11 20:23:00 +04:00
|
|
|
struct puffs_usermount *pu = puffs_cc_getusermount(pcc);
|
2006-12-29 18:35:39 +03:00
|
|
|
struct psshfs_node *psn = pn->pn_data;
|
|
|
|
struct psshfs_dir *olddir, *testd;
|
2007-05-05 19:49:51 +04:00
|
|
|
struct puffs_framebuf *pb;
|
2006-12-29 18:35:39 +03:00
|
|
|
uint32_t reqid = NEXTREQ(pctx);
|
2007-02-27 17:17:14 +03:00
|
|
|
uint32_t count, dhandlen;
|
2006-12-29 18:35:39 +03:00
|
|
|
char *dhand = NULL;
|
2007-02-27 17:17:14 +03:00
|
|
|
size_t nent;
|
2006-12-29 18:35:39 +03:00
|
|
|
char *longname;
|
|
|
|
int idx, rv;
|
|
|
|
|
|
|
|
assert(pn->pn_va.va_type == VDIR);
|
2007-05-15 17:46:47 +04:00
|
|
|
idx = 0;
|
|
|
|
olddir = psn->dir;
|
|
|
|
nent = psn->dentnext;
|
2006-12-29 18:35:39 +03:00
|
|
|
|
|
|
|
if (psn->dir && (time(NULL) - psn->dentread) < PSSHFS_REFRESHIVAL)
|
|
|
|
return 0;
|
|
|
|
|
2007-06-21 17:53:00 +04:00
|
|
|
if ((rv = puffs_inval_namecache_dir(pu, pn)))
|
|
|
|
warn("readdir: dcache inval fail %p", pn);
|
2007-01-09 21:23:21 +03:00
|
|
|
|
2007-05-05 19:49:51 +04:00
|
|
|
pb = psbuf_makeout();
|
2007-01-15 03:42:21 +03:00
|
|
|
psbuf_req_str(pb, SSH_FXP_OPENDIR, reqid, PNPATH(pn));
|
2007-05-11 20:23:00 +04:00
|
|
|
GETRESPONSE(pb);
|
2006-12-29 18:35:39 +03:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2007-02-10 02:36:17 +03:00
|
|
|
/*
|
|
|
|
* 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);
|
|
|
|
|
2006-12-29 18:35:39 +03:00
|
|
|
psn->dentnext = 0;
|
|
|
|
psn->denttot = 0;
|
|
|
|
psn->dir = NULL;
|
2007-05-20 21:47:12 +04:00
|
|
|
psn->nextda = 0;
|
2006-12-29 18:35:39 +03:00
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
reqid = NEXTREQ(pctx);
|
2007-05-05 19:49:51 +04:00
|
|
|
psbuf_recycleout(pb);
|
2006-12-29 18:35:39 +03:00
|
|
|
psbuf_req_data(pb, SSH_FXP_READDIR, reqid, dhand, dhandlen);
|
2007-05-11 20:23:00 +04:00
|
|
|
GETRESPONSE(pb);
|
2006-12-29 18:35:39 +03:00
|
|
|
|
|
|
|
/* check for EOF */
|
2007-05-05 19:49:51 +04:00
|
|
|
if (psbuf_get_type(pb) == SSH_FXP_STATUS) {
|
2006-12-29 18:35:39 +03:00
|
|
|
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);
|
2007-05-05 19:49:51 +04:00
|
|
|
if ((rv = psbuf_get_str(pb,
|
|
|
|
&psn->dir[idx].entryname, NULL)))
|
2006-12-29 18:35:39 +03:00
|
|
|
goto out;
|
2007-05-05 19:49:51 +04:00
|
|
|
if ((rv = psbuf_get_str(pb, &longname, NULL)))
|
2006-12-29 18:35:39 +03:00
|
|
|
goto out;
|
2007-05-15 18:17:30 +04:00
|
|
|
if ((rv = psbuf_get_vattr(pb, &psn->dir[idx].va))) {
|
|
|
|
free(longname);
|
2006-12-29 18:35:39 +03:00
|
|
|
goto out;
|
2007-05-15 18:17:30 +04:00
|
|
|
}
|
2006-12-29 18:35:39 +03:00
|
|
|
if (sscanf(longname, "%*s%d",
|
|
|
|
&psn->dir[idx].va.va_nlink) != 1) {
|
|
|
|
rv = EPROTO;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
free(longname);
|
|
|
|
|
|
|
|
testd = lookup(olddir, nent, psn->dir[idx].entryname);
|
|
|
|
if (testd) {
|
|
|
|
psn->dir[idx].entry = testd->entry;
|
2007-02-10 02:36:17 +03:00
|
|
|
psn->dir[idx].va = testd->va;
|
2006-12-29 18:35:39 +03:00
|
|
|
} else {
|
|
|
|
psn->dir[idx].entry = NULL;
|
|
|
|
psn->dir[idx].va.va_fileid = pctx->nextino++;
|
|
|
|
}
|
2007-02-10 02:36:17 +03:00
|
|
|
/*
|
|
|
|
* XXX: there's a dangling pointer race here if
|
|
|
|
* the server responds to our queries out-of-order.
|
|
|
|
* fixxxme some day
|
|
|
|
*/
|
2007-05-20 21:47:12 +04:00
|
|
|
readdir_getattr(puffs_cc_getusermount(pcc),
|
2007-05-05 19:49:51 +04:00
|
|
|
psn, PNPATH(pn), idx);
|
2007-05-21 00:06:23 +04:00
|
|
|
|
2006-12-29 18:35:39 +03:00
|
|
|
psn->dir[idx].valid = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2007-05-20 21:47:12 +04:00
|
|
|
/* fire off getattr requests */
|
|
|
|
readdir_getattr_send(pu, psn);
|
|
|
|
|
2006-12-29 18:35:39 +03:00
|
|
|
/* XXX: rv */
|
|
|
|
psn->dentnext = idx;
|
|
|
|
freedircache(olddir, nent);
|
|
|
|
|
|
|
|
reqid = NEXTREQ(pctx);
|
2007-05-05 19:49:51 +04:00
|
|
|
psbuf_recycleout(pb);
|
2006-12-29 18:35:39 +03:00
|
|
|
psbuf_req_data(pb, SSH_FXP_CLOSE, reqid, dhand, dhandlen);
|
2007-05-11 20:23:00 +04:00
|
|
|
JUSTSEND(pb);
|
2007-03-13 21:00:34 +03:00
|
|
|
free(dhand);
|
2007-05-20 21:47:12 +04:00
|
|
|
|
2007-03-22 16:11:00 +03:00
|
|
|
return rv;
|
2006-12-29 18:35:39 +03:00
|
|
|
|
|
|
|
wayout:
|
|
|
|
free(dhand);
|
2007-03-13 21:00:34 +03:00
|
|
|
PSSHFSRETURN(rv);
|
2006-12-29 18:35:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
struct puffs_node *
|
|
|
|
makenode(struct puffs_usermount *pu, struct puffs_node *parent,
|
|
|
|
struct psshfs_dir *pd, const struct vattr *vap)
|
|
|
|
{
|
|
|
|
struct psshfs_node *psn_parent = parent->pn_data;
|
|
|
|
struct psshfs_node *psn;
|
|
|
|
struct puffs_node *pn;
|
|
|
|
|
|
|
|
psn = emalloc(sizeof(struct psshfs_node));
|
|
|
|
memset(psn, 0, sizeof(struct psshfs_node));
|
|
|
|
|
|
|
|
pn = puffs_pn_new(pu, psn);
|
|
|
|
if (!pn) {
|
|
|
|
free(psn);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
puffs_setvattr(&pn->pn_va, &pd->va);
|
2007-02-10 02:36:17 +03:00
|
|
|
psn->attrread = pd->attrread;
|
2006-12-29 18:35:39 +03:00
|
|
|
puffs_setvattr(&pn->pn_va, vap);
|
|
|
|
|
|
|
|
pd->entry = pn;
|
|
|
|
psn->parent = parent;
|
|
|
|
psn_parent->childcount++;
|
|
|
|
|
2007-08-23 19:19:40 +04:00
|
|
|
LIST_INIT(&psn->dw);
|
|
|
|
|
2007-05-21 00:06:23 +04:00
|
|
|
if (pd->getattr_pb) {
|
|
|
|
psn->getattr_pb = pd->getattr_pb;
|
|
|
|
pd->getattr_pb = NULL;
|
|
|
|
}
|
|
|
|
|
2006-12-29 18:35:39 +03:00
|
|
|
return pn;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct puffs_node *
|
|
|
|
allocnode(struct puffs_usermount *pu, struct puffs_node *parent,
|
|
|
|
const char *entryname, const struct vattr *vap)
|
|
|
|
{
|
2007-04-12 19:09:00 +04:00
|
|
|
struct psshfs_ctx *pctx = puffs_getspecific(pu);
|
2006-12-29 18:35:39 +03:00
|
|
|
struct psshfs_dir *pd;
|
2007-01-08 00:59:27 +03:00
|
|
|
struct puffs_node *pn;
|
2006-12-29 18:35:39 +03:00
|
|
|
|
|
|
|
pd = direnter(parent, entryname);
|
|
|
|
|
|
|
|
pd->va.va_fileid = pctx->nextino++;
|
2007-01-07 22:29:55 +03:00
|
|
|
if (vap->va_type == VDIR) {
|
2006-12-29 18:35:39 +03:00
|
|
|
pd->va.va_nlink = 2;
|
2007-01-07 22:29:55 +03:00
|
|
|
parent->pn_va.va_nlink++;
|
|
|
|
} else {
|
2006-12-29 18:35:39 +03:00
|
|
|
pd->va.va_nlink = 1;
|
2007-01-07 22:29:55 +03:00
|
|
|
}
|
2006-12-29 18:35:39 +03:00
|
|
|
|
2007-01-08 00:59:27 +03:00
|
|
|
pn = makenode(pu, parent, pd, vap);
|
|
|
|
if (pn)
|
|
|
|
pd->va.va_fileid = pn->pn_va.va_fileid;
|
|
|
|
|
|
|
|
return pn;
|
2006-12-29 18:35:39 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
struct psshfs_dir *
|
|
|
|
direnter(struct puffs_node *parent, const char *entryname)
|
|
|
|
{
|
|
|
|
struct psshfs_node *psn_parent = parent->pn_data;
|
|
|
|
struct psshfs_dir *pd;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* create directory entry */
|
|
|
|
if (psn_parent->denttot == psn_parent->dentnext)
|
|
|
|
allocdirs(psn_parent);
|
|
|
|
|
|
|
|
i = psn_parent->dentnext;
|
|
|
|
pd = &psn_parent->dir[i];
|
|
|
|
pd->entryname = estrdup(entryname);
|
|
|
|
pd->valid = 1;
|
2007-02-10 02:36:17 +03:00
|
|
|
pd->attrread = 0;
|
2007-01-09 15:34:20 +03:00
|
|
|
puffs_vattr_null(&pd->va);
|
2006-12-29 18:35:39 +03:00
|
|
|
psn_parent->dentnext++;
|
|
|
|
|
|
|
|
return pd;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-02-15 16:07:29 +03:00
|
|
|
doreclaim(struct puffs_node *pn)
|
|
|
|
{
|
|
|
|
struct psshfs_node *psn = pn->pn_data;
|
|
|
|
struct psshfs_node *psn_parent;
|
|
|
|
struct psshfs_dir *dent;
|
|
|
|
|
|
|
|
psn_parent = psn->parent->pn_data;
|
|
|
|
psn_parent->childcount--;
|
|
|
|
|
2007-03-13 21:00:34 +03:00
|
|
|
/*
|
|
|
|
* Null out entry from directory. Do not treat a missing entry
|
|
|
|
* as an invariant error, since the node might be removed from
|
|
|
|
* under us, and we might do a readdir before the reclaim resulting
|
|
|
|
* in no directory entry in the parent directory.
|
|
|
|
*/
|
2007-02-15 16:07:29 +03:00
|
|
|
dent = lookup_by_entry(psn_parent->dir, psn_parent->dentnext, pn);
|
2007-03-13 21:00:34 +03:00
|
|
|
if (dent)
|
|
|
|
dent->entry = NULL;
|
2007-02-15 16:07:29 +03:00
|
|
|
|
2007-05-20 21:47:12 +04:00
|
|
|
if (pn->pn_va.va_type == VDIR) {
|
2007-02-15 16:07:29 +03:00
|
|
|
freedircache(psn->dir, psn->dentnext);
|
2007-05-21 00:27:04 +04:00
|
|
|
psn->denttot = psn->dentnext = 0;
|
2007-05-20 21:47:12 +04:00
|
|
|
free(psn->da);
|
|
|
|
}
|
2007-02-15 16:07:29 +03:00
|
|
|
|
|
|
|
puffs_pn_put(pn);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nukenode(struct puffs_node *node, const char *entryname, int reclaim)
|
2006-12-29 18:35:39 +03:00
|
|
|
{
|
|
|
|
struct psshfs_node *psn, *psn_parent;
|
|
|
|
struct psshfs_dir *pd;
|
|
|
|
|
|
|
|
psn = node->pn_data;
|
|
|
|
psn_parent = psn->parent->pn_data;
|
|
|
|
pd = lookup(psn_parent->dir, psn_parent->dentnext, entryname);
|
|
|
|
assert(pd != NULL);
|
|
|
|
pd->valid = 0;
|
|
|
|
free(pd->entryname);
|
|
|
|
pd->entryname = NULL;
|
|
|
|
|
2007-02-15 16:07:29 +03:00
|
|
|
if (node->pn_va.va_type == VDIR)
|
2006-12-29 18:35:39 +03:00
|
|
|
psn->parent->pn_va.va_nlink--;
|
2007-01-11 21:50:42 +03:00
|
|
|
|
2007-02-15 16:07:29 +03:00
|
|
|
if (reclaim)
|
|
|
|
doreclaim(node);
|
2006-12-29 18:35:39 +03:00
|
|
|
}
|