0001: /*
0002: * SSHTools - Java SSH2 API
0003: *
0004: * Copyright (C) 2002-2003 Lee David Painter and Contributors.
0005: *
0006: * Contributions made by:
0007: *
0008: * Brett Smith
0009: * Richard Pernavas
0010: * Erwin Bolwidt
0011: *
0012: * This program is free software; you can redistribute it and/or
0013: * modify it under the terms of the GNU General Public License
0014: * as published by the Free Software Foundation; either version 2
0015: * of the License, or (at your option) any later version.
0016: *
0017: * This program is distributed in the hope that it will be useful,
0018: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0019: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0020: * GNU General Public License for more details.
0021: *
0022: * You should have received a copy of the GNU General Public License
0023: * along with this program; if not, write to the Free Software
0024: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0025: */
0026: package com.sshtools.daemon.vfs;
0027:
0028: import com.sshtools.daemon.configuration.PlatformConfiguration;
0029: import com.sshtools.daemon.platform.InvalidHandleException;
0030: import com.sshtools.daemon.platform.NativeAuthenticationProvider;
0031: import com.sshtools.daemon.platform.NativeFileSystemProvider;
0032: import com.sshtools.daemon.platform.PermissionDeniedException;
0033: import com.sshtools.daemon.platform.UnsupportedFileOperationException;
0034:
0035: import com.sshtools.j2ssh.SshThread;
0036: import com.sshtools.j2ssh.configuration.ConfigurationException;
0037: import com.sshtools.j2ssh.configuration.ConfigurationLoader;
0038: import com.sshtools.j2ssh.io.UnsignedInteger32;
0039: import com.sshtools.j2ssh.io.UnsignedInteger64;
0040: import com.sshtools.j2ssh.sftp.FileAttributes;
0041: import com.sshtools.j2ssh.sftp.SftpFile;
0042:
0043: import org.apache.commons.logging.Log;
0044: import org.apache.commons.logging.LogFactory;
0045:
0046: import java.io.EOFException;
0047: import java.io.File;
0048: import java.io.FileNotFoundException;
0049: import java.io.IOException;
0050: import java.io.RandomAccessFile;
0051:
0052: import java.util.HashMap;
0053: import java.util.Iterator;
0054: import java.util.Map;
0055:
0056: /**
0057: *
0058: *
0059: * @author $author$
0060: * @version $Revision: 1.32 $
0061: */
0062: public class VirtualFileSystem extends NativeFileSystemProvider {
0063: private static String USER_HOME = "/home/";
0064: private static Map vfsmounts;
0065: private static VFSMount vfsroot;
0066: private static Log log = LogFactory.getLog(VirtualFileSystem.class);
0067: private static VFSPermissionHandler permissionHandler = null;
0068:
0069: static {
0070: try {
0071: vfsmounts = ((PlatformConfiguration) ConfigurationLoader
0072: .getConfiguration(PlatformConfiguration.class))
0073: .getVFSMounts();
0074: vfsroot = ((PlatformConfiguration) ConfigurationLoader
0075: .getConfiguration(PlatformConfiguration.class))
0076: .getVFSRoot();
0077: } catch (ConfigurationException ex) {
0078: log.error("Failed to initialize the Virtual File System",
0079: ex);
0080: }
0081: }
0082:
0083: private Map openFiles = new HashMap();
0084:
0085: /**
0086: * Creates a new VirtualFileSystem object.
0087: *
0088: * @throws IOException
0089: */
0090: public VirtualFileSystem() throws IOException {
0091: if (!ConfigurationLoader
0092: .isConfigurationAvailable(PlatformConfiguration.class)) {
0093: throw new IOException(
0094: "No valid platform configuration available");
0095: }
0096: }
0097:
0098: public static void setPermissionHandler(
0099: VFSPermissionHandler permissionHandler) {
0100: VirtualFileSystem.permissionHandler = permissionHandler;
0101: }
0102:
0103: private static String getVFSHomeDirectory(String username)
0104: throws FileNotFoundException {
0105: if (permissionHandler != null) {
0106: return permissionHandler.getVFSHomeDirectory(username);
0107: } else {
0108: return USER_HOME + username;
0109: }
0110: }
0111:
0112: private static String getNFSHomeDirectory()
0113: throws FileNotFoundException {
0114: try {
0115: if (Thread.currentThread() instanceof SshThread
0116: && SshThread.hasUserContext()) {
0117: NativeAuthenticationProvider nap = NativeAuthenticationProvider
0118: .getInstance();
0119:
0120: return nap.getHomeDirectory(SshThread
0121: .getCurrentThreadUser());
0122: } else {
0123: throw new FileNotFoundException(
0124: "There is no user logged in");
0125: }
0126: } catch (IOException e) {
0127: throw new FileNotFoundException(e.getMessage());
0128: }
0129: }
0130:
0131: /**
0132: *
0133: *
0134: * @param str
0135: * @param with
0136: *
0137: * @return
0138: */
0139: public static boolean startsWithIgnoreCase(String str, String with) {
0140: return str.substring(
0141: 0,
0142: (with.length() > str.length()) ? str.length() : with
0143: .length()).equalsIgnoreCase(with);
0144: }
0145:
0146: /**
0147: *
0148: *
0149: * @param nfspath
0150: *
0151: * @return
0152: *
0153: * @throws FileNotFoundException
0154: */
0155: public static String translateNFSPath(String nfspath)
0156: throws FileNotFoundException {
0157: nfspath = nfspath.replace('\\', '/');
0158:
0159: // ./ means home
0160: if (nfspath.startsWith("./")) {
0161: nfspath = nfspath.substring(2);
0162: }
0163:
0164: //if (startsWithIgnoreCase(nfspath, nfshome)) {
0165: try {
0166: String nfshome = getNFSHomeDirectory().replace('\\', '/');
0167: nfshome = translateCanonicalPath(nfshome, nfshome);
0168:
0169: String vfshome = getVFSHomeDirectory(SshThread
0170: .getCurrentThreadUser());
0171:
0172: // First check for the userhome
0173: log.debug("NFSPath=" + nfspath);
0174: log.debug("NFSHome=" + nfshome);
0175: nfspath = translateCanonicalPath(nfspath, nfshome);
0176:
0177: int idx = nfspath.indexOf(nfshome);
0178:
0179: return vfshome + nfspath.substring(nfshome.length());
0180:
0181: // StringBuffer buf = new StringBuffer(nfspath);
0182: // buf = buf.replace(idx, idx + nfshome.length(), vfshome);
0183: // return buf.toString(); /*nfspath.replaceFirst(nfshome, vfshome);*/
0184: //}
0185: } catch (FileNotFoundException ex) { /* Ignore as we will try other mounts */
0186: }
0187:
0188: // Now lets translate from the available mounts
0189: Iterator it = vfsmounts.entrySet().iterator();
0190: Map.Entry entry;
0191: String mount;
0192: String path;
0193: VFSMount m;
0194:
0195: while (it.hasNext()) {
0196: entry = (Map.Entry) it.next();
0197: mount = (String) entry.getKey();
0198: m = (VFSMount) entry.getValue();
0199: path = m.getPath();
0200: log.debug(m.getMount() + "=" + m.getPath());
0201:
0202: // if (startsWithIgnoreCase(nfspath, path)) {
0203: try {
0204: nfspath = translateCanonicalPath(nfspath, path);
0205:
0206: int idx = nfspath.indexOf(path);
0207: StringBuffer buf = new StringBuffer(nfspath);
0208: buf = buf.replace(idx, idx + path.length(), mount);
0209:
0210: return buf.toString();
0211: } catch (FileNotFoundException ex) {
0212: /* Ingore as we will try other mounts */
0213: }
0214:
0215: // }
0216: }
0217:
0218: // if (startsWithIgnoreCase(nfspath, vfsroot.getPath())) {
0219: log.debug("VFSRoot=" + vfsroot.getPath());
0220: nfspath = translateCanonicalPath(nfspath, vfsroot.getPath());
0221: path = nfspath.substring(vfsroot.getPath().length()); //replaceFirst(vfsroot.getPath(), "");
0222:
0223: return (path.startsWith("/") ? path : ("/" + path));
0224:
0225: // } else {
0226: // throw new FileNotFoundException(nfspath + " could not be found");
0227: // }
0228: }
0229:
0230: private static VFSMount getMount(String vfspath)
0231: throws FileNotFoundException, IOException {
0232: String vfshome = getVFSHomeDirectory(SshThread
0233: .getCurrentThreadUser());
0234: VFSMount m;
0235:
0236: if (vfspath.startsWith("/")) {
0237: if (vfspath.startsWith(vfshome)) {
0238: m = new VFSMount(vfshome, getNFSHomeDirectory());
0239: m.setPermissions(new VFSPermission(SshThread
0240: .getCurrentThreadUser(), "rwx"));
0241:
0242: return m;
0243: } else {
0244: Iterator it = vfsmounts.entrySet().iterator();
0245: Map.Entry entry;
0246: String mount;
0247:
0248: while (it.hasNext()) {
0249: entry = (Map.Entry) it.next();
0250: mount = (String) entry.getKey();
0251:
0252: if (vfspath.startsWith(mount)) {
0253: return (VFSMount) entry.getValue();
0254: }
0255: }
0256:
0257: if (vfsroot != null) {
0258: return vfsroot;
0259: } else {
0260: throw new FileNotFoundException(
0261: "The path was not found");
0262: }
0263: }
0264: } else {
0265: m = new VFSMount(vfshome, getNFSHomeDirectory());
0266: m.setPermissions(new VFSPermission(vfshome
0267: .substring(vfshome.lastIndexOf("/")), "rwx"));
0268:
0269: return m;
0270: }
0271: }
0272:
0273: /**
0274: *
0275: *
0276: * @param vfspath
0277: *
0278: * @return
0279: *
0280: * @throws FileNotFoundException
0281: */
0282: public static String translateVFSPath(String vfspath)
0283: throws FileNotFoundException {
0284: return translateVFSPath(vfspath, null);
0285: }
0286:
0287: public static String translateVFSPath(String vfspath, String vfscwd)
0288: throws FileNotFoundException {
0289: // Translate any backslashes for sanity
0290: vfspath = vfspath.replace('\\', '/').trim();
0291:
0292: try {
0293: if (!vfspath.startsWith("/")) {
0294: // Work out the path using the current directory
0295: String path = (((vfscwd == null) || vfscwd.trim()
0296: .equals("")) ? getVFSHomeDirectory(SshThread
0297: .getCurrentThreadUser()) : vfscwd);
0298: vfspath = path + (path.endsWith("/") ? "" : "/")
0299: + vfspath;
0300: }
0301:
0302: String nfshome = getNFSHomeDirectory().replace('\\', '/');
0303: String vfshome = getVFSHomeDirectory(SshThread
0304: .getCurrentThreadUser());
0305:
0306: if (vfspath.startsWith(vfshome)) {
0307: // Return the canonicalized system dependent path
0308: if (vfspath.length() > vfshome.length()) {
0309: return translateCanonicalPath(nfshome
0310: + (nfshome.endsWith("/") ? "" : "/")
0311: + vfspath.substring(vfshome.length() + 1),
0312: nfshome);
0313: } else {
0314: return translateCanonicalPath(nfshome, nfshome);
0315: }
0316: }
0317: } catch (FileNotFoundException ex) {
0318: // Ignore since we dont always need to be running as a user
0319: }
0320:
0321: // The path does not refer to the absolute USER_HOME
0322: // so we will look up using the platform.xml VFS mounts
0323: Iterator it = vfsmounts.entrySet().iterator();
0324: Map.Entry entry;
0325: String mount;
0326: String path;
0327: VFSMount m;
0328:
0329: while (it.hasNext()) {
0330: entry = (Map.Entry) it.next();
0331: mount = (String) entry.getKey();
0332: m = (VFSMount) entry.getValue();
0333: path = m.getPath();
0334:
0335: if (vfspath.startsWith(mount)) {
0336: // Lets translate the path, making sure we do not move outside
0337: // vfs with ..
0338: String str = path + vfspath.substring(mount.length());
0339:
0340: // vfspath.replaceFirst(mount,
0341: // path)
0342: return translateCanonicalPath(str, path);
0343: }
0344: }
0345:
0346: // If we reached here then the VFS path did not refer to an optional mount
0347: // or the users home directory, so lets attempt to use the VFS root is there
0348: // is one defined
0349: if (vfsroot != null) {
0350: path = vfsroot.getPath()
0351: + (vfsroot.getPath().endsWith("/") ? vfspath
0352: .substring(1) : vfspath);
0353:
0354: return translateCanonicalPath(path, vfsroot.getPath());
0355: } else {
0356: throw new FileNotFoundException(
0357: "The file could not be found");
0358: }
0359: }
0360:
0361: /*else {
0362: try {
0363: String nfshome = (nfscwd == null || nfscwd.trim().equals("") ? getNFSHomeDirectory() : nfscwd);
0364: String path = nfshome + (nfshome.endsWith("/") ? "" : "/") + vfspath;
0365: return translateCanonicalPath(path, nfshome);
0366: }
0367: catch (FileNotFoundException ex1) {
0368: throw new FileNotFoundException(
0369: "Only fully qualified VFS paths can be translated outside of a user context");
0370: }
0371: /* String path = nfshome + (nfshome.endsWith("/") ? "" : "/")
0372: + vfspath;
0373: return translateCanonicalPath(path, nfshome);*/
0374:
0375: //}
0376: /**
0377: *
0378: *
0379: * @param path
0380: * @param securemount
0381: *
0382: * @return
0383: *
0384: * @throws FileNotFoundException
0385: */
0386: public static String translateCanonicalPath(String path,
0387: String securemount) throws FileNotFoundException {
0388: try {
0389: log.debug("Translating for canonical path " + path
0390: + " against secure mount " + securemount);
0391:
0392: File f = new File(path);
0393: String canonical = f.getCanonicalPath().replace('\\', '/');
0394: File f2 = new File(securemount);
0395: String canonical2 = f2.getCanonicalPath()
0396: .replace('\\', '/');
0397:
0398: // Verify that the canonical path does not exit out of the mount
0399: if (canonical.startsWith(canonical2)) {
0400: return canonical;
0401: } else {
0402: throw new FileNotFoundException(path
0403: + " could not be found");
0404: }
0405: } catch (IOException ex) {
0406: throw new FileNotFoundException(path
0407: + " could not be found");
0408: }
0409: }
0410:
0411: /**
0412: *
0413: *
0414: * @param path
0415: *
0416: * @return
0417: *
0418: * @throws PermissionDeniedException
0419: * @throws FileNotFoundException
0420: * @throws IOException
0421: */
0422: public boolean makeDirectory(String path)
0423: throws PermissionDeniedException, FileNotFoundException,
0424: IOException {
0425: // String realPath = path;
0426: path = VirtualFileSystem.translateVFSPath(path);
0427:
0428: File f = new File(path);
0429: verifyPermissions(SshThread.getCurrentThreadUser(), path, "rw");
0430: log.debug("Creating directory " + f.getAbsolutePath());
0431:
0432: return f.mkdir();
0433: }
0434:
0435: /**
0436: *
0437: *
0438: * @param path
0439: *
0440: * @return
0441: *
0442: * @throws FileNotFoundException
0443: * @throws IOException
0444: */
0445: public VFSPermission getVFSPermission(String path)
0446: throws FileNotFoundException, IOException {
0447: VFSMount mount = getMount(translateNFSPath(path));
0448:
0449: if (mount.getPermissions().containsKey(
0450: SshThread.getCurrentThreadUser())) {
0451: return (VFSPermission) mount.getPermissions().get(
0452: SshThread.getCurrentThreadUser());
0453: } else {
0454: return (VFSPermission) mount.getPermissions()
0455: .get("default");
0456: }
0457: }
0458:
0459: /**
0460: *
0461: *
0462: * @param handle
0463: *
0464: * @return
0465: *
0466: * @throws IOException
0467: * @throws InvalidHandleException
0468: */
0469: public FileAttributes getFileAttributes(byte[] handle)
0470: throws IOException, InvalidHandleException {
0471: String shandle = new String(handle);
0472:
0473: if (openFiles.containsKey(shandle)) {
0474: Object obj = openFiles.get(shandle);
0475: File f;
0476:
0477: if (obj instanceof OpenFile) {
0478: f = ((OpenFile) obj).getFile();
0479: } else if (obj instanceof OpenDirectory) {
0480: f = ((OpenDirectory) obj).getFile();
0481: } else {
0482: throw new IOException("Unexpected open file handle");
0483: }
0484:
0485: VFSPermission permissions = getVFSPermission(f
0486: .getAbsolutePath());
0487:
0488: if (permissions == null) {
0489: throw new IOException("No default permissions set");
0490: }
0491:
0492: FileAttributes attrs = new FileAttributes();
0493: attrs.setSize(new UnsignedInteger64(String.valueOf(f
0494: .length())));
0495: attrs.setTimes(new UnsignedInteger32(
0496: f.lastModified() / 1000), new UnsignedInteger32(f
0497: .lastModified() / 1000));
0498:
0499: boolean canExec = true;
0500:
0501: try {
0502: if (System.getSecurityManager() != null) {
0503: System.getSecurityManager().checkExec(
0504: f.getCanonicalPath());
0505: }
0506: } catch (SecurityException ex1) {
0507: canExec = false;
0508: }
0509:
0510: attrs.setPermissions((((f.canRead() && permissions
0511: .canRead()) ? "r" : "-")
0512: + ((f.canWrite() && permissions.canWrite()) ? "w"
0513: : "-") + ((canExec && permissions
0514: .canExecute()) ? "x" : "-")));
0515: attrs.setPermissions(new UnsignedInteger32(attrs
0516: .getPermissions().longValue()
0517: | (f.isDirectory() ? FileAttributes.S_IFDIR
0518: : FileAttributes.S_IFREG)));
0519:
0520: return attrs;
0521: } else {
0522: throw new InvalidHandleException("The handle is invalid");
0523: }
0524: }
0525:
0526: /**
0527: *
0528: *
0529: * @param path
0530: *
0531: * @return
0532: *
0533: * @throws IOException
0534: * @throws FileNotFoundException
0535: */
0536: public FileAttributes getFileAttributes(String path)
0537: throws IOException, FileNotFoundException {
0538: log.debug("Getting file attributes for " + path);
0539: path = translateVFSPath(path);
0540:
0541: // Look up the VFS mount attributes
0542: File f = new File(path);
0543: path = f.getCanonicalPath();
0544:
0545: if (!f.exists()) {
0546: throw new FileNotFoundException(path + " doesn't exist");
0547: }
0548:
0549: VFSPermission permissions = getVFSPermission(path);
0550:
0551: if (permissions == null) {
0552: throw new IOException("No default permissions set");
0553: }
0554:
0555: FileAttributes attrs = new FileAttributes();
0556: attrs
0557: .setSize(new UnsignedInteger64(String.valueOf(f
0558: .length())));
0559: attrs.setTimes(new UnsignedInteger32(f.lastModified() / 1000),
0560: new UnsignedInteger32(f.lastModified() / 1000));
0561:
0562: boolean canExec = true;
0563:
0564: try {
0565: if (System.getSecurityManager() != null) {
0566: System.getSecurityManager().checkExec(
0567: f.getCanonicalPath());
0568: }
0569: } catch (SecurityException ex1) {
0570: canExec = false;
0571: }
0572:
0573: attrs
0574: .setPermissions((((f.canRead() && permissions.canRead()) ? "r"
0575: : "-")
0576: + ((f.canWrite() && permissions.canWrite()) ? "w"
0577: : "-") + ((canExec && permissions
0578: .canExecute()) ? "x" : "-")));
0579: attrs.setPermissions(new UnsignedInteger32(attrs
0580: .getPermissions().longValue()
0581: | (f.isDirectory() ? FileAttributes.S_IFDIR
0582: : FileAttributes.S_IFREG)));
0583:
0584: return attrs;
0585: }
0586:
0587: /**
0588: *
0589: *
0590: * @param path
0591: *
0592: * @return
0593: *
0594: * @throws PermissionDeniedException
0595: * @throws FileNotFoundException
0596: * @throws IOException
0597: */
0598: public byte[] openDirectory(String path)
0599: throws PermissionDeniedException, FileNotFoundException,
0600: IOException {
0601: String realPath = path;
0602: path = VirtualFileSystem.translateVFSPath(path);
0603:
0604: File f = new File(path);
0605: verifyPermissions(SshThread.getCurrentThreadUser(), path, "r");
0606:
0607: if (f.exists()) {
0608: if (f.isDirectory()) {
0609: openFiles.put(f.toString(), new OpenDirectory(realPath,
0610: path, f));
0611:
0612: return f.toString().getBytes("US-ASCII");
0613: } else {
0614: throw new IOException(translateNFSPath(path)
0615: + " is not a directory");
0616: }
0617: } else {
0618: throw new FileNotFoundException(translateNFSPath(path)
0619: + " does not exist");
0620: }
0621: }
0622:
0623: /**
0624: *
0625: *
0626: * @param handle
0627: *
0628: * @return
0629: *
0630: * @throws InvalidHandleException
0631: * @throws EOFException
0632: * @throws IOException
0633: */
0634: public SftpFile[] readDirectory(byte[] handle)
0635: throws InvalidHandleException, EOFException, IOException {
0636: String shandle = new String(handle);
0637:
0638: if (openFiles.containsKey(shandle)) {
0639: Object obj = openFiles.get(shandle);
0640:
0641: if (obj instanceof OpenDirectory) {
0642: OpenDirectory dir = (OpenDirectory) obj;
0643: int pos = dir.getPosition();
0644: File[] children = dir.getChildren();
0645:
0646: if (children == null) {
0647: throw new IOException("Permission denined.");
0648: }
0649:
0650: int count = ((children.length - pos) < 100) ? (children.length - pos)
0651: : 100;
0652:
0653: if (count > 0) {
0654: SftpFile[] files = new SftpFile[count];
0655:
0656: for (int i = 0; i < files.length; i++) {
0657: File f = children[pos + i];
0658: String absolutePath = dir.realPath + "/"
0659: + f.getName();
0660: SftpFile sftpfile = new SftpFile(f.getName(),
0661: getFileAttributes(absolutePath));
0662: files[i] = sftpfile;
0663: }
0664:
0665: dir.readpos = pos + files.length;
0666:
0667: return files;
0668: } else {
0669: throw new EOFException("There are no more files");
0670: }
0671: } else {
0672: throw new InvalidHandleException(
0673: "Handle is not an open directory");
0674: }
0675: } else {
0676: throw new InvalidHandleException("The handle is invalid");
0677: }
0678: }
0679:
0680: /**
0681: *
0682: *
0683: * @param path
0684: * @param flags
0685: * @param attrs
0686: *
0687: * @return
0688: *
0689: * @throws PermissionDeniedException
0690: * @throws FileNotFoundException
0691: * @throws IOException
0692: */
0693: public byte[] openFile(String path, UnsignedInteger32 flags,
0694: FileAttributes attrs) throws PermissionDeniedException,
0695: FileNotFoundException, IOException {
0696: path = VirtualFileSystem.translateVFSPath(path);
0697:
0698: File f = new File(path);
0699: verifyPermissions(SshThread.getCurrentThreadUser(), path, "r");
0700:
0701: // Check if the file does not exist and process according to flags
0702: if (!f.exists()) {
0703: if ((flags.intValue() & NativeFileSystemProvider.OPEN_CREATE) == NativeFileSystemProvider.OPEN_CREATE) {
0704: // The file does not exist and the create flag is present so lets create it
0705: if (!f.createNewFile()) {
0706: throw new IOException(translateNFSPath(path)
0707: + " could not be created");
0708: }
0709: } else {
0710: // The file does not exist and no create flag present
0711: throw new FileNotFoundException(translateNFSPath(path)
0712: + " does not exist");
0713: }
0714: } else {
0715: if (((flags.intValue() & NativeFileSystemProvider.OPEN_CREATE) == NativeFileSystemProvider.OPEN_CREATE)
0716: && ((flags.intValue() & NativeFileSystemProvider.OPEN_EXCLUSIVE) == NativeFileSystemProvider.OPEN_EXCLUSIVE)) {
0717: // The file exists but the EXCL flag is set which requires that the
0718: // file should not exist prior to creation, so throw a status exception
0719: throw new IOException(translateNFSPath(path)
0720: + " already exists");
0721: }
0722: }
0723:
0724: // The file now exists so open the file according to the flags yb building the relevant
0725: // flags for the RandomAccessFile class
0726: String mode = "r"
0727: + (((flags.intValue() & NativeFileSystemProvider.OPEN_WRITE) == NativeFileSystemProvider.OPEN_WRITE) ? "ws"
0728: : "");
0729: RandomAccessFile raf = new RandomAccessFile(f, mode);
0730:
0731: // Determine whether we need to truncate the file
0732: if (((flags.intValue() & NativeFileSystemProvider.OPEN_CREATE) == NativeFileSystemProvider.OPEN_CREATE)
0733: && ((flags.intValue() & NativeFileSystemProvider.OPEN_TRUNCATE) == NativeFileSystemProvider.OPEN_TRUNCATE)) {
0734: // Set the length to zero
0735: raf.setLength(0);
0736: }
0737:
0738: // Record the open file
0739: openFiles.put(raf.toString(), new OpenFile(f, raf, flags));
0740:
0741: // Return the handle
0742: return raf.toString().getBytes("US-ASCII");
0743: }
0744:
0745: /**
0746: *
0747: *
0748: * @param handle
0749: * @param offset
0750: * @param len
0751: *
0752: * @return
0753: *
0754: * @throws InvalidHandleException
0755: * @throws EOFException
0756: * @throws IOException
0757: */
0758: public byte[] readFile(byte[] handle, UnsignedInteger64 offset,
0759: UnsignedInteger32 len) throws InvalidHandleException,
0760: EOFException, IOException {
0761: String shandle = new String(handle);
0762:
0763: if (openFiles.containsKey(shandle)) {
0764: Object obj = openFiles.get(shandle);
0765:
0766: if (obj instanceof OpenFile) {
0767: OpenFile file = (OpenFile) obj;
0768:
0769: if ((file.getFlags().intValue() & NativeFileSystemProvider.OPEN_READ) == NativeFileSystemProvider.OPEN_READ) {
0770: byte[] buf = new byte[len.intValue()];
0771:
0772: if (file.getRandomAccessFile().getFilePointer() != offset
0773: .longValue()) {
0774: file.getRandomAccessFile().seek(
0775: offset.longValue());
0776: }
0777:
0778: int read = file.getRandomAccessFile().read(buf);
0779:
0780: if (read >= 0) {
0781: if (read == buf.length) {
0782: return buf;
0783: } else {
0784: byte[] tmp = new byte[read];
0785: System.arraycopy(buf, 0, tmp, 0, read);
0786:
0787: return tmp;
0788: }
0789: } else {
0790: throw new EOFException("The file is EOF");
0791: }
0792: } else {
0793: throw new InvalidHandleException(
0794: "The file handle was not opened for reading");
0795: }
0796: } else {
0797: throw new InvalidHandleException(
0798: "Handle is not an open file");
0799: }
0800: } else {
0801: throw new InvalidHandleException("The handle is invalid");
0802: }
0803: }
0804:
0805: /**
0806: *
0807: *
0808: * @param handle
0809: * @param offset
0810: * @param data
0811: * @param off
0812: * @param len
0813: *
0814: * @throws InvalidHandleException
0815: * @throws IOException
0816: */
0817: public void writeFile(byte[] handle, UnsignedInteger64 offset,
0818: byte[] data, int off, int len)
0819: throws InvalidHandleException, IOException {
0820: String shandle = new String(handle);
0821:
0822: if (openFiles.containsKey(shandle)) {
0823: Object obj = openFiles.get(shandle);
0824:
0825: if (obj instanceof OpenFile) {
0826: OpenFile file = (OpenFile) obj;
0827:
0828: if ((file.getFlags().intValue() & NativeFileSystemProvider.OPEN_WRITE) == NativeFileSystemProvider.OPEN_WRITE) {
0829: if ((file.getFlags().intValue() & NativeFileSystemProvider.OPEN_APPEND) == NativeFileSystemProvider.OPEN_APPEND) {
0830: // Force the data to be written to the end of the file by seeking to the end
0831: file.getRandomAccessFile().seek(
0832: file.getRandomAccessFile().length());
0833: } else if (file.getRandomAccessFile()
0834: .getFilePointer() != offset.longValue()) {
0835: // Move the file pointer if its not in the write place
0836: file.getRandomAccessFile().seek(
0837: offset.longValue());
0838: }
0839:
0840: file.getRandomAccessFile().write(data, off, len);
0841: } else {
0842: throw new InvalidHandleException(
0843: "The file was not opened for writing");
0844: }
0845: } else {
0846: throw new InvalidHandleException(
0847: "Handle is not an open file");
0848: }
0849: } else {
0850: throw new InvalidHandleException("The handle is invalid");
0851: }
0852: }
0853:
0854: /**
0855: *
0856: *
0857: * @param handle
0858: *
0859: * @throws InvalidHandleException
0860: * @throws IOException
0861: */
0862: public void closeFile(byte[] handle) throws InvalidHandleException,
0863: IOException {
0864: String shandle = new String(handle);
0865:
0866: if (openFiles.containsKey(shandle)) {
0867: Object obj = openFiles.get(shandle);
0868:
0869: if (obj instanceof OpenDirectory) {
0870: openFiles.remove(shandle);
0871: } else if (obj instanceof OpenFile) {
0872: ((OpenFile) obj).getRandomAccessFile().close();
0873: openFiles.remove(shandle);
0874: } else {
0875: throw new InvalidHandleException(
0876: "Internal server error");
0877: }
0878: } else {
0879: throw new InvalidHandleException("The handle is invalid");
0880: }
0881: }
0882:
0883: /**
0884: *
0885: *
0886: * @param path
0887: *
0888: * @throws PermissionDeniedException
0889: * @throws IOException
0890: * @throws FileNotFoundException
0891: */
0892: public void removeFile(String path)
0893: throws PermissionDeniedException, IOException,
0894: FileNotFoundException {
0895: path = VirtualFileSystem.translateVFSPath(path);
0896:
0897: File f = new File(path);
0898:
0899: if (f.exists()) {
0900: try {
0901: if (f.isFile()) {
0902: if (!f.delete()) {
0903: throw new IOException("Failed to delete "
0904: + translateNFSPath(path));
0905: }
0906: } else {
0907: throw new IOException(
0908: translateNFSPath(path)
0909: + " is a directory, use remove directory command to remove");
0910: }
0911: } catch (SecurityException se) {
0912: throw new PermissionDeniedException("Permission denied");
0913: }
0914: } else {
0915: throw new FileNotFoundException(translateNFSPath(path)
0916: + " does not exist");
0917: }
0918: }
0919:
0920: /**
0921: *
0922: *
0923: * @param oldpath
0924: * @param newpath
0925: *
0926: * @throws PermissionDeniedException
0927: * @throws FileNotFoundException
0928: * @throws IOException
0929: */
0930: public void renameFile(String oldpath, String newpath)
0931: throws PermissionDeniedException, FileNotFoundException,
0932: IOException {
0933: oldpath = VirtualFileSystem.translateVFSPath(oldpath);
0934: newpath = VirtualFileSystem.translateVFSPath(newpath);
0935:
0936: File f = new File(oldpath);
0937: verifyPermissions(SshThread.getCurrentThreadUser(), oldpath,
0938: "rw");
0939: verifyPermissions(SshThread.getCurrentThreadUser(), newpath,
0940: "rw");
0941:
0942: if (f.exists()) {
0943: File f2 = new File(newpath);
0944:
0945: if (!f2.exists()) {
0946: if (!f.renameTo(f2)) {
0947: throw new IOException("Failed to rename file "
0948: + translateNFSPath(oldpath));
0949: }
0950: } else {
0951: throw new IOException(translateNFSPath(newpath)
0952: + " already exists");
0953: }
0954: } else {
0955: throw new FileNotFoundException(translateNFSPath(oldpath)
0956: + " does not exist");
0957: }
0958: }
0959:
0960: /**
0961: *
0962: *
0963: * @param path
0964: *
0965: * @throws PermissionDeniedException
0966: * @throws FileNotFoundException
0967: * @throws IOException
0968: */
0969: public void removeDirectory(String path)
0970: throws PermissionDeniedException, FileNotFoundException,
0971: IOException {
0972: path = VirtualFileSystem.translateVFSPath(path);
0973:
0974: File f = new File(path);
0975: verifyPermissions(SshThread.getCurrentThreadUser(), path, "rw");
0976:
0977: if (f.isDirectory()) {
0978: if (f.exists()) {
0979: if (f.listFiles().length == 0) {
0980: if (!f.delete()) {
0981: throw new IOException(
0982: "Failed to remove directory "
0983: + translateNFSPath(path));
0984: }
0985: } else {
0986: throw new IOException(translateNFSPath(path)
0987: + " is not an empty directory");
0988: }
0989: } else {
0990: throw new FileNotFoundException(translateNFSPath(path)
0991: + " does not exist");
0992: }
0993: } else {
0994: throw new IOException(translateNFSPath(path)
0995: + " is not a directory");
0996: }
0997: }
0998:
0999: /**
1000: *
1001: *
1002: * @param path
1003: * @param attrs
1004: *
1005: * @throws PermissionDeniedException
1006: * @throws IOException
1007: * @throws FileNotFoundException
1008: */
1009: public void setFileAttributes(String path, FileAttributes attrs)
1010: throws PermissionDeniedException, IOException,
1011: FileNotFoundException {
1012: // Since we cannot really set permissions, this should be ignored as we
1013: // do not want applications to fail.
1014:
1015: /*String realPath = VirtualFileSystem.translateVFSPath(path);
1016: throw new PermissionDeniedException(
1017: "Cannot set file attributes using virtual file system for file "
1018: + realPath);*/
1019: }
1020:
1021: /**
1022: *
1023: *
1024: * @param handle
1025: * @param attrs
1026: *
1027: * @throws PermissionDeniedException
1028: * @throws IOException
1029: * @throws InvalidHandleException
1030: */
1031: public void setFileAttributes(byte[] handle, FileAttributes attrs)
1032: throws PermissionDeniedException, IOException,
1033: InvalidHandleException {
1034: }
1035:
1036: /**
1037: *
1038: *
1039: * @param path
1040: *
1041: * @return
1042: *
1043: * @throws UnsupportedFileOperationException
1044: * @throws FileNotFoundException
1045: * @throws IOException
1046: * @throws PermissionDeniedException
1047: */
1048: public SftpFile readSymbolicLink(String path)
1049: throws UnsupportedFileOperationException,
1050: FileNotFoundException, IOException,
1051: PermissionDeniedException {
1052: throw new UnsupportedFileOperationException(
1053: "Symbolic links are not supported by the Virtual File System");
1054: }
1055:
1056: /**
1057: *
1058: *
1059: * @param link
1060: * @param target
1061: *
1062: * @throws UnsupportedFileOperationException
1063: * @throws FileNotFoundException
1064: * @throws IOException
1065: * @throws PermissionDeniedException
1066: */
1067: public void createSymbolicLink(String link, String target)
1068: throws UnsupportedFileOperationException,
1069: FileNotFoundException, IOException,
1070: PermissionDeniedException {
1071: throw new UnsupportedFileOperationException(
1072: "Symbolic links are not supported by the Virtual File System");
1073: }
1074:
1075: /**
1076: *
1077: *
1078: * @param path
1079: *
1080: * @return
1081: *
1082: * @throws IOException
1083: */
1084: public boolean fileExists(String path) throws IOException {
1085: File f = new File(VirtualFileSystem.translateVFSPath(path));
1086:
1087: return f.exists();
1088: }
1089:
1090: public String getDefaultPath(String username)
1091: throws FileNotFoundException {
1092: return getVFSHomeDirectory(username);
1093: }
1094:
1095: /**
1096: *
1097: *
1098: * @param path
1099: *
1100: * @return
1101: *
1102: * @throws IOException
1103: * @throws FileNotFoundException
1104: */
1105: public String getCanonicalPath(String path) throws IOException,
1106: FileNotFoundException {
1107: File f = new File(VirtualFileSystem.translateVFSPath(path));
1108:
1109: return f.getCanonicalPath();
1110: }
1111:
1112: /**
1113: *
1114: *
1115: * @param path
1116: *
1117: * @return
1118: *
1119: * @throws FileNotFoundException
1120: */
1121: public String getRealPath(String path) throws FileNotFoundException {
1122: log.debug("Get real path for '" + path + "'");
1123: path = VirtualFileSystem.translateVFSPath(path);
1124: log.debug("Translated VFS is '" + path + "'");
1125: path = VirtualFileSystem.translateNFSPath(path);
1126: log.debug("Translated NFS is '" + path + "'");
1127:
1128: return path;
1129: }
1130:
1131: /**
1132: *
1133: *
1134: * @param username
1135: * @param path
1136: * @param permissions
1137: *
1138: * @throws PermissionDeniedException
1139: * @throws FileNotFoundException
1140: * @throws IOException
1141: */
1142: public void verifyPermissions(String username, String path,
1143: String permissions) throws PermissionDeniedException,
1144: FileNotFoundException, IOException {
1145: String vfspath = translateNFSPath(path);
1146:
1147: if (permissionHandler == null) {
1148: VFSMount mount = getMount(vfspath);
1149: VFSPermission perm;
1150:
1151: if (mount.getPermissions().containsKey(
1152: SshThread.getCurrentThreadUser())) {
1153: perm = (VFSPermission) mount.getPermissions().get(
1154: SshThread.getCurrentThreadUser());
1155: } else if (mount.getPermissions().containsKey("default")) {
1156: perm = (VFSPermission) mount.getPermissions().get(
1157: "default");
1158: } else {
1159: throw new PermissionDeniedException(
1160: "No permissions set for mount");
1161: }
1162:
1163: if (!perm.verifyPermissions(permissions)) {
1164: throw new PermissionDeniedException(
1165: "Permission denied for "
1166: + translateNFSPath(path));
1167: }
1168: } else {
1169: permissionHandler.verifyPermissions(username, path,
1170: permissions);
1171: }
1172: }
1173:
1174: class OpenFile {
1175: File f;
1176: RandomAccessFile raf;
1177: UnsignedInteger32 flags;
1178:
1179: public OpenFile(File f, RandomAccessFile raf,
1180: UnsignedInteger32 flags) {
1181: this .f = f;
1182: this .raf = raf;
1183: this .flags = flags;
1184: }
1185:
1186: public File getFile() {
1187: return f;
1188: }
1189:
1190: public RandomAccessFile getRandomAccessFile() {
1191: return raf;
1192: }
1193:
1194: public UnsignedInteger32 getFlags() {
1195: return flags;
1196: }
1197: }
1198:
1199: class OpenDirectory {
1200: File f;
1201: File[] children;
1202: int readpos = 0;
1203: String path;
1204: String realPath;
1205:
1206: public OpenDirectory(String realPath, String path, File f) {
1207: this .path = path;
1208: this .realPath = realPath;
1209: this .f = f;
1210: this .children = f.listFiles();
1211: }
1212:
1213: public File getFile() {
1214: return f;
1215: }
1216:
1217: public File[] getChildren() {
1218: return children;
1219: }
1220:
1221: public int getPosition() {
1222: return readpos;
1223: }
1224:
1225: public void setPosition(int readpos) {
1226: this.readpos = readpos;
1227: }
1228: }
1229: }
|