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