LOOKUP3res *nfsproc3_lookup_3_svc(LOOKUP3args * argp, struct svc_req * rqstp) { static LOOKUP3res result; unfs3_fh_t *fh; char *path; char obj[NFS_MAXPATHLEN]; backend_statstruct buf; int res; uint32 gen; PREP(path, argp->what.dir); result.status = cat_name(path, argp->what.name, obj); cluster_lookup(obj, rqstp, &result.status); if (result.status == NFS3_OK) { res = backend_lstat(obj, &buf); if (res == -1) result.status = lookup_err(); else { if (strcmp(argp->what.name, ".") == 0 || strcmp(argp->what.name, "..") == 0) { fh = fh_comp_ptr(obj, rqstp, 0); } else { gen = backend_get_gen(buf, FD_NONE, obj); fh = fh_extend(argp->what.dir, buf.st_dev, buf.st_ino, gen); fh_cache_add(buf.st_dev, buf.st_ino, obj); } if (fh) { result.LOOKUP3res_u.resok.object.data.data_len = fh_length(fh); result.LOOKUP3res_u.resok.object.data.data_val = (char *) fh; result.LOOKUP3res_u.resok.obj_attributes = get_post_buf(buf, rqstp); } else { /* path was too long */ result.status = NFS3ERR_NAMETOOLONG; } } } /* overlaps with resfail */ result.LOOKUP3res_u.resok.dir_attributes = get_post_stat(path, rqstp); return &result; }
/* * locate file given prefix, device, and inode number */ static int locate_pfx(const char *pfx, uint32 dev, uint64 ino, char *result) { char path[NFS_MAXPATHLEN]; backend_dirstream *search; struct dirent *ent; backend_statstruct buf; int res; search = opendir(pfx); if (!search) return FALSE; while ((ent = readdir(search))) { if (strlen(pfx) + strlen(ent->d_name) + 2 >= NFS_MAXPATHLEN) continue; sprintf(path, "%s/%s", pfx, ent->d_name); res = backend_lstat(path, &buf); if (res != 0) continue; /* check for matching object */ if (buf.st_dev == dev && buf.st_ino == ino) { strcpy(result, path); st_cache = buf; st_cache_valid = TRUE; closedir(search); return TRUE; } /* descend into directories with same dev */ if (buf.st_dev == dev && S_ISDIR(buf.st_mode) && strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0) { res = locate_pfx(path, dev, ino, result); if (res == TRUE) { closedir(search); return TRUE; } } } closedir(search); return FALSE; }
/* * lowlevel routine for getting post-operation attributes */ static post_op_attr get_post_ll(const char *path, uint32 dev, uint64 ino, struct svc_req *req) { backend_statstruct buf; int res; if (!path) return error_attr; res = backend_lstat(path, &buf); if (res == -1) return error_attr; /* protect against local fs race */ if (dev != buf.st_dev || ino != buf.st_ino) return error_attr; return get_post_buf(buf, req); }
/* * compute post-operation attributes given a stat buffer */ post_op_attr get_post_buf(backend_statstruct buf, struct svc_req * req) { post_op_attr result; debug("get_post_buf STAT",""); result.attributes_follow = TRUE; if (S_ISDIR(buf.st_mode)) result.post_op_attr_u.attributes.type = NF3DIR; else if (S_ISBLK(buf.st_mode)) result.post_op_attr_u.attributes.type = NF3BLK; else if (S_ISCHR(buf.st_mode)) result.post_op_attr_u.attributes.type = NF3CHR; #ifdef S_ISLNK else if (S_ISLNK(buf.st_mode)) result.post_op_attr_u.attributes.type = NF3LNK; #endif /* S_ISLNK */ #ifdef S_ISSOCK else if (S_ISSOCK(buf.st_mode)) result.post_op_attr_u.attributes.type = NF3SOCK; #endif /* S_ISSOCK */ else if (S_ISFIFO(buf.st_mode)) result.post_op_attr_u.attributes.type = NF3FIFO; else result.post_op_attr_u.attributes.type = NF3REG; /* adapt permissions for executable files */ if (opt_readable_executables && S_ISREG(buf.st_mode)) { if (buf.st_mode & S_IXUSR) buf.st_mode |= S_IRUSR; if (buf.st_mode & S_IXGRP) buf.st_mode |= S_IRGRP; if (buf.st_mode & S_IXOTH) buf.st_mode |= S_IROTH; } result.post_op_attr_u.attributes.mode = buf.st_mode & 0xFFFF; result.post_op_attr_u.attributes.nlink = buf.st_nlink; /* If -s, translate uids */ if (opt_singleuser) { unsigned int req_uid = 0; unsigned int req_gid = 0; struct authunix_parms *auth = (void *) req->rq_clntcred; uid_t ruid = backend_getuid(); if (req->rq_cred.oa_flavor == AUTH_UNIX) { req_uid = auth->aup_uid; req_gid = auth->aup_gid; } if ((buf.st_uid == ruid) || (ruid == 0)) result.post_op_attr_u.attributes.uid = req_uid; else result.post_op_attr_u.attributes.uid = 0; if ((buf.st_gid == backend_getgid()) || (ruid == 0)) result.post_op_attr_u.attributes.gid = req_gid; else result.post_op_attr_u.attributes.gid = 0; } else { /* Normal case */ result.post_op_attr_u.attributes.uid = buf.st_uid; result.post_op_attr_u.attributes.gid = buf.st_gid; } result.post_op_attr_u.attributes.size = buf.st_size; result.post_op_attr_u.attributes.used = buf.st_blocks * 512; result.post_op_attr_u.attributes.rdev.specdata1 = (buf.st_rdev >> 8) & 0xFF; result.post_op_attr_u.attributes.rdev.specdata2 = buf.st_rdev & 0xFF; result.post_op_attr_u.attributes.fsid = buf.st_dev; /* If this is a removable export point, we should return the preset fsid for all objects which resides in the same file system as the exported directory */ if (exports_opts & OPT_REMOVABLE) { backend_statstruct epbuf; if (backend_lstat(export_path, &epbuf) != -1 && buf.st_dev == epbuf.st_dev) { result.post_op_attr_u.attributes.fsid = export_fsid; } } #ifdef WIN32 /* Recent Linux kernels (2.6.24 and newer) exposes large fileids even to non-LFS 32-bit applications, unless kernel parameter nfs.enable_ino64=0. This means that applications will fail with EOVERFLOW. On Windows, we always have large st_ino:s. To avoid trouble, we truncate to 32 bits */ result.post_op_attr_u.attributes.fileid = (buf.st_ino >> 32) ^ (buf.st_ino & 0xffffffff); #else result.post_op_attr_u.attributes.fileid = buf.st_ino; #endif result.post_op_attr_u.attributes.atime.seconds = buf.st_atime; result.post_op_attr_u.attributes.atime.nseconds = 0; result.post_op_attr_u.attributes.mtime.seconds = buf.st_mtime; result.post_op_attr_u.attributes.mtime.nseconds = 0; result.post_op_attr_u.attributes.ctime.seconds = buf.st_ctime; result.post_op_attr_u.attributes.ctime.nseconds = 0; //debug("get_post_buf filei %d",result.post_op_attr_u.attributes.fsid); return result; }