1 /* $NetBSD: fs.c,v 1.24 2011/06/22 04:03:23 mrg Exp $ */
4 * Copyright (c) 2006-2009 Antti Kantee. All Rights Reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
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
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include "sftp_proto.h"
39 #define DO_IO(fname, a1, a2, a3, a4, rv) \
41 puffs_framebuf_seekset(a2, 0); \
43 rv = fname(a1, a2, a3, a4); \
45 return rv ? rv : EPROTO; \
47 } while (/*CONSTCOND*/0)
49 #define reterr(str, rv) \
53 } while (/*CONSTCOND*/0)
55 /* openssh extensions */
56 static const struct extunit {
62 "posix-rename@openssh.com",
64 SFTP_EXT_POSIX_RENAME,
66 "statvfs@openssh.com",
70 "fstatvfs@openssh.com",
80 psshfs_handshake(struct puffs_usermount *pu, int fd)
82 struct psshfs_ctx *pctx = puffs_getspecific(pu);
83 struct puffs_framebuf *pb;
84 struct puffs_pathobj *po_root;
85 struct puffs_node *pn_root;
86 struct vattr va, *rva;
87 const struct extunit *extu;
94 psbuf_put_1(pb, SSH_FXP_INIT);
95 psbuf_put_4(pb, SFTP_PROTOVERSION);
96 DO_IO(psbuf_write, pu, pb, fd, &done, rv);
98 puffs_framebuf_recycle(pb);
99 DO_IO(psbuf_read, pu, pb, fd, &done, rv);
100 if (psbuf_get_type(pb) != SSH_FXP_VERSION)
101 reterr((stderr, "invalid server response: %d",
102 psbuf_get_type(pb)), EPROTO);
103 pctx->protover = psbuf_get_reqid(pb);
106 * Check out which extensions are available. Currently
107 * we are only interested in the openssh statvfs extension.
110 if (psbuf_get_str(pb, &ext, NULL) != 0)
112 if (psbuf_get_str(pb, &val, NULL) != 0)
115 for (extu = exttable; extu->ext; extu++)
116 if (strcmp(ext, extu->ext) == 0
117 && strcmp(val, extu->val) == 0)
118 pctx->extensions |= extu->extflag;
121 /* scope out our rootpath */
122 psbuf_recycleout(pb);
123 psbuf_put_1(pb, SSH_FXP_REALPATH);
124 psbuf_put_4(pb, NEXTREQ(pctx));
125 psbuf_put_str(pb, pctx->mountpath);
126 DO_IO(psbuf_write, pu, pb, fd, &done, rv);
128 puffs_framebuf_recycle(pb);
129 DO_IO(psbuf_read, pu, pb, fd, &done, rv);
130 if (psbuf_get_type(pb) != SSH_FXP_NAME)
131 reterr((stderr, "invalid server realpath response for \"%s\"",
132 pctx->mountpath), EPROTO);
133 if (psbuf_get_4(pb, &count) == -1)
134 reterr((stderr, "invalid realpath response: count"), EPROTO);
135 if (psbuf_get_str(pb, &rootpath, NULL) == -1)
136 reterr((stderr, "invalid realpath response: rootpath"), EPROTO);
138 /* stat the rootdir so that we know it's a dir */
139 psbuf_recycleout(pb);
140 psbuf_req_str(pb, SSH_FXP_LSTAT, NEXTREQ(pctx), rootpath);
141 DO_IO(psbuf_write, pu, pb, fd, &done, rv);
143 puffs_framebuf_recycle(pb);
144 DO_IO(psbuf_read, pu, pb, fd, &done, rv);
146 rv = psbuf_expect_attrs(pb, &va);
148 reterr((stderr, "couldn't stat rootpath"), rv);
149 puffs_framebuf_destroy(pb);
151 if (puffs_mode2vt(va.va_mode) != VDIR)
152 reterr((stderr, "remote path (%s) not a directory", rootpath),
155 pn_root = puffs_getroot(pu);
156 rva = &pn_root->pn_va;
157 puffs_setvattr(rva, &va);
159 po_root = puffs_getrootpathobj(pu);
161 err(1, "getrootpathobj");
162 po_root->po_path = rootpath;
163 po_root->po_len = strlen(rootpath);
169 psshfs_fs_statvfs(struct puffs_usermount *pu, struct statvfs *sbp)
175 memset(sbp, 0, sizeof(*sbp));
176 sbp->f_bsize = sbp->f_frsize = 512;
178 if ((pctx->extensions & SFTP_EXT_STATVFS) == 0)
181 psbuf_req_str(pb, SSH_FXP_EXTENDED, reqid, "statvfs@openssh.com");
182 psbuf_put_str(pb, pctx->mountpath);
183 GETRESPONSE(pb, pctx->sshfd);
185 type = psbuf_get_type(pb);
186 if (type != SSH_FXP_EXTENDED_REPLY) {
187 /* use the default */
191 psbuf_get_8(pb, &tmpval);
192 sbp->f_bsize = tmpval;
193 psbuf_get_8(pb, &tmpval);
194 sbp->f_frsize = tmpval;
195 psbuf_get_8(pb, &sbp->f_blocks);
196 psbuf_get_8(pb, &sbp->f_bfree);
197 psbuf_get_8(pb, &sbp->f_bavail);
198 psbuf_get_8(pb, &sbp->f_files);
199 psbuf_get_8(pb, &sbp->f_ffree);
200 psbuf_get_8(pb, &sbp->f_favail);
202 psbuf_get_8(pb, &tmpval); /* fsid */
203 psbuf_get_8(pb, &tmpval); /* flag */
204 psbuf_get_8(pb, &tmpval);
205 sbp->f_namemax = tmpval;
208 sbp->f_bresvd = sbp->f_bfree - sbp->f_bavail;
209 sbp->f_fresvd = sbp->f_ffree - sbp->f_favail;
217 psshfs_fs_unmount(struct puffs_usermount *pu, int flags)
219 struct psshfs_ctx *pctx = puffs_getspecific(pu);
221 kill(pctx->sshpid, SIGTERM);
223 if (pctx->numconnections == 2) {
224 kill(pctx->sshpid_data, SIGTERM);
225 close(pctx->sshfd_data);
232 psshfs_fs_nodetofh(struct puffs_usermount *pu, puffs_cookie_t cookie,
233 void *fid, size_t *fidsize)
235 struct psshfs_ctx *pctx = puffs_getspecific(pu);
236 struct puffs_node *pn = cookie;
237 struct psshfs_node *psn = pn->pn_data;
238 struct psshfs_fid *pf = fid;
240 pf->mounttime = pctx->mounttime;
243 psn->stat |= PSN_HASFH;
249 psshfs_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize,
250 struct puffs_newinfo *pni)
252 struct psshfs_ctx *pctx = puffs_getspecific(pu);
253 struct psshfs_fid *pf = fid;
254 struct puffs_node *pn = pf->node;
255 struct psshfs_node *psn;
258 if (pf->mounttime != pctx->mounttime)
263 if ((psn->stat & PSN_HASFH) == 0)
266 /* update node attributes */
267 rv = getnodeattr(pu, pn, NULL);
271 puffs_newinfo_setcookie(pni, pn);
272 puffs_newinfo_setvtype(pni, pn->pn_va.va_type);
273 puffs_newinfo_setsize(pni, pn->pn_va.va_size);