fs.c revision 1.17 1 /* $NetBSD: fs.c,v 1.17 2008/09/06 12:29:57 pooka Exp $ */
2
3 /*
4 * Copyright (c) 2006 Antti Kantee. All Rights Reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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.
14 *
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
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/cdefs.h>
29 #ifndef lint
30 __RCSID("$NetBSD: fs.c,v 1.17 2008/09/06 12:29:57 pooka Exp $");
31 #endif /* !lint */
32
33 #include <err.h>
34 #include <errno.h>
35 #include <puffs.h>
36 #include <signal.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40
41 #include "psshfs.h"
42 #include "sftp_proto.h"
43
44 #define DO_IO(fname, a1, a2, a3, a4, rv) \
45 do { \
46 puffs_framebuf_seekset(a2, 0); \
47 *(a4) = 0; \
48 rv = fname(a1, a2, a3, a4); \
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; \
53 } \
54 } while (/*CONSTCOND*/0)
55
56 #define reterr(str, rv) \
57 do { \
58 fprintf str; \
59 return rv; \
60 } while (/*CONSTCOND*/0)
61
62 int
63 psshfs_handshake(struct puffs_usermount *pu)
64 {
65 struct psshfs_ctx *pctx = puffs_getspecific(pu);
66 struct puffs_framebuf *pb;
67 struct puffs_pathobj *po_root;
68 struct puffs_node *pn_root;
69 struct vattr va, *rva;
70 char *rootpath;
71 uint32_t count;
72 int rv, done;
73
74 pb = psbuf_makeout();
75 psbuf_put_1(pb, SSH_FXP_INIT);
76 psbuf_put_4(pb, SFTP_PROTOVERSION);
77 DO_IO(psbuf_write, pu, pb, pctx->sshfd, &done, rv);
78
79 puffs_framebuf_recycle(pb);
80 DO_IO(psbuf_read, pu, pb, pctx->sshfd, &done, rv);
81 if (psbuf_get_type(pb) != SSH_FXP_VERSION)
82 reterr((stderr, "invalid server response: %d",
83 psbuf_get_type(pb)), EPROTO);
84 pctx->protover = psbuf_get_reqid(pb);
85 /* might contain some other stuff, but we're not interested */
86
87 /* scope out our rootpath */
88 psbuf_recycleout(pb);
89 psbuf_put_1(pb, SSH_FXP_REALPATH);
90 psbuf_put_4(pb, NEXTREQ(pctx));
91 psbuf_put_str(pb, pctx->mountpath);
92 DO_IO(psbuf_write, pu, pb, pctx->sshfd, &done, rv);
93
94 puffs_framebuf_recycle(pb);
95 DO_IO(psbuf_read, pu, pb, pctx->sshfd, &done, rv);
96 if (psbuf_get_type(pb) != SSH_FXP_NAME)
97 reterr((stderr, "invalid server realpath response for \"%s\"",
98 pctx->mountpath), EPROTO);
99 if (psbuf_get_4(pb, &count) == -1)
100 reterr((stderr, "invalid realpath response: count"), EPROTO);
101 if (psbuf_get_str(pb, &rootpath, NULL) == -1)
102 reterr((stderr, "invalid realpath response: rootpath"), EPROTO);
103
104 /* stat the rootdir so that we know it's a dir */
105 psbuf_recycleout(pb);
106 psbuf_req_str(pb, SSH_FXP_LSTAT, NEXTREQ(pctx), rootpath);
107 DO_IO(psbuf_write, pu, pb, pctx->sshfd, &done, rv);
108
109 puffs_framebuf_recycle(pb);
110 DO_IO(psbuf_read, pu, pb, pctx->sshfd, &done, rv);
111
112 rv = psbuf_expect_attrs(pb, &va);
113 if (rv)
114 reterr((stderr, "couldn't stat rootpath"), rv);
115 puffs_framebuf_destroy(pb);
116
117 if (puffs_mode2vt(va.va_mode) != VDIR)
118 reterr((stderr, "remote path (%s) not a directory", rootpath),
119 ENOTDIR);
120
121 pn_root = puffs_getroot(pu);
122 rva = &pn_root->pn_va;
123 puffs_setvattr(rva, &va);
124
125 po_root = puffs_getrootpathobj(pu);
126 if (po_root == NULL)
127 err(1, "getrootpathobj");
128 po_root->po_path = rootpath;
129 po_root->po_len = strlen(rootpath);
130
131 return 0;
132 }
133
134 int
135 psshfs_fs_unmount(struct puffs_usermount *pu, int flags)
136 {
137 struct psshfs_ctx *pctx = puffs_getspecific(pu);
138
139 kill(pctx->sshpid, SIGTERM);
140 close(pctx->sshfd);
141 return 0;
142 }
143
144 int
145 psshfs_fs_nodetofh(struct puffs_usermount *pu, puffs_cookie_t cookie,
146 void *fid, size_t *fidsize)
147 {
148 struct psshfs_ctx *pctx = puffs_getspecific(pu);
149 struct puffs_node *pn = cookie;
150 struct psshfs_node *psn = pn->pn_data;
151 struct psshfs_fid *pf = fid;
152
153 pf->mounttime = pctx->mounttime;
154 pf->node = pn;
155
156 psn->stat |= PSN_HASFH;
157
158 return 0;
159 }
160
161 int
162 psshfs_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize,
163 struct puffs_newinfo *pni)
164 {
165 struct psshfs_ctx *pctx = puffs_getspecific(pu);
166 struct psshfs_fid *pf = fid;
167 struct puffs_node *pn = pf->node;
168 struct psshfs_node *psn;
169 int rv;
170
171 if (pf->mounttime != pctx->mounttime)
172 return EINVAL;
173 if (pn == 0)
174 return EINVAL;
175 psn = pn->pn_data;
176 if ((psn->stat & PSN_HASFH) == 0)
177 return EINVAL;
178
179 /* update node attributes */
180 rv = getnodeattr(pu, pn);
181 if (rv)
182 return EINVAL;
183
184 puffs_newinfo_setcookie(pni, pn);
185 puffs_newinfo_setvtype(pni, pn->pn_va.va_type);
186 puffs_newinfo_setsize(pni, pn->pn_va.va_size);
187
188 return 0;
189 }
190