Commit | Line | Data |
---|---|---|
e1a31032 KM |
1 | /* |
2 | * $Id: nfs_subr.c,v 5.2 90/06/23 22:19:50 jsp Rel $ | |
3 | * | |
4 | * Copyright (c) 1990 Jan-Simon Pendry | |
5 | * Copyright (c) 1990 Imperial College of Science, Technology & Medicine | |
6 | * Copyright (c) 1990 The Regents of the University of California. | |
7 | * All rights reserved. | |
8 | * | |
9 | * This code is derived from software contributed to Berkeley by | |
10 | * Jan-Simon Pendry at Imperial College, London. | |
11 | * | |
1c15e888 C |
12 | * Redistribution and use in source and binary forms are permitted provided |
13 | * that: (1) source distributions retain this entire copyright notice and | |
14 | * comment, and (2) distributions including binaries display the following | |
15 | * acknowledgement: ``This product includes software developed by the | |
16 | * University of California, Berkeley and its contributors'' in the | |
17 | * documentation or other materials provided with the distribution and in | |
18 | * all advertising materials mentioning features or use of this software. | |
19 | * Neither the name of the University nor the names of its contributors may | |
20 | * be used to endorse or promote products derived from this software without | |
21 | * specific prior written permission. | |
22 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED | |
23 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF | |
24 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
e1a31032 | 25 | * |
1c15e888 | 26 | * @(#)nfs_subr.c 5.1 (Berkeley) 6/29/90 |
e1a31032 KM |
27 | */ |
28 | ||
29 | #include "am.h" | |
30 | ||
31 | /* | |
32 | * Convert from UN*X to NFS error code | |
33 | */ | |
34 | #ifdef NFS_ERROR_MAPPING | |
35 | NFS_ERROR_MAPPING | |
36 | #define nfs_error(e) \ | |
37 | ((nfsstat)((e) > NFS_LOMAP && (e) < NFS_HIMAP ? \ | |
38 | nfs_errormap[(e) - NFS_LOMAP] : (e))) | |
39 | #else | |
40 | #define nfs_error(e) ((nfsstat)(e)) | |
41 | #endif /* NFS_ERROR_MAPPING */ | |
42 | ||
43 | static char *do_readlink(mp, error_return, attrpp) | |
44 | am_node *mp; | |
45 | int *error_return; | |
46 | struct attrstat **attrpp; | |
47 | { | |
48 | char *ln; | |
49 | ||
50 | /* | |
51 | * If there is a readlink method, then use | |
52 | * that, otherwise if a link exists use | |
53 | * that, otherwise use the mount point. | |
54 | */ | |
55 | if (mp->am_mnt->mf_ops->readlink) { | |
56 | int retry = 0; | |
57 | mp = (*mp->am_mnt->mf_ops->readlink)(mp, &retry); | |
58 | if (mp == 0) { | |
59 | *error_return = retry; | |
60 | return 0; | |
61 | } | |
62 | /*reschedule_timeout_mp();*/ | |
63 | } | |
64 | if (mp->am_link) { | |
65 | ln = mp->am_link; | |
66 | } else { | |
67 | ln = mp->am_mnt->mf_mount; | |
68 | } | |
69 | if (attrpp) | |
70 | *attrpp = &mp->am_mnt->mf_attr; | |
71 | return ln; | |
72 | } | |
73 | ||
74 | /*ARGSUSED*/ | |
75 | voidp | |
76 | nfsproc_null_2(argp, rqstp) | |
77 | voidp argp; | |
78 | struct svc_req *rqstp; | |
79 | { | |
80 | static char res; | |
81 | ||
82 | return (voidp) &res; | |
83 | } | |
84 | ||
85 | ||
86 | /*ARGSUSED*/ | |
87 | struct attrstat * | |
88 | nfsproc_getattr_2(argp, rqstp) | |
89 | struct nfs_fh *argp; | |
90 | struct svc_req *rqstp; | |
91 | { | |
92 | static struct attrstat res; | |
93 | am_node *mp; | |
94 | int retry; | |
95 | ||
96 | #ifdef DEBUG | |
97 | Debug(D_TRACE) | |
98 | plog(XLOG_DEBUG, "gettattr:"); | |
99 | #endif /* DEBUG */ | |
100 | ||
101 | mp = fh_to_mp2(argp, &retry); | |
102 | if (mp == 0) { | |
103 | #ifdef PRECISE_SYMLINKS | |
104 | getattr_retry: | |
105 | #endif /* PRECISE_SYMLINKS */ | |
106 | ||
107 | if (retry < 0) | |
108 | return 0; | |
109 | res.status = nfs_error(retry); | |
110 | } else { | |
111 | struct attrstat *attrp = &mp->am_mnt->mf_attr; | |
112 | #ifdef PRECISE_SYMLINKS | |
113 | if (mp->am_mnt->mf_fattr.type == NFLNK) { | |
114 | /* | |
115 | * Make sure we can read the link, | |
116 | * and then determine the length. | |
117 | */ | |
118 | char *ln = do_readlink(mp, &retry, &attrp); | |
119 | if (ln == 0) | |
120 | goto getattr_retry; | |
121 | } | |
122 | #endif /* PRECISE_SYMLINKS */ | |
123 | #ifdef DEBUG | |
124 | Debug(D_TRACE) | |
125 | plog(XLOG_DEBUG, "\tstat(%s), size = %d", mp->am_path, attrp->attrstat_u.attributes.size); | |
126 | #endif /* DEBUG */ | |
127 | mp->am_stats.s_getattr++; | |
128 | return attrp; | |
129 | } | |
130 | ||
131 | return &res; | |
132 | } | |
133 | ||
134 | ||
135 | /*ARGSUSED*/ | |
136 | struct attrstat * | |
137 | nfsproc_setattr_2(argp, rqstp) | |
138 | struct sattrargs *argp; | |
139 | struct svc_req *rqstp; | |
140 | { | |
141 | static struct attrstat res; | |
142 | ||
143 | if (!fh_to_mp(&argp->file)) | |
144 | res.status = nfs_error(ESTALE); | |
145 | else | |
146 | res.status = nfs_error(EROFS); | |
147 | ||
148 | return &res; | |
149 | } | |
150 | ||
151 | ||
152 | /*ARGSUSED*/ | |
153 | voidp | |
154 | nfsproc_root_2(argp, rqstp) | |
155 | voidp argp; | |
156 | struct svc_req *rqstp; | |
157 | { | |
158 | static char res; | |
159 | ||
160 | return (voidp)&res; | |
161 | } | |
162 | ||
163 | ||
164 | /*ARGSUSED*/ | |
165 | struct diropres * | |
166 | nfsproc_lookup_2(argp, rqstp) | |
167 | struct diropargs *argp; | |
168 | struct svc_req *rqstp; | |
169 | { | |
170 | static struct diropres res; | |
171 | am_node *mp; | |
172 | int retry; | |
173 | ||
174 | #ifdef DEBUG | |
175 | Debug(D_TRACE) | |
176 | plog(XLOG_DEBUG, "lookup:"); | |
177 | #endif /* DEBUG */ | |
178 | ||
179 | mp = fh_to_mp2(&argp->dir, &retry); | |
180 | if (mp == 0) { | |
181 | if (retry < 0) | |
182 | return 0; | |
183 | res.status = nfs_error(retry); | |
184 | } else { | |
185 | int error; | |
186 | am_node *ap; | |
187 | #ifdef DEBUG | |
188 | Debug(D_TRACE) | |
189 | plog(XLOG_DEBUG, "\tlookuppn(%s, %s)", mp->am_path, argp->name); | |
190 | #endif /* DEBUG */ | |
191 | ap = (*mp->am_mnt->mf_ops->lookuppn)(mp, argp->name, &error, VLOOK_CREATE); | |
192 | if (ap == 0) { | |
193 | if (error < 0) { | |
194 | #ifdef DEBUG | |
195 | dlog("Not sending RPC reply"); | |
196 | #endif /* DEBUG */ | |
197 | amd_stats.d_drops++; | |
198 | return 0; | |
199 | } | |
200 | res.status = nfs_error(error); | |
201 | } else { | |
202 | #ifdef DEBUG | |
203 | if (ap->am_mnt->mf_fattr.size < 0) | |
204 | dlog("\tERROR: size = %d!", ap->am_mnt->mf_fattr.size); | |
205 | #endif /* DEBUG */ | |
206 | mp_to_fh(ap, &res.diropres_u.diropres.file); | |
207 | res.diropres_u.diropres.attributes = ap->am_mnt->mf_fattr; | |
208 | res.status = NFS_OK; | |
209 | } | |
210 | mp->am_stats.s_lookup++; | |
211 | /*reschedule_timeout_mp();*/ | |
212 | } | |
213 | ||
214 | return &res; | |
215 | } | |
216 | ||
217 | ||
218 | /*ARGSUSED*/ | |
219 | struct readlinkres * | |
220 | nfsproc_readlink_2(argp, rqstp) | |
221 | struct nfs_fh *argp; | |
222 | struct svc_req *rqstp; | |
223 | { | |
224 | static struct readlinkres res; | |
225 | am_node *mp; | |
226 | int retry; | |
227 | ||
228 | #ifdef DEBUG | |
229 | Debug(D_TRACE) | |
230 | plog(XLOG_DEBUG, "readlink:"); | |
231 | #endif /* DEBUG */ | |
232 | ||
233 | mp = fh_to_mp2(argp, &retry); | |
234 | if (mp == 0) { | |
235 | readlink_retry: | |
236 | if (retry < 0) | |
237 | return 0; | |
238 | res.status = nfs_error(retry); | |
239 | } else { | |
240 | char *ln = do_readlink(mp, &retry, (struct attrstat *) 0); | |
241 | if (ln == 0) | |
242 | goto readlink_retry; | |
243 | res.status = NFS_OK; | |
244 | #ifdef DEBUG | |
245 | Debug(D_TRACE) | |
246 | if (ln) | |
247 | plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln); | |
248 | #endif /* DEBUG */ | |
249 | res.readlinkres_u.data = ln; | |
250 | mp->am_stats.s_readlink++; | |
251 | } | |
252 | ||
253 | return &res; | |
254 | } | |
255 | ||
256 | ||
257 | /*ARGSUSED*/ | |
258 | struct readres * | |
259 | nfsproc_read_2(argp, rqstp) | |
260 | struct readargs *argp; | |
261 | struct svc_req *rqstp; | |
262 | { | |
263 | static struct readres res; | |
264 | ||
265 | bzero((char *)&res, sizeof(res)); | |
266 | ||
267 | res.status = nfs_error(EACCES); | |
268 | ||
269 | return &res; | |
270 | } | |
271 | ||
272 | ||
273 | /*ARGSUSED*/ | |
274 | voidp | |
275 | nfsproc_writecache_2(argp, rqstp) | |
276 | voidp argp; | |
277 | struct svc_req *rqstp; | |
278 | { | |
279 | static char res; | |
280 | ||
281 | return (voidp) &res; | |
282 | } | |
283 | ||
284 | ||
285 | /*ARGSUSED*/ | |
286 | struct attrstat * | |
287 | nfsproc_write_2(argp, rqstp) | |
288 | writeargs *argp; | |
289 | struct svc_req *rqstp; | |
290 | { | |
291 | static struct attrstat res; | |
292 | ||
293 | if (!fh_to_mp(&argp->file)) | |
294 | res.status = nfs_error(ESTALE); | |
295 | else | |
296 | res.status = nfs_error(EROFS); | |
297 | ||
298 | return &res; | |
299 | } | |
300 | ||
301 | ||
302 | /*ARGSUSED*/ | |
303 | struct diropres * | |
304 | nfsproc_create_2(argp, rqstp) | |
305 | createargs *argp; | |
306 | struct svc_req *rqstp; | |
307 | { | |
308 | static struct diropres res; | |
309 | ||
310 | if (!fh_to_mp(&argp->where.dir)) | |
311 | res.status = nfs_error(ESTALE); | |
312 | else | |
313 | res.status = nfs_error(EROFS); | |
314 | ||
315 | return &res; | |
316 | } | |
317 | ||
318 | ||
319 | /*ARGSUSED*/ | |
320 | static nfsstat * | |
321 | unlink_or_rmdir(argp, rqstp, unlinkp) | |
322 | struct diropargs *argp; | |
323 | struct svc_req *rqstp; | |
324 | { | |
325 | static nfsstat res; | |
326 | int retry; | |
327 | mntfs *mf; | |
328 | am_node *mp = fh_to_mp3(&argp->dir, &retry, VLOOK_DELETE); | |
329 | if (mp == 0) { | |
330 | if (retry < 0) | |
331 | return 0; | |
332 | res = nfs_error(retry); | |
333 | goto out; | |
334 | } | |
335 | mf = mp->am_mnt; | |
336 | if (mf->mf_fattr.type != NFDIR) { | |
337 | res = nfs_error(ENOTDIR); | |
338 | goto out; | |
339 | } | |
340 | #ifdef DEBUG | |
341 | Debug(D_TRACE) | |
342 | plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->name); | |
343 | #endif /* DEBUG */ | |
344 | mp = (*mp->am_mnt->mf_ops->lookuppn)(mp, argp->name, &retry, VLOOK_DELETE); | |
345 | if (mp == 0) { | |
346 | /* | |
347 | * Ignore retries... | |
348 | */ | |
349 | if (retry < 0) | |
350 | retry = 0; | |
351 | /* | |
352 | * Usual NFS workaround... | |
353 | */ | |
354 | else if (retry == ENOENT) | |
355 | retry = 0; | |
356 | res = nfs_error(retry); | |
357 | } else { | |
358 | forcibly_timeout_mp(mp); | |
359 | res = NFS_OK; | |
360 | } | |
361 | ||
362 | out: | |
363 | return &res; | |
364 | } | |
365 | ||
366 | ||
367 | /*ARGSUSED*/ | |
368 | nfsstat * | |
369 | nfsproc_remove_2(argp, rqstp) | |
370 | struct diropargs *argp; | |
371 | struct svc_req *rqstp; | |
372 | { | |
373 | return unlink_or_rmdir(argp, rqstp, 1); | |
374 | } | |
375 | ||
376 | /*ARGSUSED*/ | |
377 | nfsstat * | |
378 | nfsproc_rename_2(argp, rqstp) | |
379 | renameargs *argp; | |
380 | struct svc_req *rqstp; | |
381 | { | |
382 | static nfsstat res; | |
383 | if (!fh_to_mp(&argp->from.dir) || !fh_to_mp(&argp->to.dir)) | |
384 | res = nfs_error(ESTALE); | |
385 | /* | |
386 | * If the kernel is doing clever things with referenced files | |
387 | * then let it pretend... | |
388 | */ | |
389 | else if (strncmp(argp->to.name, ".nfs", 4) == 0) | |
390 | res = NFS_OK; | |
391 | /* | |
392 | * otherwise a failure | |
393 | */ | |
394 | else | |
395 | res = nfs_error(EROFS); | |
396 | return &res; | |
397 | } | |
398 | ||
399 | ||
400 | /*ARGSUSED*/ | |
401 | nfsstat * | |
402 | nfsproc_link_2(argp, rqstp) | |
403 | linkargs *argp; | |
404 | struct svc_req *rqstp; | |
405 | { | |
406 | static nfsstat res; | |
407 | if (!fh_to_mp(&argp->from) || !fh_to_mp(&argp->to.dir)) | |
408 | res = nfs_error(ESTALE); | |
409 | else | |
410 | res = nfs_error(EROFS); | |
411 | ||
412 | return &res; | |
413 | } | |
414 | ||
415 | ||
416 | /*ARGSUSED*/ | |
417 | nfsstat * | |
418 | nfsproc_symlink_2(argp, rqstp) | |
419 | symlinkargs *argp; | |
420 | struct svc_req *rqstp; | |
421 | { | |
422 | static nfsstat res; | |
423 | if (!fh_to_mp(&argp->from.dir)) | |
424 | res = nfs_error(ESTALE); | |
425 | else | |
426 | res = nfs_error(EROFS); | |
427 | ||
428 | return &res; | |
429 | } | |
430 | ||
431 | ||
432 | /*ARGSUSED*/ | |
433 | struct diropres * | |
434 | nfsproc_mkdir_2(argp, rqstp) | |
435 | createargs *argp; | |
436 | struct svc_req *rqstp; | |
437 | { | |
438 | static struct diropres res; | |
439 | if (!fh_to_mp(&argp->where.dir)) | |
440 | res.status = nfs_error(ESTALE); | |
441 | else | |
442 | res.status = nfs_error(EROFS); | |
443 | ||
444 | return &res; | |
445 | } | |
446 | ||
447 | ||
448 | /*ARGSUSED*/ | |
449 | nfsstat * | |
450 | nfsproc_rmdir_2(argp, rqstp) | |
451 | struct diropargs *argp; | |
452 | struct svc_req *rqstp; | |
453 | { | |
454 | return unlink_or_rmdir(argp, rqstp, 0); | |
455 | } | |
456 | ||
457 | ||
458 | /*ARGSUSED*/ | |
459 | struct readdirres * | |
460 | nfsproc_readdir_2(argp, rqstp) | |
461 | readdirargs *argp; | |
462 | struct svc_req *rqstp; | |
463 | { | |
464 | static readdirres res; | |
465 | static entry e_res[2]; | |
466 | am_node *mp; | |
467 | int retry; | |
468 | ||
469 | #ifdef DEBUG | |
470 | Debug(D_TRACE) | |
471 | plog(XLOG_DEBUG, "readdir:"); | |
472 | #endif /* DEBUG */ | |
473 | ||
474 | mp = fh_to_mp2(&argp->dir, &retry); | |
475 | if (mp == 0) { | |
476 | if (retry < 0) | |
477 | return 0; | |
478 | res.status = nfs_error(retry); | |
479 | } else { | |
480 | #ifdef DEBUG | |
481 | Debug(D_TRACE) | |
482 | plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path); | |
483 | #endif /* DEBUG */ | |
484 | res.status = nfs_error((*mp->am_mnt->mf_ops->readdir)(mp, argp->cookie, | |
485 | &res.readdirres_u.reply, e_res)); | |
486 | mp->am_stats.s_readdir++; | |
487 | } | |
488 | ||
489 | /* XXX - need to take argp->count into account */ | |
490 | ||
491 | return &res; | |
492 | } | |
493 | ||
494 | /*ARGSUSED*/ | |
495 | struct statfsres * | |
496 | nfsproc_statfs_2(argp, rqstp) | |
497 | struct nfs_fh *argp; | |
498 | struct svc_req *rqstp; | |
499 | { | |
500 | static statfsres res; | |
501 | am_node *mp; | |
502 | int retry; | |
503 | ||
504 | #ifdef DEBUG | |
505 | Debug(D_TRACE) | |
506 | plog(XLOG_DEBUG, "statfs:"); | |
507 | #endif /* DEBUG */ | |
508 | ||
509 | mp = fh_to_mp2(argp, &retry); | |
510 | if (mp == 0) { | |
511 | if (retry < 0) | |
512 | return 0; | |
513 | res.status = nfs_error(retry); | |
514 | } else { | |
515 | statfsokres *fp; | |
516 | #ifdef DEBUG | |
517 | Debug(D_TRACE) | |
518 | plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path); | |
519 | #endif /* DEBUG */ | |
520 | /* | |
521 | * just return faked up file system information | |
522 | */ | |
523 | ||
524 | fp = &res.statfsres_u.reply; | |
525 | ||
526 | fp->tsize = 1024; | |
527 | fp->bsize = 4192; | |
528 | fp->blocks = 1; | |
529 | fp->bfree = 0; | |
530 | fp->bavail = 0; | |
531 | ||
532 | res.status = NFS_OK; | |
533 | mp->am_stats.s_statfs++; | |
534 | } | |
535 | ||
536 | return &res; | |
537 | } |