1*4f048a36Schristos /* $NetBSD: subr.c,v 1.51 2012/11/04 22:46:08 christos Exp $ */
2c3ef8ea5Spooka
3c3ef8ea5Spooka /*
4c3ef8ea5Spooka * Copyright (c) 2006 Antti Kantee. All Rights Reserved.
5c3ef8ea5Spooka *
6c3ef8ea5Spooka * Redistribution and use in source and binary forms, with or without
7c3ef8ea5Spooka * modification, are permitted provided that the following conditions
8c3ef8ea5Spooka * are met:
9c3ef8ea5Spooka * 1. Redistributions of source code must retain the above copyright
10c3ef8ea5Spooka * notice, this list of conditions and the following disclaimer.
11c3ef8ea5Spooka * 2. Redistributions in binary form must reproduce the above copyright
12c3ef8ea5Spooka * notice, this list of conditions and the following disclaimer in the
13c3ef8ea5Spooka * documentation and/or other materials provided with the distribution.
14c3ef8ea5Spooka *
15c3ef8ea5Spooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16c3ef8ea5Spooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17c3ef8ea5Spooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18c3ef8ea5Spooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19c3ef8ea5Spooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20c3ef8ea5Spooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21c3ef8ea5Spooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22c3ef8ea5Spooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23c3ef8ea5Spooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24c3ef8ea5Spooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25c3ef8ea5Spooka * SUCH DAMAGE.
26c3ef8ea5Spooka */
27c3ef8ea5Spooka
28c3ef8ea5Spooka #include <sys/cdefs.h>
29c3ef8ea5Spooka #ifndef lint
30*4f048a36Schristos __RCSID("$NetBSD: subr.c,v 1.51 2012/11/04 22:46:08 christos Exp $");
31c3ef8ea5Spooka #endif /* !lint */
32c3ef8ea5Spooka
33*4f048a36Schristos #include <stdio.h>
34c3ef8ea5Spooka #include <assert.h>
3523c02977Spooka #include <err.h>
36c3ef8ea5Spooka #include <errno.h>
37c3ef8ea5Spooka #include <puffs.h>
38c3ef8ea5Spooka #include <stdlib.h>
39c3ef8ea5Spooka #include <util.h>
40c3ef8ea5Spooka
41c3ef8ea5Spooka #include "psshfs.h"
42c3ef8ea5Spooka #include "sftp_proto.h"
43c3ef8ea5Spooka
44c3ef8ea5Spooka static void
freedircache(struct psshfs_dir * base,size_t count)45c3ef8ea5Spooka freedircache(struct psshfs_dir *base, size_t count)
46c3ef8ea5Spooka {
475866121cSpooka size_t i;
48c3ef8ea5Spooka
49c3ef8ea5Spooka for (i = 0; i < count; i++) {
50c3ef8ea5Spooka free(base[i].entryname);
51c3ef8ea5Spooka base[i].entryname = NULL;
52c3ef8ea5Spooka }
53c3ef8ea5Spooka
54c3ef8ea5Spooka free(base);
55c3ef8ea5Spooka }
56c3ef8ea5Spooka
57c3ef8ea5Spooka #define ENTRYCHUNK 16
58c3ef8ea5Spooka static void
allocdirs(struct psshfs_node * psn)59c3ef8ea5Spooka allocdirs(struct psshfs_node *psn)
60c3ef8ea5Spooka {
61c3ef8ea5Spooka size_t oldtot = psn->denttot;
62c3ef8ea5Spooka
63c3ef8ea5Spooka psn->denttot += ENTRYCHUNK;
64c3ef8ea5Spooka psn->dir = erealloc(psn->dir,
65c3ef8ea5Spooka psn->denttot * sizeof(struct psshfs_dir));
66c3ef8ea5Spooka memset(psn->dir + oldtot, 0, ENTRYCHUNK * sizeof(struct psshfs_dir));
67c3ef8ea5Spooka }
68c3ef8ea5Spooka
69968196afSpooka static void
setpnva(struct puffs_usermount * pu,struct puffs_node * pn,const struct vattr * vap)70968196afSpooka setpnva(struct puffs_usermount *pu, struct puffs_node *pn,
71968196afSpooka const struct vattr *vap)
72968196afSpooka {
73c4291c19Spooka struct psshfs_ctx *pctx = puffs_getspecific(pu);
74968196afSpooka struct psshfs_node *psn = pn->pn_data;
75c4291c19Spooka struct vattr modva;
76968196afSpooka
77968196afSpooka /*
78968196afSpooka * Check if the file was modified from below us.
79968196afSpooka * If so, invalidate page cache. This is the only
80968196afSpooka * sensible place we can do this in.
81968196afSpooka */
82968196afSpooka if (pn->pn_va.va_mtime.tv_sec != PUFFS_VNOVAL)
83968196afSpooka if (pn->pn_va.va_mtime.tv_sec != vap->va_mtime.tv_sec
84968196afSpooka && pn->pn_va.va_type == VREG)
85968196afSpooka puffs_inval_pagecache_node(pu, pn);
86968196afSpooka
87c4291c19Spooka modva = *vap;
88c4291c19Spooka if (pctx->domangleuid && modva.va_uid == pctx->mangleuid)
89c4291c19Spooka modva.va_uid = pctx->myuid;
90c4291c19Spooka if (pctx->domanglegid && modva.va_gid == pctx->manglegid)
91c4291c19Spooka modva.va_gid = pctx->mygid;
92c4291c19Spooka
93c4291c19Spooka puffs_setvattr(&pn->pn_va, &modva);
94968196afSpooka psn->attrread = time(NULL);
95968196afSpooka }
96968196afSpooka
97c3ef8ea5Spooka struct psshfs_dir *
lookup(struct psshfs_dir * bdir,size_t ndir,const char * name)98f5fed534Spooka lookup(struct psshfs_dir *bdir, size_t ndir, const char *name)
99c3ef8ea5Spooka {
100f5fed534Spooka struct psshfs_dir *test;
1015866121cSpooka size_t i;
102c3ef8ea5Spooka
103c3ef8ea5Spooka for (i = 0; i < ndir; i++) {
104f5fed534Spooka test = &bdir[i];
105f5fed534Spooka if (test->valid != 1)
106c3ef8ea5Spooka continue;
107f5fed534Spooka if (strcmp(test->entryname, name) == 0)
108f5fed534Spooka return test;
109f5fed534Spooka }
110f5fed534Spooka
111f5fed534Spooka return NULL;
112f5fed534Spooka }
113f5fed534Spooka
114f5fed534Spooka static struct psshfs_dir *
lookup_by_entry(struct psshfs_dir * bdir,size_t ndir,struct puffs_node * entry)115f5fed534Spooka lookup_by_entry(struct psshfs_dir *bdir, size_t ndir, struct puffs_node *entry)
116f5fed534Spooka {
117f5fed534Spooka struct psshfs_dir *test;
1185866121cSpooka size_t i;
119f5fed534Spooka
120f5fed534Spooka for (i = 0; i < ndir; i++) {
121f5fed534Spooka test = &bdir[i];
122f5fed534Spooka if (test->valid != 1)
123f5fed534Spooka continue;
124f5fed534Spooka if (test->entry == entry)
125f5fed534Spooka return test;
126c3ef8ea5Spooka }
127c3ef8ea5Spooka
128c3ef8ea5Spooka return NULL;
129c3ef8ea5Spooka }
130c3ef8ea5Spooka
1313fe3f654Spooka
1323fe3f654Spooka void
closehandles(struct puffs_usermount * pu,struct psshfs_node * psn,int which)1333fe3f654Spooka closehandles(struct puffs_usermount *pu, struct psshfs_node *psn, int which)
1343fe3f654Spooka {
1353fe3f654Spooka struct psshfs_ctx *pctx = puffs_getspecific(pu);
1363fe3f654Spooka struct puffs_framebuf *pb1, *pb2;
1373fe3f654Spooka uint32_t reqid;
1383fe3f654Spooka
1393fe3f654Spooka if (psn->fhand_r && (which & HANDLE_READ)) {
1403fe3f654Spooka assert(psn->lazyopen_r == NULL);
1413fe3f654Spooka
1423fe3f654Spooka pb1 = psbuf_makeout();
1433fe3f654Spooka reqid = NEXTREQ(pctx);
1443fe3f654Spooka psbuf_req_data(pb1, SSH_FXP_CLOSE, reqid,
1453fe3f654Spooka psn->fhand_r, psn->fhand_r_len);
1468ff91531Spooka puffs_framev_enqueue_justsend(pu, pctx->sshfd_data, pb1, 1, 0);
1473fe3f654Spooka free(psn->fhand_r);
1483fe3f654Spooka psn->fhand_r = NULL;
1493fe3f654Spooka }
1503fe3f654Spooka
1513fe3f654Spooka if (psn->fhand_w && (which & HANDLE_WRITE)) {
1523fe3f654Spooka assert(psn->lazyopen_w == NULL);
1533fe3f654Spooka
1543fe3f654Spooka pb2 = psbuf_makeout();
1553fe3f654Spooka reqid = NEXTREQ(pctx);
1563fe3f654Spooka psbuf_req_data(pb2, SSH_FXP_CLOSE, reqid,
1573fe3f654Spooka psn->fhand_w, psn->fhand_w_len);
1588ff91531Spooka puffs_framev_enqueue_justsend(pu, pctx->sshfd_data, pb2, 1, 0);
1593fe3f654Spooka free(psn->fhand_w);
1603fe3f654Spooka psn->fhand_w = NULL;
1613fe3f654Spooka }
1623fe3f654Spooka
1633fe3f654Spooka psn->stat |= PSN_HANDLECLOSE;
1643fe3f654Spooka }
1653fe3f654Spooka
1663fe3f654Spooka void
lazyopen_rresp(struct puffs_usermount * pu,struct puffs_framebuf * pb,void * arg,int error)1673fe3f654Spooka lazyopen_rresp(struct puffs_usermount *pu, struct puffs_framebuf *pb,
1683fe3f654Spooka void *arg, int error)
1693fe3f654Spooka {
1703fe3f654Spooka struct psshfs_node *psn = arg;
1713fe3f654Spooka
1723fe3f654Spooka /* XXX: this is not enough */
1733fe3f654Spooka if (psn->stat & PSN_RECLAIMED) {
1743fe3f654Spooka error = ENOENT;
1753fe3f654Spooka goto moreout;
1763fe3f654Spooka }
1773fe3f654Spooka if (error)
1783fe3f654Spooka goto out;
1793fe3f654Spooka
1803fe3f654Spooka error = psbuf_expect_handle(pb, &psn->fhand_r, &psn->fhand_r_len);
1813fe3f654Spooka
1823fe3f654Spooka out:
1833fe3f654Spooka psn->lazyopen_err_r = error;
1843fe3f654Spooka psn->lazyopen_r = NULL;
1853fe3f654Spooka if (error)
1863fe3f654Spooka psn->stat &= ~PSN_DOLAZY_R;
1873fe3f654Spooka if (psn->stat & PSN_HANDLECLOSE && (psn->stat & PSN_LAZYWAIT_R) == 0)
1883fe3f654Spooka closehandles(pu, psn, HANDLE_READ);
1893fe3f654Spooka moreout:
1903fe3f654Spooka puffs_framebuf_destroy(pb);
1913fe3f654Spooka }
1923fe3f654Spooka
1933fe3f654Spooka void
lazyopen_wresp(struct puffs_usermount * pu,struct puffs_framebuf * pb,void * arg,int error)1943fe3f654Spooka lazyopen_wresp(struct puffs_usermount *pu, struct puffs_framebuf *pb,
1953fe3f654Spooka void *arg, int error)
1963fe3f654Spooka {
1973fe3f654Spooka struct psshfs_node *psn = arg;
1983fe3f654Spooka
1993fe3f654Spooka /* XXX: this is not enough */
2003fe3f654Spooka if (psn->stat & PSN_RECLAIMED) {
2013fe3f654Spooka error = ENOENT;
2023fe3f654Spooka goto moreout;
2033fe3f654Spooka }
2043fe3f654Spooka if (error)
2053fe3f654Spooka goto out;
2063fe3f654Spooka
2073fe3f654Spooka error = psbuf_expect_handle(pb, &psn->fhand_w, &psn->fhand_w_len);
2083fe3f654Spooka
2093fe3f654Spooka out:
2103fe3f654Spooka psn->lazyopen_err_w = error;
2113fe3f654Spooka psn->lazyopen_w = NULL;
2123fe3f654Spooka if (error)
2133fe3f654Spooka psn->stat &= ~PSN_DOLAZY_W;
2143fe3f654Spooka if (psn->stat & PSN_HANDLECLOSE && (psn->stat & PSN_LAZYWAIT_W) == 0)
2153fe3f654Spooka closehandles(pu, psn, HANDLE_WRITE);
2163fe3f654Spooka moreout:
2173fe3f654Spooka puffs_framebuf_destroy(pb);
2183fe3f654Spooka }
2193fe3f654Spooka
220306e0025Spooka struct readdirattr {
221306e0025Spooka struct psshfs_node *psn;
222306e0025Spooka int idx;
223306e0025Spooka char entryname[MAXPATHLEN+1];
224306e0025Spooka };
225306e0025Spooka
226c3ef8ea5Spooka int
getpathattr(struct puffs_usermount * pu,const char * path,struct vattr * vap)22721913eabSpooka getpathattr(struct puffs_usermount *pu, const char *path, struct vattr *vap)
2287517e20cSpooka {
22921913eabSpooka PSSHFSAUTOVAR(pu);
2307517e20cSpooka
2317517e20cSpooka psbuf_req_str(pb, SSH_FXP_LSTAT, reqid, path);
2328ff91531Spooka GETRESPONSE(pb, pctx->sshfd);
2337517e20cSpooka
2347517e20cSpooka rv = psbuf_expect_attrs(pb, vap);
2357517e20cSpooka
236e3468dbcSpooka out:
2377517e20cSpooka PSSHFSRETURN(rv);
2387517e20cSpooka }
2397517e20cSpooka
2407517e20cSpooka int
getnodeattr(struct puffs_usermount * pu,struct puffs_node * pn,const char * path)241326638b5Spooka getnodeattr(struct puffs_usermount *pu, struct puffs_node *pn, const char *path)
2427517e20cSpooka {
243a56f46a5Spooka struct psshfs_ctx *pctx = puffs_getspecific(pu);
2447517e20cSpooka struct psshfs_node *psn = pn->pn_data;
2457517e20cSpooka struct vattr va;
246f845b0daSpooka int rv;
2477517e20cSpooka
248a56f46a5Spooka if (!psn->attrread || REFRESHTIMEOUT(pctx, time(NULL)-psn->attrread)) {
249326638b5Spooka rv = getpathattr(pu, path ? path : PNPATH(pn), &va);
2507517e20cSpooka if (rv)
2517517e20cSpooka return rv;
2527517e20cSpooka
253968196afSpooka setpnva(pu, pn, &va);
2547517e20cSpooka }
2557517e20cSpooka
2567517e20cSpooka return 0;
2577517e20cSpooka }
2587517e20cSpooka
2597517e20cSpooka int
sftp_readdir(struct puffs_usermount * pu,struct psshfs_ctx * pctx,struct puffs_node * pn)260a86a0093Spooka sftp_readdir(struct puffs_usermount *pu, struct psshfs_ctx *pctx,
261c3ef8ea5Spooka struct puffs_node *pn)
262c3ef8ea5Spooka {
263a86a0093Spooka struct puffs_cc *pcc = puffs_cc_getcc(pu);
264c3ef8ea5Spooka struct psshfs_node *psn = pn->pn_data;
265c3ef8ea5Spooka struct psshfs_dir *olddir, *testd;
2660e7bdfc1Spooka struct puffs_framebuf *pb;
267c3ef8ea5Spooka uint32_t reqid = NEXTREQ(pctx);
268ad70c5abSpooka uint32_t count, dhandlen;
269c3ef8ea5Spooka char *dhand = NULL;
270ad70c5abSpooka size_t nent;
27138602220Spooka char *longname = NULL;
2725866121cSpooka size_t idx;
2735866121cSpooka int rv;
274c3ef8ea5Spooka
275c3ef8ea5Spooka assert(pn->pn_va.va_type == VDIR);
276e3468dbcSpooka idx = 0;
277e3468dbcSpooka olddir = psn->dir;
278e3468dbcSpooka nent = psn->dentnext;
279c3ef8ea5Spooka
280c5afd8dcSpooka if (psn->dir && psn->dentread
281c5afd8dcSpooka && !REFRESHTIMEOUT(pctx, time(NULL) - psn->dentread))
282c3ef8ea5Spooka return 0;
283c3ef8ea5Spooka
284375257e2Spooka if (psn->dentread) {
28523c02977Spooka if ((rv = puffs_inval_namecache_dir(pu, pn)))
28623c02977Spooka warn("readdir: dcache inval fail %p", pn);
287375257e2Spooka }
2889da6af0aSpooka
2890e7bdfc1Spooka pb = psbuf_makeout();
2905d293715Spooka psbuf_req_str(pb, SSH_FXP_OPENDIR, reqid, PNPATH(pn));
291c64b357fSpooka if (puffs_framev_enqueue_cc(pcc, pctx->sshfd, pb, 0) == -1) {
292c64b357fSpooka rv = errno;
293c64b357fSpooka goto wayout;
294c64b357fSpooka }
295c3ef8ea5Spooka rv = psbuf_expect_handle(pb, &dhand, &dhandlen);
296c3ef8ea5Spooka if (rv)
297c3ef8ea5Spooka goto wayout;
298c3ef8ea5Spooka
299c3ef8ea5Spooka /*
300c3ef8ea5Spooka * Well, the following is O(n^2), so feel free to improve if it
301c3ef8ea5Spooka * gets too taxing on your system.
302c3ef8ea5Spooka */
303c3ef8ea5Spooka
304306e0025Spooka /*
305306e0025Spooka * note: for the "getattr in batch" to work, this must be before
306306e0025Spooka * the attribute-getting. Otherwise times for first entries in
307306e0025Spooka * large directories might expire before the directory itself and
308306e0025Spooka * result in one-by-one attribute fetching.
309306e0025Spooka */
310306e0025Spooka psn->dentread = time(NULL);
311306e0025Spooka
312c3ef8ea5Spooka psn->dentnext = 0;
313c3ef8ea5Spooka psn->denttot = 0;
314c3ef8ea5Spooka psn->dir = NULL;
315c3ef8ea5Spooka
316c3ef8ea5Spooka for (;;) {
317c3ef8ea5Spooka reqid = NEXTREQ(pctx);
3180e7bdfc1Spooka psbuf_recycleout(pb);
319c3ef8ea5Spooka psbuf_req_data(pb, SSH_FXP_READDIR, reqid, dhand, dhandlen);
3208ff91531Spooka GETRESPONSE(pb, pctx->sshfd);
321c3ef8ea5Spooka
322c3ef8ea5Spooka /* check for EOF */
3230e7bdfc1Spooka if (psbuf_get_type(pb) == SSH_FXP_STATUS) {
324c3ef8ea5Spooka rv = psbuf_expect_status(pb);
325c3ef8ea5Spooka goto out;
326c3ef8ea5Spooka }
327c3ef8ea5Spooka rv = psbuf_expect_name(pb, &count);
328c3ef8ea5Spooka if (rv)
329c3ef8ea5Spooka goto out;
330c3ef8ea5Spooka
331c3ef8ea5Spooka for (; count--; idx++) {
332c3ef8ea5Spooka if (idx == psn->denttot)
333c3ef8ea5Spooka allocdirs(psn);
3340e7bdfc1Spooka if ((rv = psbuf_get_str(pb,
3350e7bdfc1Spooka &psn->dir[idx].entryname, NULL)))
336c3ef8ea5Spooka goto out;
33738602220Spooka if ((rv = psbuf_get_str(pb, &longname, NULL)) != 0)
338c3ef8ea5Spooka goto out;
33938602220Spooka if ((rv = psbuf_get_vattr(pb, &psn->dir[idx].va)) != 0)
340c3ef8ea5Spooka goto out;
341c3ef8ea5Spooka if (sscanf(longname, "%*s%d",
342c3ef8ea5Spooka &psn->dir[idx].va.va_nlink) != 1) {
343c3ef8ea5Spooka rv = EPROTO;
344c3ef8ea5Spooka goto out;
345c3ef8ea5Spooka }
346c3ef8ea5Spooka free(longname);
34738602220Spooka longname = NULL;
348c3ef8ea5Spooka
34900b48f3eSpooka /*
35073655f9fSpooka * In case of DOT, copy the attributes (mostly
35173655f9fSpooka * because we want the link count for the root dir).
35273655f9fSpooka */
35373655f9fSpooka if (strcmp(psn->dir[idx].entryname, ".") == 0) {
35473655f9fSpooka setpnva(pu, pn, &psn->dir[idx].va);
35573655f9fSpooka }
35673655f9fSpooka
35773655f9fSpooka /*
35800b48f3eSpooka * Check if we already have a psshfs_dir for the
35900b48f3eSpooka * name we are processing. If so, use the old one.
36000b48f3eSpooka * If not, create a new one
36100b48f3eSpooka */
362c3ef8ea5Spooka testd = lookup(olddir, nent, psn->dir[idx].entryname);
363c3ef8ea5Spooka if (testd) {
364c3ef8ea5Spooka psn->dir[idx].entry = testd->entry;
36500b48f3eSpooka /*
36600b48f3eSpooka * Has entry. Update attributes to what
36700b48f3eSpooka * we just got from the server.
36800b48f3eSpooka */
36900b48f3eSpooka if (testd->entry) {
370f845b0daSpooka setpnva(pu, testd->entry,
371f845b0daSpooka &psn->dir[idx].va);
372074f023aSpooka psn->dir[idx].va.va_fileid
373074f023aSpooka = testd->entry->pn_va.va_fileid;
37400b48f3eSpooka
37500b48f3eSpooka /*
37600b48f3eSpooka * No entry. This can happen in two cases:
37700b48f3eSpooka * 1) the file was created "behind our back"
37800b48f3eSpooka * on the server
37900b48f3eSpooka * 2) we do two readdirs before we instantiate
38000b48f3eSpooka * the node (or run with -t 0).
38100b48f3eSpooka *
38200b48f3eSpooka * Cache attributes from the server in
38300b48f3eSpooka * case we want to instantiate this node
384343d2779Spooka * soon. Also preserve the old inode number
385343d2779Spooka * which was given when the dirent was created.
38600b48f3eSpooka */
38700b48f3eSpooka } else {
38800b48f3eSpooka psn->dir[idx].va.va_fileid
389794adab5Spooka = testd->va.va_fileid;
390794adab5Spooka testd->va = psn->dir[idx].va;
39100b48f3eSpooka }
39200b48f3eSpooka
39300b48f3eSpooka /* No previous entry? Initialize this one. */
394c3ef8ea5Spooka } else {
395c3ef8ea5Spooka psn->dir[idx].entry = NULL;
396c3ef8ea5Spooka psn->dir[idx].va.va_fileid = pctx->nextino++;
397c3ef8ea5Spooka }
398f845b0daSpooka psn->dir[idx].attrread = psn->dentread;
399c3ef8ea5Spooka psn->dir[idx].valid = 1;
400c3ef8ea5Spooka }
401c3ef8ea5Spooka }
402c3ef8ea5Spooka
403c3ef8ea5Spooka out:
404c3ef8ea5Spooka /* XXX: rv */
405c3ef8ea5Spooka psn->dentnext = idx;
406c3ef8ea5Spooka freedircache(olddir, nent);
407c3ef8ea5Spooka
408c3ef8ea5Spooka reqid = NEXTREQ(pctx);
4090e7bdfc1Spooka psbuf_recycleout(pb);
410c3ef8ea5Spooka psbuf_req_data(pb, SSH_FXP_CLOSE, reqid, dhand, dhandlen);
411485aeac1Spooka puffs_framev_enqueue_justsend(pu, pctx->sshfd, pb, 1, 0);
412f446ae6bSpooka free(dhand);
41338602220Spooka free(longname);
414a769baf0Spooka
4157517e20cSpooka return rv;
416c3ef8ea5Spooka
417c3ef8ea5Spooka wayout:
418c3ef8ea5Spooka free(dhand);
419f446ae6bSpooka PSSHFSRETURN(rv);
420c3ef8ea5Spooka }
421c3ef8ea5Spooka
422c3ef8ea5Spooka struct puffs_node *
makenode(struct puffs_usermount * pu,struct puffs_node * parent,const struct psshfs_dir * pd,const struct vattr * vap)423c3ef8ea5Spooka makenode(struct puffs_usermount *pu, struct puffs_node *parent,
424326638b5Spooka const struct psshfs_dir *pd, const struct vattr *vap)
425c3ef8ea5Spooka {
426c3ef8ea5Spooka struct psshfs_node *psn_parent = parent->pn_data;
427c3ef8ea5Spooka struct psshfs_node *psn;
428c3ef8ea5Spooka struct puffs_node *pn;
429c3ef8ea5Spooka
430c3ef8ea5Spooka psn = emalloc(sizeof(struct psshfs_node));
431c3ef8ea5Spooka memset(psn, 0, sizeof(struct psshfs_node));
432c3ef8ea5Spooka
433c3ef8ea5Spooka pn = puffs_pn_new(pu, psn);
434c3ef8ea5Spooka if (!pn) {
435c3ef8ea5Spooka free(psn);
436c3ef8ea5Spooka return NULL;
437c3ef8ea5Spooka }
438968196afSpooka setpnva(pu, pn, &pd->va);
439968196afSpooka setpnva(pu, pn, vap);
440f845b0daSpooka psn->attrread = pd->attrread;
441c3ef8ea5Spooka
442c3ef8ea5Spooka psn->parent = parent;
443c3ef8ea5Spooka psn_parent->childcount++;
444c3ef8ea5Spooka
4458543b6baSpooka TAILQ_INIT(&psn->pw);
4469b93e5eaSpooka
447c3ef8ea5Spooka return pn;
448c3ef8ea5Spooka }
449c3ef8ea5Spooka
450c3ef8ea5Spooka struct puffs_node *
allocnode(struct puffs_usermount * pu,struct puffs_node * parent,const char * entryname,const struct vattr * vap)451c3ef8ea5Spooka allocnode(struct puffs_usermount *pu, struct puffs_node *parent,
452c3ef8ea5Spooka const char *entryname, const struct vattr *vap)
453c3ef8ea5Spooka {
45495a18d20Spooka struct psshfs_ctx *pctx = puffs_getspecific(pu);
455c3ef8ea5Spooka struct psshfs_dir *pd;
45694f62e9bSpooka struct puffs_node *pn;
457c3ef8ea5Spooka
458c3ef8ea5Spooka pd = direnter(parent, entryname);
459c3ef8ea5Spooka
460c3ef8ea5Spooka pd->va.va_fileid = pctx->nextino++;
461c53a62f5Spooka if (vap->va_type == VDIR) {
462c3ef8ea5Spooka pd->va.va_nlink = 2;
463c53a62f5Spooka parent->pn_va.va_nlink++;
464c53a62f5Spooka } else {
465c3ef8ea5Spooka pd->va.va_nlink = 1;
466c53a62f5Spooka }
467c3ef8ea5Spooka
46894f62e9bSpooka pn = makenode(pu, parent, pd, vap);
469326638b5Spooka if (pn) {
47094f62e9bSpooka pd->va.va_fileid = pn->pn_va.va_fileid;
471326638b5Spooka pd->entry = pn;
472326638b5Spooka }
47394f62e9bSpooka
47494f62e9bSpooka return pn;
475c3ef8ea5Spooka }
476c3ef8ea5Spooka
477c3ef8ea5Spooka struct psshfs_dir *
direnter(struct puffs_node * parent,const char * entryname)478c3ef8ea5Spooka direnter(struct puffs_node *parent, const char *entryname)
479c3ef8ea5Spooka {
480c3ef8ea5Spooka struct psshfs_node *psn_parent = parent->pn_data;
481c3ef8ea5Spooka struct psshfs_dir *pd;
482c3ef8ea5Spooka int i;
483c3ef8ea5Spooka
484c3ef8ea5Spooka /* create directory entry */
485c3ef8ea5Spooka if (psn_parent->denttot == psn_parent->dentnext)
486c3ef8ea5Spooka allocdirs(psn_parent);
487c3ef8ea5Spooka
488c3ef8ea5Spooka i = psn_parent->dentnext;
489c3ef8ea5Spooka pd = &psn_parent->dir[i];
490c3ef8ea5Spooka pd->entryname = estrdup(entryname);
491c3ef8ea5Spooka pd->valid = 1;
492306e0025Spooka pd->attrread = 0;
4936ee2e9c0Spooka puffs_vattr_null(&pd->va);
494c3ef8ea5Spooka psn_parent->dentnext++;
495c3ef8ea5Spooka
496c3ef8ea5Spooka return pd;
497c3ef8ea5Spooka }
498c3ef8ea5Spooka
499c3ef8ea5Spooka void
doreclaim(struct puffs_node * pn)500f5fed534Spooka doreclaim(struct puffs_node *pn)
501f5fed534Spooka {
502f5fed534Spooka struct psshfs_node *psn = pn->pn_data;
503f5fed534Spooka struct psshfs_node *psn_parent;
504f5fed534Spooka struct psshfs_dir *dent;
505f5fed534Spooka
506f5fed534Spooka psn_parent = psn->parent->pn_data;
507f5fed534Spooka psn_parent->childcount--;
508f5fed534Spooka
509f446ae6bSpooka /*
510f446ae6bSpooka * Null out entry from directory. Do not treat a missing entry
511f446ae6bSpooka * as an invariant error, since the node might be removed from
512f446ae6bSpooka * under us, and we might do a readdir before the reclaim resulting
513f446ae6bSpooka * in no directory entry in the parent directory.
514f446ae6bSpooka */
515f5fed534Spooka dent = lookup_by_entry(psn_parent->dir, psn_parent->dentnext, pn);
516f446ae6bSpooka if (dent)
517f5fed534Spooka dent->entry = NULL;
518f5fed534Spooka
519a769baf0Spooka if (pn->pn_va.va_type == VDIR) {
520f5fed534Spooka freedircache(psn->dir, psn->dentnext);
521d32c8fa5Spooka psn->denttot = psn->dentnext = 0;
522a769baf0Spooka }
5236b4d0688Spooka if (psn->symlink)
5246b4d0688Spooka free(psn->symlink);
525f5fed534Spooka
526f5fed534Spooka puffs_pn_put(pn);
527f5fed534Spooka }
528f5fed534Spooka
529f5fed534Spooka void
nukenode(struct puffs_node * node,const char * entryname,int reclaim)530f5fed534Spooka nukenode(struct puffs_node *node, const char *entryname, int reclaim)
531c3ef8ea5Spooka {
532c3ef8ea5Spooka struct psshfs_node *psn, *psn_parent;
533c3ef8ea5Spooka struct psshfs_dir *pd;
534c3ef8ea5Spooka
535c3ef8ea5Spooka psn = node->pn_data;
536c3ef8ea5Spooka psn_parent = psn->parent->pn_data;
537c3ef8ea5Spooka pd = lookup(psn_parent->dir, psn_parent->dentnext, entryname);
538c3ef8ea5Spooka assert(pd != NULL);
539c3ef8ea5Spooka pd->valid = 0;
540c3ef8ea5Spooka free(pd->entryname);
541c3ef8ea5Spooka pd->entryname = NULL;
542c3ef8ea5Spooka
543f5fed534Spooka if (node->pn_va.va_type == VDIR)
544c3ef8ea5Spooka psn->parent->pn_va.va_nlink--;
5450ac91974Spooka
546f5fed534Spooka if (reclaim)
547f5fed534Spooka doreclaim(node);
548c3ef8ea5Spooka }
549