Commit 54bfbce0 authored by Tigran Mkrtchyan's avatar Tigran Mkrtchyan
Browse files

nfs: decouple nfs code from chimera-core

parent b5d85bef
......@@ -60,6 +60,11 @@
<constructor-arg value="${chimera.db.dialect}" />
</bean>
<bean id="vfs" class="org.dcache.chimera.nfs.vfs.ChimeraVfs">
<description>Chimera Filesystem</description>
<constructor-arg ref="fileSystem"/>
</bean>
<bean id="export" class="org.dcache.chimera.nfs.ExportFile">
<description>Export file</description>
<constructor-arg>
......@@ -102,7 +107,7 @@
<constructor-arg ref="mds-factory"/>
<constructor-arg ref="device-manager" />
<constructor-arg ref="acl-handler" />
<constructor-arg ref="fileSystem" />
<constructor-arg ref="vfs" />
<constructor-arg ref="idmapd" />
<constructor-arg ref="export" />
</bean>
......@@ -115,7 +120,7 @@
<constructor-arg index="0" ref="ds-factory"/>
<constructor-arg index="1" ref="device-manager" />
<constructor-arg index="2" ref="acl-handler" />
<constructor-arg index="3" ref="fileSystem" />
<constructor-arg index="3" ref="vfs" />
<constructor-arg index="4"><null/></constructor-arg>
<constructor-arg index="5"><null/></constructor-arg>
</bean>
......@@ -161,7 +166,7 @@
-->
<bean id="nfs3" class="org.dcache.chimera.nfs.v3.NfsServerV3">
<description>NFSv3 server</description>
<constructor-arg ref="fileSystem" />
<constructor-arg ref="vfs" />
<constructor-arg ref="export" />
</bean>
......
......@@ -16,7 +16,7 @@
*/
package org.dcache.chimera.nfs;
import org.dcache.chimera.FsInode;
import org.dcache.chimera.nfs.vfs.Inode;
/**
* An inode entry with verifier.
......@@ -25,10 +25,10 @@ import org.dcache.chimera.FsInode;
*/
public class InodeCacheEntry<T> {
private final FsInode _inode;
private final Inode _inode;
private final T _verifier;
public InodeCacheEntry(FsInode inode, T verifier) {
public InodeCacheEntry(Inode inode, T verifier) {
_inode = inode;
_verifier = verifier;
}
......
......@@ -35,9 +35,9 @@ import org.dcache.chimera.nfs.v3.xdr.wcc_attr;
import java.util.concurrent.TimeUnit;
import javax.security.auth.Subject;
import org.dcache.chimera.FsInode;
import org.dcache.chimera.ChimeraFsException;
import org.dcache.chimera.UnixPermission;
import org.dcache.chimera.nfs.vfs.Inode;
import org.dcache.chimera.nfs.v3.xdr.post_op_attr;
import org.dcache.chimera.nfs.v3.xdr.pre_op_attr;
import org.dcache.chimera.nfs.v3.xdr.wcc_data;
......@@ -115,7 +115,7 @@ public class HimeraNfsUtils {
}
public static void set_sattr( FsInode inode, sattr3 s) throws ChimeraFsException {
public static void set_sattr( Inode inode, sattr3 s) throws ChimeraFsException {
long now = System.currentTimeMillis();
......
......@@ -17,8 +17,6 @@
package org.dcache.chimera.nfs.v4;
import org.dcache.chimera.FileSystemProvider;
import org.dcache.chimera.FsInode;
import org.dcache.chimera.nfs.ChimeraNFSException;
import org.dcache.chimera.nfs.ExportFile;
import org.dcache.chimera.nfs.v4.xdr.nfs_resop4;
......@@ -30,23 +28,25 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import org.dcache.chimera.nfs.vfs.Inode;
import org.dcache.chimera.nfs.NfsUser;
import org.dcache.chimera.nfs.vfs.VirtualFileSystem;
public class CompoundContext {
private static final Logger _log = LoggerFactory.getLogger(CompoundContext.class);
private FsInode _rootInode = null;
private FsInode _currentInode = null;
private FsInode _savedInode = null;
private Inode _rootInode = null;
private Inode _currentInode = null;
private Inode _savedInode = null;
private final int _minorversion;
private NFSv41Session _session = null;
private final List<nfs_resop4> _processedOps;
private final FileSystemProvider _fs;
private final VirtualFileSystem _fs;
private final RpcCall _callInfo;
private final UnixUser _user;
private final ExportFile _exportFile;
......@@ -64,7 +64,7 @@ public class CompoundContext {
* @param call RPC call
* @param exportFile list of servers exports.
*/
public CompoundContext(List<nfs_resop4> processedOps, int minorversion, FileSystemProvider fs,
public CompoundContext(List<nfs_resop4> processedOps, int minorversion, VirtualFileSystem fs,
NFSv4StateHandler stateHandler,
NFSv41DeviceManager deviceManager, AclHandler aclHandler, RpcCall call,
NfsIdMapping idMapping,
......@@ -88,7 +88,7 @@ public class CompoundContext {
return _user;
}
public FileSystemProvider getFs() {
public VirtualFileSystem getFs() {
return _fs;
}
......@@ -115,7 +115,7 @@ public class CompoundContext {
* @return file handle
* @throws ChimeraNFSException
*/
public FsInode currentInode() throws ChimeraNFSException {
public Inode currentInode() throws ChimeraNFSException {
if( _currentInode == null ) {
throw new ChimeraNFSException(nfsstat4.NFS4ERR_NOFILEHANDLE, "no file handle");
}
......@@ -128,7 +128,7 @@ public class CompoundContext {
* @param inode
* @throws ChimeraNFSException
*/
public void currentInode(FsInode inode) throws ChimeraNFSException {
public void currentInode(Inode inode) throws ChimeraNFSException {
_currentInode = inode;
_log.debug("current Inode: {}", _currentInode );
}
......@@ -142,11 +142,11 @@ public class CompoundContext {
_currentInode = null;
}
public FsInode rootInode() {
public Inode rootInode() {
return _rootInode;
}
public void rootInode(FsInode inode) {
public void rootInode(Inode inode) {
_rootInode = inode;
_log.debug("root Inode: {}", _rootInode );
}
......@@ -165,7 +165,7 @@ public class CompoundContext {
_log.debug("restored Inode: {}", _currentInode );
}
public FsInode savedInode() throws ChimeraNFSException {
public Inode savedInode() throws ChimeraNFSException {
if( _savedInode == null ) {
throw new ChimeraNFSException(nfsstat4.NFS4ERR_NOFILEHANDLE, "no file handle");
}
......
......@@ -17,8 +17,6 @@
package org.dcache.chimera.nfs.v4;
import org.dcache.chimera.FsInode;
import org.dcache.chimera.FsInodeType;
import org.dcache.chimera.nfs.v4.xdr.*;
import org.dcache.xdr.OncRpcException;
import org.dcache.xdr.XdrBuffer;
......@@ -35,6 +33,7 @@ import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import org.dcache.chimera.nfs.ChimeraNFSException;
import org.dcache.chimera.nfs.vfs.Inode;
import org.dcache.utils.Bytes;
import org.dcache.utils.net.InetSocketAddresses;
......@@ -83,13 +82,13 @@ public class DeviceManager implements NFSv41DeviceManager {
* int, java.net.InetAddress)
*/
@Override
public Layout layoutGet(FsInode inode, int ioMode, NFS4Client client, stateid4 stateid)
public Layout layoutGet(Inode inode, int ioMode, NFS4Client client, stateid4 stateid)
throws IOException {
device_addr4 deviceAddr;
deviceid4 deviceId;
if (inode.type() != FsInodeType.INODE) {
if (inode.type() != Inode.Type.LEGACY) {
deviceId = MDS_ID;
} else {
......@@ -109,7 +108,7 @@ public class DeviceManager implements NFSv41DeviceManager {
_deviceMap.put(deviceId, deviceAddr);
}
nfs_fh4 fh = new nfs_fh4(inode.toFullString().getBytes());
nfs_fh4 fh = new nfs_fh4(inode.toFileHandle());
// -1 is special value, which means entire file
layout4 layout = Layout.getLayoutSegment(deviceId, fh, ioMode, 0, nfs4_prot.NFS4_UINT64_MAX);
......
......@@ -17,7 +17,6 @@
package org.dcache.chimera.nfs.v4;
import org.dcache.chimera.FileSystemProvider;
import org.dcache.chimera.nfs.ChimeraNFSException;
import org.dcache.chimera.nfs.ExportFile;
import org.dcache.chimera.nfs.v4.xdr.COMPOUND4args;
......@@ -37,10 +36,11 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.dcache.chimera.nfs.vfs.VirtualFileSystem;
public class NFSServerV41 extends nfs4_prot_NFS4_PROGRAM_ServerStub {
private final FileSystemProvider _fs;
private final VirtualFileSystem _fs;
private final ExportFile _exportFile;
private static final Logger _log = LoggerFactory.getLogger(NFSServerV41.class);
private final NFSv4OperationFactory _operationFactory;
......@@ -50,7 +50,7 @@ public class NFSServerV41 extends nfs4_prot_NFS4_PROGRAM_ServerStub {
private final NfsIdMapping _idMapping;
public NFSServerV41(NFSv4OperationFactory operationFactory,
NFSv41DeviceManager deviceManager, AclHandler aclHandler, FileSystemProvider fs,
NFSv41DeviceManager deviceManager, AclHandler aclHandler, VirtualFileSystem fs,
NfsIdMapping idMapping,
ExportFile exportFile) throws OncRpcException, IOException {
......
......@@ -17,13 +17,13 @@
package org.dcache.chimera.nfs.v4;
import org.dcache.chimera.FsInode;
import org.dcache.chimera.nfs.v4.xdr.device_addr4;
import org.dcache.chimera.nfs.v4.xdr.deviceid4;
import org.dcache.chimera.nfs.v4.xdr.stateid4;
import java.io.IOException;
import java.util.List;
import org.dcache.chimera.nfs.vfs.Inode;
public interface NFSv41DeviceManager {
......@@ -41,7 +41,7 @@ public interface NFSv41DeviceManager {
* @return
* @throws IOException
*/
public Layout layoutGet(FsInode inode, int ioMode, NFS4Client client, stateid4 stateid)
public Layout layoutGet(Inode inode, int ioMode, NFS4Client client, stateid4 stateid)
throws IOException;
/**
......
......@@ -24,7 +24,7 @@ import org.dcache.chimera.nfs.v4.xdr.nfs_argop4;
import org.dcache.chimera.nfs.v4.xdr.nfs_opnum4;
import org.dcache.chimera.nfs.v4.xdr.CLOSE4res;
import org.dcache.chimera.nfs.ChimeraNFSException;
import org.dcache.chimera.FsInode;
import org.dcache.chimera.nfs.vfs.Inode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -42,7 +42,7 @@ public class OperationCLOSE extends AbstractNFSv4Operation {
try {
FsInode inode = context.currentInode();
Inode inode = context.currentInode();
if (context.getSession() == null) {
context.getStateHandler().updateClientLeaseTime(_args.opclose.open_stateid);
......
......@@ -28,8 +28,7 @@ import org.dcache.chimera.nfs.v4.xdr.CREATE4res;
import org.dcache.chimera.nfs.v4.xdr.CREATE4resok;
import org.dcache.chimera.nfs.ChimeraNFSException;
import org.dcache.chimera.ChimeraFsException;
import org.dcache.chimera.FsInode;
import org.dcache.chimera.UnixPermission;
import org.dcache.chimera.nfs.vfs.Inode;
import org.dcache.chimera.posix.AclHandler;
import org.dcache.chimera.posix.Stat;
import org.dcache.chimera.posix.UnixAcl;
......@@ -53,7 +52,7 @@ public class OperationCREATE extends AbstractNFSv4Operation {
fattr4 objAttr = _args.opcreate.createattrs;
int type = _args.opcreate.objtype.type;
String name = new String(_args.opcreate.objname.value.value.value);
FsInode inode = null;
Inode inode = null;
......@@ -77,7 +76,7 @@ public class OperationCREATE extends AbstractNFSv4Operation {
throw new ChimeraNFSException(nfsstat4.NFS4ERR_NAMETOOLONG, "name too long");
}
if (!context.currentInode().isDirectory()) {
if (context.currentInode().type() != Inode.Type.DIRECTORY) {
throw new ChimeraNFSException(nfsstat4.NFS4ERR_NOTDIR, "not a directory");
}
......@@ -88,7 +87,7 @@ public class OperationCREATE extends AbstractNFSv4Operation {
// TODO: this check have to be moved into JdbcFs
try {
inode = context.currentInode().inodeOf(name);
inode = context.getFs().inodeOf(context.currentInode(), name);
throw new ChimeraNFSException(nfsstat4.NFS4ERR_EXIST, "path already exist");
} catch (ChimeraFsException hfe) {
}
......@@ -96,33 +95,29 @@ public class OperationCREATE extends AbstractNFSv4Operation {
switch (type) {
case nfs_ftype4.NF4DIR:
inode = context.currentInode().mkdir(name);
inode = context.getFs().mkdir(context.currentInode(), name,
context.getUser().getUID(), context.getUser().getGID(), 777);
break;
case nfs_ftype4.NF4LNK:
byte[] linkDest = _args.opcreate.objtype.linkdata.value.value.value;
inode = context.getFs().createLink(context.currentInode(), name,
context.getUser().getUID(), context.getUser().getGID(),
777, linkDest);
String linkDest = new String(_args.opcreate.objtype.linkdata.value.value.value);
inode = context.getFs().symlink(context.currentInode(), name, linkDest,
context.getUser().getUID(), context.getUser().getGID(), 777);
break;
case nfs_ftype4.NF4BLK:
inode = context.getFs().createFile(context.currentInode(), name,
context.getUser().getUID(), context.getUser().getGID(),
777, UnixPermission.S_IFBLK);
inode = context.getFs().create(context.currentInode(), Inode.Type.BLOCK, name,
context.getUser().getUID(), context.getUser().getGID(), 777);
break;
case nfs_ftype4.NF4CHR:
inode = context.getFs().createFile(context.currentInode(), name,
context.getUser().getUID(), context.getUser().getGID(),
777, UnixPermission.S_IFCHR);
inode = context.getFs().create(context.currentInode(), Inode.Type.CHAR, name,
context.getUser().getUID(), context.getUser().getGID(), 777);
break;
case nfs_ftype4.NF4FIFO:
inode = context.getFs().createFile(context.currentInode(), name,
context.getUser().getUID(), context.getUser().getGID(),
777, UnixPermission.S_IFIFO);
inode = context.getFs().create(context.currentInode(), Inode.Type.FIFO, name,
context.getUser().getUID(), context.getUser().getGID(), 777);
break;
case nfs_ftype4.NF4SOCK:
inode = context.getFs().createFile(context.currentInode(), name,
context.getUser().getUID(), context.getUser().getGID(),
777, UnixPermission.S_IFSOCK);
inode = context.getFs().create(context.currentInode(), Inode.Type.SOCK, name,
context.getUser().getUID(), context.getUser().getGID(), 777);
break;
case nfs_ftype4.NF4ATTRDIR:
case nfs_ftype4.NF4NAMEDATTR:
......
......@@ -93,11 +93,11 @@ import org.dcache.chimera.ChimeraFsException;
import org.dcache.xdr.XdrAble;
import org.dcache.xdr.XdrBuffer;
import org.dcache.xdr.XdrEncodingStream;
import org.dcache.chimera.FsInode;
import org.dcache.chimera.FsStat;
import org.dcache.chimera.UnixPermission;
import org.dcache.chimera.nfs.vfs.Inode;
import org.dcache.chimera.nfs.vfs.VirtualFileSystem;
import org.dcache.chimera.nfs.v4.acl.Ace;
import org.dcache.chimera.nfs.v4.acl.AclStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -118,6 +118,7 @@ public class OperationGETATTR extends AbstractNFSv4Operation {
res.resok4 = new GETATTR4resok();
res.resok4.obj_attributes = getAttributes(_args.opgetattr.attr_request,
context.getFs(),
context.currentInode(), context);
res.status = nfsstat4.NFS4_OK;
......@@ -136,7 +137,7 @@ public class OperationGETATTR extends AbstractNFSv4Operation {
}
static fattr4 getAttributes(bitmap4 bitmap, FsInode inode, CompoundContext context) throws Exception {
static fattr4 getAttributes(bitmap4 bitmap, VirtualFileSystem fs, Inode inode, CompoundContext context) throws Exception {
int[] mask = new int[bitmap.value.length];
for( int i = 0; i < mask.length; i++) {
......@@ -156,7 +157,7 @@ public class OperationGETATTR extends AbstractNFSv4Operation {
int newmask = (mask[i/32] >> (i-(32*(i/32))) );
if( (newmask & 1) > 0 ) {
XdrAble attrXdr = fattr2xdr(i, inode, context);
XdrAble attrXdr = fattr2xdr(i, fs, inode, context);
if( attrXdr != null) {
_log.debug(" getAttributes : {} ({}) OK.",
new Object[] { i, attrMask2String(i)} );
......@@ -192,11 +193,11 @@ public class OperationGETATTR extends AbstractNFSv4Operation {
}
private static FsStat getFsStat(FsStat fsStat, FsInode inode) throws ChimeraFsException {
private static FsStat getFsStat(FsStat fsStat, VirtualFileSystem fs) throws ChimeraFsException {
if (fsStat != null) {
return fsStat;
}
return inode.getFs().getFsStat();
return fs.getFsStat();
}
/**
......@@ -211,7 +212,7 @@ public class OperationGETATTR extends AbstractNFSv4Operation {
*/
// read/read-write
private static XdrAble fattr2xdr( int fattr , FsInode inode, CompoundContext context) throws Exception {
private static XdrAble fattr2xdr( int fattr , VirtualFileSystem fs, Inode inode, CompoundContext context) throws Exception {
XdrAble ret = null;
FsStat fsStat = null;
......@@ -278,37 +279,18 @@ public class OperationGETATTR extends AbstractNFSv4Operation {
break;
case nfs4_prot.FATTR4_FILEHANDLE :
nfs_fh4 fh = new nfs_fh4();
fh.value = inode.toFullString().getBytes();
fh.value = inode.toFileHandle();
fattr4_filehandle filehandle = new fattr4_filehandle(fh);
ret = filehandle;
break;
case nfs4_prot.FATTR4_ACL :
/*
* TODO:
* here is the place to talk with ACL module
* for now we just reply some thing
*/
nfsace4[] aces = null;
/*
* use dummy store
*/
nfsace4[] savedAcl = AclStore.getInstance().getAcl(inode);
if( savedAcl != null ) {
aces = new nfsace4[savedAcl.length];
System.arraycopy(savedAcl, 0, aces, 0, savedAcl.length);
}else{
aces = new nfsace4[0];
}
case nfs4_prot.FATTR4_ACL:
_log.debug("{}", new Ace(aces) );
nfsace4[] aces = inode.getAcl();
_log.debug("{}", new Ace(aces));
fattr4_acl acl = new fattr4_acl(aces);
fattr4_acl acl = new fattr4_acl(aces);
ret = acl;
ret = acl;
break;
case nfs4_prot.FATTR4_ACLSUPPORT :
fattr4_aclsupport aclSupport = new fattr4_aclsupport();
......@@ -338,17 +320,17 @@ public class OperationGETATTR extends AbstractNFSv4Operation {
ret = fileid;
break;
case nfs4_prot.FATTR4_FILES_AVAIL:
fsStat = getFsStat(fsStat, inode);
fsStat = getFsStat(fsStat, fs);
fattr4_files_avail files_avail = new fattr4_files_avail(new uint64_t(fsStat.getTotalFiles() - fsStat.getUsedFiles()));
ret = files_avail;
break;
case nfs4_prot.FATTR4_FILES_FREE:
fsStat = getFsStat(fsStat, inode);
fsStat = getFsStat(fsStat, fs);
fattr4_files_free files_free = new fattr4_files_free(new uint64_t(fsStat.getTotalFiles() - fsStat.getUsedFiles()));
ret = files_free;
break;
case nfs4_prot.FATTR4_FILES_TOTAL:
fsStat = getFsStat(fsStat, inode);
fsStat = getFsStat(fsStat, fs);
fattr4_files_total files_total = new fattr4_files_total(new uint64_t(fsStat.getTotalFiles()));
ret = files_total;
break;
......@@ -425,17 +407,17 @@ public class OperationGETATTR extends AbstractNFSv4Operation {
ret = rawdev;
break;
case nfs4_prot.FATTR4_SPACE_AVAIL:
fsStat = getFsStat(fsStat, inode);
fsStat = getFsStat(fsStat, fs);
uint64_t spaceAvail = new uint64_t(fsStat.getTotalSpace() - fsStat.getUsedSpace());
ret = spaceAvail;
break;
case nfs4_prot.FATTR4_SPACE_FREE:
fsStat = getFsStat(fsStat, inode);
fsStat = getFsStat(fsStat, fs);
fattr4_space_free space_free = new fattr4_space_free(new uint64_t(fsStat.getTotalSpace() - fsStat.getUsedSpace()));
ret = space_free;
break;
case nfs4_prot.FATTR4_SPACE_TOTAL:
fsStat = getFsStat(fsStat, inode);
fsStat = getFsStat(fsStat, fs);
fattr4_space_total space_total = new fattr4_space_total(new uint64_t(fsStat.getTotalSpace()));
ret = space_total;
break;
......
......@@ -44,7 +44,7 @@ public class OperationGETFH extends AbstractNFSv4Operation {
res.resok4 = new GETFH4resok();
res.resok4.object = new nfs_fh4();
res.resok4.object.value = context.currentInode().toFullString().getBytes();
res.resok4.object.value = context.currentInode().toFileHandle();
res.status = nfsstat4.NFS4_OK;
}catch(ChimeraNFSException he) {
res.status = he.getStatus();
......
......@@ -55,7 +55,8 @@ public class OperationLINK extends AbstractNFSv4Operation {
throw new ChimeraNFSException( nfsstat4.NFS4ERR_ACCESS, "Permission denied." );
}
context.getFs().createHLink(context.currentInode(), context.savedInode(),newName );
context.getFs().link(context.currentInode(), context.savedInode(), newName,
context.getUser().getUID(), context.getUser().getGID());
_result.oplink.resok4 = new LINK4resok();
_result.oplink.resok4.cinfo = new change_info4();
......
......@@ -23,7 +23,7 @@ import org.dcache.chimera.nfs.v4.xdr.nfs_opnum4;
import org.dcache.chimera.nfs.v4.xdr.LOOKUP4res;
import org.dcache.chimera.nfs.ChimeraNFSException;
import org.dcache.chimera.FileNotFoundHimeraFsException;
import org.dcache.chimera.FsInode;
import org.dcache.chimera.nfs.vfs.Inode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -44,11 +44,11 @@ public class OperationLOOKUP extends AbstractNFSv4Operation {
String name = NameFilter.convert(_args.oplookup.objname.value.value.value);
if( context.currentInode().isLink() ) {
if( context.currentInode().type() == Inode.Type.SYMLINK ) {
throw new ChimeraNFSException(nfsstat4.NFS4ERR_SYMLINK, "parent not a symbolic link");
}
if( !context.currentInode().isDirectory() ) {
if( context.currentInode().type() != Inode.Type.DIRECTORY ) {
throw new ChimeraNFSException(nfsstat4.NFS4ERR_NOTDIR, "parent not a directory");
}
......@@ -64,7 +64,7 @@ public class OperationLOOKUP extends AbstractNFSv4Operation {
throw new ChimeraNFSException(nfsstat4.NFS4ERR_BADNAME, "bad name '.' or '..'");
}
FsInode newInode = context.currentInode().inodeOf(name);
Inode newInode = context.getFs().inodeOf(context.currentInode(), name);
if( !newInode.exists() ) {
res.status = nfsstat4.NFS4ERR_NOENT;
}
......
......@@ -22,7 +22,7 @@ import org.dcache.chimera.nfs.v4.xdr.nfs_argop4;
import org.dcache.chimera.nfs.v4.xdr.nfs_opnum4;
import org.dcache.chimera.nfs.v4.xdr.LOOKUPP4res;
import org.dcache.chimera.nfs.ChimeraNFSException;
import org.dcache.chimera.FsInode;
import org.dcache.chimera.nfs.vfs.Inode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
......@@ -40,12 +40,12 @@ public class OperationLOOKUPP extends AbstractNFSv4Operation {
try {
if( !context.currentInode().isDirectory() ) {
if( context.currentInode().type() != Inode.Type.DIRECTORY) {
throw new ChimeraNFSException(nfsstat4.NFS4ERR_NOTDIR, "parent not a directory");
}
FsInode parent = context.currentInode().getParent();
if( (parent == null) || context.currentInode().toString().equals(FsInode.getRoot(context.getFs()).toString()) ) {