OperationGETATTR extends AbstractNFSv4Operation { static Optional<? extends XdrAble> fattr2xdr(int fattr, VirtualFileSystem fs, Inode inode, Stat stat, CompoundContext context) throws IOException { FsStat fsStat = null; switch (fattr) { case nfs4_prot.FATTR4_SUPPORTED_ATTRS: int[] bitmap; if (context.getMinorversion() == 0) { bitmap = SUPPORTED_ATTRS_V4_0; } else { bitmap = context.getDeviceManager().isPresent() ? SUPPORTED_ATTRS_V4_1 : SUPPORTED_ATTRS_V4_1_NO_PNFS; } return Optional.of(new fattr4_supported_attrs(bitmap)); case nfs4_prot.FATTR4_TYPE: fattr4_type type = new fattr4_type(unixType2NFS(stat.getMode())); return Optional.of(type); case nfs4_prot.FATTR4_FH_EXPIRE_TYPE: fattr4_fh_expire_type fh_expire_type = new fattr4_fh_expire_type(nfs4_prot.FH4_PERSISTENT); return Optional.of(fh_expire_type); case nfs4_prot.FATTR4_CHANGE: fattr4_change change = new fattr4_change(stat.getGeneration()); return Optional.of(change); case nfs4_prot.FATTR4_SIZE: fattr4_size size = new fattr4_size(stat.getSize()); return Optional.of(size); case nfs4_prot.FATTR4_LINK_SUPPORT: fattr4_link_support link_support = new fattr4_link_support(true); return Optional.of(link_support); case nfs4_prot.FATTR4_SYMLINK_SUPPORT: fattr4_symlink_support symlink_support = new fattr4_symlink_support(true); return Optional.of(symlink_support); case nfs4_prot.FATTR4_NAMED_ATTR: fattr4_named_attr named_attr = new fattr4_named_attr(false); return Optional.of(named_attr); case nfs4_prot.FATTR4_FSID: fsid4 fsid = new fsid4(); fsid.major = new uint64_t(17); fsid.minor = new uint64_t(17); return Optional.of(new fattr4_fsid(fsid)); case nfs4_prot.FATTR4_UNIQUE_HANDLES: return Optional.of(new fattr4_unique_handles(true)); case nfs4_prot.FATTR4_LEASE_TIME: return Optional.of(new fattr4_lease_time(context.getStateHandler().getLeaseTime())); case nfs4_prot.FATTR4_RDATTR_ERROR: return Optional.empty(); case nfs4_prot.FATTR4_FILEHANDLE: nfs_fh4 fh = new nfs_fh4(); fh.value = inode.toNfsHandle(); return Optional.of(new fattr4_filehandle(fh)); case nfs4_prot.FATTR4_ACL: nfsace4[] aces = context.getFs().getAcl(inode); return Optional.of(new fattr4_acl(aces)); case nfs4_prot.FATTR4_ACLSUPPORT: fattr4_aclsupport aclSupport = new fattr4_aclsupport( nfs4_prot.ACL4_SUPPORT_ALLOW_ACL| nfs4_prot.ACL4_SUPPORT_DENY_ACL); return Optional.of(aclSupport); case nfs4_prot.FATTR4_ARCHIVE: return Optional.empty(); case nfs4_prot.FATTR4_CANSETTIME: return Optional.of(new fattr4_cansettime(true)); case nfs4_prot.FATTR4_CASE_INSENSITIVE: return Optional.of(new fattr4_case_insensitive(fs.getCaseInsensitive())); case nfs4_prot.FATTR4_CASE_PRESERVING: return Optional.of(new fattr4_case_preserving(fs.getCasePreserving())); case nfs4_prot.FATTR4_CHOWN_RESTRICTED: return Optional.empty(); case nfs4_prot.FATTR4_FILEID: return Optional.of(new fattr4_fileid(stat.getFileId())); case nfs4_prot.FATTR4_FILES_AVAIL: fsStat = getFsStat(fsStat, fs); fattr4_files_avail files_avail = new fattr4_files_avail(fsStat.getTotalFiles() - fsStat.getUsedFiles()); return Optional.of(files_avail); case nfs4_prot.FATTR4_FILES_FREE: fsStat = getFsStat(fsStat, fs); fattr4_files_free files_free = new fattr4_files_free(fsStat.getTotalFiles() - fsStat.getUsedFiles()); return Optional.of(files_free); case nfs4_prot.FATTR4_FILES_TOTAL: fsStat = getFsStat(fsStat, fs); return Optional.of(new fattr4_files_total(fsStat.getTotalFiles())); case nfs4_prot.FATTR4_FS_LOCATIONS: return Optional.empty(); case nfs4_prot.FATTR4_HIDDEN: return Optional.empty(); case nfs4_prot.FATTR4_HOMOGENEOUS: return Optional.of(new fattr4_homogeneous(true)); case nfs4_prot.FATTR4_MAXFILESIZE: return Optional.of(new fattr4_maxfilesize(NFSv4Defaults.NFS4_MAXFILESIZE)); case nfs4_prot.FATTR4_MAXLINK: return Optional.of(new fattr4_maxlink(NFSv4Defaults.NFS4_MAXLINK)); case nfs4_prot.FATTR4_MAXNAME: return Optional.of(new fattr4_maxname(NFSv4Defaults.NFS4_MAXFILENAME)); case nfs4_prot.FATTR4_MAXREAD: return Optional.of(new fattr4_maxread(NFSv4Defaults.NFS4_MAXIOBUFFERSIZE)); case nfs4_prot.FATTR4_MAXWRITE: fattr4_maxwrite maxwrite = new fattr4_maxwrite(NFSv4Defaults.NFS4_MAXIOBUFFERSIZE); return Optional.of(maxwrite); case nfs4_prot.FATTR4_MIMETYPE: return Optional.empty(); case nfs4_prot.FATTR4_MODE: return Optional.of(new fattr4_mode(stat.getMode() & 07777)); case nfs4_prot.FATTR4_NO_TRUNC: return Optional.of(new fattr4_no_trunc(true)); case nfs4_prot.FATTR4_NUMLINKS: return Optional.of(new fattr4_numlinks(stat.getNlink())); case nfs4_prot.FATTR4_OWNER: String owner_s = context.getFs().getIdMapper().uidToPrincipal(stat.getUid()); utf8str_mixed user = new utf8str_mixed(owner_s); return Optional.of(new fattr4_owner(user)); case nfs4_prot.FATTR4_OWNER_GROUP: String group_s = context.getFs().getIdMapper().gidToPrincipal(stat.getGid()); utf8str_mixed group = new utf8str_mixed(group_s); return Optional.of(new fattr4_owner(group)); case nfs4_prot.FATTR4_QUOTA_AVAIL_HARD: return Optional.empty(); case nfs4_prot.FATTR4_QUOTA_AVAIL_SOFT: return Optional.empty(); case nfs4_prot.FATTR4_QUOTA_USED: return Optional.empty(); case nfs4_prot.FATTR4_RAWDEV: specdata4 dev = new specdata4(); dev.specdata1 = 0; dev.specdata2 = 0; return Optional.of(new fattr4_rawdev(dev)); case nfs4_prot.FATTR4_SPACE_AVAIL: fsStat = getFsStat(fsStat, fs); fattr4_space_avail spaceAvail = new fattr4_space_avail(fsStat.getTotalSpace() - fsStat.getUsedSpace()); return Optional.of(spaceAvail); case nfs4_prot.FATTR4_SPACE_FREE: fsStat = getFsStat(fsStat, fs); fattr4_space_free space_free = new fattr4_space_free(fsStat.getTotalSpace() - fsStat.getUsedSpace()); return Optional.of(space_free); case nfs4_prot.FATTR4_SPACE_TOTAL: fsStat = getFsStat(fsStat, fs); return Optional.of(new fattr4_space_total(fsStat.getTotalSpace())); case nfs4_prot.FATTR4_SPACE_USED: return Optional.of(new fattr4_space_used(stat.getSize())); case nfs4_prot.FATTR4_SYSTEM: return Optional.empty(); case nfs4_prot.FATTR4_TIME_ACCESS: fattr4_time_access atime = new fattr4_time_access(stat.getATime()); return Optional.of(atime); case nfs4_prot.FATTR4_TIME_BACKUP: return Optional.empty(); case nfs4_prot.FATTR4_TIME_CREATE: fattr4_time_create ctime = new fattr4_time_create(stat.getCTime()); return Optional.of(ctime); case nfs4_prot.FATTR4_TIME_DELTA: return Optional.of(new fattr4_time_delta( new nfstime4(TimeUnit.SECONDS.toMillis(1)))); case nfs4_prot.FATTR4_TIME_METADATA: fattr4_time_metadata mdtime = new fattr4_time_metadata(stat.getCTime()); return Optional.of(mdtime); case nfs4_prot.FATTR4_TIME_MODIFY: fattr4_time_modify mtime = new fattr4_time_modify(stat.getMTime()); return Optional.of(mtime); case nfs4_prot.FATTR4_MOUNTED_ON_FILEID: long mofi = stat.getFileId(); if (mofi == 0x00b0a23a ) { mofi = 0x12345678; } fattr4_mounted_on_fileid mounted_on_fileid = new fattr4_mounted_on_fileid(mofi); return Optional.of(mounted_on_fileid); case nfs4_prot.FATTR4_FS_LAYOUT_TYPES: fattr4_fs_layout_types fs_layout_type = new fattr4_fs_layout_types(); final Optional<NFSv41DeviceManager> pnfsDeviceManager = context .getDeviceManager(); if (!pnfsDeviceManager.isPresent()) { return Optional.empty(); } List<layouttype4> exportLayouts = context .getExportTable() .exports(context.getRemoteSocketAddress().getAddress()) .findFirst() .orElseThrow(AccessException::new) .getLayoutTypes(); Set<layouttype4> supportedLayouts = pnfsDeviceManager.get().getLayoutTypes(); if (exportLayouts.isEmpty()) { fs_layout_type.value = new int[] {layouttype4.LAYOUT4_NFSV4_1_FILES.getValue()}; } else { fs_layout_type.value = exportLayouts.stream() .filter(e -> supportedLayouts.contains(e)) .mapToInt(layouttype4::getValue) .toArray(); } return Optional.of(fs_layout_type); case nfs4_prot.FATTR4_SUPPATTR_EXCLCREAT: return Optional.of(new fattr4_supported_attrs(NFSv4FileAttributes.EXCLCREAT_ATTR)); case nfs4_prot.FATTR4_XATTR_SUPPORT: return Optional.of(new fattr4_xattr_support(true)); case nfs4_prot.FATTR4_TIME_MODIFY_SET: case nfs4_prot.FATTR4_TIME_ACCESS_SET: throw new InvalException("getattr of write-only attributes"); default: _log.debug("GETATTR for #{}", fattr); return Optional.empty(); } } OperationGETATTR(nfs_argop4 args); @Override void process(CompoundContext context, nfs_resop4 result); static String attrMask2String( int offset );  }
@Test public void testDefaultLayoutType() throws IOException, URISyntaxException { NFSv41DeviceManager dm = mock(NFSv41DeviceManager.class); RpcCall call = mock(RpcCall.class); RpcTransport transport = mock(RpcTransport.class); ExportFile exportFile = new ExportFile(ClassLoader.getSystemResource("org/dcache/nfs/exports").toURI()); given(dm.getLayoutTypes()).willReturn(Sets.newHashSet(layouttype4.values())); given(transport.getRemoteSocketAddress()).willReturn(new InetSocketAddress("172.16.4.1", 0)); given(call.getCredential()).willReturn(new RpcAuthTypeNone()); given(call.getTransport()).willReturn(transport); CompoundContext context = new CompoundContextBuilder() .withDeviceManager(dm) .withCall(call) .withExportTable(exportFile) .build(); Optional<fattr4_fs_layout_types> res = (Optional<fattr4_fs_layout_types>) OperationGETATTR.fattr2xdr(nfs4_prot.FATTR4_FS_LAYOUT_TYPES, null, null, null, context); assertArrayEquals("export without explicit layout type must return nfsv41_files layout", new int[] {layouttype4.LAYOUT4_NFSV4_1_FILES.getValue()}, res.get().value); }