1 /*
2 * SSHTools - Java SSH2 API
3 *
4 * Copyright (C) 2002-2003 Lee David Painter and Contributors.
5 *
6 * Contributions made by:
7 *
8 * Brett Smith
9 * Richard Pernavas
10 * Erwin Bolwidt
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 */
26 package com.sshtools.daemon.vfs;
27
28 import com.sshtools.daemon.configuration.PlatformConfiguration;
29 import com.sshtools.daemon.platform.InvalidHandleException;
30 import com.sshtools.daemon.platform.NativeAuthenticationProvider;
31 import com.sshtools.daemon.platform.NativeFileSystemProvider;
32 import com.sshtools.daemon.platform.PermissionDeniedException;
33 import com.sshtools.daemon.platform.UnsupportedFileOperationException;
34
35 import com.sshtools.j2ssh.SshThread;
36 import com.sshtools.j2ssh.configuration.ConfigurationException;
37 import com.sshtools.j2ssh.configuration.ConfigurationLoader;
38 import com.sshtools.j2ssh.io.UnsignedInteger32;
39 import com.sshtools.j2ssh.io.UnsignedInteger64;
40 import com.sshtools.j2ssh.sftp.FileAttributes;
41 import com.sshtools.j2ssh.sftp.SftpFile;
42
43 import org.apache.commons.logging.Log;
44 import org.apache.commons.logging.LogFactory;
45
46 import java.io.EOFException;
47 import java.io.File;
48 import java.io.FileNotFoundException;
49 import java.io.IOException;
50 import java.io.RandomAccessFile;
51
52 import java.util.HashMap;
53 import java.util.Iterator;
54 import java.util.Map;
55
56
57 /**
58 *
59 *
60 * @author $author$
61 * @version $Revision: 1.32 $
62 */
63 public class VirtualFileSystem extends NativeFileSystemProvider {
64 private static String USER_HOME = "/home/";
65 private static Map vfsmounts;
66 private static VFSMount vfsroot;
67 private static Log log = LogFactory.getLog(VirtualFileSystem.class);
68 private static VFSPermissionHandler permissionHandler = null;
69
70 static {
71 try {
72 vfsmounts = ((PlatformConfiguration) ConfigurationLoader.getConfiguration(PlatformConfiguration.class)).getVFSMounts();
73 vfsroot = ((PlatformConfiguration) ConfigurationLoader.getConfiguration(PlatformConfiguration.class)).getVFSRoot();
74 } catch (ConfigurationException ex) {
75 log.error("Failed to initialize the Virtual File System", ex);
76 }
77 }
78
79 private Map openFiles = new HashMap();
80
81 /**
82 * Creates a new VirtualFileSystem object.
83 *
84 * @throws IOException
85 */
86 public VirtualFileSystem() throws IOException {
87 if (!ConfigurationLoader.isConfigurationAvailable(
88 PlatformConfiguration.class)) {
89 throw new IOException("No valid platform configuration available");
90 }
91 }
92
93 public static void setPermissionHandler(
94 VFSPermissionHandler permissionHandler) {
95 VirtualFileSystem.permissionHandler = permissionHandler;
96 }
97
98 private static String getVFSHomeDirectory(String username)
99 throws FileNotFoundException {
100 if (permissionHandler != null) {
101 return permissionHandler.getVFSHomeDirectory(username);
102 } else {
103 return USER_HOME + username;
104 }
105 }
106
107 private static String getNFSHomeDirectory() throws FileNotFoundException {
108 try {
109 if (Thread.currentThread() instanceof SshThread &&
110 SshThread.hasUserContext()) {
111 NativeAuthenticationProvider nap = NativeAuthenticationProvider.getInstance();
112
113 return nap.getHomeDirectory(SshThread.getCurrentThreadUser());
114 } else {
115 throw new FileNotFoundException("There is no user logged in");
116 }
117 } catch (IOException e) {
118 throw new FileNotFoundException(e.getMessage());
119 }
120 }
121
122 /**
123 *
124 *
125 * @param str
126 * @param with
127 *
128 * @return
129 */
130 public static boolean startsWithIgnoreCase(String str, String with) {
131 return str.substring(0,
132 (with.length() > str.length()) ? str.length() : with.length())
133 .equalsIgnoreCase(with);
134 }
135
136 /**
137 *
138 *
139 * @param nfspath
140 *
141 * @return
142 *
143 * @throws FileNotFoundException
144 */
145 public static String translateNFSPath(String nfspath)
146 throws FileNotFoundException {
147 nfspath = nfspath.replace('\\', '/');
148
149 // ./ means home
150 if (nfspath.startsWith("./")) {
151 nfspath = nfspath.substring(2);
152 }
153
154 //if (startsWithIgnoreCase(nfspath, nfshome)) {
155 try {
156 String nfshome = getNFSHomeDirectory().replace('\\', '/');
157 nfshome = translateCanonicalPath(nfshome, nfshome);
158
159 String vfshome = getVFSHomeDirectory(SshThread.getCurrentThreadUser());
160
161 // First check for the userhome
162 log.debug("NFSPath=" + nfspath);
163 log.debug("NFSHome=" + nfshome);
164 nfspath = translateCanonicalPath(nfspath, nfshome);
165
166 int idx = nfspath.indexOf(nfshome);
167
168 return vfshome + nfspath.substring(nfshome.length());
169
170 // StringBuffer buf = new StringBuffer(nfspath);
171 // buf = buf.replace(idx, idx + nfshome.length(), vfshome);
172 // return buf.toString(); /*nfspath.replaceFirst(nfshome, vfshome);*/
173 //}
174 } catch (FileNotFoundException ex) { /* Ignore as we will try other mounts */
175 }
176
177 // Now lets translate from the available mounts
178 Iterator it = vfsmounts.entrySet().iterator();
179 Map.Entry entry;
180 String mount;
181 String path;
182 VFSMount m;
183
184 while (it.hasNext()) {
185 entry = (Map.Entry) it.next();
186 mount = (String) entry.getKey();
187 m = (VFSMount) entry.getValue();
188 path = m.getPath();
189 log.debug(m.getMount() + "=" + m.getPath());
190
191 // if (startsWithIgnoreCase(nfspath, path)) {
192 try {
193 nfspath = translateCanonicalPath(nfspath, path);
194
195 int idx = nfspath.indexOf(path);
196 StringBuffer buf = new StringBuffer(nfspath);
197 buf = buf.replace(idx, idx + path.length(), mount);
198
199 return buf.toString();
200 } catch (FileNotFoundException ex) {
201 /* Ingore as we will try other mounts */
202 }
203
204 // }
205 }
206
207 // if (startsWithIgnoreCase(nfspath, vfsroot.getPath())) {
208 log.debug("VFSRoot=" + vfsroot.getPath());
209 nfspath = translateCanonicalPath(nfspath, vfsroot.getPath());
210 path = nfspath.substring(vfsroot.getPath().length()); //replaceFirst(vfsroot.getPath(), "");
211
212 return (path.startsWith("/") ? path : ("/" + path));
213
214 // } else {
215 // throw new FileNotFoundException(nfspath + " could not be found");
216 // }
217 }
218
219 private static VFSMount getMount(String vfspath)
220 throws FileNotFoundException, IOException {
221 String vfshome = getVFSHomeDirectory(SshThread.getCurrentThreadUser());
222 VFSMount m;
223
224 if (vfspath.startsWith("/")) {
225 if (vfspath.startsWith(vfshome)) {
226 m = new VFSMount(vfshome, getNFSHomeDirectory());
227 m.setPermissions(new VFSPermission(
228 SshThread.getCurrentThreadUser(), "rwx"));
229
230 return m;
231 } else {
232 Iterator it = vfsmounts.entrySet().iterator();
233 Map.Entry entry;
234 String mount;
235
236 while (it.hasNext()) {
237 entry = (Map.Entry) it.next();
238 mount = (String) entry.getKey();
239
240 if (vfspath.startsWith(mount)) {
241 return (VFSMount) entry.getValue();
242 }
243 }
244
245 if (vfsroot != null) {
246 return vfsroot;
247 } else {
248 throw new FileNotFoundException("The path was not found");
249 }
250 }
251 } else {
252 m = new VFSMount(vfshome, getNFSHomeDirectory());
253 m.setPermissions(new VFSPermission(vfshome.substring(
254 vfshome.lastIndexOf("/")), "rwx"));
255
256 return m;
257 }
258 }
259
260 /**
261 *
262 *
263 * @param vfspath
264 *
265 * @return
266 *
267 * @throws FileNotFoundException
268 */
269 public static String translateVFSPath(String vfspath)
270 throws FileNotFoundException {
271 return translateVFSPath(vfspath, null);
272 }
273
274 public static String translateVFSPath(String vfspath, String vfscwd)
275 throws FileNotFoundException {
276 // Translate any backslashes for sanity
277 vfspath = vfspath.replace('\\', '/').trim();
278
279 try {
280 if (!vfspath.startsWith("/")) {
281 // Work out the path using the current directory
282 String path = (((vfscwd == null) || vfscwd.trim().equals(""))
283 ? getVFSHomeDirectory(SshThread.getCurrentThreadUser())
284 : vfscwd);
285 vfspath = path + (path.endsWith("/") ? "" : "/") + vfspath;
286 }
287
288 String nfshome = getNFSHomeDirectory().replace('\\', '/');
289 String vfshome = getVFSHomeDirectory(SshThread.getCurrentThreadUser());
290
291 if (vfspath.startsWith(vfshome)) {
292 // Return the canonicalized system dependent path
293 if (vfspath.length() > vfshome.length()) {
294 return translateCanonicalPath(nfshome +
295 (nfshome.endsWith("/") ? "" : "/") +
296 vfspath.substring(vfshome.length() + 1), nfshome);
297 } else {
298 return translateCanonicalPath(nfshome, nfshome);
299 }
300 }
301 } catch (FileNotFoundException ex) {
302 // Ignore since we dont always need to be running as a user
303 }
304
305 // The path does not refer to the absolute USER_HOME
306 // so we will look up using the platform.xml VFS mounts
307 Iterator it = vfsmounts.entrySet().iterator();
308 Map.Entry entry;
309 String mount;
310 String path;
311 VFSMount m;
312
313 while (it.hasNext()) {
314 entry = (Map.Entry) it.next();
315 mount = (String) entry.getKey();
316 m = (VFSMount) entry.getValue();
317 path = m.getPath();
318
319 if (vfspath.startsWith(mount)) {
320 // Lets translate the path, making sure we do not move outside
321 // vfs with ..
322 String str = path + vfspath.substring(mount.length());
323
324 // vfspath.replaceFirst(mount,
325 // path)
326 return translateCanonicalPath(str, path);
327 }
328 }
329
330 // If we reached here then the VFS path did not refer to an optional mount
331 // or the users home directory, so lets attempt to use the VFS root is there
332 // is one defined
333 if (vfsroot != null) {
334 path = vfsroot.getPath() +
335 (vfsroot.getPath().endsWith("/") ? vfspath.substring(1) : vfspath);
336
337 return translateCanonicalPath(path, vfsroot.getPath());
338 } else {
339 throw new FileNotFoundException("The file could not be found");
340 }
341 }
342
343 /*else {
344 try {
345 String nfshome = (nfscwd == null || nfscwd.trim().equals("") ? getNFSHomeDirectory() : nfscwd);
346 String path = nfshome + (nfshome.endsWith("/") ? "" : "/") + vfspath;
347 return translateCanonicalPath(path, nfshome);
348 }
349 catch (FileNotFoundException ex1) {
350 throw new FileNotFoundException(
351 "Only fully qualified VFS paths can be translated outside of a user context");
352 }
353 /* String path = nfshome + (nfshome.endsWith("/") ? "" : "/")
354 + vfspath;
355 return translateCanonicalPath(path, nfshome);*/
356
357 //}
358
359 /**
360 *
361 *
362 * @param path
363 * @param securemount
364 *
365 * @return
366 *
367 * @throws FileNotFoundException
368 */
369 public static String translateCanonicalPath(String path, String securemount)
370 throws FileNotFoundException {
371 try {
372 log.debug("Translating for canonical path " + path +
373 " against secure mount " + securemount);
374
375 File f = new File(path);
376 String canonical = f.getCanonicalPath().replace('\\', '/');
377 File f2 = new File(securemount);
378 String canonical2 = f2.getCanonicalPath().replace('\\', '/');
379
380 // Verify that the canonical path does not exit out of the mount
381 if (canonical.startsWith(canonical2)) {
382 return canonical;
383 } else {
384 throw new FileNotFoundException(path + " could not be found");
385 }
386 } catch (IOException ex) {
387 throw new FileNotFoundException(path + " could not be found");
388 }
389 }
390
391 /**
392 *
393 *
394 * @param path
395 *
396 * @return
397 *
398 * @throws PermissionDeniedException
399 * @throws FileNotFoundException
400 * @throws IOException
401 */
402 public boolean makeDirectory(String path)
403 throws PermissionDeniedException, FileNotFoundException, IOException {
404 // String realPath = path;
405 path = VirtualFileSystem.translateVFSPath(path);
406
407 File f = new File(path);
408 verifyPermissions(SshThread.getCurrentThreadUser(), path, "rw");
409 log.debug("Creating directory " + f.getAbsolutePath());
410
411 return f.mkdir();
412 }
413
414 /**
415 *
416 *
417 * @param path
418 *
419 * @return
420 *
421 * @throws FileNotFoundException
422 * @throws IOException
423 */
424 public VFSPermission getVFSPermission(String path)
425 throws FileNotFoundException, IOException {
426 VFSMount mount = getMount(translateNFSPath(path));
427
428 if (mount.getPermissions().containsKey(SshThread.getCurrentThreadUser())) {
429 return (VFSPermission) mount.getPermissions().get(SshThread.getCurrentThreadUser());
430 } else {
431 return (VFSPermission) mount.getPermissions().get("default");
432 }
433 }
434
435 /**
436 *
437 *
438 * @param handle
439 *
440 * @return
441 *
442 * @throws IOException
443 * @throws InvalidHandleException
444 */
445 public FileAttributes getFileAttributes(byte[] handle)
446 throws IOException, InvalidHandleException {
447 String shandle = new String(handle);
448
449 if (openFiles.containsKey(shandle)) {
450 Object obj = openFiles.get(shandle);
451 File f;
452
453 if (obj instanceof OpenFile) {
454 f = ((OpenFile) obj).getFile();
455 } else if (obj instanceof OpenDirectory) {
456 f = ((OpenDirectory) obj).getFile();
457 } else {
458 throw new IOException("Unexpected open file handle");
459 }
460
461 VFSPermission permissions = getVFSPermission(f.getAbsolutePath());
462
463 if (permissions == null) {
464 throw new IOException("No default permissions set");
465 }
466
467 FileAttributes attrs = new FileAttributes();
468 attrs.setSize(new UnsignedInteger64(String.valueOf(f.length())));
469 attrs.setTimes(new UnsignedInteger32(f.lastModified() / 1000),
470 new UnsignedInteger32(f.lastModified() / 1000));
471
472 boolean canExec = true;
473
474 try {
475 if (System.getSecurityManager() != null) {
476 System.getSecurityManager().checkExec(f.getCanonicalPath());
477 }
478 } catch (SecurityException ex1) {
479 canExec = false;
480 }
481
482 attrs.setPermissions((((f.canRead() && permissions.canRead()) ? "r"
483 : "-") +
484 ((f.canWrite() && permissions.canWrite()) ? "w" : "-") +
485 ((canExec && permissions.canExecute()) ? "x" : "-")));
486 attrs.setPermissions(new UnsignedInteger32(attrs.getPermissions()
487 .longValue() |
488 (f.isDirectory() ? FileAttributes.S_IFDIR
489 : FileAttributes.S_IFREG)));
490
491 return attrs;
492 } else {
493 throw new InvalidHandleException("The handle is invalid");
494 }
495 }
496
497 /**
498 *
499 *
500 * @param path
501 *
502 * @return
503 *
504 * @throws IOException
505 * @throws FileNotFoundException
506 */
507 public FileAttributes getFileAttributes(String path)
508 throws IOException, FileNotFoundException {
509 log.debug("Getting file attributes for " + path);
510 path = translateVFSPath(path);
511
512 // Look up the VFS mount attributes
513 File f = new File(path);
514 path = f.getCanonicalPath();
515
516 if (!f.exists()) {
517 throw new FileNotFoundException(path + " doesn't exist");
518 }
519
520 VFSPermission permissions = getVFSPermission(path);
521
522 if (permissions == null) {
523 throw new IOException("No default permissions set");
524 }
525
526 FileAttributes attrs = new FileAttributes();
527 attrs.setSize(new UnsignedInteger64(String.valueOf(f.length())));
528 attrs.setTimes(new UnsignedInteger32(f.lastModified() / 1000),
529 new UnsignedInteger32(f.lastModified() / 1000));
530
531 boolean canExec = true;
532
533 try {
534 if (System.getSecurityManager() != null) {
535 System.getSecurityManager().checkExec(f.getCanonicalPath());
536 }
537 } catch (SecurityException ex1) {
538 canExec = false;
539 }
540
541 attrs.setPermissions((((f.canRead() && permissions.canRead()) ? "r" : "-") +
542 ((f.canWrite() && permissions.canWrite()) ? "w" : "-") +
543 ((canExec && permissions.canExecute()) ? "x" : "-")));
544 attrs.setPermissions(new UnsignedInteger32(attrs.getPermissions()
545 .longValue() |
546 (f.isDirectory() ? FileAttributes.S_IFDIR : FileAttributes.S_IFREG)));
547
548 return attrs;
549 }
550
551 /**
552 *
553 *
554 * @param path
555 *
556 * @return
557 *
558 * @throws PermissionDeniedException
559 * @throws FileNotFoundException
560 * @throws IOException
561 */
562 public byte[] openDirectory(String path)
563 throws PermissionDeniedException, FileNotFoundException, IOException {
564 String realPath = path;
565 path = VirtualFileSystem.translateVFSPath(path);
566
567 File f = new File(path);
568 verifyPermissions(SshThread.getCurrentThreadUser(), path, "r");
569
570 if (f.exists()) {
571 if (f.isDirectory()) {
572 openFiles.put(f.toString(), new OpenDirectory(realPath, path, f));
573
574 return f.toString().getBytes("US-ASCII");
575 } else {
576 throw new IOException(translateNFSPath(path) +
577 " is not a directory");
578 }
579 } else {
580 throw new FileNotFoundException(translateNFSPath(path) +
581 " does not exist");
582 }
583 }
584
585 /**
586 *
587 *
588 * @param handle
589 *
590 * @return
591 *
592 * @throws InvalidHandleException
593 * @throws EOFException
594 * @throws IOException
595 */
596 public SftpFile[] readDirectory(byte[] handle)
597 throws InvalidHandleException, EOFException, IOException {
598 String shandle = new String(handle);
599
600 if (openFiles.containsKey(shandle)) {
601 Object obj = openFiles.get(shandle);
602
603 if (obj instanceof OpenDirectory) {
604 OpenDirectory dir = (OpenDirectory) obj;
605 int pos = dir.getPosition();
606 File[] children = dir.getChildren();
607
608 if (children == null) {
609 throw new IOException("Permission denined.");
610 }
611
612 int count = ((children.length - pos) < 100)
613 ? (children.length - pos) : 100;
614
615 if (count > 0) {
616 SftpFile[] files = new SftpFile[count];
617
618 for (int i = 0; i < files.length; i++) {
619 File f = children[pos + i];
620 String absolutePath = dir.realPath + "/" + f.getName();
621 SftpFile sftpfile = new SftpFile(f.getName(),
622 getFileAttributes(absolutePath));
623 files[i] = sftpfile;
624 }
625
626 dir.readpos = pos + files.length;
627
628 return files;
629 } else {
630 throw new EOFException("There are no more files");
631 }
632 } else {
633 throw new InvalidHandleException(
634 "Handle is not an open directory");
635 }
636 } else {
637 throw new InvalidHandleException("The handle is invalid");
638 }
639 }
640
641 /**
642 *
643 *
644 * @param path
645 * @param flags
646 * @param attrs
647 *
648 * @return
649 *
650 * @throws PermissionDeniedException
651 * @throws FileNotFoundException
652 * @throws IOException
653 */
654 public byte[] openFile(String path, UnsignedInteger32 flags,
655 FileAttributes attrs)
656 throws PermissionDeniedException, FileNotFoundException, IOException {
657 path = VirtualFileSystem.translateVFSPath(path);
658
659 File f = new File(path);
660 verifyPermissions(SshThread.getCurrentThreadUser(), path, "r");
661
662 // Check if the file does not exist and process according to flags
663 if (!f.exists()) {
664 if ((flags.intValue() & NativeFileSystemProvider.OPEN_CREATE) == NativeFileSystemProvider.OPEN_CREATE) {
665 // The file does not exist and the create flag is present so lets create it
666 if (!f.createNewFile()) {
667 throw new IOException(translateNFSPath(path) +
668 " could not be created");
669 }
670 } else {
671 // The file does not exist and no create flag present
672 throw new FileNotFoundException(translateNFSPath(path) +
673 " does not exist");
674 }
675 } else {
676 if (((flags.intValue() & NativeFileSystemProvider.OPEN_CREATE) == NativeFileSystemProvider.OPEN_CREATE) &&
677 ((flags.intValue() &
678 NativeFileSystemProvider.OPEN_EXCLUSIVE) == NativeFileSystemProvider.OPEN_EXCLUSIVE)) {
679 // The file exists but the EXCL flag is set which requires that the
680 // file should not exist prior to creation, so throw a status exception
681 throw new IOException(translateNFSPath(path) +
682 " already exists");
683 }
684 }
685
686 // The file now exists so open the file according to the flags yb building the relevant
687 // flags for the RandomAccessFile class
688 String mode = "r" +
689 (((flags.intValue() & NativeFileSystemProvider.OPEN_WRITE) == NativeFileSystemProvider.OPEN_WRITE)
690 ? "ws" : "");
691 RandomAccessFile raf = new RandomAccessFile(f, mode);
692
693 // Determine whether we need to truncate the file
694 if (((flags.intValue() & NativeFileSystemProvider.OPEN_CREATE) == NativeFileSystemProvider.OPEN_CREATE) &&
695 ((flags.intValue() & NativeFileSystemProvider.OPEN_TRUNCATE) == NativeFileSystemProvider.OPEN_TRUNCATE)) {
696 // Set the length to zero
697 raf.setLength(0);
698 }
699
700 // Record the open file
701 openFiles.put(raf.toString(), new OpenFile(f, raf, flags));
702
703 // Return the handle
704 return raf.toString().getBytes("US-ASCII");
705 }
706
707 /**
708 *
709 *
710 * @param handle
711 * @param offset
712 * @param len
713 *
714 * @return
715 *
716 * @throws InvalidHandleException
717 * @throws EOFException
718 * @throws IOException
719 */
720 public byte[] readFile(byte[] handle, UnsignedInteger64 offset,
721 UnsignedInteger32 len)
722 throws InvalidHandleException, EOFException, IOException {
723 String shandle = new String(handle);
724
725 if (openFiles.containsKey(shandle)) {
726 Object obj = openFiles.get(shandle);
727
728 if (obj instanceof OpenFile) {
729 OpenFile file = (OpenFile) obj;
730
731 if ((file.getFlags().intValue() &
732 NativeFileSystemProvider.OPEN_READ) == NativeFileSystemProvider.OPEN_READ) {
733 byte[] buf = new byte[len.intValue()];
734
735 if (file.getRandomAccessFile().getFilePointer() != offset.longValue()) {
736 file.getRandomAccessFile().seek(offset.longValue());
737 }
738
739 int read = file.getRandomAccessFile().read(buf);
740
741 if (read >= 0) {
742 if (read == buf.length) {
743 return buf;
744 } else {
745 byte[] tmp = new byte[read];
746 System.arraycopy(buf, 0, tmp, 0, read);
747
748 return tmp;
749 }
750 } else {
751 throw new EOFException("The file is EOF");
752 }
753 } else {
754 throw new InvalidHandleException(
755 "The file handle was not opened for reading");
756 }
757 } else {
758 throw new InvalidHandleException("Handle is not an open file");
759 }
760 } else {
761 throw new InvalidHandleException("The handle is invalid");
762 }
763 }
764
765 /**
766 *
767 *
768 * @param handle
769 * @param offset
770 * @param data
771 * @param off
772 * @param len
773 *
774 * @throws InvalidHandleException
775 * @throws IOException
776 */
777 public void writeFile(byte[] handle, UnsignedInteger64 offset, byte[] data,
778 int off, int len) throws InvalidHandleException, IOException {
779 String shandle = new String(handle);
780
781 if (openFiles.containsKey(shandle)) {
782 Object obj = openFiles.get(shandle);
783
784 if (obj instanceof OpenFile) {
785 OpenFile file = (OpenFile) obj;
786
787 if ((file.getFlags().intValue() &
788 NativeFileSystemProvider.OPEN_WRITE) == NativeFileSystemProvider.OPEN_WRITE) {
789 if ((file.getFlags().intValue() &
790 NativeFileSystemProvider.OPEN_APPEND) == NativeFileSystemProvider.OPEN_APPEND) {
791 // Force the data to be written to the end of the file by seeking to the end
792 file.getRandomAccessFile().seek(file.getRandomAccessFile()
793 .length());
794 } else if (file.getRandomAccessFile().getFilePointer() != offset.longValue()) {
795 // Move the file pointer if its not in the write place
796 file.getRandomAccessFile().seek(offset.longValue());
797 }
798
799 file.getRandomAccessFile().write(data, off, len);
800 } else {
801 throw new InvalidHandleException(
802 "The file was not opened for writing");
803 }
804 } else {
805 throw new InvalidHandleException("Handle is not an open file");
806 }
807 } else {
808 throw new InvalidHandleException("The handle is invalid");
809 }
810 }
811
812 /**
813 *
814 *
815 * @param handle
816 *
817 * @throws InvalidHandleException
818 * @throws IOException
819 */
820 public void closeFile(byte[] handle)
821 throws InvalidHandleException, IOException {
822 String shandle = new String(handle);
823
824 if (openFiles.containsKey(shandle)) {
825 Object obj = openFiles.get(shandle);
826
827 if (obj instanceof OpenDirectory) {
828 openFiles.remove(shandle);
829 } else if (obj instanceof OpenFile) {
830 ((OpenFile) obj).getRandomAccessFile().close();
831 openFiles.remove(shandle);
832 } else {
833 throw new InvalidHandleException("Internal server error");
834 }
835 } else {
836 throw new InvalidHandleException("The handle is invalid");
837 }
838 }
839
840 /**
841 *
842 *
843 * @param path
844 *
845 * @throws PermissionDeniedException
846 * @throws IOException
847 * @throws FileNotFoundException
848 */
849 public void removeFile(String path)
850 throws PermissionDeniedException, IOException, FileNotFoundException {
851 path = VirtualFileSystem.translateVFSPath(path);
852
853 File f = new File(path);
854
855 if (f.exists()) {
856 try {
857 if (f.isFile()) {
858 if (!f.delete()) {
859 throw new IOException("Failed to delete " +
860 translateNFSPath(path));
861 }
862 } else {
863 throw new IOException(translateNFSPath(path) +
864 " is a directory, use remove directory command to remove");
865 }
866 } catch (SecurityException se) {
867 throw new PermissionDeniedException("Permission denied");
868 }
869 } else {
870 throw new FileNotFoundException(translateNFSPath(path) +
871 " does not exist");
872 }
873 }
874
875 /**
876 *
877 *
878 * @param oldpath
879 * @param newpath
880 *
881 * @throws PermissionDeniedException
882 * @throws FileNotFoundException
883 * @throws IOException
884 */
885 public void renameFile(String oldpath, String newpath)
886 throws PermissionDeniedException, FileNotFoundException, IOException {
887 oldpath = VirtualFileSystem.translateVFSPath(oldpath);
888 newpath = VirtualFileSystem.translateVFSPath(newpath);
889
890 File f = new File(oldpath);
891 verifyPermissions(SshThread.getCurrentThreadUser(), oldpath, "rw");
892 verifyPermissions(SshThread.getCurrentThreadUser(), newpath, "rw");
893
894 if (f.exists()) {
895 File f2 = new File(newpath);
896
897 if (!f2.exists()) {
898 if (!f.renameTo(f2)) {
899 throw new IOException("Failed to rename file " +
900 translateNFSPath(oldpath));
901 }
902 } else {
903 throw new IOException(translateNFSPath(newpath) +
904 " already exists");
905 }
906 } else {
907 throw new FileNotFoundException(translateNFSPath(oldpath) +
908 " does not exist");
909 }
910 }
911
912 /**
913 *
914 *
915 * @param path
916 *
917 * @throws PermissionDeniedException
918 * @throws FileNotFoundException
919 * @throws IOException
920 */
921 public void removeDirectory(String path)
922 throws PermissionDeniedException, FileNotFoundException, IOException {
923 path = VirtualFileSystem.translateVFSPath(path);
924
925 File f = new File(path);
926 verifyPermissions(SshThread.getCurrentThreadUser(), path, "rw");
927
928 if (f.isDirectory()) {
929 if (f.exists()) {
930 if (f.listFiles().length == 0) {
931 if (!f.delete()) {
932 throw new IOException("Failed to remove directory " +
933 translateNFSPath(path));
934 }
935 } else {
936 throw new IOException(translateNFSPath(path) +
937 " is not an empty directory");
938 }
939 } else {
940 throw new FileNotFoundException(translateNFSPath(path) +
941 " does not exist");
942 }
943 } else {
944 throw new IOException(translateNFSPath(path) +
945 " is not a directory");
946 }
947 }
948
949 /**
950 *
951 *
952 * @param path
953 * @param attrs
954 *
955 * @throws PermissionDeniedException
956 * @throws IOException
957 * @throws FileNotFoundException
958 */
959 public void setFileAttributes(String path, FileAttributes attrs)
960 throws PermissionDeniedException, IOException, FileNotFoundException {
961 // Since we cannot really set permissions, this should be ignored as we
962 // do not want applications to fail.
963
964 /*String realPath = VirtualFileSystem.translateVFSPath(path);
965 throw new PermissionDeniedException(
966 "Cannot set file attributes using virtual file system for file "
967 + realPath);*/
968 }
969
970 /**
971 *
972 *
973 * @param handle
974 * @param attrs
975 *
976 * @throws PermissionDeniedException
977 * @throws IOException
978 * @throws InvalidHandleException
979 */
980 public void setFileAttributes(byte[] handle, FileAttributes attrs)
981 throws PermissionDeniedException, IOException, InvalidHandleException {
982 }
983
984 /**
985 *
986 *
987 * @param path
988 *
989 * @return
990 *
991 * @throws UnsupportedFileOperationException
992 * @throws FileNotFoundException
993 * @throws IOException
994 * @throws PermissionDeniedException
995 */
996 public SftpFile readSymbolicLink(String path)
997 throws UnsupportedFileOperationException, FileNotFoundException,
998 IOException, PermissionDeniedException {
999 throw new UnsupportedFileOperationException(
1000 "Symbolic links are not supported by the Virtual File System");
1001 }
1002
1003 /**
1004 *
1005 *
1006 * @param link
1007 * @param target
1008 *
1009 * @throws UnsupportedFileOperationException
1010 * @throws FileNotFoundException
1011 * @throws IOException
1012 * @throws PermissionDeniedException
1013 */
1014 public void createSymbolicLink(String link, String target)
1015 throws UnsupportedFileOperationException, FileNotFoundException,
1016 IOException, PermissionDeniedException {
1017 throw new UnsupportedFileOperationException(
1018 "Symbolic links are not supported by the Virtual File System");
1019 }
1020
1021 /**
1022 *
1023 *
1024 * @param path
1025 *
1026 * @return
1027 *
1028 * @throws IOException
1029 */
1030 public boolean fileExists(String path) throws IOException {
1031 File f = new File(VirtualFileSystem.translateVFSPath(path));
1032
1033 return f.exists();
1034 }
1035
1036 public String getDefaultPath(String username) throws FileNotFoundException {
1037 return getVFSHomeDirectory(username);
1038 }
1039
1040 /**
1041 *
1042 *
1043 * @param path
1044 *
1045 * @return
1046 *
1047 * @throws IOException
1048 * @throws FileNotFoundException
1049 */
1050 public String getCanonicalPath(String path)
1051 throws IOException, FileNotFoundException {
1052 File f = new File(VirtualFileSystem.translateVFSPath(path));
1053
1054 return f.getCanonicalPath();
1055 }
1056
1057 /**
1058 *
1059 *
1060 * @param path
1061 *
1062 * @return
1063 *
1064 * @throws FileNotFoundException
1065 */
1066 public String getRealPath(String path) throws FileNotFoundException {
1067 log.debug("Get real path for '" + path + "'");
1068 path = VirtualFileSystem.translateVFSPath(path);
1069 log.debug("Translated VFS is '" + path + "'");
1070 path = VirtualFileSystem.translateNFSPath(path);
1071 log.debug("Translated NFS is '" + path + "'");
1072
1073 return path;
1074 }
1075
1076 /**
1077 *
1078 *
1079 * @param username
1080 * @param path
1081 * @param permissions
1082 *
1083 * @throws PermissionDeniedException
1084 * @throws FileNotFoundException
1085 * @throws IOException
1086 */
1087 public void verifyPermissions(String username, String path,
1088 String permissions)
1089 throws PermissionDeniedException, FileNotFoundException, IOException {
1090 String vfspath = translateNFSPath(path);
1091
1092 if (permissionHandler == null) {
1093 VFSMount mount = getMount(vfspath);
1094 VFSPermission perm;
1095
1096 if (mount.getPermissions().containsKey(SshThread.getCurrentThreadUser())) {
1097 perm = (VFSPermission) mount.getPermissions().get(SshThread.getCurrentThreadUser());
1098 } else if (mount.getPermissions().containsKey("default")) {
1099 perm = (VFSPermission) mount.getPermissions().get("default");
1100 } else {
1101 throw new PermissionDeniedException(
1102 "No permissions set for mount");
1103 }
1104
1105 if (!perm.verifyPermissions(permissions)) {
1106 throw new PermissionDeniedException("Permission denied for " +
1107 translateNFSPath(path));
1108 }
1109 } else {
1110 permissionHandler.verifyPermissions(username, path, permissions);
1111 }
1112 }
1113
1114 class OpenFile {
1115 File f;
1116 RandomAccessFile raf;
1117 UnsignedInteger32 flags;
1118
1119 public OpenFile(File f, RandomAccessFile raf, UnsignedInteger32 flags) {
1120 this.f = f;
1121 this.raf = raf;
1122 this.flags = flags;
1123 }
1124
1125 public File getFile() {
1126 return f;
1127 }
1128
1129 public RandomAccessFile getRandomAccessFile() {
1130 return raf;
1131 }
1132
1133 public UnsignedInteger32 getFlags() {
1134 return flags;
1135 }
1136 }
1137
1138 class OpenDirectory {
1139 File f;
1140 File[] children;
1141 int readpos = 0;
1142 String path;
1143 String realPath;
1144
1145 public OpenDirectory(String realPath, String path, File f) {
1146 this.path = path;
1147 this.realPath = realPath;
1148 this.f = f;
1149 this.children = f.listFiles();
1150 }
1151
1152 public File getFile() {
1153 return f;
1154 }
1155
1156 public File[] getChildren() {
1157 return children;
1158 }
1159
1160 public int getPosition() {
1161 return readpos;
1162 }
1163
1164 public void setPosition(int readpos) {
1165 this.readpos = readpos;
1166 }
1167 }
1168 }