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