1 /*
2 * Copyright (c) 1990 Jan-Simon Pendry
3 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Jan-Simon Pendry at Imperial College, London.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * from: @(#)nfs_subr.c 8.1 (Berkeley) 6/6/93
35 * $Id: nfs_subr.c,v 1.9 2015/01/22 03:43:58 guenther Exp $
36 */
37
38 #include "am.h"
39
40 /*
41 * Convert from UN*X to NFS error code
42 */
43 #ifdef NFS_ERROR_MAPPING
44 NFS_ERROR_MAPPING
45 #define nfs_error(e) \
46 ((nfsstat)((e) > NFS_LOMAP && (e) < NFS_HIMAP ? \
47 nfs_errormap[(e) - NFS_LOMAP] : (e)))
48 #else
49 #define nfs_error(e) ((nfsstat)(e))
50 #endif /* NFS_ERROR_MAPPING */
51
52 static char *
do_readlink(am_node * mp,int * error_return,struct attrstat ** attrpp)53 do_readlink(am_node *mp, int *error_return, struct attrstat **attrpp)
54 {
55 char *ln;
56
57 /*
58 * If there is a readlink method, then use
59 * that, otherwise if a link exists use
60 * that, otherwise use the mount point.
61 */
62 if (mp->am_mnt->mf_ops->readlink) {
63 int retry = 0;
64 mp = (*mp->am_mnt->mf_ops->readlink)(mp, &retry);
65 if (mp == 0) {
66 *error_return = retry;
67 return 0;
68 }
69 /*reschedule_timeout_mp();*/
70 }
71 if (mp->am_link) {
72 ln = mp->am_link;
73 } else {
74 ln = mp->am_mnt->mf_mount;
75 }
76 if (attrpp)
77 *attrpp = &mp->am_attr;
78 return ln;
79 }
80
81 void *
nfsproc_null_2_svc(void * argp,struct svc_req * rqstp)82 nfsproc_null_2_svc(void *argp, struct svc_req *rqstp)
83 {
84 static char res;
85
86 return &res;
87 }
88
89
90 struct attrstat *
nfsproc_getattr_2_svc(struct nfs_fh * argp,struct svc_req * rqstp)91 nfsproc_getattr_2_svc(struct nfs_fh *argp, struct svc_req *rqstp)
92 {
93 static struct attrstat res;
94 am_node *mp;
95 int retry;
96
97 #ifdef DEBUG
98 Debug(D_TRACE)
99 plog(XLOG_DEBUG, "gettattr:");
100 #endif /* DEBUG */
101
102 mp = fh_to_mp2(argp, &retry);
103 if (mp == 0) {
104 getattr_retry:
105
106 if (retry < 0)
107 return 0;
108 res.status = nfs_error(retry);
109 } else {
110 struct attrstat *attrp = &mp->am_attr;
111 if (mp->am_fattr.type == NFLNK) {
112 /*
113 * Make sure we can read the link,
114 * and then determine the length.
115 */
116 char *ln = do_readlink(mp, &retry, &attrp);
117 if (ln == 0)
118 goto getattr_retry;
119 }
120 #ifdef DEBUG
121 Debug(D_TRACE)
122 plog(XLOG_DEBUG, "\tstat(%s), size = %d", mp->am_path, attrp->attrstat_u.attributes.size);
123 #endif /* DEBUG */
124 mp->am_stats.s_getattr++;
125 return attrp;
126 }
127
128 return &res;
129 }
130
131
132 struct attrstat *
nfsproc_setattr_2_svc(struct sattrargs * argp,struct svc_req * rqstp)133 nfsproc_setattr_2_svc(struct sattrargs *argp, struct svc_req *rqstp)
134 {
135 static struct attrstat res;
136
137 if (!fh_to_mp(&argp->file))
138 res.status = nfs_error(ESTALE);
139 else
140 res.status = nfs_error(EROFS);
141
142 return &res;
143 }
144
145
146 void *
nfsproc_root_2_svc(void * argp,struct svc_req * rqstp)147 nfsproc_root_2_svc(void *argp, struct svc_req *rqstp)
148 {
149 static char res;
150
151 return &res;
152 }
153
154
155 struct diropres *
nfsproc_lookup_2_svc(struct diropargs * argp,struct svc_req * rqstp)156 nfsproc_lookup_2_svc(struct diropargs *argp, struct svc_req *rqstp)
157 {
158 static struct diropres res;
159 am_node *mp;
160 int retry;
161
162 #ifdef DEBUG
163 Debug(D_TRACE)
164 plog(XLOG_DEBUG, "lookup:");
165 #endif /* DEBUG */
166
167 mp = fh_to_mp2(&argp->dir, &retry);
168 if (mp == 0) {
169 if (retry < 0)
170 return 0;
171 res.status = nfs_error(retry);
172 } else {
173 int error;
174 am_node *ap;
175 #ifdef DEBUG
176 Debug(D_TRACE)
177 plog(XLOG_DEBUG, "\tlookuppn(%s, %s)", mp->am_path, argp->name);
178 #endif /* DEBUG */
179 ap = (*mp->am_mnt->mf_ops->lookuppn)(mp, argp->name, &error, VLOOK_CREATE);
180 if (ap == 0) {
181 if (error < 0) {
182 #ifdef DEBUG
183 dlog("Not sending RPC reply");
184 #endif /* DEBUG */
185 amd_stats.d_drops++;
186 return 0;
187 }
188 res.status = nfs_error(error);
189 } else {
190 mp_to_fh(ap, &res.diropres_u.diropres.file);
191 res.diropres_u.diropres.attributes = ap->am_fattr;
192 res.status = NFS_OK;
193 }
194 mp->am_stats.s_lookup++;
195 /*reschedule_timeout_mp();*/
196 }
197
198 return &res;
199 }
200
201
202 struct readlinkres *
nfsproc_readlink_2_svc(struct nfs_fh * argp,struct svc_req * rqstp)203 nfsproc_readlink_2_svc(struct nfs_fh *argp, struct svc_req *rqstp)
204 {
205 static struct readlinkres res;
206 am_node *mp;
207 int retry;
208
209 #ifdef DEBUG
210 Debug(D_TRACE)
211 plog(XLOG_DEBUG, "readlink:");
212 #endif /* DEBUG */
213
214 mp = fh_to_mp2(argp, &retry);
215 if (mp == 0) {
216 readlink_retry:
217 if (retry < 0)
218 return 0;
219 res.status = nfs_error(retry);
220 } else {
221 char *ln = do_readlink(mp, &retry, (struct attrstat **) 0);
222 if (ln == 0)
223 goto readlink_retry;
224 res.status = NFS_OK;
225 #ifdef DEBUG
226 Debug(D_TRACE)
227 if (ln)
228 plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln);
229 #endif /* DEBUG */
230 res.readlinkres_u.data = ln;
231 mp->am_stats.s_readlink++;
232 }
233
234 return &res;
235 }
236
237
238 struct readres *
nfsproc_read_2_svc(struct readargs * argp,struct svc_req * rqstp)239 nfsproc_read_2_svc(struct readargs *argp, struct svc_req *rqstp)
240 {
241 static struct readres res;
242
243 bzero(&res, sizeof(res));
244
245 res.status = nfs_error(EACCES);
246
247 return &res;
248 }
249
250
251 void *
nfsproc_writecache_2_svc(void * argp,struct svc_req * rqstp)252 nfsproc_writecache_2_svc(void *argp, struct svc_req *rqstp)
253 {
254 static char res;
255
256 return &res;
257 }
258
259
260 struct attrstat *
nfsproc_write_2_svc(writeargs * argp,struct svc_req * rqstp)261 nfsproc_write_2_svc(writeargs *argp, struct svc_req *rqstp)
262 {
263 static struct attrstat res;
264
265 if (!fh_to_mp(&argp->file))
266 res.status = nfs_error(ESTALE);
267 else
268 res.status = nfs_error(EROFS);
269
270 return &res;
271 }
272
273
274 struct diropres *
nfsproc_create_2_svc(createargs * argp,struct svc_req * rqstp)275 nfsproc_create_2_svc(createargs *argp, struct svc_req *rqstp)
276 {
277 static struct diropres res;
278
279 if (!fh_to_mp(&argp->where.dir))
280 res.status = nfs_error(ESTALE);
281 else
282 res.status = nfs_error(EROFS);
283
284 return &res;
285 }
286
287
288 static nfsstat *
unlink_or_rmdir(struct diropargs * argp,struct svc_req * rqstp,int unlinkp)289 unlink_or_rmdir(struct diropargs *argp, struct svc_req *rqstp,
290 int unlinkp)
291 {
292 static nfsstat res;
293 int retry;
294 /*mntfs *mf;*/
295 am_node *mp = fh_to_mp3(&argp->dir, &retry, VLOOK_DELETE);
296
297 if (mp == 0) {
298 if (retry < 0)
299 return 0;
300 res = nfs_error(retry);
301 goto out;
302 }
303 /*mf = mp->am_mnt;*/
304 if (mp->am_fattr.type != NFDIR) {
305 res = nfs_error(ENOTDIR);
306 goto out;
307 }
308 #ifdef DEBUG
309 Debug(D_TRACE)
310 plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->name);
311 #endif /* DEBUG */
312 mp = (*mp->am_mnt->mf_ops->lookuppn)(mp, argp->name, &retry, VLOOK_DELETE);
313 if (mp == 0) {
314 /*
315 * Ignore retries...
316 */
317 if (retry < 0)
318 retry = 0;
319 /*
320 * Usual NFS workaround...
321 */
322 else if (retry == ENOENT)
323 retry = 0;
324 res = nfs_error(retry);
325 } else {
326 forcibly_timeout_mp(mp);
327 res = NFS_OK;
328 }
329
330 out:
331 return &res;
332 }
333
334
335 nfsstat *
nfsproc_remove_2_svc(struct diropargs * argp,struct svc_req * rqstp)336 nfsproc_remove_2_svc(struct diropargs *argp, struct svc_req *rqstp)
337 {
338 return unlink_or_rmdir(argp, rqstp, TRUE);
339 }
340
341 nfsstat *
nfsproc_rename_2_svc(renameargs * argp,struct svc_req * rqstp)342 nfsproc_rename_2_svc(renameargs *argp, struct svc_req *rqstp)
343 {
344 static nfsstat res;
345 if (!fh_to_mp(&argp->from.dir) || !fh_to_mp(&argp->to.dir))
346 res = nfs_error(ESTALE);
347 /*
348 * If the kernel is doing clever things with referenced files
349 * then let it pretend...
350 */
351 else if (strncmp(argp->to.name, ".nfs", 4) == 0)
352 res = NFS_OK;
353 /*
354 * otherwise a failure
355 */
356 else
357 res = nfs_error(EROFS);
358 return &res;
359 }
360
361
362 nfsstat *
nfsproc_link_2_svc(linkargs * argp,struct svc_req * rqstp)363 nfsproc_link_2_svc(linkargs *argp, struct svc_req *rqstp)
364 {
365 static nfsstat res;
366 if (!fh_to_mp(&argp->from) || !fh_to_mp(&argp->to.dir))
367 res = nfs_error(ESTALE);
368 else
369 res = nfs_error(EROFS);
370
371 return &res;
372 }
373
374
375 nfsstat *
nfsproc_symlink_2_svc(symlinkargs * argp,struct svc_req * rqstp)376 nfsproc_symlink_2_svc(symlinkargs *argp, struct svc_req *rqstp)
377 {
378 static nfsstat res;
379 if (!fh_to_mp(&argp->from.dir))
380 res = nfs_error(ESTALE);
381 else
382 res = nfs_error(EROFS);
383
384 return &res;
385 }
386
387
388 struct diropres *
nfsproc_mkdir_2_svc(createargs * argp,struct svc_req * rqstp)389 nfsproc_mkdir_2_svc(createargs *argp, struct svc_req *rqstp)
390 {
391 static struct diropres res;
392 if (!fh_to_mp(&argp->where.dir))
393 res.status = nfs_error(ESTALE);
394 else
395 res.status = nfs_error(EROFS);
396
397 return &res;
398 }
399
400
401 nfsstat *
nfsproc_rmdir_2_svc(struct diropargs * argp,struct svc_req * rqstp)402 nfsproc_rmdir_2_svc(struct diropargs *argp, struct svc_req *rqstp)
403 {
404 return unlink_or_rmdir(argp, rqstp, FALSE);
405 }
406
407
408 struct readdirres *
nfsproc_readdir_2_svc(readdirargs * argp,struct svc_req * rqstp)409 nfsproc_readdir_2_svc(readdirargs *argp, struct svc_req *rqstp)
410 {
411 static readdirres res;
412 static entry e_res[MAX_READDIR_ENTRIES];
413 am_node *mp;
414 int retry;
415
416 #ifdef DEBUG
417 Debug(D_TRACE)
418 plog(XLOG_DEBUG, "readdir:");
419 #endif /* DEBUG */
420
421 mp = fh_to_mp2(&argp->dir, &retry);
422 if (mp == 0) {
423 if (retry < 0)
424 return 0;
425 res.status = nfs_error(retry);
426 } else {
427 #ifdef DEBUG
428 Debug(D_TRACE)
429 plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path);
430 #endif /* DEBUG */
431 res.status = nfs_error((*mp->am_mnt->mf_ops->readdir)(mp, argp->cookie,
432 &res.readdirres_u.reply, e_res, argp->count));
433 mp->am_stats.s_readdir++;
434 }
435
436 return &res;
437 }
438
439 struct statfsres *
nfsproc_statfs_2_svc(struct nfs_fh * argp,struct svc_req * rqstp)440 nfsproc_statfs_2_svc(struct nfs_fh *argp, struct svc_req *rqstp)
441 {
442 static statfsres res;
443 am_node *mp;
444 int retry;
445
446 #ifdef DEBUG
447 Debug(D_TRACE)
448 plog(XLOG_DEBUG, "statfs:");
449 #endif /* DEBUG */
450
451 mp = fh_to_mp2(argp, &retry);
452 if (mp == 0) {
453 if (retry < 0)
454 return 0;
455 res.status = nfs_error(retry);
456 } else {
457 statfsokres *fp;
458 #ifdef DEBUG
459 Debug(D_TRACE)
460 plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path);
461 #endif /* DEBUG */
462 /*
463 * just return faked up file system information
464 */
465
466 fp = &res.statfsres_u.reply;
467
468 fp->tsize = 1024;
469 fp->bsize = 4096;
470 fp->blocks = 0;
471 fp->bfree = 0;
472 fp->bavail = 0;
473
474 res.status = NFS_OK;
475 mp->am_stats.s_statfs++;
476 }
477
478 return &res;
479 }
480