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