Fri Oct 29 16:13:51 2010 UTC ()
Make error message more userfriendly in cases where server does
not support sftp.


(pooka)
diff -r1.22 -r1.23 src/usr.sbin/puffs/mount_psshfs/fs.c
diff -r1.61 -r1.62 src/usr.sbin/puffs/mount_psshfs/node.c
diff -r1.61 -r1.62 src/usr.sbin/puffs/mount_psshfs/psshfs.c

cvs diff -r1.22 -r1.23 src/usr.sbin/puffs/mount_psshfs/fs.c (switch to unified diff)

--- src/usr.sbin/puffs/mount_psshfs/fs.c 2010/04/01 02:34:09 1.22
+++ src/usr.sbin/puffs/mount_psshfs/fs.c 2010/10/29 16:13:51 1.23
@@ -1,281 +1,279 @@ @@ -1,281 +1,279 @@
1/* $NetBSD: fs.c,v 1.22 2010/04/01 02:34:09 pooka Exp $ */ 1/* $NetBSD: fs.c,v 1.23 2010/10/29 16:13:51 pooka Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2006-2009 Antti Kantee. All Rights Reserved. 4 * Copyright (c) 2006-2009 Antti Kantee. All Rights Reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 * 14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE. 25 * SUCH DAMAGE.
26 */ 26 */
27 27
28#include <sys/cdefs.h> 28#include <sys/cdefs.h>
29#ifndef lint 29#ifndef lint
30__RCSID("$NetBSD: fs.c,v 1.22 2010/04/01 02:34:09 pooka Exp $"); 30__RCSID("$NetBSD: fs.c,v 1.23 2010/10/29 16:13:51 pooka Exp $");
31#endif /* !lint */ 31#endif /* !lint */
32 32
33#include <err.h> 33#include <err.h>
34#include <errno.h> 34#include <errno.h>
35#include <puffs.h> 35#include <puffs.h>
36#include <signal.h> 36#include <signal.h>
37#include <stdio.h> 37#include <stdio.h>
38#include <stdlib.h> 38#include <stdlib.h>
39#include <unistd.h> 39#include <unistd.h>
40 40
41#include "psshfs.h" 41#include "psshfs.h"
42#include "sftp_proto.h" 42#include "sftp_proto.h"
43 43
44#define DO_IO(fname, a1, a2, a3, a4, rv) \ 44#define DO_IO(fname, a1, a2, a3, a4, rv) \
45do { \ 45do { \
46 puffs_framebuf_seekset(a2, 0); \ 46 puffs_framebuf_seekset(a2, 0); \
47 *(a4) = 0; \ 47 *(a4) = 0; \
48 rv = fname(a1, a2, a3, a4); \ 48 rv = fname(a1, a2, a3, a4); \
49 if (rv || a4 == 0) { \ 49 if (rv || a4 == 0) { \
50 fprintf(stderr, "psshfs_handshake failed %d (%s) %d\n", \ 
51 rv, strerror(rv), *a4); \ 
52 return rv ? rv : EPROTO; \ 50 return rv ? rv : EPROTO; \
53 } \ 51 } \
54} while (/*CONSTCOND*/0) 52} while (/*CONSTCOND*/0)
55 53
56#define reterr(str, rv) \ 54#define reterr(str, rv) \
57do { \ 55do { \
58 fprintf str; \ 56 fprintf str; \
59 return rv; \ 57 return rv; \
60} while (/*CONSTCOND*/0) 58} while (/*CONSTCOND*/0)
61 59
62/* openssh extensions */ 60/* openssh extensions */
63static const struct extunit { 61static const struct extunit {
64 const char *ext; 62 const char *ext;
65 const char *val; 63 const char *val;
66 int extflag; 64 int extflag;
67} exttable[] = { 65} exttable[] = {
68{ 66{
69 "posix-rename@openssh.com", 67 "posix-rename@openssh.com",
70 "1", 68 "1",
71 SFTP_EXT_POSIX_RENAME, 69 SFTP_EXT_POSIX_RENAME,
72},{ 70},{
73 "statvfs@openssh.com", 71 "statvfs@openssh.com",
74 "2", 72 "2",
75 SFTP_EXT_STATVFS, 73 SFTP_EXT_STATVFS,
76},{ 74},{
77 "fstatvfs@openssh.com", 75 "fstatvfs@openssh.com",
78 "2", 76 "2",
79 SFTP_EXT_FSTATVFS, 77 SFTP_EXT_FSTATVFS,
80},{ 78},{
81 NULL, 79 NULL,
82 NULL, 80 NULL,
83 0 81 0
84}}; 82}};
85  83
86int 84int
87psshfs_handshake(struct puffs_usermount *pu, int fd) 85psshfs_handshake(struct puffs_usermount *pu, int fd)
88{ 86{
89 struct psshfs_ctx *pctx = puffs_getspecific(pu); 87 struct psshfs_ctx *pctx = puffs_getspecific(pu);
90 struct puffs_framebuf *pb; 88 struct puffs_framebuf *pb;
91 struct puffs_pathobj *po_root; 89 struct puffs_pathobj *po_root;
92 struct puffs_node *pn_root; 90 struct puffs_node *pn_root;
93 struct vattr va, *rva; 91 struct vattr va, *rva;
94 const struct extunit *extu; 92 const struct extunit *extu;
95 char *rootpath; 93 char *rootpath;
96 char *ext, *val; 94 char *ext, *val;
97 uint32_t count; 95 uint32_t count;
98 int rv, done; 96 int rv, done;
99 97
100 pb = psbuf_makeout(); 98 pb = psbuf_makeout();
101 psbuf_put_1(pb, SSH_FXP_INIT); 99 psbuf_put_1(pb, SSH_FXP_INIT);
102 psbuf_put_4(pb, SFTP_PROTOVERSION); 100 psbuf_put_4(pb, SFTP_PROTOVERSION);
103 DO_IO(psbuf_write, pu, pb, fd, &done, rv); 101 DO_IO(psbuf_write, pu, pb, fd, &done, rv);
104 102
105 puffs_framebuf_recycle(pb); 103 puffs_framebuf_recycle(pb);
106 DO_IO(psbuf_read, pu, pb, fd, &done, rv); 104 DO_IO(psbuf_read, pu, pb, fd, &done, rv);
107 if (psbuf_get_type(pb) != SSH_FXP_VERSION) 105 if (psbuf_get_type(pb) != SSH_FXP_VERSION)
108 reterr((stderr, "invalid server response: %d", 106 reterr((stderr, "invalid server response: %d",
109 psbuf_get_type(pb)), EPROTO); 107 psbuf_get_type(pb)), EPROTO);
110 pctx->protover = psbuf_get_reqid(pb); 108 pctx->protover = psbuf_get_reqid(pb);
111 109
112 /* 110 /*
113 * Check out which extensions are available. Currently 111 * Check out which extensions are available. Currently
114 * we are only interested in the openssh statvfs extension. 112 * we are only interested in the openssh statvfs extension.
115 */ 113 */
116 for (;;) { 114 for (;;) {
117 if (psbuf_get_str(pb, &ext, NULL) != 0) 115 if (psbuf_get_str(pb, &ext, NULL) != 0)
118 break; 116 break;
119 if (psbuf_get_str(pb, &val, NULL) != 0) 117 if (psbuf_get_str(pb, &val, NULL) != 0)
120 break; 118 break;
121 119
122 for (extu = exttable; extu->ext; extu++) 120 for (extu = exttable; extu->ext; extu++)
123 if (strcmp(ext, extu->ext) == 0 121 if (strcmp(ext, extu->ext) == 0
124 && strcmp(val, extu->val) == 0) 122 && strcmp(val, extu->val) == 0)
125 pctx->extensions |= extu->extflag; 123 pctx->extensions |= extu->extflag;
126 } 124 }
127 125
128 /* scope out our rootpath */ 126 /* scope out our rootpath */
129 psbuf_recycleout(pb); 127 psbuf_recycleout(pb);
130 psbuf_put_1(pb, SSH_FXP_REALPATH); 128 psbuf_put_1(pb, SSH_FXP_REALPATH);
131 psbuf_put_4(pb, NEXTREQ(pctx)); 129 psbuf_put_4(pb, NEXTREQ(pctx));
132 psbuf_put_str(pb, pctx->mountpath); 130 psbuf_put_str(pb, pctx->mountpath);
133 DO_IO(psbuf_write, pu, pb, fd, &done, rv); 131 DO_IO(psbuf_write, pu, pb, fd, &done, rv);
134 132
135 puffs_framebuf_recycle(pb); 133 puffs_framebuf_recycle(pb);
136 DO_IO(psbuf_read, pu, pb, fd, &done, rv); 134 DO_IO(psbuf_read, pu, pb, fd, &done, rv);
137 if (psbuf_get_type(pb) != SSH_FXP_NAME) 135 if (psbuf_get_type(pb) != SSH_FXP_NAME)
138 reterr((stderr, "invalid server realpath response for \"%s\"", 136 reterr((stderr, "invalid server realpath response for \"%s\"",
139 pctx->mountpath), EPROTO); 137 pctx->mountpath), EPROTO);
140 if (psbuf_get_4(pb, &count) == -1) 138 if (psbuf_get_4(pb, &count) == -1)
141 reterr((stderr, "invalid realpath response: count"), EPROTO); 139 reterr((stderr, "invalid realpath response: count"), EPROTO);
142 if (psbuf_get_str(pb, &rootpath, NULL) == -1) 140 if (psbuf_get_str(pb, &rootpath, NULL) == -1)
143 reterr((stderr, "invalid realpath response: rootpath"), EPROTO); 141 reterr((stderr, "invalid realpath response: rootpath"), EPROTO);
144 142
145 /* stat the rootdir so that we know it's a dir */ 143 /* stat the rootdir so that we know it's a dir */
146 psbuf_recycleout(pb); 144 psbuf_recycleout(pb);
147 psbuf_req_str(pb, SSH_FXP_LSTAT, NEXTREQ(pctx), rootpath); 145 psbuf_req_str(pb, SSH_FXP_LSTAT, NEXTREQ(pctx), rootpath);
148 DO_IO(psbuf_write, pu, pb, fd, &done, rv); 146 DO_IO(psbuf_write, pu, pb, fd, &done, rv);
149 147
150 puffs_framebuf_recycle(pb); 148 puffs_framebuf_recycle(pb);
151 DO_IO(psbuf_read, pu, pb, fd, &done, rv); 149 DO_IO(psbuf_read, pu, pb, fd, &done, rv);
152 150
153 rv = psbuf_expect_attrs(pb, &va); 151 rv = psbuf_expect_attrs(pb, &va);
154 if (rv) 152 if (rv)
155 reterr((stderr, "couldn't stat rootpath"), rv); 153 reterr((stderr, "couldn't stat rootpath"), rv);
156 puffs_framebuf_destroy(pb); 154 puffs_framebuf_destroy(pb);
157 155
158 if (puffs_mode2vt(va.va_mode) != VDIR) 156 if (puffs_mode2vt(va.va_mode) != VDIR)
159 reterr((stderr, "remote path (%s) not a directory", rootpath), 157 reterr((stderr, "remote path (%s) not a directory", rootpath),
160 ENOTDIR); 158 ENOTDIR);
161 159
162 pn_root = puffs_getroot(pu); 160 pn_root = puffs_getroot(pu);
163 rva = &pn_root->pn_va; 161 rva = &pn_root->pn_va;
164 puffs_setvattr(rva, &va); 162 puffs_setvattr(rva, &va);
165 163
166 po_root = puffs_getrootpathobj(pu); 164 po_root = puffs_getrootpathobj(pu);
167 if (po_root == NULL) 165 if (po_root == NULL)
168 err(1, "getrootpathobj"); 166 err(1, "getrootpathobj");
169 po_root->po_path = rootpath; 167 po_root->po_path = rootpath;
170 po_root->po_len = strlen(rootpath); 168 po_root->po_len = strlen(rootpath);
171 169
172 return 0; 170 return 0;
173} 171}
174 172
175int 173int
176psshfs_fs_statvfs(struct puffs_usermount *pu, struct statvfs *sbp) 174psshfs_fs_statvfs(struct puffs_usermount *pu, struct statvfs *sbp)
177{ 175{
178 PSSHFSAUTOVAR(pu); 176 PSSHFSAUTOVAR(pu);
179 uint64_t tmpval; 177 uint64_t tmpval;
180 uint8_t type; 178 uint8_t type;
181 179
182 memset(sbp, 0, sizeof(*sbp)); 180 memset(sbp, 0, sizeof(*sbp));
183 sbp->f_bsize = sbp->f_frsize = sbp->f_iosize = 512; 181 sbp->f_bsize = sbp->f_frsize = sbp->f_iosize = 512;
184 182
185 if ((pctx->extensions & SFTP_EXT_STATVFS) == 0) 183 if ((pctx->extensions & SFTP_EXT_STATVFS) == 0)
186 goto out; 184 goto out;
187 185
188 psbuf_req_str(pb, SSH_FXP_EXTENDED, reqid, "statvfs@openssh.com"); 186 psbuf_req_str(pb, SSH_FXP_EXTENDED, reqid, "statvfs@openssh.com");
189 psbuf_put_str(pb, pctx->mountpath); 187 psbuf_put_str(pb, pctx->mountpath);
190 GETRESPONSE(pb, pctx->sshfd); 188 GETRESPONSE(pb, pctx->sshfd);
191 189
192 type = psbuf_get_type(pb); 190 type = psbuf_get_type(pb);
193 if (type != SSH_FXP_EXTENDED_REPLY) { 191 if (type != SSH_FXP_EXTENDED_REPLY) {
194 /* use the default */ 192 /* use the default */
195 goto out; 193 goto out;
196 } 194 }
197 195
198 psbuf_get_8(pb, &tmpval); 196 psbuf_get_8(pb, &tmpval);
199 sbp->f_bsize = tmpval; 197 sbp->f_bsize = tmpval;
200 psbuf_get_8(pb, &tmpval); 198 psbuf_get_8(pb, &tmpval);
201 sbp->f_frsize = tmpval; 199 sbp->f_frsize = tmpval;
202 psbuf_get_8(pb, &sbp->f_blocks); 200 psbuf_get_8(pb, &sbp->f_blocks);
203 psbuf_get_8(pb, &sbp->f_bfree); 201 psbuf_get_8(pb, &sbp->f_bfree);
204 psbuf_get_8(pb, &sbp->f_bavail); 202 psbuf_get_8(pb, &sbp->f_bavail);
205 psbuf_get_8(pb, &sbp->f_files); 203 psbuf_get_8(pb, &sbp->f_files);
206 psbuf_get_8(pb, &sbp->f_ffree); 204 psbuf_get_8(pb, &sbp->f_ffree);
207 psbuf_get_8(pb, &sbp->f_favail); 205 psbuf_get_8(pb, &sbp->f_favail);
208 206
209 psbuf_get_8(pb, &tmpval); /* fsid */ 207 psbuf_get_8(pb, &tmpval); /* fsid */
210 psbuf_get_8(pb, &tmpval); /* flag */ 208 psbuf_get_8(pb, &tmpval); /* flag */
211 psbuf_get_8(pb, &tmpval); 209 psbuf_get_8(pb, &tmpval);
212 sbp->f_namemax = tmpval; 210 sbp->f_namemax = tmpval;
213 211
214 sbp->f_bresvd = sbp->f_bfree - sbp->f_bavail; 212 sbp->f_bresvd = sbp->f_bfree - sbp->f_bavail;
215 sbp->f_fresvd = sbp->f_ffree - sbp->f_favail; 213 sbp->f_fresvd = sbp->f_ffree - sbp->f_favail;
216 214
217 out: 215 out:
218 PSSHFSRETURN(rv); 216 PSSHFSRETURN(rv);
219} 217}
220 218
221int 219int
222psshfs_fs_unmount(struct puffs_usermount *pu, int flags) 220psshfs_fs_unmount(struct puffs_usermount *pu, int flags)
223{ 221{
224 struct psshfs_ctx *pctx = puffs_getspecific(pu); 222 struct psshfs_ctx *pctx = puffs_getspecific(pu);
225 223
226 kill(pctx->sshpid, SIGTERM); 224 kill(pctx->sshpid, SIGTERM);
227 close(pctx->sshfd); 225 close(pctx->sshfd);
228 if (pctx->numconnections == 2) { 226 if (pctx->numconnections == 2) {
229 kill(pctx->sshpid_data, SIGTERM); 227 kill(pctx->sshpid_data, SIGTERM);
230 close(pctx->sshfd_data); 228 close(pctx->sshfd_data);
231 } 229 }
232 230
233 return 0; 231 return 0;
234} 232}
235 233
236int 234int
237psshfs_fs_nodetofh(struct puffs_usermount *pu, puffs_cookie_t cookie, 235psshfs_fs_nodetofh(struct puffs_usermount *pu, puffs_cookie_t cookie,
238 void *fid, size_t *fidsize) 236 void *fid, size_t *fidsize)
239{ 237{
240 struct psshfs_ctx *pctx = puffs_getspecific(pu); 238 struct psshfs_ctx *pctx = puffs_getspecific(pu);
241 struct puffs_node *pn = cookie; 239 struct puffs_node *pn = cookie;
242 struct psshfs_node *psn = pn->pn_data; 240 struct psshfs_node *psn = pn->pn_data;
243 struct psshfs_fid *pf = fid; 241 struct psshfs_fid *pf = fid;
244 242
245 pf->mounttime = pctx->mounttime; 243 pf->mounttime = pctx->mounttime;
246 pf->node = pn; 244 pf->node = pn;
247 245
248 psn->stat |= PSN_HASFH; 246 psn->stat |= PSN_HASFH;
249 247
250 return 0; 248 return 0;
251} 249}
252 250
253int 251int
254psshfs_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize, 252psshfs_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize,
255 struct puffs_newinfo *pni) 253 struct puffs_newinfo *pni)
256{ 254{
257 struct psshfs_ctx *pctx = puffs_getspecific(pu); 255 struct psshfs_ctx *pctx = puffs_getspecific(pu);
258 struct psshfs_fid *pf = fid; 256 struct psshfs_fid *pf = fid;
259 struct puffs_node *pn = pf->node; 257 struct puffs_node *pn = pf->node;
260 struct psshfs_node *psn; 258 struct psshfs_node *psn;
261 int rv; 259 int rv;
262 260
263 if (pf->mounttime != pctx->mounttime) 261 if (pf->mounttime != pctx->mounttime)
264 return EINVAL; 262 return EINVAL;
265 if (pn == 0) 263 if (pn == 0)
266 return EINVAL; 264 return EINVAL;
267 psn = pn->pn_data; 265 psn = pn->pn_data;
268 if ((psn->stat & PSN_HASFH) == 0) 266 if ((psn->stat & PSN_HASFH) == 0)
269 return EINVAL; 267 return EINVAL;
270 268
271 /* update node attributes */ 269 /* update node attributes */
272 rv = getnodeattr(pu, pn, NULL); 270 rv = getnodeattr(pu, pn, NULL);
273 if (rv) 271 if (rv)
274 return EINVAL; 272 return EINVAL;
275 273
276 puffs_newinfo_setcookie(pni, pn); 274 puffs_newinfo_setcookie(pni, pn);
277 puffs_newinfo_setvtype(pni, pn->pn_va.va_type); 275 puffs_newinfo_setvtype(pni, pn->pn_va.va_type);
278 puffs_newinfo_setsize(pni, pn->pn_va.va_size); 276 puffs_newinfo_setsize(pni, pn->pn_va.va_size);
279 277
280 return 0; 278 return 0;
281} 279}

cvs diff -r1.61 -r1.62 src/usr.sbin/puffs/mount_psshfs/node.c (switch to unified diff)

--- src/usr.sbin/puffs/mount_psshfs/node.c 2010/04/01 02:34:09 1.61
+++ src/usr.sbin/puffs/mount_psshfs/node.c 2010/10/29 16:13:51 1.62
@@ -1,887 +1,888 @@ @@ -1,887 +1,888 @@
1/* $NetBSD: node.c,v 1.61 2010/04/01 02:34:09 pooka Exp $ */ 1/* $NetBSD: node.c,v 1.62 2010/10/29 16:13:51 pooka Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2006-2009 Antti Kantee. All Rights Reserved. 4 * Copyright (c) 2006-2009 Antti Kantee. All Rights Reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 * 14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE. 25 * SUCH DAMAGE.
26 */ 26 */
27 27
28#include <sys/cdefs.h> 28#include <sys/cdefs.h>
29#ifndef lint 29#ifndef lint
30__RCSID("$NetBSD: node.c,v 1.61 2010/04/01 02:34:09 pooka Exp $"); 30__RCSID("$NetBSD: node.c,v 1.62 2010/10/29 16:13:51 pooka Exp $");
31#endif /* !lint */ 31#endif /* !lint */
32 32
33#include <assert.h> 33#include <assert.h>
34#include <errno.h> 34#include <errno.h>
35#include <stdio.h> 35#include <stdio.h>
36#include <stdlib.h> 36#include <stdlib.h>
37 37
38#include "psshfs.h" 38#include "psshfs.h"
39#include "sftp_proto.h" 39#include "sftp_proto.h"
40 40
41int 41int
42psshfs_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc, 42psshfs_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc,
43 struct puffs_newinfo *pni, const struct puffs_cn *pcn) 43 struct puffs_newinfo *pni, const struct puffs_cn *pcn)
44{ 44{
45 struct psshfs_ctx *pctx = puffs_getspecific(pu); 45 struct psshfs_ctx *pctx = puffs_getspecific(pu);
46 struct puffs_node *pn_dir = opc; 46 struct puffs_node *pn_dir = opc;
47 struct psshfs_node *psn, *psn_dir = pn_dir->pn_data; 47 struct psshfs_node *psn, *psn_dir = pn_dir->pn_data;
48 struct puffs_node *pn; 48 struct puffs_node *pn;
49 struct psshfs_dir *pd; 49 struct psshfs_dir *pd;
50 struct vattr va; 50 struct vattr va;
51 int rv; 51 int rv;
52 52
53 if (PCNISDOTDOT(pcn)) { 53 if (PCNISDOTDOT(pcn)) {
54 psn = psn_dir->parent->pn_data; 54 psn = psn_dir->parent->pn_data;
55 psn->stat &= ~PSN_RECLAIMED; 55 psn->stat &= ~PSN_RECLAIMED;
56 56
57 puffs_newinfo_setcookie(pni, psn_dir->parent); 57 puffs_newinfo_setcookie(pni, psn_dir->parent);
58 puffs_newinfo_setvtype(pni, VDIR); 58 puffs_newinfo_setvtype(pni, VDIR);
59 return 0; 59 return 0;
60 } 60 }
61 61
62 rv = sftp_readdir(pu, pctx, pn_dir); 62 rv = sftp_readdir(pu, pctx, pn_dir);
63 if (rv) { 63 if (rv) {
64 if (rv != EPERM) 64 if (rv != EPERM)
65 return rv; 65 return rv;
66 66
67 /* 67 /*
68 * Can't read the directory. We still might be 68 * Can't read the directory. We still might be
69 * able to find the node with getattr in -r+x dirs 69 * able to find the node with getattr in -r+x dirs
70 */ 70 */
71 rv = getpathattr(pu, PCNPATH(pcn), &va); 71 rv = getpathattr(pu, PCNPATH(pcn), &va);
72 if (rv) 72 if (rv)
73 return rv; 73 return rv;
74 74
75 /* guess */ 75 /* guess */
76 if (va.va_type == VDIR) 76 if (va.va_type == VDIR)
77 va.va_nlink = 2; 77 va.va_nlink = 2;
78 else 78 else
79 va.va_nlink = 1; 79 va.va_nlink = 1;
80 80
81 pn = allocnode(pu, pn_dir, pcn->pcn_name, &va); 81 pn = allocnode(pu, pn_dir, pcn->pcn_name, &va);
82 psn = pn->pn_data; 82 psn = pn->pn_data;
83 psn->attrread = time(NULL); 83 psn->attrread = time(NULL);
84 } else { 84 } else {
85 pd = lookup(psn_dir->dir, psn_dir->dentnext, pcn->pcn_name); 85 pd = lookup(psn_dir->dir, psn_dir->dentnext, pcn->pcn_name);
86 if (!pd) { 86 if (!pd) {
87 return ENOENT; 87 return ENOENT;
88 } 88 }
89 89
90 if (pd->entry) 90 if (pd->entry)
91 pn = pd->entry; 91 pn = pd->entry;
92 else 92 else
93 pd->entry = pn = makenode(pu, pn_dir, pd, &pd->va); 93 pd->entry = pn = makenode(pu, pn_dir, pd, &pd->va);
94 94
95 /* 95 /*
96 * sure sure we have fresh attributes. most likely we will 96 * sure sure we have fresh attributes. most likely we will
97 * have them cached. we might not if we go through: 97 * have them cached. we might not if we go through:
98 * create - reclaim - lookup (this). 98 * create - reclaim - lookup (this).
99 */ 99 */
100 rv = getnodeattr(pu, pn, PCNPATH(pcn)); 100 rv = getnodeattr(pu, pn, PCNPATH(pcn));
101 if (rv) 101 if (rv)
102 return rv; 102 return rv;
103 103
104 psn = pn->pn_data; 104 psn = pn->pn_data;
105 } 105 }
106 106
107 psn->stat &= ~PSN_RECLAIMED; 107 psn->stat &= ~PSN_RECLAIMED;
108 108
109 puffs_newinfo_setcookie(pni, pn); 109 puffs_newinfo_setcookie(pni, pn);
110 puffs_newinfo_setvtype(pni, pn->pn_va.va_type); 110 puffs_newinfo_setvtype(pni, pn->pn_va.va_type);
111 puffs_newinfo_setsize(pni, pn->pn_va.va_size); 111 puffs_newinfo_setsize(pni, pn->pn_va.va_size);
112 112
113 return 0; 113 return 0;
114} 114}
115 115
116int 116int
117psshfs_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc, 117psshfs_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc,
118 struct vattr *vap, const struct puffs_cred *pcr) 118 struct vattr *vap, const struct puffs_cred *pcr)
119{ 119{
120 struct puffs_node *pn = opc; 120 struct puffs_node *pn = opc;
121 int rv; 121 int rv;
122 122
123 rv = getnodeattr(pu, pn, NULL); 123 rv = getnodeattr(pu, pn, NULL);
124 if (rv) 124 if (rv)
125 return rv; 125 return rv;
126 126
127 memcpy(vap, &pn->pn_va, sizeof(struct vattr)); 127 memcpy(vap, &pn->pn_va, sizeof(struct vattr));
128 128
129 return 0; 129 return 0;
130} 130}
131 131
132int 132int
133psshfs_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc, 133psshfs_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc,
134 const struct vattr *va, const struct puffs_cred *pcr) 134 const struct vattr *va, const struct puffs_cred *pcr)
135{ 135{
136 PSSHFSAUTOVAR(pu); 136 PSSHFSAUTOVAR(pu);
137 struct vattr kludgeva; 137 struct vattr kludgeva;
138 struct puffs_node *pn = opc; 138 struct puffs_node *pn = opc;
139 139
140 psbuf_req_str(pb, SSH_FXP_SETSTAT, reqid, PNPATH(pn)); 140 psbuf_req_str(pb, SSH_FXP_SETSTAT, reqid, PNPATH(pn));
141 141
142 memcpy(&kludgeva, va, sizeof(struct vattr)); 142 memcpy(&kludgeva, va, sizeof(struct vattr));
143 143
144 /* XXX: kludge due to openssh server implementation */ 144 /* XXX: kludge due to openssh server implementation */
145 if (va->va_atime.tv_sec != PUFFS_VNOVAL 145 if (va->va_atime.tv_sec != PUFFS_VNOVAL
146 && va->va_mtime.tv_sec == PUFFS_VNOVAL) { 146 && va->va_mtime.tv_sec == PUFFS_VNOVAL) {
147 if (pn->pn_va.va_mtime.tv_sec != PUFFS_VNOVAL) 147 if (pn->pn_va.va_mtime.tv_sec != PUFFS_VNOVAL)
148 kludgeva.va_mtime.tv_sec = pn->pn_va.va_mtime.tv_sec; 148 kludgeva.va_mtime.tv_sec = pn->pn_va.va_mtime.tv_sec;
149 else 149 else
150 kludgeva.va_mtime.tv_sec = va->va_atime.tv_sec; 150 kludgeva.va_mtime.tv_sec = va->va_atime.tv_sec;
151 } 151 }
152 if (va->va_mtime.tv_sec != PUFFS_VNOVAL 152 if (va->va_mtime.tv_sec != PUFFS_VNOVAL
153 && va->va_atime.tv_sec == PUFFS_VNOVAL) { 153 && va->va_atime.tv_sec == PUFFS_VNOVAL) {
154 if (pn->pn_va.va_atime.tv_sec != PUFFS_VNOVAL) 154 if (pn->pn_va.va_atime.tv_sec != PUFFS_VNOVAL)
155 kludgeva.va_atime.tv_sec = pn->pn_va.va_atime.tv_sec; 155 kludgeva.va_atime.tv_sec = pn->pn_va.va_atime.tv_sec;
156 else 156 else
157 kludgeva.va_atime.tv_sec = va->va_mtime.tv_sec; 157 kludgeva.va_atime.tv_sec = va->va_mtime.tv_sec;
158 } 158 }
159  159
160 psbuf_put_vattr(pb, &kludgeva, pctx); 160 psbuf_put_vattr(pb, &kludgeva, pctx);
161 GETRESPONSE(pb, pctx->sshfd); 161 GETRESPONSE(pb, pctx->sshfd);
162 162
163 rv = psbuf_expect_status(pb); 163 rv = psbuf_expect_status(pb);
164 if (rv == 0) 164 if (rv == 0)
165 puffs_setvattr(&pn->pn_va, &kludgeva); 165 puffs_setvattr(&pn->pn_va, &kludgeva);
166 166
167 out: 167 out:
168 PSSHFSRETURN(rv); 168 PSSHFSRETURN(rv);
169} 169}
170 170
171int 171int
172psshfs_node_create(struct puffs_usermount *pu, puffs_cookie_t opc, 172psshfs_node_create(struct puffs_usermount *pu, puffs_cookie_t opc,
173 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 173 struct puffs_newinfo *pni, const struct puffs_cn *pcn,
174 const struct vattr *va) 174 const struct vattr *va)
175{ 175{
176 PSSHFSAUTOVAR(pu); 176 PSSHFSAUTOVAR(pu);
177 struct puffs_node *pn = opc; 177 struct puffs_node *pn = opc;
178 struct puffs_node *pn_new; 178 struct puffs_node *pn_new;
179 char *fhand = NULL; 179 char *fhand = NULL;
180 uint32_t fhandlen; 180 uint32_t fhandlen;
181 181
182 /* Create node on server first */ 182 /* Create node on server first */
183 psbuf_req_str(pb, SSH_FXP_OPEN, reqid, PCNPATH(pcn)); 183 psbuf_req_str(pb, SSH_FXP_OPEN, reqid, PCNPATH(pcn));
184 psbuf_put_4(pb, SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC); 184 psbuf_put_4(pb, SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC);
185 psbuf_put_vattr(pb, va, pctx); 185 psbuf_put_vattr(pb, va, pctx);
186 GETRESPONSE(pb, pctx->sshfd); 186 GETRESPONSE(pb, pctx->sshfd);
187 rv = psbuf_expect_handle(pb, &fhand, &fhandlen); 187 rv = psbuf_expect_handle(pb, &fhand, &fhandlen);
188 if (rv) 188 if (rv)
189 goto out; 189 goto out;
190 190
191 /* 191 /*
192 * Do *not* create the local node before getting a response 192 * Do *not* create the local node before getting a response
193 * from the server. Otherwise we might screw up consistency, 193 * from the server. Otherwise we might screw up consistency,
194 * namely that the node can be looked up before create has 194 * namely that the node can be looked up before create has
195 * returned (mind you, the kernel will unlock the directory 195 * returned (mind you, the kernel will unlock the directory
196 * before the create call from userspace returns). 196 * before the create call from userspace returns).
197 */ 197 */
198 pn_new = allocnode(pu, pn, pcn->pcn_name, va); 198 pn_new = allocnode(pu, pn, pcn->pcn_name, va);
199 if (!pn_new) { 199 if (!pn_new) {
200 struct puffs_framebuf *pb2 = psbuf_makeout(); 200 struct puffs_framebuf *pb2 = psbuf_makeout();
201 reqid = NEXTREQ(pctx); 201 reqid = NEXTREQ(pctx);
202 psbuf_req_str(pb2, SSH_FXP_REMOVE, reqid, PCNPATH(pcn)); 202 psbuf_req_str(pb2, SSH_FXP_REMOVE, reqid, PCNPATH(pcn));
203 JUSTSEND(pb2, pctx->sshfd); 203 JUSTSEND(pb2, pctx->sshfd);
204 rv = ENOMEM; 204 rv = ENOMEM;
205 } 205 }
206 206
207 if (pn_new) 207 if (pn_new)
208 puffs_newinfo_setcookie(pni, pn_new); 208 puffs_newinfo_setcookie(pni, pn_new);
209 209
210 reqid = NEXTREQ(pctx); 210 reqid = NEXTREQ(pctx);
211 psbuf_recycleout(pb); 211 psbuf_recycleout(pb);
212 psbuf_req_data(pb, SSH_FXP_CLOSE, reqid, fhand, fhandlen); 212 psbuf_req_data(pb, SSH_FXP_CLOSE, reqid, fhand, fhandlen);
213 JUSTSEND(pb, pctx->sshfd); 213 JUSTSEND(pb, pctx->sshfd);
214 free(fhand); 214 free(fhand);
215 return rv; 215 return rv;
216 216
217 out: 217 out:
218 free(fhand); 218 free(fhand);
219 PSSHFSRETURN(rv); 219 PSSHFSRETURN(rv);
220} 220}
221 221
222/* 222/*
223 * Open a file handle. This is used for read and write. We do not 223 * Open a file handle. This is used for read and write. We do not
224 * wait here for the success or failure of this operation. This is 224 * wait here for the success or failure of this operation. This is
225 * because otherwise opening and closing file handles would block 225 * because otherwise opening and closing file handles would block
226 * reading potentially cached information. Rather, we defer the wait 226 * reading potentially cached information. Rather, we defer the wait
227 * to read/write and therefore allow cached access without a wait. 227 * to read/write and therefore allow cached access without a wait.
228 * 228 *
229 * If we have not yet succesfully opened a type of handle, we do wait 229 * If we have not yet succesfully opened a type of handle, we do wait
230 * here. Also, if a lazy open fails, we revert back to the same 230 * here. Also, if a lazy open fails, we revert back to the same
231 * state of waiting. 231 * state of waiting.
232 */ 232 */
233int 233int
234psshfs_node_open(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, 234psshfs_node_open(struct puffs_usermount *pu, puffs_cookie_t opc, int mode,
235 const struct puffs_cred *pcr) 235 const struct puffs_cred *pcr)
236{ 236{
237 struct puffs_cc *pcc = puffs_cc_getcc(pu); 237 struct puffs_cc *pcc = puffs_cc_getcc(pu);
238 struct psshfs_ctx *pctx = puffs_getspecific(pu); 238 struct psshfs_ctx *pctx = puffs_getspecific(pu);
239 struct puffs_framebuf *pb, *pb2; 239 struct puffs_framebuf *pb, *pb2;
240 struct vattr va; 240 struct vattr va;
241 struct puffs_node *pn = opc; 241 struct puffs_node *pn = opc;
242 struct psshfs_node *psn = pn->pn_data; 242 struct psshfs_node *psn = pn->pn_data;
243 uint32_t reqid; 243 uint32_t reqid;
244 int didread, didwrite; 244 int didread, didwrite;
245 int rv = 0; 245 int rv = 0;
246 246
247 if (pn->pn_va.va_type == VDIR) 247 if (pn->pn_va.va_type == VDIR)
248 return 0; 248 return 0;
249 249
250 puffs_setback(pcc, PUFFS_SETBACK_INACT_N1); 250 puffs_setback(pcc, PUFFS_SETBACK_INACT_N1);
251 puffs_vattr_null(&va); 251 puffs_vattr_null(&va);
252 didread = didwrite = 0; 252 didread = didwrite = 0;
253 if (mode & FREAD && psn->fhand_r == NULL && psn->lazyopen_r == NULL) { 253 if (mode & FREAD && psn->fhand_r == NULL && psn->lazyopen_r == NULL) {
254 pb = psbuf_makeout(); 254 pb = psbuf_makeout();
255 255
256 reqid = NEXTREQ(pctx); 256 reqid = NEXTREQ(pctx);
257 psbuf_req_str(pb, SSH_FXP_OPEN, reqid, PNPATH(pn)); 257 psbuf_req_str(pb, SSH_FXP_OPEN, reqid, PNPATH(pn));
258 psbuf_put_4(pb, SSH_FXF_READ); 258 psbuf_put_4(pb, SSH_FXF_READ);
259 psbuf_put_vattr(pb, &va, pctx); 259 psbuf_put_vattr(pb, &va, pctx);
260 260
261 if (puffs_framev_enqueue_cb(pu, pctx->sshfd_data, pb, 261 if (puffs_framev_enqueue_cb(pu, pctx->sshfd_data, pb,
262 lazyopen_rresp, psn, 0) == -1) { 262 lazyopen_rresp, psn, 0) == -1) {
263 rv = errno; 263 rv = errno;
264 puffs_framebuf_destroy(pb); 264 puffs_framebuf_destroy(pb);
265 goto out; 265 goto out;
266 } 266 }
267 267
268 psn->lazyopen_r = pb; 268 psn->lazyopen_r = pb;
269 didread = 1; 269 didread = 1;
270 } 270 }
271 if (mode & FWRITE && psn->fhand_w == NULL && psn->lazyopen_w == NULL) { 271 if (mode & FWRITE && psn->fhand_w == NULL && psn->lazyopen_w == NULL) {
272 pb2 = psbuf_makeout(); 272 pb2 = psbuf_makeout();
273 273
274 reqid = NEXTREQ(pctx); 274 reqid = NEXTREQ(pctx);
275 psbuf_req_str(pb2, SSH_FXP_OPEN, reqid, PNPATH(pn)); 275 psbuf_req_str(pb2, SSH_FXP_OPEN, reqid, PNPATH(pn));
276 psbuf_put_4(pb2, SSH_FXF_WRITE); 276 psbuf_put_4(pb2, SSH_FXF_WRITE);
277 psbuf_put_vattr(pb2, &va, pctx); 277 psbuf_put_vattr(pb2, &va, pctx);
278 278
279 if (puffs_framev_enqueue_cb(pu, pctx->sshfd_data, pb2, 279 if (puffs_framev_enqueue_cb(pu, pctx->sshfd_data, pb2,
280 lazyopen_wresp, psn, 0) == -1) { 280 lazyopen_wresp, psn, 0) == -1) {
281 rv = errno; 281 rv = errno;
282 puffs_framebuf_destroy(pb2); 282 puffs_framebuf_destroy(pb2);
283 goto out; 283 goto out;
284 } 284 }
285 285
286 psn->lazyopen_w = pb2; 286 psn->lazyopen_w = pb2;
287 didwrite = 1; 287 didwrite = 1;
288 } 288 }
289 psn->stat &= ~PSN_HANDLECLOSE; 289 psn->stat &= ~PSN_HANDLECLOSE;
290 290
291 out: 291 out:
292 /* wait? */ 292 /* wait? */
293 if (didread && (psn->stat & PSN_DOLAZY_R) == 0) { 293 if (didread && (psn->stat & PSN_DOLAZY_R) == 0) {
294 assert(psn->lazyopen_r); 294 assert(psn->lazyopen_r);
295 295
296 rv = puffs_framev_framebuf_ccpromote(psn->lazyopen_r, pcc); 296 rv = puffs_framev_framebuf_ccpromote(psn->lazyopen_r, pcc);
297 lazyopen_rresp(pu, psn->lazyopen_r, psn, rv); 297 lazyopen_rresp(pu, psn->lazyopen_r, psn, rv);
298 if (psn->fhand_r) { 298 if (psn->fhand_r) {
299 psn->stat |= PSN_DOLAZY_R; 299 psn->stat |= PSN_DOLAZY_R;
300 } else { 300 } else {
301 if (psn->lazyopen_err_r) 301 if (psn->lazyopen_err_r)
302 return psn->lazyopen_err_r; 302 return psn->lazyopen_err_r;
303 return EINVAL; 303 return EINVAL;
304 } 304 }
305 } 305 }
306 306
307 /* wait? */ 307 /* wait? */
308 if (didwrite && (psn->stat & PSN_DOLAZY_W) == 0) { 308 if (didwrite && (psn->stat & PSN_DOLAZY_W) == 0) {
309 assert(psn->lazyopen_w); 309 assert(psn->lazyopen_w);
310 310
311 rv = puffs_framev_framebuf_ccpromote(psn->lazyopen_w, pcc); 311 rv = puffs_framev_framebuf_ccpromote(psn->lazyopen_w, pcc);
312 lazyopen_wresp(pu, psn->lazyopen_w, psn, rv); 312 lazyopen_wresp(pu, psn->lazyopen_w, psn, rv);
313 if (psn->fhand_w) { 313 if (psn->fhand_w) {
314 psn->stat |= PSN_DOLAZY_W; 314 psn->stat |= PSN_DOLAZY_W;
315 } else { 315 } else {
316 if (psn->lazyopen_err_w) 316 if (psn->lazyopen_err_w)
317 return psn->lazyopen_err_w; 317 return psn->lazyopen_err_w;
318 return EINVAL; 318 return EINVAL;
319 } 319 }
320 } 320 }
321 321
322 return rv; 322 return rv;
323} 323}
324 324
325int 325int
326psshfs_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc) 326psshfs_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc)
327{ 327{
328 struct puffs_node *pn = opc; 328 struct puffs_node *pn = opc;
329 329
330 closehandles(pu, pn->pn_data, HANDLE_READ | HANDLE_WRITE); 330 closehandles(pu, pn->pn_data, HANDLE_READ | HANDLE_WRITE);
331 return 0; 331 return 0;
332} 332}
333 333
334int 334int
335psshfs_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc, 335psshfs_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc,
336 struct dirent *dent, off_t *readoff, size_t *reslen, 336 struct dirent *dent, off_t *readoff, size_t *reslen,
337 const struct puffs_cred *pcr, int *eofflag, 337 const struct puffs_cred *pcr, int *eofflag,
338 off_t *cookies, size_t *ncookies) 338 off_t *cookies, size_t *ncookies)
339{ 339{
340 struct puffs_cc *pcc = puffs_cc_getcc(pu); 340 struct puffs_cc *pcc = puffs_cc_getcc(pu);
341 struct psshfs_ctx *pctx = puffs_getspecific(pu); 341 struct psshfs_ctx *pctx = puffs_getspecific(pu);
342 struct puffs_node *pn = opc; 342 struct puffs_node *pn = opc;
343 struct psshfs_node *psn = pn->pn_data; 343 struct psshfs_node *psn = pn->pn_data;
344 struct psshfs_dir *pd; 344 struct psshfs_dir *pd;
345 size_t i; 345 size_t i;
346 int rv, set_readdir; 346 int rv, set_readdir;
347 347
348 restart: 348 restart:
349 if (psn->stat & PSN_READDIR) { 349 if (psn->stat & PSN_READDIR) {
350 struct psshfs_wait pw; 350 struct psshfs_wait pw;
351 351
352 set_readdir = 0; 352 set_readdir = 0;
353 pw.pw_cc = pcc; 353 pw.pw_cc = pcc;
354 pw.pw_type = PWTYPE_READDIR; 354 pw.pw_type = PWTYPE_READDIR;
355 TAILQ_INSERT_TAIL(&psn->pw, &pw, pw_entries); 355 TAILQ_INSERT_TAIL(&psn->pw, &pw, pw_entries);
356 puffs_cc_yield(pcc); 356 puffs_cc_yield(pcc);
357 goto restart; 357 goto restart;
358 } else { 358 } else {
359 psn->stat |= PSN_READDIR; 359 psn->stat |= PSN_READDIR;
360 set_readdir = 1; 360 set_readdir = 1;
361 } 361 }
362 362
363 *ncookies = 0; 363 *ncookies = 0;
364 rv = sftp_readdir(pu, pctx, pn); 364 rv = sftp_readdir(pu, pctx, pn);
365 if (rv) 365 if (rv) {
366 goto out; 366 goto out;
 367 }
367 368
368 /* find next dirent */ 369 /* find next dirent */
369 for (i = *readoff;;i++) { 370 for (i = *readoff;;i++) {
370 if (i >= psn->dentnext) 371 if (i >= psn->dentnext)
371 goto out; 372 goto out;
372 pd = &psn->dir[i]; 373 pd = &psn->dir[i];
373 if (pd->valid) 374 if (pd->valid)
374 break; 375 break;
375 } 376 }
376 377
377 for (;;) { 378 for (;;) {
378 *readoff = i; 379 *readoff = i;
379 if (!puffs_nextdent(&dent, pd->entryname, 380 if (!puffs_nextdent(&dent, pd->entryname,
380 pd->va.va_fileid, puffs_vtype2dt(pd->va.va_type), reslen)) { 381 pd->va.va_fileid, puffs_vtype2dt(pd->va.va_type), reslen)) {
381 rv = 0; 382 rv = 0;
382 goto out; 383 goto out;
383 } 384 }
384 385
385 /* find next entry, store possible nfs key */ 386 /* find next entry, store possible nfs key */
386 do { 387 do {
387 if (++i >= psn->dentnext) 388 if (++i >= psn->dentnext)
388 goto out; 389 goto out;
389 pd = &psn->dir[i]; 390 pd = &psn->dir[i];
390 } while (pd->valid == 0); 391 } while (pd->valid == 0);
391 PUFFS_STORE_DCOOKIE(cookies, ncookies, (off_t)i); 392 PUFFS_STORE_DCOOKIE(cookies, ncookies, (off_t)i);
392 } 393 }
393 394
394 out: 395 out:
395 if (rv == 0) { 396 if (rv == 0) {
396 if (i >= psn->dentnext) 397 if (i >= psn->dentnext)
397 *eofflag = 1; 398 *eofflag = 1;
398 399
399 *readoff = i; 400 *readoff = i;
400 } 401 }
401 402
402 if (set_readdir) { 403 if (set_readdir) {
403 struct psshfs_wait *pw; 404 struct psshfs_wait *pw;
404 405
405 /* all will likely run to completion because of cache */ 406 /* all will likely run to completion because of cache */
406 TAILQ_FOREACH(pw, &psn->pw, pw_entries) { 407 TAILQ_FOREACH(pw, &psn->pw, pw_entries) {
407 assert(pw->pw_type == PWTYPE_READDIR); 408 assert(pw->pw_type == PWTYPE_READDIR);
408 puffs_cc_schedule(pw->pw_cc); 409 puffs_cc_schedule(pw->pw_cc);
409 TAILQ_REMOVE(&psn->pw, pw, pw_entries); 410 TAILQ_REMOVE(&psn->pw, pw, pw_entries);
410 } 411 }
411 412
412 psn->stat &= ~PSN_READDIR; 413 psn->stat &= ~PSN_READDIR;
413 } 414 }
414 415
415 return rv; 416 return rv;
416} 417}
417 418
418int 419int
419psshfs_node_read(struct puffs_usermount *pu, puffs_cookie_t opc, uint8_t *buf, 420psshfs_node_read(struct puffs_usermount *pu, puffs_cookie_t opc, uint8_t *buf,
420 off_t offset, size_t *resid, const struct puffs_cred *pcr, 421 off_t offset, size_t *resid, const struct puffs_cred *pcr,
421 int ioflag) 422 int ioflag)
422{ 423{
423 PSSHFSAUTOVAR(pu); 424 PSSHFSAUTOVAR(pu);
424 struct puffs_node *pn = opc; 425 struct puffs_node *pn = opc;
425 struct psshfs_node *psn = pn->pn_data; 426 struct psshfs_node *psn = pn->pn_data;
426 struct psshfs_wait *pwp; 427 struct psshfs_wait *pwp;
427 uint32_t readlen; 428 uint32_t readlen;
428 429
429 if (pn->pn_va.va_type == VDIR) { 430 if (pn->pn_va.va_type == VDIR) {
430 rv = EISDIR; 431 rv = EISDIR;
431 goto farout; 432 goto farout;
432 } 433 }
433 434
434 /* check that a lazyopen didn't fail */ 435 /* check that a lazyopen didn't fail */
435 if (!psn->fhand_r && !psn->lazyopen_r) { 436 if (!psn->fhand_r && !psn->lazyopen_r) {
436 rv = psn->lazyopen_err_r; 437 rv = psn->lazyopen_err_r;
437 goto farout; 438 goto farout;
438 } 439 }
439 440
440 /* if someone is already waiting for the lazyopen, "just" wait */ 441 /* if someone is already waiting for the lazyopen, "just" wait */
441 if (psn->stat & PSN_LAZYWAIT_R) { 442 if (psn->stat & PSN_LAZYWAIT_R) {
442 struct psshfs_wait pw; 443 struct psshfs_wait pw;
443 444
444 assert(psn->lazyopen_r); 445 assert(psn->lazyopen_r);
445 446
446 pw.pw_cc = pcc; 447 pw.pw_cc = pcc;
447 pw.pw_type = PWTYPE_READ1; 448 pw.pw_type = PWTYPE_READ1;
448 TAILQ_INSERT_TAIL(&psn->pw, &pw, pw_entries); 449 TAILQ_INSERT_TAIL(&psn->pw, &pw, pw_entries);
449 puffs_cc_yield(pcc); 450 puffs_cc_yield(pcc);
450 } 451 }
451 452
452 /* if lazyopening, wait for the result */ 453 /* if lazyopening, wait for the result */
453 if (psn->lazyopen_r) { 454 if (psn->lazyopen_r) {
454 psn->stat |= PSN_LAZYWAIT_R; 455 psn->stat |= PSN_LAZYWAIT_R;
455 rv = puffs_framev_framebuf_ccpromote(psn->lazyopen_r, pcc); 456 rv = puffs_framev_framebuf_ccpromote(psn->lazyopen_r, pcc);
456 lazyopen_rresp(pu, psn->lazyopen_r, psn, rv); 457 lazyopen_rresp(pu, psn->lazyopen_r, psn, rv);
457 458
458 /* schedule extra waiters */ 459 /* schedule extra waiters */
459 TAILQ_FOREACH(pwp, &psn->pw, pw_entries) 460 TAILQ_FOREACH(pwp, &psn->pw, pw_entries)
460 if (pwp->pw_type == PWTYPE_READ1) { 461 if (pwp->pw_type == PWTYPE_READ1) {
461 puffs_cc_schedule(pwp->pw_cc); 462 puffs_cc_schedule(pwp->pw_cc);
462 TAILQ_REMOVE(&psn->pw, pwp, pw_entries); 463 TAILQ_REMOVE(&psn->pw, pwp, pw_entries);
463 } 464 }
464 psn->stat &= ~PSN_LAZYWAIT_R; 465 psn->stat &= ~PSN_LAZYWAIT_R;
465 466
466 if ((rv = psn->lazyopen_err_r) != 0) 467 if ((rv = psn->lazyopen_err_r) != 0)
467 goto farout; 468 goto farout;
468 } 469 }
469 470
470 /* if there is still no handle, just refuse to live with this */ 471 /* if there is still no handle, just refuse to live with this */
471 if (!psn->fhand_r) { 472 if (!psn->fhand_r) {
472 rv = EINVAL; 473 rv = EINVAL;
473 goto farout; 474 goto farout;
474 } 475 }
475 476
476 readlen = *resid; 477 readlen = *resid;
477 psbuf_req_data(pb, SSH_FXP_READ, reqid, psn->fhand_r, psn->fhand_r_len); 478 psbuf_req_data(pb, SSH_FXP_READ, reqid, psn->fhand_r, psn->fhand_r_len);
478 psbuf_put_8(pb, offset); 479 psbuf_put_8(pb, offset);
479 psbuf_put_4(pb, readlen); 480 psbuf_put_4(pb, readlen);
480 481
481 /* 482 /*
482 * Do this *after* accessing the file, the handle might not 483 * Do this *after* accessing the file, the handle might not
483 * exist after blocking. 484 * exist after blocking.
484 */ 485 */
485 if (max_reads && ++psn->readcount > max_reads) { 486 if (max_reads && ++psn->readcount > max_reads) {
486 struct psshfs_wait pw; 487 struct psshfs_wait pw;
487 488
488 pw.pw_cc = pcc; 489 pw.pw_cc = pcc;
489 pw.pw_type = PWTYPE_READ2; 490 pw.pw_type = PWTYPE_READ2;
490 TAILQ_INSERT_TAIL(&psn->pw, &pw, pw_entries); 491 TAILQ_INSERT_TAIL(&psn->pw, &pw, pw_entries);
491 puffs_cc_yield(pcc); 492 puffs_cc_yield(pcc);
492 } 493 }
493 494
494 GETRESPONSE(pb, pctx->sshfd_data); 495 GETRESPONSE(pb, pctx->sshfd_data);
495 496
496 rv = psbuf_do_data(pb, buf, &readlen); 497 rv = psbuf_do_data(pb, buf, &readlen);
497 if (rv == 0) 498 if (rv == 0)
498 *resid -= readlen; 499 *resid -= readlen;
499 500
500 out: 501 out:
501 if (max_reads && --psn->readcount >= max_reads) { 502 if (max_reads && --psn->readcount >= max_reads) {
502 TAILQ_FOREACH(pwp, &psn->pw, pw_entries) 503 TAILQ_FOREACH(pwp, &psn->pw, pw_entries)
503 if (pwp->pw_type == PWTYPE_READ2) 504 if (pwp->pw_type == PWTYPE_READ2)
504 break; 505 break;
505 assert(pwp != NULL); 506 assert(pwp != NULL);
506 puffs_cc_schedule(pwp->pw_cc); 507 puffs_cc_schedule(pwp->pw_cc);
507 TAILQ_REMOVE(&psn->pw, pwp, pw_entries); 508 TAILQ_REMOVE(&psn->pw, pwp, pw_entries);
508 } 509 }
509 510
510 farout: 511 farout:
511 /* check if we need a lazyclose */ 512 /* check if we need a lazyclose */
512 if (psn->stat & PSN_HANDLECLOSE && psn->fhand_r) { 513 if (psn->stat & PSN_HANDLECLOSE && psn->fhand_r) {
513 TAILQ_FOREACH(pwp, &psn->pw, pw_entries) 514 TAILQ_FOREACH(pwp, &psn->pw, pw_entries)
514 if (pwp->pw_type == PWTYPE_READ1) 515 if (pwp->pw_type == PWTYPE_READ1)
515 break; 516 break;
516 if (pwp == NULL) 517 if (pwp == NULL)
517 closehandles(pu, psn, HANDLE_READ); 518 closehandles(pu, psn, HANDLE_READ);
518 } 519 }
519 PSSHFSRETURN(rv); 520 PSSHFSRETURN(rv);
520} 521}
521 522
522/* XXX: we should getattr for size */ 523/* XXX: we should getattr for size */
523int 524int
524psshfs_node_write(struct puffs_usermount *pu, puffs_cookie_t opc, uint8_t *buf, 525psshfs_node_write(struct puffs_usermount *pu, puffs_cookie_t opc, uint8_t *buf,
525 off_t offset, size_t *resid, const struct puffs_cred *cred, 526 off_t offset, size_t *resid, const struct puffs_cred *cred,
526 int ioflag) 527 int ioflag)
527{ 528{
528 PSSHFSAUTOVAR(pu); 529 PSSHFSAUTOVAR(pu);
529 struct psshfs_wait *pwp; 530 struct psshfs_wait *pwp;
530 struct puffs_node *pn = opc; 531 struct puffs_node *pn = opc;
531 struct psshfs_node *psn = pn->pn_data; 532 struct psshfs_node *psn = pn->pn_data;
532 uint32_t writelen; 533 uint32_t writelen;
533 534
534 if (pn->pn_va.va_type == VDIR) { 535 if (pn->pn_va.va_type == VDIR) {
535 rv = EISDIR; 536 rv = EISDIR;
536 goto out; 537 goto out;
537 } 538 }
538 539
539 /* check that a lazyopen didn't fail */ 540 /* check that a lazyopen didn't fail */
540 if (!psn->fhand_w && !psn->lazyopen_w) { 541 if (!psn->fhand_w && !psn->lazyopen_w) {
541 rv = psn->lazyopen_err_w; 542 rv = psn->lazyopen_err_w;
542 goto out; 543 goto out;
543 } 544 }
544 545
545 if (psn->stat & PSN_LAZYWAIT_W) { 546 if (psn->stat & PSN_LAZYWAIT_W) {
546 struct psshfs_wait pw; 547 struct psshfs_wait pw;
547 548
548 assert(psn->lazyopen_w); 549 assert(psn->lazyopen_w);
549 550
550 pw.pw_cc = pcc; 551 pw.pw_cc = pcc;
551 pw.pw_type = PWTYPE_WRITE; 552 pw.pw_type = PWTYPE_WRITE;
552 TAILQ_INSERT_TAIL(&psn->pw, &pw, pw_entries); 553 TAILQ_INSERT_TAIL(&psn->pw, &pw, pw_entries);
553 puffs_cc_yield(pcc); 554 puffs_cc_yield(pcc);
554 } 555 }
555 556
556 /* 557 /*
557 * If lazyopening, wait for the result. 558 * If lazyopening, wait for the result.
558 * There can still be more than oen writer at a time in case 559 * There can still be more than oen writer at a time in case
559 * the kernel issues write FAFs. 560 * the kernel issues write FAFs.
560 */ 561 */
561 if (psn->lazyopen_w) { 562 if (psn->lazyopen_w) {
562 psn->stat |= PSN_LAZYWAIT_W; 563 psn->stat |= PSN_LAZYWAIT_W;
563 rv = puffs_framev_framebuf_ccpromote(psn->lazyopen_w, pcc); 564 rv = puffs_framev_framebuf_ccpromote(psn->lazyopen_w, pcc);
564 lazyopen_wresp(pu, psn->lazyopen_w, psn, rv); 565 lazyopen_wresp(pu, psn->lazyopen_w, psn, rv);
565 566
566 /* schedule extra waiters */ 567 /* schedule extra waiters */
567 TAILQ_FOREACH(pwp, &psn->pw, pw_entries) 568 TAILQ_FOREACH(pwp, &psn->pw, pw_entries)
568 if (pwp->pw_type == PWTYPE_WRITE) { 569 if (pwp->pw_type == PWTYPE_WRITE) {
569 puffs_cc_schedule(pwp->pw_cc); 570 puffs_cc_schedule(pwp->pw_cc);
570 TAILQ_REMOVE(&psn->pw, pwp, pw_entries); 571 TAILQ_REMOVE(&psn->pw, pwp, pw_entries);
571 } 572 }
572 psn->stat &= ~PSN_LAZYWAIT_W; 573 psn->stat &= ~PSN_LAZYWAIT_W;
573 574
574 if ((rv = psn->lazyopen_err_w) != 0) 575 if ((rv = psn->lazyopen_err_w) != 0)
575 goto out; 576 goto out;
576 } 577 }
577 578
578 if (!psn->fhand_w) { 579 if (!psn->fhand_w) {
579 abort(); 580 abort();
580 rv = EINVAL; 581 rv = EINVAL;
581 goto out; 582 goto out;
582 } 583 }
583 584
584 writelen = *resid; 585 writelen = *resid;
585 psbuf_req_data(pb, SSH_FXP_WRITE, reqid, psn->fhand_w,psn->fhand_w_len); 586 psbuf_req_data(pb, SSH_FXP_WRITE, reqid, psn->fhand_w,psn->fhand_w_len);
586 psbuf_put_8(pb, offset); 587 psbuf_put_8(pb, offset);
587 psbuf_put_data(pb, buf, writelen); 588 psbuf_put_data(pb, buf, writelen);
588 GETRESPONSE(pb, pctx->sshfd_data); 589 GETRESPONSE(pb, pctx->sshfd_data);
589 590
590 rv = psbuf_expect_status(pb); 591 rv = psbuf_expect_status(pb);
591 if (rv == 0) 592 if (rv == 0)
592 *resid = 0; 593 *resid = 0;
593 594
594 if (pn->pn_va.va_size < (uint64_t)offset + writelen) 595 if (pn->pn_va.va_size < (uint64_t)offset + writelen)
595 pn->pn_va.va_size = offset + writelen; 596 pn->pn_va.va_size = offset + writelen;
596 597
597 out: 598 out:
598 /* check if we need a lazyclose */ 599 /* check if we need a lazyclose */
599 if (psn->stat & PSN_HANDLECLOSE && psn->fhand_w) { 600 if (psn->stat & PSN_HANDLECLOSE && psn->fhand_w) {
600 TAILQ_FOREACH(pwp, &psn->pw, pw_entries) 601 TAILQ_FOREACH(pwp, &psn->pw, pw_entries)
601 if (pwp->pw_type == PWTYPE_WRITE) 602 if (pwp->pw_type == PWTYPE_WRITE)
602 break; 603 break;
603 if (pwp == NULL) 604 if (pwp == NULL)
604 closehandles(pu, psn, HANDLE_WRITE); 605 closehandles(pu, psn, HANDLE_WRITE);
605 } 606 }
606 PSSHFSRETURN(rv); 607 PSSHFSRETURN(rv);
607} 608}
608 609
609int 610int
610psshfs_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc, 611psshfs_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc,
611 const struct puffs_cred *cred, char *linkvalue, size_t *linklen) 612 const struct puffs_cred *cred, char *linkvalue, size_t *linklen)
612{ 613{
613 PSSHFSAUTOVAR(pu); 614 PSSHFSAUTOVAR(pu);
614 struct puffs_node *pn = opc; 615 struct puffs_node *pn = opc;
615 struct psshfs_node *psn = pn->pn_data; 616 struct psshfs_node *psn = pn->pn_data;
616 uint32_t count; 617 uint32_t count;
617 618
618 if (pctx->protover < 3) { 619 if (pctx->protover < 3) {
619 rv = EOPNOTSUPP; 620 rv = EOPNOTSUPP;
620 goto out; 621 goto out;
621 } 622 }
622 623
623 /* 624 /*
624 * check if we can use a cached version 625 * check if we can use a cached version
625 * 626 *
626 * XXX: we might end up reading the same link multiple times 627 * XXX: we might end up reading the same link multiple times
627 * from the server if we get many requests at once, but that's 628 * from the server if we get many requests at once, but that's
628 * quite harmless as this routine is reentrant. 629 * quite harmless as this routine is reentrant.
629 */ 630 */
630 if (psn->symlink && !REFRESHTIMEOUT(pctx, time(NULL) - psn->slread)) 631 if (psn->symlink && !REFRESHTIMEOUT(pctx, time(NULL) - psn->slread))
631 goto copy; 632 goto copy;
632 633
633 if (psn->symlink) { 634 if (psn->symlink) {
634 free(psn->symlink); 635 free(psn->symlink);
635 psn->symlink = NULL; 636 psn->symlink = NULL;
636 psn->slread = 0; 637 psn->slread = 0;
637 } 638 }
638 639
639 psbuf_req_str(pb, SSH_FXP_READLINK, reqid, PNPATH(pn)); 640 psbuf_req_str(pb, SSH_FXP_READLINK, reqid, PNPATH(pn));
640 GETRESPONSE(pb, pctx->sshfd); 641 GETRESPONSE(pb, pctx->sshfd);
641 642
642 rv = psbuf_expect_name(pb, &count); 643 rv = psbuf_expect_name(pb, &count);
643 if (rv) 644 if (rv)
644 goto out; 645 goto out;
645 if (count != 1) { 646 if (count != 1) {
646 rv = EPROTO; 647 rv = EPROTO;
647 goto out; 648 goto out;
648 } 649 }
649 650
650 rv = psbuf_get_str(pb, &psn->symlink, NULL); 651 rv = psbuf_get_str(pb, &psn->symlink, NULL);
651 if (rv) 652 if (rv)
652 goto out; 653 goto out;
653 psn->slread = time(NULL); 654 psn->slread = time(NULL);
654 655
655 copy: 656 copy:
656 *linklen = strlen(psn->symlink); 657 *linklen = strlen(psn->symlink);
657 (void) memcpy(linkvalue, psn->symlink, *linklen); 658 (void) memcpy(linkvalue, psn->symlink, *linklen);
658 659
659 out: 660 out:
660 PSSHFSRETURN(rv); 661 PSSHFSRETURN(rv);
661} 662}
662 663
663static int 664static int
664doremove(struct puffs_usermount *pu, struct puffs_node *pn_dir, 665doremove(struct puffs_usermount *pu, struct puffs_node *pn_dir,
665 struct puffs_node *pn, const char *name) 666 struct puffs_node *pn, const char *name)
666{ 667{
667 PSSHFSAUTOVAR(pu); 668 PSSHFSAUTOVAR(pu);
668 int op; 669 int op;
669 670
670 if (pn->pn_va.va_type == VDIR) 671 if (pn->pn_va.va_type == VDIR)
671 op = SSH_FXP_RMDIR; 672 op = SSH_FXP_RMDIR;
672 else 673 else
673 op = SSH_FXP_REMOVE; 674 op = SSH_FXP_REMOVE;
674 675
675 psbuf_req_str(pb, op, reqid, PNPATH(pn)); 676 psbuf_req_str(pb, op, reqid, PNPATH(pn));
676 GETRESPONSE(pb, pctx->sshfd); 677 GETRESPONSE(pb, pctx->sshfd);
677 678
678 rv = psbuf_expect_status(pb); 679 rv = psbuf_expect_status(pb);
679 if (rv == 0) 680 if (rv == 0)
680 nukenode(pn, name, 0); 681 nukenode(pn, name, 0);
681 682
682 out: 683 out:
683 PSSHFSRETURN(rv); 684 PSSHFSRETURN(rv);
684} 685}
685 686
686int 687int
687psshfs_node_remove(struct puffs_usermount *pu, puffs_cookie_t opc, 688psshfs_node_remove(struct puffs_usermount *pu, puffs_cookie_t opc,
688 puffs_cookie_t targ, const struct puffs_cn *pcn) 689 puffs_cookie_t targ, const struct puffs_cn *pcn)
689{ 690{
690 struct puffs_node *pn_targ = targ; 691 struct puffs_node *pn_targ = targ;
691 int rv; 692 int rv;
692 693
693 assert(pn_targ->pn_va.va_type != VDIR); 694 assert(pn_targ->pn_va.va_type != VDIR);
694 695
695 rv = doremove(pu, opc, targ, pcn->pcn_name); 696 rv = doremove(pu, opc, targ, pcn->pcn_name);
696 if (rv == 0) 697 if (rv == 0)
697 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); 698 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
698 699
699 return rv; 700 return rv;
700} 701}
701 702
702int 703int
703psshfs_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc, 704psshfs_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc,
704 puffs_cookie_t targ, const struct puffs_cn *pcn) 705 puffs_cookie_t targ, const struct puffs_cn *pcn)
705{ 706{
706 struct puffs_node *pn_targ = targ; 707 struct puffs_node *pn_targ = targ;
707 int rv; 708 int rv;
708 709
709 assert(pn_targ->pn_va.va_type == VDIR); 710 assert(pn_targ->pn_va.va_type == VDIR);
710 711
711 rv = doremove(pu, opc, targ, pcn->pcn_name); 712 rv = doremove(pu, opc, targ, pcn->pcn_name);
712 if (rv == 0) 713 if (rv == 0)
713 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2); 714 puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N2);
714 715
715 return rv; 716 return rv;
716} 717}
717 718
718int 719int
719psshfs_node_mkdir(struct puffs_usermount *pu, puffs_cookie_t opc, 720psshfs_node_mkdir(struct puffs_usermount *pu, puffs_cookie_t opc,
720 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 721 struct puffs_newinfo *pni, const struct puffs_cn *pcn,
721 const struct vattr *va) 722 const struct vattr *va)
722{ 723{
723 PSSHFSAUTOVAR(pu); 724 PSSHFSAUTOVAR(pu);
724 struct puffs_node *pn = opc; 725 struct puffs_node *pn = opc;
725 struct puffs_node *pn_new; 726 struct puffs_node *pn_new;
726 727
727 psbuf_req_str(pb, SSH_FXP_MKDIR, reqid, PCNPATH(pcn)); 728 psbuf_req_str(pb, SSH_FXP_MKDIR, reqid, PCNPATH(pcn));
728 psbuf_put_vattr(pb, va, pctx); 729 psbuf_put_vattr(pb, va, pctx);
729 GETRESPONSE(pb, pctx->sshfd); 730 GETRESPONSE(pb, pctx->sshfd);
730 731
731 rv = psbuf_expect_status(pb); 732 rv = psbuf_expect_status(pb);
732 if (rv) 733 if (rv)
733 goto out; 734 goto out;
734 735
735 pn_new = allocnode(pu, pn, pcn->pcn_name, va); 736 pn_new = allocnode(pu, pn, pcn->pcn_name, va);
736 if (pn_new) { 737 if (pn_new) {
737 puffs_newinfo_setcookie(pni, pn_new); 738 puffs_newinfo_setcookie(pni, pn_new);
738 } else { 739 } else {
739 struct puffs_framebuf *pb2 = psbuf_makeout(); 740 struct puffs_framebuf *pb2 = psbuf_makeout();
740 reqid = NEXTREQ(pctx); 741 reqid = NEXTREQ(pctx);
741 psbuf_recycleout(pb2); 742 psbuf_recycleout(pb2);
742 psbuf_req_str(pb2, SSH_FXP_RMDIR, reqid, PCNPATH(pcn)); 743 psbuf_req_str(pb2, SSH_FXP_RMDIR, reqid, PCNPATH(pcn));
743 JUSTSEND(pb2, pctx->sshfd); 744 JUSTSEND(pb2, pctx->sshfd);
744 rv = ENOMEM; 745 rv = ENOMEM;
745 } 746 }
746 747
747 out: 748 out:
748 PSSHFSRETURN(rv); 749 PSSHFSRETURN(rv);
749} 750}
750 751
751int 752int
752psshfs_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc, 753psshfs_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc,
753 struct puffs_newinfo *pni, const struct puffs_cn *pcn, 754 struct puffs_newinfo *pni, const struct puffs_cn *pcn,
754 const struct vattr *va, const char *link_target) 755 const struct vattr *va, const char *link_target)
755{ 756{
756 PSSHFSAUTOVAR(pu); 757 PSSHFSAUTOVAR(pu);
757 struct puffs_node *pn = opc; 758 struct puffs_node *pn = opc;
758 struct puffs_node *pn_new; 759 struct puffs_node *pn_new;
759 760
760 if (pctx->protover < 3) { 761 if (pctx->protover < 3) {
761 rv = EOPNOTSUPP; 762 rv = EOPNOTSUPP;
762 goto out; 763 goto out;
763 } 764 }
764 765
765 /* 766 /*
766 * XXX: ietf says: source, target. openssh says: ietf who? 767 * XXX: ietf says: source, target. openssh says: ietf who?
767 * Let's go with openssh and build quirk tables later if we care 768 * Let's go with openssh and build quirk tables later if we care
768 */ 769 */
769 psbuf_req_str(pb, SSH_FXP_SYMLINK, reqid, link_target); 770 psbuf_req_str(pb, SSH_FXP_SYMLINK, reqid, link_target);
770 psbuf_put_str(pb, PCNPATH(pcn)); 771 psbuf_put_str(pb, PCNPATH(pcn));
771 GETRESPONSE(pb, pctx->sshfd); 772 GETRESPONSE(pb, pctx->sshfd);
772 773
773 rv = psbuf_expect_status(pb); 774 rv = psbuf_expect_status(pb);
774 if (rv) 775 if (rv)
775 goto out; 776 goto out;
776 777
777 pn_new = allocnode(pu, pn, pcn->pcn_name, va); 778 pn_new = allocnode(pu, pn, pcn->pcn_name, va);
778 if (pn_new) { 779 if (pn_new) {
779 puffs_newinfo_setcookie(pni, pn_new); 780 puffs_newinfo_setcookie(pni, pn_new);
780 } else { 781 } else {
781 struct puffs_framebuf *pb2 = psbuf_makeout(); 782 struct puffs_framebuf *pb2 = psbuf_makeout();
782 reqid = NEXTREQ(pctx); 783 reqid = NEXTREQ(pctx);
783 psbuf_recycleout(pb2); 784 psbuf_recycleout(pb2);
784 psbuf_req_str(pb2, SSH_FXP_REMOVE, reqid, PCNPATH(pcn)); 785 psbuf_req_str(pb2, SSH_FXP_REMOVE, reqid, PCNPATH(pcn));
785 JUSTSEND(pb2, pctx->sshfd); 786 JUSTSEND(pb2, pctx->sshfd);
786 rv = ENOMEM; 787 rv = ENOMEM;
787 } 788 }
788 789
789 out: 790 out:
790 PSSHFSRETURN(rv); 791 PSSHFSRETURN(rv);
791} 792}
792 793
793int 794int
794psshfs_node_rename(struct puffs_usermount *pu, puffs_cookie_t opc, 795psshfs_node_rename(struct puffs_usermount *pu, puffs_cookie_t opc,
795 puffs_cookie_t src, const struct puffs_cn *pcn_src, 796 puffs_cookie_t src, const struct puffs_cn *pcn_src,
796 puffs_cookie_t targ_dir, puffs_cookie_t targ, 797 puffs_cookie_t targ_dir, puffs_cookie_t targ,
797 const struct puffs_cn *pcn_targ) 798 const struct puffs_cn *pcn_targ)
798{ 799{
799 PSSHFSAUTOVAR(pu); 800 PSSHFSAUTOVAR(pu);
800 struct puffs_node *pn_sf = src; 801 struct puffs_node *pn_sf = src;
801 struct puffs_node *pn_td = targ_dir, *pn_tf = targ; 802 struct puffs_node *pn_td = targ_dir, *pn_tf = targ;
802 struct psshfs_node *psn_src = pn_sf->pn_data; 803 struct psshfs_node *psn_src = pn_sf->pn_data;
803 struct psshfs_node *psn_targdir = pn_td->pn_data; 804 struct psshfs_node *psn_targdir = pn_td->pn_data;
804 805
805 if (pctx->protover < 2) { 806 if (pctx->protover < 2) {
806 rv = EOPNOTSUPP; 807 rv = EOPNOTSUPP;
807 goto out; 808 goto out;
808 } 809 }
809 810
810 if (pn_tf) { 811 if (pn_tf) {
811 rv = doremove(pu, targ_dir, pn_tf, pcn_targ->pcn_name); 812 rv = doremove(pu, targ_dir, pn_tf, pcn_targ->pcn_name);
812 if (rv) 813 if (rv)
813 goto out; 814 goto out;
814 } 815 }
815 816
816 psbuf_req_str(pb, SSH_FXP_RENAME, reqid, PCNPATH(pcn_src)); 817 psbuf_req_str(pb, SSH_FXP_RENAME, reqid, PCNPATH(pcn_src));
817 psbuf_put_str(pb, PCNPATH(pcn_targ)); 818 psbuf_put_str(pb, PCNPATH(pcn_targ));
818 GETRESPONSE(pb, pctx->sshfd); 819 GETRESPONSE(pb, pctx->sshfd);
819 820
820 rv = psbuf_expect_status(pb); 821 rv = psbuf_expect_status(pb);
821 if (rv == 0) { 822 if (rv == 0) {
822 struct psshfs_dir *pd; 823 struct psshfs_dir *pd;
823 824
824 /* 825 /*
825 * XXX: interfaces didn't quite work with rename.. 826 * XXX: interfaces didn't quite work with rename..
826 * the song remains the same. go figure .. ;) 827 * the song remains the same. go figure .. ;)
827 */ 828 */
828 nukenode(pn_sf, pcn_src->pcn_name, 0); 829 nukenode(pn_sf, pcn_src->pcn_name, 0);
829 pd = direnter(pn_td, pcn_targ->pcn_name); 830 pd = direnter(pn_td, pcn_targ->pcn_name);
830 pd->entry = pn_sf; 831 pd->entry = pn_sf;
831 puffs_setvattr(&pd->va, &pn_sf->pn_va); 832 puffs_setvattr(&pd->va, &pn_sf->pn_va);
832 833
833 if (opc != targ_dir) { 834 if (opc != targ_dir) {
834 psn_targdir->childcount++; 835 psn_targdir->childcount++;
835 psn_src->parent = pn_td; 836 psn_src->parent = pn_td;
836 if (pn_sf->pn_va.va_type == VDIR) 837 if (pn_sf->pn_va.va_type == VDIR)
837 pn_td->pn_va.va_nlink++; 838 pn_td->pn_va.va_nlink++;
838 } 839 }
839 } 840 }
840 841
841 out: 842 out:
842 PSSHFSRETURN(rv); 843 PSSHFSRETURN(rv);
843} 844}
844 845
845/* 846/*
846 * So this file system happened to be written in such a way that 847 * So this file system happened to be written in such a way that
847 * lookup for ".." is hard if we lose the in-memory node. We'd 848 * lookup for ".." is hard if we lose the in-memory node. We'd
848 * need to recreate the entire directory structure from the root 849 * need to recreate the entire directory structure from the root
849 * node up to the ".." node we're looking up. 850 * node up to the ".." node we're looking up.
850 * 851 *
851 * And since our entire fs structure is purely fictional (i.e. it's 852 * And since our entire fs structure is purely fictional (i.e. it's
852 * only in-memory, not fetchable from the server), the easiest way 853 * only in-memory, not fetchable from the server), the easiest way
853 * to deal with it is to not allow nodes with children to be 854 * to deal with it is to not allow nodes with children to be
854 * reclaimed. 855 * reclaimed.
855 * 856 *
856 * If a node with children is being attempted to be reclaimed, we 857 * If a node with children is being attempted to be reclaimed, we
857 * just mark it "reclaimed" but leave it as is until all its children 858 * just mark it "reclaimed" but leave it as is until all its children
858 * have been reclaimed. If a lookup for that node is done meanwhile, 859 * have been reclaimed. If a lookup for that node is done meanwhile,
859 * it will be found by lookup() and we just remove the "reclaimed" 860 * it will be found by lookup() and we just remove the "reclaimed"
860 * bit. 861 * bit.
861 */ 862 */
862int 863int
863psshfs_node_reclaim(struct puffs_usermount *pu, puffs_cookie_t opc) 864psshfs_node_reclaim(struct puffs_usermount *pu, puffs_cookie_t opc)
864{ 865{
865 struct puffs_node *pn = opc, *pn_next, *pn_root; 866 struct puffs_node *pn = opc, *pn_next, *pn_root;
866 struct psshfs_node *psn = pn->pn_data; 867 struct psshfs_node *psn = pn->pn_data;
867 868
868 /* 869 /*
869 * don't reclaim if we have file handle issued, otherwise 870 * don't reclaim if we have file handle issued, otherwise
870 * we can't do fhtonode 871 * we can't do fhtonode
871 */ 872 */
872 if (psn->stat & PSN_HASFH) 873 if (psn->stat & PSN_HASFH)
873 return 0; 874 return 0;
874 875
875 psn->stat |= PSN_RECLAIMED; 876 psn->stat |= PSN_RECLAIMED;
876 pn_root = puffs_getroot(pu); 877 pn_root = puffs_getroot(pu);
877 for (; pn != pn_root; pn = pn_next) { 878 for (; pn != pn_root; pn = pn_next) {
878 psn = pn->pn_data; 879 psn = pn->pn_data;
879 if ((psn->stat & PSN_RECLAIMED) == 0 || psn->childcount != 0) 880 if ((psn->stat & PSN_RECLAIMED) == 0 || psn->childcount != 0)
880 break; 881 break;
881 882
882 pn_next = psn->parent; 883 pn_next = psn->parent;
883 doreclaim(pn); 884 doreclaim(pn);
884 } 885 }
885 886
886 return 0; 887 return 0;
887} 888}

cvs diff -r1.61 -r1.62 src/usr.sbin/puffs/mount_psshfs/psshfs.c (switch to unified diff)

--- src/usr.sbin/puffs/mount_psshfs/psshfs.c 2010/02/17 15:54:10 1.61
+++ src/usr.sbin/puffs/mount_psshfs/psshfs.c 2010/10/29 16:13:51 1.62
@@ -1,446 +1,446 @@ @@ -1,446 +1,446 @@
1/* $NetBSD: psshfs.c,v 1.61 2010/02/17 15:54:10 pooka Exp $ */ 1/* $NetBSD: psshfs.c,v 1.62 2010/10/29 16:13:51 pooka Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2006-2009 Antti Kantee. All Rights Reserved. 4 * Copyright (c) 2006-2009 Antti Kantee. All Rights Reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 * 14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE. 25 * SUCH DAMAGE.
26 */ 26 */
27 27
28/* 28/*
29 * psshfs: puffs sshfs 29 * psshfs: puffs sshfs
30 * 30 *
31 * psshfs implements sshfs functionality on top of puffs making it 31 * psshfs implements sshfs functionality on top of puffs making it
32 * possible to mount a filesystme through the sftp service. 32 * possible to mount a filesystme through the sftp service.
33 * 33 *
34 * psshfs can execute multiple operations in "parallel" by using the 34 * psshfs can execute multiple operations in "parallel" by using the
35 * puffs_cc framework for continuations. 35 * puffs_cc framework for continuations.
36 * 36 *
37 * Concurrency control is handled currently by vnode locking (this 37 * Concurrency control is handled currently by vnode locking (this
38 * will change in the future). Context switch locations are easy to 38 * will change in the future). Context switch locations are easy to
39 * find by grepping for puffs_framebuf_enqueue_cc(). 39 * find by grepping for puffs_framebuf_enqueue_cc().
40 */ 40 */
41 41
42#include <sys/cdefs.h> 42#include <sys/cdefs.h>
43#ifndef lint 43#ifndef lint
44__RCSID("$NetBSD: psshfs.c,v 1.61 2010/02/17 15:54:10 pooka Exp $"); 44__RCSID("$NetBSD: psshfs.c,v 1.62 2010/10/29 16:13:51 pooka Exp $");
45#endif /* !lint */ 45#endif /* !lint */
46 46
47#include <sys/types.h> 47#include <sys/types.h>
48#include <sys/wait.h> 48#include <sys/wait.h>
49 49
50#include <assert.h> 50#include <assert.h>
51#include <err.h> 51#include <err.h>
52#include <errno.h> 52#include <errno.h>
53#include <mntopts.h> 53#include <mntopts.h>
54#include <paths.h> 54#include <paths.h>
55#include <poll.h> 55#include <poll.h>
56#include <puffs.h> 56#include <puffs.h>
57#include <signal.h> 57#include <signal.h>
58#include <stdlib.h> 58#include <stdlib.h>
59#include <util.h> 59#include <util.h>
60#include <unistd.h> 60#include <unistd.h>
61 61
62#include "psshfs.h" 62#include "psshfs.h"
63 63
64static int pssh_connect(struct puffs_usermount *, int); 64static int pssh_connect(struct puffs_usermount *, int);
65static void psshfs_loopfn(struct puffs_usermount *); 65static void psshfs_loopfn(struct puffs_usermount *);
66static void usage(void); 66static void usage(void);
67static void add_ssharg(char ***, int *, const char *); 67static void add_ssharg(char ***, int *, const char *);
68static void psshfs_notify(struct puffs_usermount *, int, int); 68static void psshfs_notify(struct puffs_usermount *, int, int);
69 69
70#define SSH_PATH "/usr/bin/ssh" 70#define SSH_PATH "/usr/bin/ssh"
71 71
72unsigned int max_reads; 72unsigned int max_reads;
73static int sighup; 73static int sighup;
74 74
75static void 75static void
76add_ssharg(char ***sshargs, int *nargs, const char *arg) 76add_ssharg(char ***sshargs, int *nargs, const char *arg)
77{ 77{
78  78
79 *sshargs = realloc(*sshargs, (*nargs + 2) * sizeof(char*)); 79 *sshargs = realloc(*sshargs, (*nargs + 2) * sizeof(char*));
80 if (!*sshargs) 80 if (!*sshargs)
81 err(1, "realloc"); 81 err(1, "realloc");
82 (*sshargs)[(*nargs)++] = estrdup(arg); 82 (*sshargs)[(*nargs)++] = estrdup(arg);
83 (*sshargs)[*nargs] = NULL; 83 (*sshargs)[*nargs] = NULL;
84} 84}
85 85
86static void 86static void
87usage() 87usage()
88{ 88{
89 89
90 fprintf(stderr, "usage: %s " 90 fprintf(stderr, "usage: %s "
91 "[-ceprst] [-F configfile] [-O sshopt=value] [-o opts] " 91 "[-ceprst] [-F configfile] [-O sshopt=value] [-o opts] "
92 "user@host:path mountpath\n", 92 "user@host:path mountpath\n",
93 getprogname()); 93 getprogname());
94 exit(1); 94 exit(1);
95} 95}
96 96
97static void 97static void
98takehup(int sig) 98takehup(int sig)
99{ 99{
100 100
101 sighup = 1; 101 sighup = 1;
102} 102}
103 103
104int 104int
105main(int argc, char *argv[]) 105main(int argc, char *argv[])
106{ 106{
107 struct psshfs_ctx pctx; 107 struct psshfs_ctx pctx;
108 struct puffs_usermount *pu; 108 struct puffs_usermount *pu;
109 struct puffs_ops *pops; 109 struct puffs_ops *pops;
110 struct psshfs_node *root = &pctx.psn_root; 110 struct psshfs_node *root = &pctx.psn_root;
111 struct puffs_node *pn_root; 111 struct puffs_node *pn_root;
112 puffs_framev_fdnotify_fn notfn; 112 puffs_framev_fdnotify_fn notfn;
113 struct vattr *rva; 113 struct vattr *rva;
114 mntoptparse_t mp; 114 mntoptparse_t mp;
115 char **sshargs; 115 char **sshargs;
116 char *userhost; 116 char *userhost;
117 char *hostpath; 117 char *hostpath;
118 int mntflags, pflags, ch; 118 int mntflags, pflags, ch;
119 int detach; 119 int detach;
120 int exportfs, refreshival, numconnections; 120 int exportfs, refreshival, numconnections;
121 int nargs; 121 int nargs;
122 122
123 setprogname(argv[0]); 123 setprogname(argv[0]);
124 puffs_unmountonsignal(SIGINT, true); 124 puffs_unmountonsignal(SIGINT, true);
125 puffs_unmountonsignal(SIGTERM, true); 125 puffs_unmountonsignal(SIGTERM, true);
126 126
127 if (argc < 3) 127 if (argc < 3)
128 usage(); 128 usage();
129 129
130 memset(&pctx, 0, sizeof(pctx)); 130 memset(&pctx, 0, sizeof(pctx));
131 mntflags = pflags = exportfs = nargs = 0; 131 mntflags = pflags = exportfs = nargs = 0;
132 numconnections = 1; 132 numconnections = 1;
133 detach = 1; 133 detach = 1;
134 refreshival = DEFAULTREFRESH; 134 refreshival = DEFAULTREFRESH;
135 notfn = puffs_framev_unmountonclose; 135 notfn = puffs_framev_unmountonclose;
136 sshargs = NULL; 136 sshargs = NULL;
137 add_ssharg(&sshargs, &nargs, SSH_PATH); 137 add_ssharg(&sshargs, &nargs, SSH_PATH);
138 add_ssharg(&sshargs, &nargs, "-axs"); 138 add_ssharg(&sshargs, &nargs, "-axs");
139 add_ssharg(&sshargs, &nargs, "-oClearAllForwardings=yes"); 139 add_ssharg(&sshargs, &nargs, "-oClearAllForwardings=yes");
140 140
141 while ((ch = getopt(argc, argv, "c:eF:g:o:O:pr:st:u:")) != -1) { 141 while ((ch = getopt(argc, argv, "c:eF:g:o:O:pr:st:u:")) != -1) {
142 switch (ch) { 142 switch (ch) {
143 case 'c': 143 case 'c':
144 numconnections = atoi(optarg); 144 numconnections = atoi(optarg);
145 if (numconnections < 1 || numconnections > 2) { 145 if (numconnections < 1 || numconnections > 2) {
146 fprintf(stderr, "%s: only 1 or 2 connections " 146 fprintf(stderr, "%s: only 1 or 2 connections "
147 "permitted currently\n", getprogname()); 147 "permitted currently\n", getprogname());
148 usage(); 148 usage();
149 /*NOTREACHED*/ 149 /*NOTREACHED*/
150 } 150 }
151 break; 151 break;
152 case 'e': 152 case 'e':
153 exportfs = 1; 153 exportfs = 1;
154 break; 154 break;
155 case 'F': 155 case 'F':
156 add_ssharg(&sshargs, &nargs, "-F"); 156 add_ssharg(&sshargs, &nargs, "-F");
157 add_ssharg(&sshargs, &nargs, optarg); 157 add_ssharg(&sshargs, &nargs, optarg);
158 break; 158 break;
159 case 'g': 159 case 'g':
160 pctx.domanglegid = 1; 160 pctx.domanglegid = 1;
161 pctx.manglegid = atoi(optarg); 161 pctx.manglegid = atoi(optarg);
162 if (pctx.manglegid == (gid_t)-1) 162 if (pctx.manglegid == (gid_t)-1)
163 errx(1, "-1 not allowed for -g"); 163 errx(1, "-1 not allowed for -g");
164 pctx.mygid = getegid(); 164 pctx.mygid = getegid();
165 break; 165 break;
166 case 'O': 166 case 'O':
167 add_ssharg(&sshargs, &nargs, "-o"); 167 add_ssharg(&sshargs, &nargs, "-o");
168 add_ssharg(&sshargs, &nargs, optarg); 168 add_ssharg(&sshargs, &nargs, optarg);
169 break; 169 break;
170 case 'o': 170 case 'o':
171 mp = getmntopts(optarg, puffsmopts, &mntflags, &pflags); 171 mp = getmntopts(optarg, puffsmopts, &mntflags, &pflags);
172 if (mp == NULL) 172 if (mp == NULL)
173 err(1, "getmntopts"); 173 err(1, "getmntopts");
174 freemntopts(mp); 174 freemntopts(mp);
175 break; 175 break;
176 case 'p': 176 case 'p':
177 notfn = psshfs_notify; 177 notfn = psshfs_notify;
178 break; 178 break;
179 case 'r': 179 case 'r':
180 max_reads = atoi(optarg); 180 max_reads = atoi(optarg);
181 break; 181 break;
182 case 's': 182 case 's':
183 detach = 0; 183 detach = 0;
184 break; 184 break;
185 case 't': 185 case 't':
186 refreshival = atoi(optarg); 186 refreshival = atoi(optarg);
187 if (refreshival < 0 && refreshival != -1) 187 if (refreshival < 0 && refreshival != -1)
188 errx(1, "invalid timeout %d", refreshival); 188 errx(1, "invalid timeout %d", refreshival);
189 break; 189 break;
190 case 'u': 190 case 'u':
191 pctx.domangleuid = 1; 191 pctx.domangleuid = 1;
192 pctx.mangleuid = atoi(optarg); 192 pctx.mangleuid = atoi(optarg);
193 if (pctx.mangleuid == (uid_t)-1) 193 if (pctx.mangleuid == (uid_t)-1)
194 errx(1, "-1 not allowed for -u"); 194 errx(1, "-1 not allowed for -u");
195 pctx.myuid = geteuid(); 195 pctx.myuid = geteuid();
196 break; 196 break;
197 default: 197 default:
198 usage(); 198 usage();
199 /*NOTREACHED*/ 199 /*NOTREACHED*/
200 } 200 }
201 } 201 }
202 argc -= optind; 202 argc -= optind;
203 argv += optind; 203 argv += optind;
204 204
205 if (pflags & PUFFS_FLAG_OPDUMP) 205 if (pflags & PUFFS_FLAG_OPDUMP)
206 detach = 0; 206 detach = 0;
207 pflags |= PUFFS_FLAG_BUILDPATH; 207 pflags |= PUFFS_FLAG_BUILDPATH;
208 pflags |= PUFFS_KFLAG_WTCACHE | PUFFS_KFLAG_IAONDEMAND; 208 pflags |= PUFFS_KFLAG_WTCACHE | PUFFS_KFLAG_IAONDEMAND;
209 209
210 if (argc != 2) 210 if (argc != 2)
211 usage(); 211 usage();
212 212
213 PUFFSOP_INIT(pops); 213 PUFFSOP_INIT(pops);
214 214
215 PUFFSOP_SET(pops, psshfs, fs, unmount); 215 PUFFSOP_SET(pops, psshfs, fs, unmount);
216 PUFFSOP_SETFSNOP(pops, sync); /* XXX */ 216 PUFFSOP_SETFSNOP(pops, sync); /* XXX */
217 PUFFSOP_SET(pops, psshfs, fs, statvfs); 217 PUFFSOP_SET(pops, psshfs, fs, statvfs);
218 PUFFSOP_SET(pops, psshfs, fs, nodetofh); 218 PUFFSOP_SET(pops, psshfs, fs, nodetofh);
219 PUFFSOP_SET(pops, psshfs, fs, fhtonode); 219 PUFFSOP_SET(pops, psshfs, fs, fhtonode);
220 220
221 PUFFSOP_SET(pops, psshfs, node, lookup); 221 PUFFSOP_SET(pops, psshfs, node, lookup);
222 PUFFSOP_SET(pops, psshfs, node, create); 222 PUFFSOP_SET(pops, psshfs, node, create);
223 PUFFSOP_SET(pops, psshfs, node, open); 223 PUFFSOP_SET(pops, psshfs, node, open);
224 PUFFSOP_SET(pops, psshfs, node, inactive); 224 PUFFSOP_SET(pops, psshfs, node, inactive);
225 PUFFSOP_SET(pops, psshfs, node, readdir); 225 PUFFSOP_SET(pops, psshfs, node, readdir);
226 PUFFSOP_SET(pops, psshfs, node, getattr); 226 PUFFSOP_SET(pops, psshfs, node, getattr);
227 PUFFSOP_SET(pops, psshfs, node, setattr); 227 PUFFSOP_SET(pops, psshfs, node, setattr);
228 PUFFSOP_SET(pops, psshfs, node, mkdir); 228 PUFFSOP_SET(pops, psshfs, node, mkdir);
229 PUFFSOP_SET(pops, psshfs, node, remove); 229 PUFFSOP_SET(pops, psshfs, node, remove);
230 PUFFSOP_SET(pops, psshfs, node, readlink); 230 PUFFSOP_SET(pops, psshfs, node, readlink);
231 PUFFSOP_SET(pops, psshfs, node, rmdir); 231 PUFFSOP_SET(pops, psshfs, node, rmdir);
232 PUFFSOP_SET(pops, psshfs, node, symlink); 232 PUFFSOP_SET(pops, psshfs, node, symlink);
233 PUFFSOP_SET(pops, psshfs, node, rename); 233 PUFFSOP_SET(pops, psshfs, node, rename);
234 PUFFSOP_SET(pops, psshfs, node, read); 234 PUFFSOP_SET(pops, psshfs, node, read);
235 PUFFSOP_SET(pops, psshfs, node, write); 235 PUFFSOP_SET(pops, psshfs, node, write);
236 PUFFSOP_SET(pops, psshfs, node, reclaim); 236 PUFFSOP_SET(pops, psshfs, node, reclaim);
237 237
238 pu = puffs_init(pops, argv[0], "psshfs", &pctx, pflags); 238 pu = puffs_init(pops, argv[0], "psshfs", &pctx, pflags);
239 if (pu == NULL) 239 if (pu == NULL)
240 err(1, "puffs_init"); 240 err(1, "puffs_init");
241 241
242 pctx.mounttime = time(NULL); 242 pctx.mounttime = time(NULL);
243 pctx.refreshival = refreshival; 243 pctx.refreshival = refreshival;
244 pctx.numconnections = numconnections; 244 pctx.numconnections = numconnections;
245 245
246 userhost = argv[0]; 246 userhost = argv[0];
247 hostpath = strchr(userhost, ':'); 247 hostpath = strchr(userhost, ':');
248 if (hostpath) { 248 if (hostpath) {
249 *hostpath++ = '\0'; 249 *hostpath++ = '\0';
250 pctx.mountpath = hostpath; 250 pctx.mountpath = hostpath;
251 } else 251 } else
252 pctx.mountpath = "."; 252 pctx.mountpath = ".";
253 253
254 add_ssharg(&sshargs, &nargs, argv[0]); 254 add_ssharg(&sshargs, &nargs, argv[0]);
255 add_ssharg(&sshargs, &nargs, "sftp"); 255 add_ssharg(&sshargs, &nargs, "sftp");
256 pctx.sshargs = sshargs; 256 pctx.sshargs = sshargs;
257 257
258 pctx.nextino = 2; 258 pctx.nextino = 2;
259 memset(root, 0, sizeof(struct psshfs_node)); 259 memset(root, 0, sizeof(struct psshfs_node));
260 pn_root = puffs_pn_new(pu, root); 260 pn_root = puffs_pn_new(pu, root);
261 if (pn_root == NULL) 261 if (pn_root == NULL)
262 return errno; 262 return errno;
263 puffs_setroot(pu, pn_root); 263 puffs_setroot(pu, pn_root);
264 264
265 puffs_framev_init(pu, psbuf_read, psbuf_write, psbuf_cmp, NULL, notfn); 265 puffs_framev_init(pu, psbuf_read, psbuf_write, psbuf_cmp, NULL, notfn);
266 266
267 signal(SIGHUP, takehup); 267 signal(SIGHUP, takehup);
268 puffs_ml_setloopfn(pu, psshfs_loopfn); 268 puffs_ml_setloopfn(pu, psshfs_loopfn);
269 if (pssh_connect(pu, PSSHFD_META) == -1) 269 if (pssh_connect(pu, PSSHFD_META) == -1)
270 err(1, "can't connect meta"); 270 err(1, "can't connect meta");
271 if (puffs_framev_addfd(pu, pctx.sshfd, 271 if (puffs_framev_addfd(pu, pctx.sshfd,
272 PUFFS_FBIO_READ | PUFFS_FBIO_WRITE) == -1) 272 PUFFS_FBIO_READ | PUFFS_FBIO_WRITE) == -1)
273 err(1, "framebuf addfd meta"); 273 err(1, "framebuf addfd meta");
274 if (numconnections == 2) { 274 if (numconnections == 2) {
275 if (pssh_connect(pu, PSSHFD_DATA) == -1) 275 if (pssh_connect(pu, PSSHFD_DATA) == -1)
276 err(1, "can't connect data"); 276 err(1, "can't connect data");
277 if (puffs_framev_addfd(pu, pctx.sshfd_data, 277 if (puffs_framev_addfd(pu, pctx.sshfd_data,
278 PUFFS_FBIO_READ | PUFFS_FBIO_WRITE) == -1) 278 PUFFS_FBIO_READ | PUFFS_FBIO_WRITE) == -1)
279 err(1, "framebuf addfd data"); 279 err(1, "framebuf addfd data");
280 } else { 280 } else {
281 pctx.sshfd_data = pctx.sshfd; 281 pctx.sshfd_data = pctx.sshfd;
282 } 282 }
283 283
284 if (exportfs) 284 if (exportfs)
285 puffs_setfhsize(pu, sizeof(struct psshfs_fid), 285 puffs_setfhsize(pu, sizeof(struct psshfs_fid),
286 PUFFS_FHFLAG_NFSV2 | PUFFS_FHFLAG_NFSV3); 286 PUFFS_FHFLAG_NFSV2 | PUFFS_FHFLAG_NFSV3);
287 287
288 rva = &pn_root->pn_va; 288 rva = &pn_root->pn_va;
289 rva->va_fileid = pctx.nextino++; 289 rva->va_fileid = pctx.nextino++;
290 290
291 /* 291 /*
292 * For root link count, just guess something ridiculously high. 292 * For root link count, just guess something ridiculously high.
293 * Guessing too high has no known adverse effects, but fts(3) 293 * Guessing too high has no known adverse effects, but fts(3)
294 * doesn't like too low values. This guess will be replaced 294 * doesn't like too low values. This guess will be replaced
295 * with the real value when readdir is first called for 295 * with the real value when readdir is first called for
296 * the root directory. 296 * the root directory.
297 */ 297 */
298 rva->va_nlink = 8811; 298 rva->va_nlink = 8811;
299 299
300 if (detach) 300 if (detach)
301 if (puffs_daemon(pu, 1, 1) == -1) 301 if (puffs_daemon(pu, 1, 1) == -1)
302 err(1, "puffs_daemon"); 302 err(1, "puffs_daemon");
303 303
304 if (puffs_mount(pu, argv[1], mntflags, puffs_getroot(pu)) == -1) 304 if (puffs_mount(pu, argv[1], mntflags, puffs_getroot(pu)) == -1)
305 err(1, "puffs_mount"); 305 err(1, "puffs_mount");
306 if (puffs_setblockingmode(pu, PUFFSDEV_NONBLOCK) == -1) 306 if (puffs_setblockingmode(pu, PUFFSDEV_NONBLOCK) == -1)
307 err(1, "setblockingmode"); 307 err(1, "setblockingmode");
308 308
309 if (puffs_mainloop(pu) == -1) 309 if (puffs_mainloop(pu) == -1)
310 err(1, "mainloop"); 310 err(1, "mainloop");
311 puffs_exit(pu, 1); 311 puffs_exit(pu, 1);
312 312
313 return 0; 313 return 0;
314} 314}
315 315
316#define RETRY_MAX 100 316#define RETRY_MAX 100
317 317
318void 318void
319psshfs_notify(struct puffs_usermount *pu, int fd, int what) 319psshfs_notify(struct puffs_usermount *pu, int fd, int what)
320{ 320{
321 struct psshfs_ctx *pctx = puffs_getspecific(pu); 321 struct psshfs_ctx *pctx = puffs_getspecific(pu);
322 int nretry, which, newfd, dummy; 322 int nretry, which, newfd, dummy;
323 323
324 if (fd == pctx->sshfd) { 324 if (fd == pctx->sshfd) {
325 which = PSSHFD_META; 325 which = PSSHFD_META;
326 } else { 326 } else {
327 assert(fd == pctx->sshfd_data); 327 assert(fd == pctx->sshfd_data);
328 which = PSSHFD_DATA; 328 which = PSSHFD_DATA;
329 } 329 }
330 330
331 if (puffs_getstate(pu) != PUFFS_STATE_RUNNING) 331 if (puffs_getstate(pu) != PUFFS_STATE_RUNNING)
332 return; 332 return;
333 333
334 if (what != (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) { 334 if (what != (PUFFS_FBIO_READ | PUFFS_FBIO_WRITE)) {
335 puffs_framev_removefd(pu, fd, ECONNRESET); 335 puffs_framev_removefd(pu, fd, ECONNRESET);
336 return; 336 return;
337 } 337 }
338 close(fd); 338 close(fd);
339 339
340 /* deal with zmobies, beware of half-eaten brain */ 340 /* deal with zmobies, beware of half-eaten brain */
341 while (waitpid(-1, &dummy, WNOHANG) > 0) 341 while (waitpid(-1, &dummy, WNOHANG) > 0)
342 continue; 342 continue;
343 343
344 for (nretry = 0;;nretry++) { 344 for (nretry = 0;;nretry++) {
345 if ((newfd = pssh_connect(pu, which)) == -1) 345 if ((newfd = pssh_connect(pu, which)) == -1)
346 goto retry2; 346 goto retry2;
347 347
348 if (puffs_framev_addfd(pu, newfd, 348 if (puffs_framev_addfd(pu, newfd,
349 PUFFS_FBIO_READ | PUFFS_FBIO_WRITE) == -1) 349 PUFFS_FBIO_READ | PUFFS_FBIO_WRITE) == -1)
350 goto retry1; 350 goto retry1;
351 351
352 break; 352 break;
353 retry1: 353 retry1:
354 fprintf(stderr, "reconnect failed... "); 354 fprintf(stderr, "reconnect failed... ");
355 close(newfd); 355 close(newfd);
356 retry2: 356 retry2:
357 if (nretry < RETRY_MAX) { 357 if (nretry < RETRY_MAX) {
358 fprintf(stderr, "retry (%d left)\n", RETRY_MAX-nretry); 358 fprintf(stderr, "retry (%d left)\n", RETRY_MAX-nretry);
359 sleep(nretry); 359 sleep(nretry);
360 } else { 360 } else {
361 fprintf(stderr, "retry count exceeded, going south\n"); 361 fprintf(stderr, "retry count exceeded, going south\n");
362 exit(1); /* XXXXXXX */ 362 exit(1); /* XXXXXXX */
363 } 363 }
364 } 364 }
365} 365}
366 366
367static int 367static int
368pssh_connect(struct puffs_usermount *pu, int which) 368pssh_connect(struct puffs_usermount *pu, int which)
369{ 369{
370 struct psshfs_ctx *pctx = puffs_getspecific(pu); 370 struct psshfs_ctx *pctx = puffs_getspecific(pu);
371 char * const *sshargs = pctx->sshargs; 371 char * const *sshargs = pctx->sshargs;
372 int fds[2]; 372 int fds[2];
373 pid_t pid; 373 pid_t pid;
374 int dnfd, x; 374 int dnfd, x;
375 int *sshfd; 375 int *sshfd;
376 pid_t *sshpid; 376 pid_t *sshpid;
377 377
378 if (which == PSSHFD_META) { 378 if (which == PSSHFD_META) {
379 sshfd = &pctx->sshfd; 379 sshfd = &pctx->sshfd;
380 sshpid = &pctx->sshpid; 380 sshpid = &pctx->sshpid;
381 } else { 381 } else {
382 assert(which == PSSHFD_DATA); 382 assert(which == PSSHFD_DATA);
383 sshfd = &pctx->sshfd_data; 383 sshfd = &pctx->sshfd_data;
384 sshpid = &pctx->sshpid_data; 384 sshpid = &pctx->sshpid_data;
385 } 385 }
386 386
387 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1) 387 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1)
388 return -1; 388 return -1;
389 389
390 pid = fork(); 390 pid = fork();
391 switch (pid) { 391 switch (pid) {
392 case -1: 392 case -1:
393 return -1; 393 return -1;
394 /*NOTREACHED*/ 394 /*NOTREACHED*/
395 case 0: /* child */ 395 case 0: /* child */
396 if (dup2(fds[0], STDIN_FILENO) == -1) 396 if (dup2(fds[0], STDIN_FILENO) == -1)
397 err(1, "child dup2"); 397 err(1, "child dup2");
398 if (dup2(fds[0], STDOUT_FILENO) == -1) 398 if (dup2(fds[0], STDOUT_FILENO) == -1)
399 err(1, "child dup2"); 399 err(1, "child dup2");
400 close(fds[0]); 400 close(fds[0]);
401 close(fds[1]); 401 close(fds[1]);
402 402
403 dnfd = open(_PATH_DEVNULL, O_RDWR); 403 dnfd = open(_PATH_DEVNULL, O_RDWR);
404 if (dnfd != -1) 404 if (dnfd != -1)
405 dup2(dnfd, STDERR_FILENO); 405 dup2(dnfd, STDERR_FILENO);
406 406
407 execvp(sshargs[0], sshargs); 407 execvp(sshargs[0], sshargs);
408 /*NOTREACHED*/ 408 /*NOTREACHED*/
409 break; 409 break;
410 default: 410 default:
411 *sshpid = pid; 411 *sshpid = pid;
412 *sshfd = fds[1]; 412 *sshfd = fds[1];
413 close(fds[0]); 413 close(fds[0]);
414 break; 414 break;
415 } 415 }
416 416
417 if (psshfs_handshake(pu, *sshfd) != 0) 417 if (psshfs_handshake(pu, *sshfd) != 0)
418 errx(1, "psshfs_handshake %d", which); 418 errx(1, "handshake failed, server does not support sftp?");
419 x = 1; 419 x = 1;
420 if (ioctl(*sshfd, FIONBIO, &x) == -1) 420 if (ioctl(*sshfd, FIONBIO, &x) == -1)
421 err(1, "nonblocking descriptor %d", which); 421 err(1, "nonblocking descriptor %d", which);
422 422
423 return *sshfd; 423 return *sshfd;
424} 424}
425 425
426static void * 426static void *
427invalone(struct puffs_usermount *pu, struct puffs_node *pn, void *arg) 427invalone(struct puffs_usermount *pu, struct puffs_node *pn, void *arg)
428{ 428{
429 struct psshfs_node *psn = pn->pn_data; 429 struct psshfs_node *psn = pn->pn_data;
430 430
431 psn->attrread = 0; 431 psn->attrread = 0;
432 psn->dentread = 0; 432 psn->dentread = 0;
433 psn->slread = 0; 433 psn->slread = 0;
434 434
435 return NULL; 435 return NULL;
436} 436}
437 437
438static void 438static void
439psshfs_loopfn(struct puffs_usermount *pu) 439psshfs_loopfn(struct puffs_usermount *pu)
440{ 440{
441 441
442 if (sighup) { 442 if (sighup) {
443 puffs_pn_nodewalk(pu, invalone, NULL); 443 puffs_pn_nodewalk(pu, invalone, NULL);
444 sighup = 0; 444 sighup = 0;
445 } 445 }
446} 446}