mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-24 17:32:48 +00:00
NFS server support added to filesystem server, includes mount and portmapper services plus an NFS v3 server.
Not enabled or wired in yet. git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@4742 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.oncrpc.nfs;
|
||||
|
||||
/**
|
||||
* Bad Cookie Exception Class
|
||||
*
|
||||
* @author GKSpencer
|
||||
*/
|
||||
public class BadCookieException extends Exception {
|
||||
|
||||
// Object version id
|
||||
|
||||
private static final long serialVersionUID = -6689748925525944869L;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public BadCookieException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param msg String
|
||||
*/
|
||||
public BadCookieException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.oncrpc.nfs;
|
||||
|
||||
/**
|
||||
* Bad Handle Exception Class
|
||||
*
|
||||
* @author GKSpencer
|
||||
*/
|
||||
public class BadHandleException extends Exception {
|
||||
|
||||
// Object version id
|
||||
|
||||
private static final long serialVersionUID = 5928520475130958599L;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public BadHandleException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param msg String
|
||||
*/
|
||||
public BadHandleException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.oncrpc.nfs;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* File Id Cache Class
|
||||
*
|
||||
* <p>Converts a file/directory id to a share relative path.
|
||||
*
|
||||
* @author GKSpencer
|
||||
*/
|
||||
public class FileIdCache {
|
||||
|
||||
// File id to path cache
|
||||
|
||||
private Hashtable<Integer, String> m_idCache;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public FileIdCache() {
|
||||
m_idCache = new Hashtable<Integer, String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an entry to the cache
|
||||
*
|
||||
* @param fid int
|
||||
* @param path String
|
||||
*/
|
||||
public final void addPath(int fid, String path) {
|
||||
m_idCache.put(new Integer(fid), path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a file id to a path
|
||||
*
|
||||
* @param fid int
|
||||
* @return String
|
||||
*/
|
||||
public final String findPath(int fid) {
|
||||
return (String) m_idCache.get(new Integer(fid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an entry from the cache
|
||||
*
|
||||
* @param fid int
|
||||
*/
|
||||
public final void deletePath(int fid) {
|
||||
m_idCache.remove(new Integer(fid));
|
||||
}
|
||||
}
|
267
source/java/org/alfresco/filesys/server/oncrpc/nfs/NFS.java
Normal file
267
source/java/org/alfresco/filesys/server/oncrpc/nfs/NFS.java
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.oncrpc.nfs;
|
||||
|
||||
/**
|
||||
* NFS Server Constants Class
|
||||
*
|
||||
* @author GKSpencer
|
||||
*/
|
||||
public final class NFS {
|
||||
|
||||
// Default NFS server port
|
||||
|
||||
public static final int DefaultPort = 2049;
|
||||
|
||||
// Program and version id
|
||||
|
||||
public static final int ProgramId = 100003;
|
||||
public static final int VersionId = 3;
|
||||
|
||||
// RPC procedure ids
|
||||
|
||||
public static final int ProcNull = 0;
|
||||
public static final int ProcGetAttr = 1;
|
||||
public static final int ProcSetAttr = 2;
|
||||
public static final int ProcLookup = 3;
|
||||
public static final int ProcAccess = 4;
|
||||
public static final int ProcReadLink = 5;
|
||||
public static final int ProcRead = 6;
|
||||
public static final int ProcWrite = 7;
|
||||
public static final int ProcCreate = 8;
|
||||
public static final int ProcMkDir = 9;
|
||||
public static final int ProcSymLink = 10;
|
||||
public static final int ProcMkNode = 11;
|
||||
public static final int ProcRemove = 12;
|
||||
public static final int ProcRmDir = 13;
|
||||
public static final int ProcRename = 14;
|
||||
public static final int ProcLink = 15;
|
||||
public static final int ProcReadDir = 16;
|
||||
public static final int ProcReadDirPlus = 17;
|
||||
public static final int ProcFsStat = 18;
|
||||
public static final int ProcFsInfo = 19;
|
||||
public static final int ProcPathConf = 20;
|
||||
public static final int ProcCommit = 21;
|
||||
public static final int ProcMax = 21;
|
||||
|
||||
// NFS server status codes
|
||||
|
||||
public static final int StsSuccess = 0;
|
||||
public static final int StsPerm = 1;
|
||||
public static final int StsNoEnt = 2;
|
||||
public static final int StsIO = 5;
|
||||
public static final int StsNxIO = 6;
|
||||
public static final int StsAccess = 13;
|
||||
public static final int StsExist = 17;
|
||||
public static final int StsXDev = 18;
|
||||
public static final int StsNoDev = 19;
|
||||
public static final int StsNotDir = 20;
|
||||
public static final int StsIsDir = 21;
|
||||
public static final int StsInVal = 22;
|
||||
public static final int StsFBig = 27;
|
||||
public static final int StsNoSpc = 28;
|
||||
public static final int StsROFS = 30;
|
||||
public static final int StsMLink = 31;
|
||||
public static final int StsNameTooLong = 63;
|
||||
public static final int StsNotEmpty = 66;
|
||||
public static final int StsDQuot = 69;
|
||||
public static final int StsStale = 70;
|
||||
public static final int StsRemote = 71;
|
||||
public static final int StsBadHandle = 10001;
|
||||
public static final int StsNotSync = 10002;
|
||||
public static final int StsBadCookie = 10003;
|
||||
public static final int StsNotSupp = 10004;
|
||||
public static final int StsTooSmall = 10005;
|
||||
public static final int StsServerFault = 10006;
|
||||
public static final int StsBadType = 10007;
|
||||
public static final int StsJukeBox = 10008;
|
||||
|
||||
// Data structure limits
|
||||
|
||||
public static final int FileHandleSize = 32; // can be 64 for NFS v3
|
||||
public static final int WriteVerfSize = 8;
|
||||
public static final int CreateVerfSize = 8;
|
||||
public static final int CookieVerfSize = 8;
|
||||
|
||||
// File types
|
||||
|
||||
public static final int FileTypeReg = 1;
|
||||
public static final int FileTypeDir = 2;
|
||||
public static final int FileTypeBlk = 3;
|
||||
public static final int FileTypeChr = 4;
|
||||
public static final int FileTypeLnk = 5;
|
||||
public static final int FileTypeSock = 6;
|
||||
public static final int FileTypeFifo = 7;
|
||||
|
||||
// Filesystem properties
|
||||
|
||||
public static final int FileSysLink = 0x0001; // supports hard links
|
||||
public static final int FileSysSymLink = 0x0002; // supports symbolic links
|
||||
public static final int FileSysHomogeneuos = 0x0004; // PATHCONF valid for all files
|
||||
public static final int FileSysCanSetTime = 0x0008; // can set time on server side
|
||||
|
||||
// Access mask
|
||||
|
||||
public static final int AccessRead = 0x0001;
|
||||
public static final int AccessLookup = 0x0002;
|
||||
public static final int AccessModify = 0x0004;
|
||||
public static final int AccessExtend = 0x0008;
|
||||
public static final int AccessDelete = 0x0010;
|
||||
public static final int AccessExecute = 0x0020;
|
||||
public static final int AccessAll = 0x003F;
|
||||
|
||||
// Create mode values
|
||||
|
||||
public static final int CreateUnchecked = 1;
|
||||
public static final int CreateGuarded = 2;
|
||||
public static final int CreateExclusive = 3;
|
||||
|
||||
// Write request stable values
|
||||
|
||||
public static final int WriteUnstable = 0;
|
||||
public static final int WriteDataSync = 1;
|
||||
public static final int WriteFileSync = 2;
|
||||
|
||||
// Set attributes file timestamp settings
|
||||
|
||||
public static final int DoNotSetTime = 0;
|
||||
public static final int SetTimeServer = 1;
|
||||
public static final int SetTimeClient = 2;
|
||||
|
||||
// RPC procedure names
|
||||
|
||||
private static final String[] _procNames = { "Null", "GetAttr", "SetAttr",
|
||||
"Lookup", "Access", "ReadLink", "Read", "Write", "Create", "MkDir",
|
||||
"SymLink", "MkNode", "Remove", "RmDir", "Rename", "Link",
|
||||
"ReadDir", "ReadDirPlus", "FsStat", "FsInfo", "PathConf", "Commit" };
|
||||
|
||||
/**
|
||||
* Return a procedure id as a name
|
||||
*
|
||||
* @param id
|
||||
* int
|
||||
* @return String
|
||||
*/
|
||||
public final static String getProcedureName(int id) {
|
||||
if (id < 0 || id > ProcMax)
|
||||
return null;
|
||||
return _procNames[id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an error status string for the specified status code
|
||||
*
|
||||
* @param sts
|
||||
* int
|
||||
* @return String
|
||||
*/
|
||||
public static final String getStatusString(int sts) {
|
||||
String str = null;
|
||||
|
||||
switch (sts) {
|
||||
case StsSuccess:
|
||||
str = "Success status";
|
||||
break;
|
||||
case StsAccess:
|
||||
str = "Access denied";
|
||||
break;
|
||||
case StsBadCookie:
|
||||
str = "Bad cookie";
|
||||
break;
|
||||
case StsBadHandle:
|
||||
str = "Bad handle";
|
||||
break;
|
||||
case StsBadType:
|
||||
str = "Bad type";
|
||||
break;
|
||||
case StsDQuot:
|
||||
str = "Quota exceeded";
|
||||
break;
|
||||
case StsPerm:
|
||||
str = "No permission";
|
||||
break;
|
||||
case StsExist:
|
||||
str = "Already exists";
|
||||
break;
|
||||
case StsFBig:
|
||||
str = "File too large";
|
||||
break;
|
||||
case StsInVal:
|
||||
str = "Invalid argument";
|
||||
break;
|
||||
case StsIO:
|
||||
str = "I/O error";
|
||||
break;
|
||||
case StsIsDir:
|
||||
str = "Is directory";
|
||||
break;
|
||||
case StsJukeBox:
|
||||
str = "Jukebox";
|
||||
break;
|
||||
case StsMLink:
|
||||
str = "Too many hard links";
|
||||
break;
|
||||
case StsNameTooLong:
|
||||
str = "Name too long";
|
||||
break;
|
||||
case StsNoDev:
|
||||
str = "No such device";
|
||||
break;
|
||||
case StsNoEnt:
|
||||
str = "No entity";
|
||||
break;
|
||||
case StsNoSpc:
|
||||
str = "No space left on device";
|
||||
break;
|
||||
case StsNotSync:
|
||||
str = "Update synchronization mismatch";
|
||||
break;
|
||||
case StsNotDir:
|
||||
str = "Not directory";
|
||||
break;
|
||||
case StsNotEmpty:
|
||||
str = "Not empty";
|
||||
break;
|
||||
case StsNotSupp:
|
||||
str = "Not supported";
|
||||
break;
|
||||
case StsNxIO:
|
||||
str = "Nxio";
|
||||
break;
|
||||
case StsRemote:
|
||||
str = "Too many levels of remote in path";
|
||||
break;
|
||||
case StsROFS:
|
||||
str = "Readonly filesystem";
|
||||
break;
|
||||
case StsServerFault:
|
||||
str = "Server fault";
|
||||
break;
|
||||
case StsStale:
|
||||
str = "Stale";
|
||||
break;
|
||||
case StsTooSmall:
|
||||
str = "Too small";
|
||||
break;
|
||||
case StsXDev:
|
||||
str = "Cross device hard link attempted";
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
@@ -0,0 +1,417 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.oncrpc.nfs;
|
||||
|
||||
import org.alfresco.filesys.server.oncrpc.RpcPacket;
|
||||
import org.alfresco.filesys.util.DataPacker;
|
||||
|
||||
/**
|
||||
* NFS Handle Class
|
||||
*
|
||||
* <p>Contains constants and static methods used with NFS handles.
|
||||
*
|
||||
* @author GKSpencer
|
||||
*/
|
||||
public class NFSHandle {
|
||||
|
||||
// Version
|
||||
|
||||
public static final byte VERSION = 1;
|
||||
public static final byte MIN_VERSION = 1;
|
||||
public static final byte MAX_VERSION = 1;
|
||||
|
||||
// Handle types
|
||||
|
||||
public static final byte TYPE_SHARE = 1;
|
||||
public static final byte TYPE_DIR = 2;
|
||||
public static final byte TYPE_FILE = 3;
|
||||
|
||||
// Offsets to fields within the handle
|
||||
|
||||
private static final int VERSION_OFFSET = 0;
|
||||
private static final int TYPE_OFFSET = 1;
|
||||
private static final int SHARE_OFFSET = 2;
|
||||
private static final int DIR_OFFSET = 6;
|
||||
private static final int FILE_OFFSET = 10;
|
||||
private static final int NAME_OFFSET = 14;
|
||||
|
||||
/**
|
||||
* Return the handle version
|
||||
*
|
||||
* @param handle byte[]
|
||||
*/
|
||||
public static final int isVersion(byte[] handle)
|
||||
{
|
||||
return (int) handle[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the handle type
|
||||
*
|
||||
* @param handle byte[]
|
||||
* @return int
|
||||
*/
|
||||
public static final int isType(byte[] handle)
|
||||
{
|
||||
return (int) handle[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the handle is a share type handle
|
||||
*
|
||||
* @param handle byte[]
|
||||
* @return boolean
|
||||
*/
|
||||
public static final boolean isShareHandle(byte[] handle)
|
||||
{
|
||||
if (handle[1] == TYPE_SHARE)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the handle is a directory type handle
|
||||
*
|
||||
* @param handle byte[]
|
||||
* @return boolean
|
||||
*/
|
||||
public static final boolean isDirectoryHandle(byte[] handle)
|
||||
{
|
||||
if (handle[1] == TYPE_DIR)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the handle is a file type handle
|
||||
*
|
||||
* @param handle byte[]
|
||||
* @return boolean
|
||||
*/
|
||||
public static final boolean isFileHandle(byte[] handle)
|
||||
{
|
||||
if (handle[1] == TYPE_FILE)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack a share handle
|
||||
*
|
||||
* @param name String
|
||||
* @param handle byte[]
|
||||
*/
|
||||
public static final void packShareHandle(String name, byte[] handle)
|
||||
{
|
||||
|
||||
// Pack a share handle
|
||||
|
||||
handle[0] = VERSION;
|
||||
handle[1] = TYPE_SHARE;
|
||||
|
||||
// Pack the hash code of the share name
|
||||
|
||||
DataPacker.putInt(name.hashCode(), handle, SHARE_OFFSET);
|
||||
|
||||
// Null pad the handle
|
||||
|
||||
int pos = SHARE_OFFSET + 4;
|
||||
|
||||
while (pos < handle.length)
|
||||
handle[pos++] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack a share handle
|
||||
*
|
||||
* @param name String
|
||||
* @param rpc RpcPacket
|
||||
* @param hlen int
|
||||
*/
|
||||
public static final void packShareHandle(String name, RpcPacket rpc, int hlen)
|
||||
{
|
||||
|
||||
// Pack a share handle
|
||||
|
||||
rpc.packInt(hlen);
|
||||
|
||||
rpc.packByte(VERSION);
|
||||
rpc.packByte(TYPE_SHARE);
|
||||
|
||||
// Pack the hash code of the share name
|
||||
|
||||
rpc.packInt(name.hashCode());
|
||||
|
||||
// Null pad the handle
|
||||
|
||||
rpc.packNulls(hlen - 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack a directory handle
|
||||
*
|
||||
* @param shareId int
|
||||
* @param dirId int
|
||||
* @param handle byte[]
|
||||
*/
|
||||
public static final void packDirectoryHandle(int shareId, int dirId, byte[] handle)
|
||||
{
|
||||
|
||||
// Pack a directory handle
|
||||
|
||||
handle[0] = VERSION;
|
||||
handle[1] = TYPE_DIR;
|
||||
|
||||
DataPacker.putInt(shareId, handle, 2);
|
||||
DataPacker.putInt(dirId, handle, 6);
|
||||
|
||||
// Null pad the handle
|
||||
|
||||
for (int i = 10; i < handle.length; i++)
|
||||
handle[i] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack a directory handle
|
||||
*
|
||||
* @param shareId int
|
||||
* @param dirId int
|
||||
* @param rpc RpcPacket
|
||||
* @param hlen int
|
||||
*/
|
||||
public static final void packDirectoryHandle(int shareId, int dirId, RpcPacket rpc, int hlen)
|
||||
{
|
||||
|
||||
// Pack a directory handle
|
||||
|
||||
rpc.packInt(hlen);
|
||||
|
||||
rpc.packByte(VERSION);
|
||||
rpc.packByte(TYPE_DIR);
|
||||
|
||||
rpc.packInt(shareId);
|
||||
rpc.packInt(dirId);
|
||||
|
||||
// Null pad the handle
|
||||
|
||||
rpc.packNulls(hlen - 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack a file handle
|
||||
*
|
||||
* @param shareId int
|
||||
* @param dirId int
|
||||
* @param fileId int
|
||||
* @param handle byte[]
|
||||
*/
|
||||
public static final void packFileHandle(int shareId, int dirId, int fileId, byte[] handle)
|
||||
{
|
||||
|
||||
// Pack a directory handle
|
||||
|
||||
handle[0] = VERSION;
|
||||
handle[1] = TYPE_FILE;
|
||||
|
||||
DataPacker.putInt(shareId, handle, 2);
|
||||
DataPacker.putInt(dirId, handle, 6);
|
||||
DataPacker.putInt(fileId, handle, 10);
|
||||
|
||||
// Null pad the handle
|
||||
|
||||
for (int i = 14; i < handle.length; i++)
|
||||
handle[i] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack a file handle
|
||||
*
|
||||
* @param shareId int
|
||||
* @param dirId int
|
||||
* @param fileId int
|
||||
* @param rpc RpcPacket
|
||||
* @param hlen int
|
||||
*/
|
||||
public static final void packFileHandle(int shareId, int dirId, int fileId, RpcPacket rpc, int hlen)
|
||||
{
|
||||
|
||||
// Pack a directory handle
|
||||
|
||||
rpc.packInt(hlen);
|
||||
|
||||
rpc.packByte(VERSION);
|
||||
rpc.packByte(TYPE_FILE);
|
||||
|
||||
rpc.packInt(shareId);
|
||||
rpc.packInt(dirId);
|
||||
rpc.packInt(fileId);
|
||||
|
||||
// Null pad the handle
|
||||
|
||||
rpc.packNulls(hlen - 14);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpack a share id from a handle
|
||||
*
|
||||
* @param handle byte[]
|
||||
* @return int
|
||||
*/
|
||||
public static final int unpackShareId(byte[] handle)
|
||||
{
|
||||
|
||||
// Check if the handle is a share type handle
|
||||
|
||||
int shareId = -1;
|
||||
|
||||
if (handle[1] == TYPE_SHARE || handle[1] == TYPE_DIR || handle[1] == TYPE_FILE)
|
||||
{
|
||||
|
||||
// Unpack the share id
|
||||
|
||||
shareId = DataPacker.getInt(handle, 2);
|
||||
}
|
||||
|
||||
// Return the share id, or -1 if wrong handle type
|
||||
|
||||
return shareId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpack a directory id from a handle
|
||||
*
|
||||
* @param handle byte[]
|
||||
* @return int
|
||||
*/
|
||||
public static final int unpackDirectoryId(byte[] handle)
|
||||
{
|
||||
|
||||
// Check if the handle is a directory or file type handle
|
||||
|
||||
int dirId = -1;
|
||||
|
||||
if (handle[1] == TYPE_DIR || handle[1] == TYPE_FILE)
|
||||
{
|
||||
|
||||
// Unpack the directory id
|
||||
|
||||
dirId = DataPacker.getInt(handle, 6);
|
||||
}
|
||||
|
||||
// Return the directory id, or -1 if wrong handle type
|
||||
|
||||
return dirId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpack a file id from a handle
|
||||
*
|
||||
* @param handle byte[]
|
||||
* @return int
|
||||
*/
|
||||
public static final int unpackFileId(byte[] handle)
|
||||
{
|
||||
|
||||
// Check if the handle is a file type handle
|
||||
|
||||
int fileId = -1;
|
||||
|
||||
if (handle[1] == TYPE_FILE)
|
||||
{
|
||||
|
||||
// Unpack the file id
|
||||
|
||||
fileId = DataPacker.getInt(handle, 10);
|
||||
}
|
||||
|
||||
// Return the file id, or -1 if wrong handle type
|
||||
|
||||
return fileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an NFS handle as a string
|
||||
*
|
||||
* @param handle byte[]
|
||||
* @return String
|
||||
*/
|
||||
public static final String asString(byte[] handle)
|
||||
{
|
||||
|
||||
// Check if the handle is a valid type
|
||||
|
||||
StringBuffer str = new StringBuffer();
|
||||
str.append("[");
|
||||
|
||||
switch (handle[1])
|
||||
{
|
||||
|
||||
// Share/mountpoint type handle
|
||||
|
||||
case TYPE_SHARE:
|
||||
str.append("Share:0x");
|
||||
str.append(Integer.toHexString(DataPacker.getInt(handle, 2)));
|
||||
break;
|
||||
|
||||
// Directory handle
|
||||
|
||||
case TYPE_DIR:
|
||||
str.append("Dir:share=0x");
|
||||
str.append(Integer.toHexString(DataPacker.getInt(handle, 2)));
|
||||
str.append(",dir=0x");
|
||||
str.append(Integer.toHexString(DataPacker.getInt(handle, 6)));
|
||||
break;
|
||||
|
||||
// File handle
|
||||
|
||||
case TYPE_FILE:
|
||||
str.append("File:share=0x");
|
||||
str.append(Integer.toHexString(DataPacker.getInt(handle, 2)));
|
||||
str.append(",dir=0x");
|
||||
str.append(Integer.toHexString(DataPacker.getInt(handle, 6)));
|
||||
str.append(",file=0x");
|
||||
str.append(Integer.toHexString(DataPacker.getInt(handle, 10)));
|
||||
break;
|
||||
}
|
||||
|
||||
// Return the handle string
|
||||
|
||||
str.append("]");
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a handle is valid
|
||||
*
|
||||
* @param handle byte[]
|
||||
* @return boolean
|
||||
*/
|
||||
public static final boolean isValid(byte[] handle)
|
||||
{
|
||||
|
||||
// Check if the version is valid
|
||||
|
||||
if (handle[0] < MIN_VERSION || handle[0] > MAX_VERSION)
|
||||
return false;
|
||||
|
||||
// Check if the handle type is valid
|
||||
|
||||
if (handle[1] == TYPE_SHARE || handle[1] == TYPE_DIR || handle[1] == TYPE_FILE)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
5104
source/java/org/alfresco/filesys/server/oncrpc/nfs/NFSServer.java
Normal file
5104
source/java/org/alfresco/filesys/server/oncrpc/nfs/NFSServer.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.oncrpc.nfs;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* NFS Server Session Table Class
|
||||
*
|
||||
* @author GKSpencer
|
||||
*/
|
||||
public class NFSSessionTable {
|
||||
|
||||
// Session list
|
||||
|
||||
private Hashtable<Object, NFSSrvSession> m_sessions;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*/
|
||||
public NFSSessionTable()
|
||||
{
|
||||
m_sessions = new Hashtable<Object, NFSSrvSession>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of sessions in the list
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int numberOfSessions()
|
||||
{
|
||||
return m_sessions.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a session to the list
|
||||
*
|
||||
* @param sess NFSSrvSession
|
||||
*/
|
||||
public final void addSession(NFSSrvSession sess)
|
||||
{
|
||||
m_sessions.put(sess.getAuthIdentifier(), sess);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the session using the authentication identifier
|
||||
*
|
||||
* @param authIdent Object
|
||||
* @return NFSSrvSession
|
||||
*/
|
||||
public final NFSSrvSession findSession(Object authIdent)
|
||||
{
|
||||
return (NFSSrvSession) m_sessions.get(authIdent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a session from the list
|
||||
*
|
||||
* @param sess NFSSrvSession
|
||||
* @return NFSSrvSession
|
||||
*/
|
||||
public final NFSSrvSession removeSession(NFSSrvSession sess)
|
||||
{
|
||||
return removeSession(sess.getAuthIdentifier());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a session from the list
|
||||
*
|
||||
* @param authIdent Object
|
||||
* @return NFSSrvSession
|
||||
*/
|
||||
public final NFSSrvSession removeSession(Object authIdent)
|
||||
{
|
||||
|
||||
// Find the required session
|
||||
|
||||
NFSSrvSession sess = findSession(authIdent);
|
||||
|
||||
// Remove the session and return the removed session
|
||||
|
||||
m_sessions.remove(authIdent);
|
||||
return sess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerate the session ids
|
||||
*
|
||||
* @return Enumeration
|
||||
*/
|
||||
public final Enumeration<Object> enumerate()
|
||||
{
|
||||
return m_sessions.keys();
|
||||
}
|
||||
}
|
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.oncrpc.nfs;
|
||||
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
|
||||
import org.alfresco.filesys.server.NetworkServer;
|
||||
import org.alfresco.filesys.server.SrvSession;
|
||||
import org.alfresco.filesys.server.core.DeviceInterface;
|
||||
import org.alfresco.filesys.server.filesys.SearchContext;
|
||||
import org.alfresco.filesys.server.filesys.TreeConnection;
|
||||
import org.alfresco.filesys.server.filesys.TreeConnectionHash;
|
||||
import org.alfresco.filesys.server.oncrpc.Rpc;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* NFS Server Session Class
|
||||
*
|
||||
* @author GKSpencer
|
||||
*/
|
||||
public class NFSSrvSession extends SrvSession {
|
||||
|
||||
// Debug logging
|
||||
|
||||
private static final Log logger = LogFactory.getLog("org.alfresco.nfs.protocol");
|
||||
|
||||
// Default and maximum number of search slots
|
||||
|
||||
private static final int DefaultSearches = 32;
|
||||
private static final int MaxSearches = 256;
|
||||
|
||||
// Remote address and port
|
||||
|
||||
private InetAddress m_remAddr;
|
||||
private int m_remPort;
|
||||
|
||||
// Session type (TCP or UDP)
|
||||
|
||||
private int m_type;
|
||||
|
||||
// Authentication identifier
|
||||
//
|
||||
// Identifies this session uniquely within the authentication type being used by the client
|
||||
|
||||
private Object m_authIdentifier;
|
||||
|
||||
// Active tree connections
|
||||
|
||||
private TreeConnectionHash m_connections;
|
||||
|
||||
// Cache of currently open files
|
||||
|
||||
private NetworkFileCache m_fileCache;
|
||||
|
||||
// Last time the session was accessed. Used to determine when to expire UDP sessions.
|
||||
|
||||
private long m_lastAccess;
|
||||
|
||||
// Active search list for this session
|
||||
|
||||
private SearchContext[] m_search;
|
||||
private int m_searchCount;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param srv NetworkServer
|
||||
* @param addr InetAddress
|
||||
* @param port int
|
||||
* @param type int
|
||||
*/
|
||||
public NFSSrvSession(NetworkServer srv, InetAddress addr, int port, int type)
|
||||
{
|
||||
super(-1, srv, "NFS", null);
|
||||
|
||||
// Save the remove address/port and type
|
||||
|
||||
m_remAddr = addr;
|
||||
m_remPort = port;
|
||||
m_type = type;
|
||||
|
||||
// Create a unique id for the session from the remote address, port and type
|
||||
|
||||
StringBuffer str = new StringBuffer();
|
||||
|
||||
str.append(type == Rpc.TCP ? "T" : "U");
|
||||
str.append(m_remAddr.getHostAddress());
|
||||
str.append(":");
|
||||
str.append(m_remPort);
|
||||
|
||||
setUniqueId(str.toString());
|
||||
|
||||
// Set the remote name
|
||||
|
||||
setRemoteName(m_remAddr.getHostAddress());
|
||||
|
||||
// Initialize the last access date/time
|
||||
|
||||
setLastAccess(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the session type
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int isType()
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the open file cache
|
||||
*
|
||||
* @return NetworkFileCache
|
||||
*/
|
||||
public final NetworkFileCache getFileCache()
|
||||
{
|
||||
if (m_fileCache == null)
|
||||
m_fileCache = new NetworkFileCache(getUniqueId());
|
||||
return m_fileCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the session has an authentication identifier
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasAuthIdentifier()
|
||||
{
|
||||
return m_authIdentifier != null ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the authentication identifier
|
||||
*
|
||||
* @return Object
|
||||
*/
|
||||
public final Object getAuthIdentifier()
|
||||
{
|
||||
return m_authIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the client network address
|
||||
*
|
||||
* @return InetAddress
|
||||
*/
|
||||
public InetAddress getRemoteAddress()
|
||||
{
|
||||
return m_remAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the remote port
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int getRemotePort()
|
||||
{
|
||||
return m_remPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last access date/time for the session
|
||||
*
|
||||
* @return long
|
||||
*/
|
||||
public final long getLastAccess()
|
||||
{
|
||||
return m_lastAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the tree connection for the specified share hash
|
||||
*
|
||||
* @param shareHash int
|
||||
* @return TreeConnection
|
||||
*/
|
||||
public final TreeConnection findConnection(int shareHash)
|
||||
{
|
||||
if (m_connections == null)
|
||||
return null;
|
||||
return m_connections.findConnection(shareHash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new connection to the list of active tree connections for this session
|
||||
*
|
||||
* @param tree TreeConnection
|
||||
*/
|
||||
public final void addConnection(TreeConnection tree)
|
||||
{
|
||||
if (m_connections == null)
|
||||
m_connections = new TreeConnectionHash();
|
||||
m_connections.addConnection(tree);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a connection from the list of active tree connections for this session
|
||||
*
|
||||
* @param tree TreeConnection
|
||||
*/
|
||||
public final void removeConnection(TreeConnection tree)
|
||||
{
|
||||
if (m_connections == null)
|
||||
return;
|
||||
m_connections.deleteConnection(tree.getSharedDevice().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the authentication identifier
|
||||
*
|
||||
* @param authIdent Object
|
||||
*/
|
||||
public final void setAuthIdentifier(Object authIdent)
|
||||
{
|
||||
m_authIdentifier = authIdent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the last access date/time for the session
|
||||
*
|
||||
* @param dateTime long
|
||||
*/
|
||||
public final void setLastAccess(long dateTime)
|
||||
{
|
||||
m_lastAccess = dateTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the last access date/time for the session
|
||||
*/
|
||||
public final void setLastAccess()
|
||||
{
|
||||
m_lastAccess = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the session, cleanup any resources.
|
||||
*/
|
||||
public void closeSession()
|
||||
{
|
||||
|
||||
// Cleanup open files, tree connections and searches
|
||||
|
||||
cleanupSession();
|
||||
|
||||
// Call the base class
|
||||
|
||||
super.closeSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a slot in the active searches list for a new search.
|
||||
*
|
||||
* @param search SearchContext
|
||||
* @return int Search slot index, or -1 if there are no more search slots available.
|
||||
*/
|
||||
protected synchronized final int allocateSearchSlot(SearchContext search)
|
||||
{
|
||||
|
||||
// Check if the search array has been allocated
|
||||
|
||||
if (m_search == null)
|
||||
m_search = new SearchContext[DefaultSearches];
|
||||
|
||||
// Find a free slot for the new search
|
||||
|
||||
int idx = 0;
|
||||
|
||||
while (idx < m_search.length && m_search[idx] != null)
|
||||
idx++;
|
||||
|
||||
// Check if we found a free slot
|
||||
|
||||
if (idx == m_search.length)
|
||||
{
|
||||
|
||||
// The search array needs to be extended, check if we reached the limit.
|
||||
|
||||
if (m_search.length >= MaxSearches)
|
||||
return -1;
|
||||
|
||||
// Extend the search array
|
||||
|
||||
SearchContext[] newSearch = new SearchContext[m_search.length * 2];
|
||||
System.arraycopy(m_search, 0, newSearch, 0, m_search.length);
|
||||
m_search = newSearch;
|
||||
}
|
||||
|
||||
// If the search context is valid then store in the allocated slot
|
||||
|
||||
if (search != null)
|
||||
m_search[idx] = search;
|
||||
|
||||
// Return the allocated search slot index
|
||||
|
||||
m_searchCount++;
|
||||
return idx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deallocate the specified search context/slot.
|
||||
*
|
||||
* @param ctxId int
|
||||
*/
|
||||
protected synchronized final void deallocateSearchSlot(int ctxId)
|
||||
{
|
||||
|
||||
// Check if the search array has been allocated and that the index is valid
|
||||
|
||||
if (m_search == null || ctxId >= m_search.length)
|
||||
return;
|
||||
|
||||
// Close the search
|
||||
|
||||
if (m_search[ctxId] != null)
|
||||
m_search[ctxId].closeSearch();
|
||||
|
||||
// Free the specified search context slot
|
||||
|
||||
m_searchCount--;
|
||||
m_search[ctxId] = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the NFS server that the session is associated with
|
||||
*
|
||||
* @return NFSServer
|
||||
*/
|
||||
public final NFSServer getNFSServer()
|
||||
{
|
||||
return (NFSServer) getServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the search context for the specified search id.
|
||||
*
|
||||
* @return com.starla.smbsrv.SearchContext
|
||||
* @param srchId int
|
||||
*/
|
||||
protected final SearchContext getSearchContext(int srchId)
|
||||
{
|
||||
|
||||
// Check if the search array is valid and the search index is valid
|
||||
|
||||
if (m_search == null || srchId >= m_search.length)
|
||||
return null;
|
||||
|
||||
// Return the required search context
|
||||
|
||||
return m_search[srchId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of active tree searches.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int getSearchCount()
|
||||
{
|
||||
return m_searchCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the seach context in the specified slot.
|
||||
*
|
||||
* @param slot Slot to store the search context.
|
||||
* @param srch com.starla.smbsrv.SearchContext
|
||||
*/
|
||||
protected final void setSearchContext(int slot, SearchContext srch)
|
||||
{
|
||||
|
||||
// Check if the search slot id is valid
|
||||
|
||||
if (m_search == null || slot > m_search.length)
|
||||
return;
|
||||
|
||||
// Store the context
|
||||
|
||||
m_search[slot] = srch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup any resources owned by this session, close files, searches and change notification requests.
|
||||
*/
|
||||
protected final void cleanupSession()
|
||||
{
|
||||
|
||||
// Debug
|
||||
|
||||
if (logger.isDebugEnabled() && hasDebug(NFSServer.DBG_SESSION))
|
||||
logger.debug("NFS Cleanup session, searches=" + getSearchCount() + ", files="
|
||||
+ (m_fileCache != null ? m_fileCache.numberOfEntries() : 0) + ", treeConns="
|
||||
+ (m_connections != null ? m_connections.numberOfEntries() : 0));
|
||||
|
||||
// Check if there are any active searches
|
||||
|
||||
if (m_search != null)
|
||||
{
|
||||
|
||||
// Close all active searches
|
||||
|
||||
for (int idx = 0; idx < m_search.length; idx++)
|
||||
{
|
||||
|
||||
// Check if the current search slot is active
|
||||
|
||||
if (m_search[idx] != null)
|
||||
deallocateSearchSlot(idx);
|
||||
}
|
||||
|
||||
// Release the search context list, clear the search count
|
||||
|
||||
m_search = null;
|
||||
m_searchCount = 0;
|
||||
}
|
||||
|
||||
// Close any open files
|
||||
|
||||
if (m_fileCache != null)
|
||||
m_fileCache.closeAllFiles();
|
||||
|
||||
// Check if there are open tree connections
|
||||
|
||||
if (m_connections != null && m_connections.numberOfEntries() > 0)
|
||||
{
|
||||
|
||||
// Enumerate the active connections
|
||||
|
||||
Enumeration conns = m_connections.enumerateConnections();
|
||||
|
||||
while (conns.hasMoreElements())
|
||||
{
|
||||
|
||||
// Get the current tree connection
|
||||
|
||||
TreeConnection tree = (TreeConnection) conns.nextElement();
|
||||
|
||||
tree.closeConnection(this);
|
||||
|
||||
// Inform the driver that the connection has been closed
|
||||
|
||||
DeviceInterface devIface = tree.getInterface();
|
||||
if (devIface != null)
|
||||
devIface.treeClosed(this, tree);
|
||||
|
||||
// Release the connection list
|
||||
|
||||
m_connections = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.oncrpc.nfs;
|
||||
|
||||
import java.util.*;
|
||||
import java.io.*;
|
||||
|
||||
import org.alfresco.filesys.server.filesys.DiskInterface;
|
||||
import org.alfresco.filesys.server.filesys.NetworkFile;
|
||||
import org.alfresco.filesys.server.filesys.TreeConnection;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Network File Cache Class
|
||||
*
|
||||
* <p>Caches the network files that are currently being accessed by the NFS server.
|
||||
*
|
||||
* @author GKSpencer
|
||||
*/
|
||||
public class NetworkFileCache {
|
||||
|
||||
// Debug logging
|
||||
|
||||
private static final Log logger = LogFactory.getLog(NetworkFileCache.class);
|
||||
|
||||
// Default file timeout
|
||||
|
||||
public static final long DefaultFileTimeout = 5000L; // 5 seconds
|
||||
|
||||
// Network file cache, key is the file id
|
||||
|
||||
private Hashtable<Integer, FileEntry> m_fileCache;
|
||||
|
||||
// File expiry thread
|
||||
|
||||
private FileExpiry m_expiryThread;
|
||||
|
||||
// File timeout
|
||||
|
||||
private long m_fileTmo = DefaultFileTimeout;
|
||||
|
||||
// Debug enable flag
|
||||
|
||||
private boolean m_debug = false;
|
||||
|
||||
/**
|
||||
* File Entry Class
|
||||
*/
|
||||
protected class FileEntry {
|
||||
|
||||
// Network file
|
||||
|
||||
private NetworkFile m_file;
|
||||
|
||||
// Disk share connection
|
||||
|
||||
private TreeConnection m_conn;
|
||||
|
||||
// File timeout
|
||||
|
||||
private long m_timeout;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param file
|
||||
* NetworkFile
|
||||
* @param conn
|
||||
* TreeConnection
|
||||
*/
|
||||
public FileEntry(NetworkFile file, TreeConnection conn) {
|
||||
m_file = file;
|
||||
m_conn = conn;
|
||||
updateTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the file timeout
|
||||
*
|
||||
* @return long
|
||||
*/
|
||||
public final long getTimeout() {
|
||||
return m_timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the network file
|
||||
*
|
||||
* @return NetworkFile
|
||||
*/
|
||||
public final NetworkFile getFile() {
|
||||
return m_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the disk share connection
|
||||
*
|
||||
* @return TreeConnection
|
||||
*/
|
||||
public final TreeConnection getConnection() {
|
||||
return m_conn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the file timeout
|
||||
*/
|
||||
public final void updateTimeout() {
|
||||
m_timeout = System.currentTimeMillis() + m_fileTmo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the file timeout
|
||||
*
|
||||
* @param tmo
|
||||
* long
|
||||
*/
|
||||
public final void updateTimeout(long tmo) {
|
||||
m_timeout = tmo;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* File Expiry Thread Class
|
||||
*/
|
||||
protected class FileExpiry implements Runnable {
|
||||
|
||||
// Expiry thread
|
||||
|
||||
private Thread m_thread;
|
||||
|
||||
// Wakeup interval
|
||||
|
||||
private long m_wakeup;
|
||||
|
||||
// Shutdown flag
|
||||
|
||||
private boolean m_shutdown;
|
||||
|
||||
/**
|
||||
* Class Constructor
|
||||
*
|
||||
* @param wakeup
|
||||
* long
|
||||
* @param name
|
||||
* String
|
||||
*/
|
||||
public FileExpiry(long wakeup, String name) {
|
||||
|
||||
// Set the wakeup interval
|
||||
|
||||
m_wakeup = wakeup;
|
||||
|
||||
// Create and start the file expiry thread
|
||||
|
||||
m_thread = new Thread(this);
|
||||
m_thread.setDaemon(true);
|
||||
m_thread.setName("NFSFileExpiry_" + name);
|
||||
m_thread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Main thread method
|
||||
*/
|
||||
public void run() {
|
||||
|
||||
// Loop until shutdown
|
||||
|
||||
while (m_shutdown == false) {
|
||||
|
||||
// Sleep for a while
|
||||
|
||||
try {
|
||||
Thread.sleep(m_wakeup);
|
||||
} catch (InterruptedException ex) {
|
||||
}
|
||||
|
||||
// Get the current system time
|
||||
|
||||
long timeNow = System.currentTimeMillis();
|
||||
|
||||
// Check for expired files
|
||||
|
||||
synchronized (m_fileCache) {
|
||||
|
||||
// Enumerate the cache entries
|
||||
|
||||
Enumeration enm = m_fileCache.keys();
|
||||
|
||||
while (enm.hasMoreElements()) {
|
||||
|
||||
// Get the current key
|
||||
|
||||
Integer fileId = (Integer) enm.nextElement();
|
||||
|
||||
// Get the file entry and check if it has expired
|
||||
|
||||
FileEntry fentry = (FileEntry) m_fileCache.get(fileId);
|
||||
|
||||
if (fentry != null && fentry.getTimeout() < timeNow) {
|
||||
|
||||
// Get the network file
|
||||
|
||||
NetworkFile netFile = fentry.getFile();
|
||||
|
||||
// Check if the file has an I/O request pending, if
|
||||
// so then reset the file expiry time
|
||||
// for the file
|
||||
|
||||
if (netFile.hasIOPending()) {
|
||||
|
||||
// Update the expiry time for the file entry
|
||||
|
||||
fentry.updateTimeout();
|
||||
|
||||
// DEBUG
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("NFSFileExpiry: I/O pending file=" + fentry.getFile().getFullName() + ", fid=" + fileId);
|
||||
} else {
|
||||
|
||||
// File entry has expired, remove it from the
|
||||
// cache
|
||||
|
||||
m_fileCache.remove(fileId);
|
||||
|
||||
// Close the file via the disk interface
|
||||
|
||||
try {
|
||||
|
||||
// Get the disk interface
|
||||
|
||||
DiskInterface disk = (DiskInterface) fentry
|
||||
.getConnection().getInterface();
|
||||
|
||||
// Close the file
|
||||
|
||||
disk.closeFile(null,
|
||||
fentry.getConnection(), netFile);
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
|
||||
// DEBUG
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("NFSFileExpiry: Closed file=" + fentry.getFile().getFullName() + ", fid=" + fileId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the file expiry thread to shutdown
|
||||
*/
|
||||
public final void requestShutdown() {
|
||||
|
||||
// Set the shutdown flag
|
||||
|
||||
m_shutdown = true;
|
||||
|
||||
// Wakeup the thread
|
||||
|
||||
try {
|
||||
m_thread.interrupt();
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
|
||||
// Wait for the expiry thread to complete
|
||||
|
||||
try {
|
||||
m_thread.join(DefaultFileTimeout);
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param name
|
||||
* String
|
||||
*/
|
||||
public NetworkFileCache(String name) {
|
||||
|
||||
// Create the file cache
|
||||
|
||||
m_fileCache = new Hashtable<Integer, FileEntry>();
|
||||
|
||||
// Start the file expiry thread
|
||||
|
||||
m_expiryThread = new FileExpiry(DefaultFileTimeout / 4, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if debug output is enabled
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasDebug() {
|
||||
return m_debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a file to the cache
|
||||
*
|
||||
* @param file
|
||||
* NetworkFile
|
||||
* @param conn
|
||||
* TreeConnection
|
||||
*/
|
||||
public synchronized final void addFile(NetworkFile file, TreeConnection conn) {
|
||||
synchronized (m_fileCache) {
|
||||
m_fileCache.put(new Integer(file.getFileId()), new FileEntry(file,
|
||||
conn));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a file from the cache
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
public synchronized final void removeFile(int id) {
|
||||
|
||||
// Create the search key
|
||||
|
||||
Integer fileId = new Integer(id);
|
||||
|
||||
synchronized (m_fileCache) {
|
||||
m_fileCache.remove(fileId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a file via the file id
|
||||
*
|
||||
* @param id
|
||||
* int
|
||||
* @return NetworkFile
|
||||
*/
|
||||
public synchronized final NetworkFile findFile(int id) {
|
||||
|
||||
// Create the search key
|
||||
|
||||
Integer fileId = new Integer(id);
|
||||
FileEntry fentry = null;
|
||||
|
||||
synchronized (m_fileCache) {
|
||||
fentry = (FileEntry) m_fileCache.get(fileId);
|
||||
}
|
||||
|
||||
// Return the file, or null if not found
|
||||
|
||||
if (fentry != null) {
|
||||
|
||||
// Update the file timeout and return the file
|
||||
|
||||
fentry.updateTimeout();
|
||||
return fentry.getFile();
|
||||
}
|
||||
|
||||
// Invalid file id
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the count of entries in the cache
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public final int numberOfEntries() {
|
||||
return m_fileCache.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the expiry cache, close and remove all files from the cache and
|
||||
* stop the expiry thread.
|
||||
*/
|
||||
public final void closeAllFiles() {
|
||||
|
||||
// Enumerate the cache entries
|
||||
|
||||
Enumeration keys = m_fileCache.keys();
|
||||
|
||||
while (keys.hasMoreElements()) {
|
||||
|
||||
// Get the current key and lookup the matching value
|
||||
|
||||
Integer key = (Integer) keys.nextElement();
|
||||
FileEntry entry = (FileEntry) m_fileCache.get(key);
|
||||
|
||||
// Expire the file entry
|
||||
|
||||
entry.updateTimeout(0L);
|
||||
}
|
||||
|
||||
// Shutdown the expiry thread, this should close the files
|
||||
|
||||
m_expiryThread.requestShutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the cache entries to the debug device
|
||||
*/
|
||||
public final void dumpCache() {
|
||||
|
||||
// Dump the count of entries in the cache
|
||||
|
||||
logger.debug("NetworkFileCache entries=" + numberOfEntries());
|
||||
|
||||
// Enumerate the cache entries
|
||||
|
||||
Enumeration keys = m_fileCache.keys();
|
||||
|
||||
while (keys.hasMoreElements()) {
|
||||
|
||||
// Get the current key and lookup the matching value
|
||||
|
||||
Integer key = (Integer) keys.nextElement();
|
||||
FileEntry entry = (FileEntry) m_fileCache.get(key);
|
||||
|
||||
// Dump the entry details
|
||||
|
||||
logger.debug("fid=" + key + ": " + entry);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.oncrpc.nfs;
|
||||
|
||||
import org.alfresco.filesys.server.filesys.SearchContext;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Search Cache Class
|
||||
*
|
||||
* <p>Holds the details of the active searches for the NFS server
|
||||
*
|
||||
* @author GKSpencer
|
||||
*/
|
||||
public class SearchCache {
|
||||
|
||||
// Debug logging
|
||||
|
||||
private static final Log logger = LogFactory.getLog(SearchCache.class);
|
||||
|
||||
// Maximum number of active searches
|
||||
|
||||
public static final int MaximumSearches = 255;
|
||||
|
||||
// Default search timeout
|
||||
|
||||
public static final long DefaultSearchTimeout = 30000L; // 30 seconds
|
||||
|
||||
// Array of active searches, last allocated index
|
||||
|
||||
private SearchEntry[] m_searches;
|
||||
private int m_lastIdx;
|
||||
|
||||
// Search timeout
|
||||
|
||||
private long m_searchTmo = DefaultSearchTimeout;
|
||||
|
||||
// Debug enable flag
|
||||
|
||||
private boolean m_debug = true;
|
||||
|
||||
/**
|
||||
* Search Entry Class
|
||||
*/
|
||||
protected class SearchEntry
|
||||
{
|
||||
|
||||
// Search context
|
||||
|
||||
private SearchContext m_search;
|
||||
|
||||
// Search timeout
|
||||
|
||||
private long m_timeout;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param search SearchContext
|
||||
*/
|
||||
public SearchEntry(SearchContext search)
|
||||
{
|
||||
m_search = search;
|
||||
updateTimeout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the search timeout
|
||||
*
|
||||
* @return long
|
||||
*/
|
||||
public final long getTimeout()
|
||||
{
|
||||
return m_timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the search context
|
||||
*
|
||||
* @return SearchContext
|
||||
*/
|
||||
public final SearchContext getSearch()
|
||||
{
|
||||
return m_search;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the search timeout
|
||||
*/
|
||||
public final void updateTimeout()
|
||||
{
|
||||
m_timeout = System.currentTimeMillis() + m_searchTmo;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Search Expiry Thread Class
|
||||
*/
|
||||
protected class SearchExpiry implements Runnable
|
||||
{
|
||||
|
||||
// Expiry thread
|
||||
|
||||
private Thread m_thread;
|
||||
|
||||
// Wakeup interval
|
||||
|
||||
private long m_wakeup;
|
||||
|
||||
/**
|
||||
* Class Constructor
|
||||
*
|
||||
* @param wakeup long
|
||||
*/
|
||||
public SearchExpiry(long wakeup)
|
||||
{
|
||||
|
||||
// Set the wakeup interval
|
||||
|
||||
m_wakeup = wakeup;
|
||||
|
||||
// Create and start the search expiry thread
|
||||
|
||||
m_thread = new Thread(this);
|
||||
m_thread.setDaemon(true);
|
||||
m_thread.setName("NFSSearchExpiry");
|
||||
m_thread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Main thread method
|
||||
*/
|
||||
public void run()
|
||||
{
|
||||
|
||||
// Loop until shutdown
|
||||
|
||||
while (true)
|
||||
{
|
||||
|
||||
// Sleep for a while
|
||||
|
||||
try
|
||||
{
|
||||
Thread.sleep(m_wakeup);
|
||||
} catch (InterruptedException ex)
|
||||
{
|
||||
}
|
||||
|
||||
// Get the current system time
|
||||
|
||||
long timeNow = System.currentTimeMillis();
|
||||
|
||||
// Check for expired searches
|
||||
|
||||
synchronized (m_searches)
|
||||
{
|
||||
|
||||
// Check all allocated slots
|
||||
|
||||
for (int i = 0; i < m_searches.length; i++)
|
||||
{
|
||||
|
||||
// Check if the current slot has a valid entry
|
||||
|
||||
if (m_searches[i] != null && m_searches[i].getTimeout() < timeNow)
|
||||
{
|
||||
|
||||
// Remove the current search entry
|
||||
|
||||
SearchEntry entry = m_searches[i];
|
||||
m_searches[i] = null;
|
||||
|
||||
// Close the search
|
||||
|
||||
entry.getSearch().closeSearch();
|
||||
|
||||
// DEBUG
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
logger.debug("NFSSearchExpiry: Closed search=" + entry.getSearch().getSearchString()
|
||||
+ ", id=" + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public SearchCache()
|
||||
{
|
||||
|
||||
// Create the active search list
|
||||
|
||||
m_searches = new SearchEntry[MaximumSearches];
|
||||
|
||||
// Start the search expiry thread
|
||||
|
||||
new SearchExpiry(DefaultSearchTimeout / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if debug output is enabled
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasDebug()
|
||||
{
|
||||
return m_debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a search slot
|
||||
*
|
||||
* @param search SearchContext
|
||||
* @return int
|
||||
*/
|
||||
public final int allocateSearchId(SearchContext search)
|
||||
{
|
||||
|
||||
synchronized (m_searches)
|
||||
{
|
||||
|
||||
// Search for a free slot in the search list
|
||||
|
||||
int cnt = 0;
|
||||
|
||||
while (cnt < MaximumSearches)
|
||||
{
|
||||
|
||||
// Check if the index has wrapped
|
||||
|
||||
if (m_lastIdx >= MaximumSearches)
|
||||
m_lastIdx = 0;
|
||||
|
||||
// Check if the current slot is empty
|
||||
|
||||
if (m_searches[m_lastIdx] == null)
|
||||
{
|
||||
|
||||
// Use this slot
|
||||
|
||||
SearchEntry entry = new SearchEntry(search);
|
||||
m_searches[m_lastIdx] = entry;
|
||||
return m_lastIdx++;
|
||||
} else
|
||||
m_lastIdx++;
|
||||
|
||||
// Update the slot count
|
||||
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
// No empty search slot found
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release a search slot
|
||||
*
|
||||
* @param id int
|
||||
*/
|
||||
public final void releaseSearchId(int id)
|
||||
{
|
||||
|
||||
// Range check the id
|
||||
|
||||
if (id < 0 || id >= MaximumSearches)
|
||||
return;
|
||||
|
||||
// Delete the search entry
|
||||
|
||||
synchronized (m_searches)
|
||||
{
|
||||
m_searches[id] = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the required search context
|
||||
*
|
||||
* @param id int
|
||||
* @return SearchContext
|
||||
*/
|
||||
public final SearchContext getSearch(int id)
|
||||
{
|
||||
|
||||
// Range check the id
|
||||
|
||||
if (id < 0 || id >= MaximumSearches)
|
||||
return null;
|
||||
|
||||
// Get the search entry
|
||||
|
||||
SearchEntry entry = null;
|
||||
|
||||
synchronized (m_searches)
|
||||
{
|
||||
entry = m_searches[id];
|
||||
}
|
||||
|
||||
// Return the search context, if valid
|
||||
|
||||
if (entry != null)
|
||||
{
|
||||
|
||||
// Update the search timeout and return the search
|
||||
|
||||
entry.updateTimeout();
|
||||
return entry.getSearch();
|
||||
}
|
||||
|
||||
// Invalid search
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the active search list
|
||||
*/
|
||||
public final void dumpSearches()
|
||||
{
|
||||
|
||||
synchronized (m_searches)
|
||||
{
|
||||
|
||||
// Find all active searches in the list
|
||||
|
||||
for (int i = 0; i < m_searches.length; i++)
|
||||
{
|
||||
|
||||
// Check if the current search slot is active
|
||||
|
||||
if (m_searches[i] != null)
|
||||
{
|
||||
|
||||
// Get the search details
|
||||
|
||||
SearchEntry entry = m_searches[i];
|
||||
|
||||
logger.debug("" + i + ": " + entry.getSearch().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.oncrpc.nfs;
|
||||
|
||||
/**
|
||||
* Share Details Class
|
||||
*
|
||||
* <p>Contains the file id cache, active search cache and tree connection details
|
||||
* of a shared filesystem.
|
||||
*
|
||||
* @author GKSpencer
|
||||
*/
|
||||
public class ShareDetails {
|
||||
|
||||
// Share name
|
||||
|
||||
private String m_name;
|
||||
|
||||
// File id to path conversion cache
|
||||
|
||||
private FileIdCache m_idCache;
|
||||
|
||||
// Flag to indicate if the filesystem driver for this share supports file id
|
||||
// lookups
|
||||
// via the FileIdInterface
|
||||
|
||||
private boolean m_fileIdLookup;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param name String
|
||||
* @param fileIdSupport boolean
|
||||
*/
|
||||
public ShareDetails(String name, boolean fileIdSupport)
|
||||
{
|
||||
|
||||
// Save the share name
|
||||
|
||||
m_name = name;
|
||||
|
||||
// Set the file id support flag
|
||||
|
||||
m_fileIdLookup = fileIdSupport;
|
||||
|
||||
// Create the file id and search caches
|
||||
|
||||
m_idCache = new FileIdCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the share name
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public final String getName()
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the file id cache
|
||||
*
|
||||
* @return FileIdCache
|
||||
*/
|
||||
public final FileIdCache getFileIdCache()
|
||||
{
|
||||
return m_idCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the filesystem driver for this share has file id support
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public final boolean hasFileIdSupport()
|
||||
{
|
||||
return m_fileIdLookup;
|
||||
}
|
||||
}
|
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.oncrpc.nfs;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Share Details Hash Class
|
||||
*
|
||||
* <p>Hashtable of ShareDetails for the available disk shared devices. ShareDetails are indexed using the
|
||||
* hash of the share name to allow mounts to be persistent across server restarts.
|
||||
*
|
||||
* @author GKSpencer
|
||||
*/
|
||||
public class ShareDetailsHash {
|
||||
|
||||
// Share name hash to share details
|
||||
|
||||
private Hashtable<Integer, ShareDetails> m_details;
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*/
|
||||
public ShareDetailsHash()
|
||||
{
|
||||
m_details = new Hashtable<Integer, ShareDetails>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add share details to the list of available shares
|
||||
*
|
||||
* @param details ShareDetails
|
||||
*/
|
||||
public final void addDetails(ShareDetails details)
|
||||
{
|
||||
m_details.put(new Integer(details.getName().hashCode()), details);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete share details from the list
|
||||
*
|
||||
* @param shareName String
|
||||
* @return ShareDetails
|
||||
*/
|
||||
public final ShareDetails deleteDetails(String shareName)
|
||||
{
|
||||
return (ShareDetails) m_details.get(new Integer(shareName.hashCode()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find share details for the specified share name
|
||||
*
|
||||
* @param shareName String
|
||||
* @return ShareDetails
|
||||
*/
|
||||
public final ShareDetails findDetails(String shareName)
|
||||
{
|
||||
|
||||
// Get the share details for the associated share name
|
||||
|
||||
ShareDetails details = (ShareDetails) m_details.get(new Integer(shareName.hashCode()));
|
||||
|
||||
// Return the share details
|
||||
|
||||
return details;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find share details for the specified share name hash code
|
||||
*
|
||||
* @param hashCode int
|
||||
* @return ShareDetails
|
||||
*/
|
||||
public final ShareDetails findDetails(int hashCode)
|
||||
{
|
||||
|
||||
// Get the share details for the associated share name
|
||||
|
||||
ShareDetails details = (ShareDetails) m_details.get(new Integer(hashCode));
|
||||
|
||||
// Return the share details
|
||||
|
||||
return details;
|
||||
}
|
||||
}
|
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2005 Alfresco, Inc.
|
||||
*
|
||||
* Licensed under the Mozilla Public License version 1.1
|
||||
* with a permitted attribution clause. You may obtain a
|
||||
* copy of the License at
|
||||
*
|
||||
* http://www.alfresco.org/legal/license.txt
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
* either express or implied. See the License for the specific
|
||||
* language governing permissions and limitations under the
|
||||
* License.
|
||||
*/
|
||||
package org.alfresco.filesys.server.oncrpc.nfs;
|
||||
|
||||
/**
|
||||
* Stale Handle Exception Class
|
||||
*
|
||||
* @author GKSpencer
|
||||
*/
|
||||
public class StaleHandleException extends Exception {
|
||||
|
||||
// Object version id
|
||||
|
||||
private static final long serialVersionUID = -8607694363687774475L;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public StaleHandleException()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Class constructor
|
||||
*
|
||||
* @param msg String
|
||||
*/
|
||||
public StaleHandleException(String msg)
|
||||
{
|
||||
super(msg);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user