1 18 package net.sf.drftpd.remotefile; 19 20 import java.io.FileNotFoundException ; 21 import java.io.IOException ; 22 import java.io.Serializable ; 23 import java.rmi.RemoteException ; 24 import java.util.ArrayList ; 25 import java.util.Collection ; 26 import java.util.Collections ; 27 import java.util.Hashtable ; 28 import java.util.Iterator ; 29 import java.util.List ; 30 import java.util.Map ; 31 import java.util.Set ; 32 import java.util.Stack ; 33 import java.util.StringTokenizer ; 34 35 import net.sf.drftpd.FatalException; 36 import net.sf.drftpd.FileExistsException; 37 import net.sf.drftpd.NoAvailableSlaveException; 38 import net.sf.drftpd.ObjectNotFoundException; 39 import net.sf.drftpd.PermissionDeniedException; 40 import net.sf.drftpd.SFVFile; 41 import net.sf.drftpd.SlaveUnavailableException; 42 import net.sf.drftpd.master.RemoteSlave; 43 import net.sf.drftpd.master.config.FtpConfig; 44 import net.sf.drftpd.slave.Slave; 45 import net.sf.drftpd.slave.Transfer; 46 import net.sf.drftpd.slave.TransferStatus; 47 import net.sf.drftpd.util.ListUtils; 48 49 import org.apache.log4j.Level; 50 import org.apache.log4j.Logger; 51 52 58 public class LinkedRemoteFile 59 implements Serializable , Comparable , LinkedRemoteFileInterface { 60 public static class CaseInsensitiveHashtable extends Hashtable { 61 62 public CaseInsensitiveHashtable() { 63 super(); 64 } 65 66 public CaseInsensitiveHashtable(int initialCapacity) { 67 super(initialCapacity); 68 } 69 70 public CaseInsensitiveHashtable( 71 int initialCapacity, 72 float loadFactor) { 73 super(initialCapacity, loadFactor); 74 } 75 76 public CaseInsensitiveHashtable(Map t) { 77 super(t); 78 } 79 80 } 81 public static class NonExistingFile { 82 private LinkedRemoteFile _file; 83 private String _path; 84 public NonExistingFile(LinkedRemoteFile file, String path) { 85 _file = file; 86 _path = path; 87 } 88 89 93 public boolean exists() { 94 return _path == null; 95 } 96 97 public LinkedRemoteFile getFile() { 98 return _file; 99 } 100 101 public String getPath() { 102 return _path; 103 } 104 105 109 public boolean hasPath() { 110 return _path != null; 111 } 112 113 public String toString() { 114 return "[NonExistingFile:file=" 115 + getFile().getPath() 116 + ",path=" 117 + getPath() 118 + "]"; 119 } 120 } 121 private static final Logger logger = 122 Logger.getLogger(LinkedRemoteFile.class.getName()); 123 static final long serialVersionUID = 3585958839961835107L; 124 125 public static void recursiveRenameLoop( 126 LinkedRemoteFile fromDir, 127 LinkedRemoteFile toDir) { 128 logger.debug( 129 "recursiveRenameLoop(" 130 + fromDir.getPath() 131 + ", " 132 + toDir.getPath() 133 + ")"); 134 for (Iterator iter = 135 new ArrayList (fromDir.getMap().values()).iterator(); 136 iter.hasNext(); 137 ) { 138 LinkedRemoteFile fromFile = (LinkedRemoteFile) iter.next(); 139 140 LinkedRemoteFile toFile; 141 try { 142 toFile = (LinkedRemoteFile) toDir.getFile(fromFile.getName()); 143 } catch (QueuedDeletionException e) { 144 fromFile.delete(); 145 continue; 146 } catch (FileNotFoundException e) { 147 toFile = toDir.putFile(fromFile); 148 } 149 if (fromFile.isDirectory()) { 150 recursiveRenameLoop(fromFile, toFile); 151 } else { 152 recursiveRenameLoopFile(fromFile, toFile); 153 } 154 } 155 if (fromDir.isEmpty()) { 156 fromDir.delete(); 157 } 158 } 159 160 public static void recursiveRenameLoopFile( 161 LinkedRemoteFile fromFile, 162 LinkedRemoteFile toFile) { 163 logger.debug( 164 "recursiveRenameLoopFile(" 165 + fromFile.getPath() 166 + ", " 167 + toFile.getPath()); 168 169 Iterator iterator = new ArrayList (fromFile.getSlaves()).iterator(); 170 while (iterator.hasNext()) { 171 RemoteSlave rslave = (RemoteSlave) iterator.next(); 172 if (rslave.isAvailable()) { 173 toFile.addSlave(rslave); 174 fromFile.removeSlave(rslave); 175 } else { 176 logger.debug(rslave + " is offline"); 177 fromFile.queueRename(toFile); 178 } 179 } 180 } 181 182 private static void recursiveSetRSlaveAndConfig( 183 LinkedRemoteFile dir, 184 FtpConfig ftpConfig, 185 RemoteSlave rslave) { 186 187 dir._ftpConfig = ftpConfig; 188 if (dir.isFile()) { 189 dir.addSlave(rslave); 190 } 191 if (dir.isDirectory()) { 192 for (Iterator iter = dir.getFiles().iterator(); iter.hasNext();) { 193 recursiveSetRSlaveAndConfig( 194 (LinkedRemoteFile) iter.next(), 195 ftpConfig, 196 rslave); 197 } 198 } 199 } 200 private long _checkSum; 201 202 private CaseInsensitiveHashtable _files; 203 private transient FtpConfig _ftpConfig; 204 private String _group; 205 207 private boolean _isDeleted = false; 209 private long _lastModified; 210 211 private long _length; 212 private String _link; 213 private String _name; 214 private String _owner; 215 216 private LinkedRemoteFile _parent; 217 protected List _slaves; 219 private long _xfertime = 0; 220 221 protected SFVFile sfvFile; 222 228 public LinkedRemoteFile(FtpConfig ftpConfig) { 229 _ftpConfig = ftpConfig; 230 231 _lastModified = System.currentTimeMillis(); 232 _length = 0; 233 _parent = null; 234 _name = ""; 235 _files = new CaseInsensitiveHashtable(); 236 _slaves = Collections.synchronizedList(new ArrayList (1)); 237 } 238 239 253 private LinkedRemoteFile( 254 LinkedRemoteFile parent, 255 RemoteFileInterface file, 256 FtpConfig cfg) { 257 this(parent, file, file.getName(), cfg); 258 } 259 260 private LinkedRemoteFile( 261 LinkedRemoteFile parent, 262 RemoteFileInterface file, 263 String name, 264 FtpConfig cfg) { 265 266 if (!ListUtils.isLegalFileName(name)) 267 throw new IllegalArgumentException ("Illegal filename"); 268 269 if (!file.isFile() && !file.isDirectory()) 270 throw new IllegalArgumentException ( 271 "File is not a file nor a directory: " + file); 272 273 if (_length == -1) 274 throw new IllegalArgumentException ("length() == -1 for " + file); 275 276 _ftpConfig = cfg; 277 _lastModified = file.lastModified(); 278 _isDeleted = file.isDeleted(); 279 setOwner(file.getUsername()); 280 setGroup(file.getGroupname()); 281 _checkSum = file.getCheckSumCached(); 282 _parent = parent; 283 if (file.isLink()) { 284 _link = file.getLinkPath(); 285 } 286 if (parent == null) { 287 _name = ""; 288 } else { 289 _name = name.toString(); 290 } 291 292 if (file.isFile()) { 293 _length = file.length(); 294 _slaves = 295 Collections.synchronizedList(new ArrayList (file.getSlaves())); 296 try { 297 getParentFile().addSize(length()); 298 } catch (FileNotFoundException ok) { 299 } 301 } else if (file.isDirectory()) { 302 _files = 307 new CaseInsensitiveHashtable(file.getFiles().size()); 308 Stack dirstack = new Stack (); 309 for (Iterator iter = file.getFiles().iterator(); iter.hasNext();) { 311 RemoteFileInterface file2 = (RemoteFileInterface) iter.next(); 312 if (file2.isDirectory()) { 314 dirstack.push(file2); 315 continue; 316 } 317 _files.put( 319 file2.getName(), 320 new LinkedRemoteFile(this, file2, _ftpConfig)); 321 } 322 323 Iterator i = dirstack.iterator(); 324 while (i.hasNext()) { 325 RemoteFileInterface file2 = (RemoteFileInterface) i.next(); 326 String filename = file2.getName(); 327 _files.put( 329 filename, 330 new LinkedRemoteFile(this, file2, _ftpConfig)); 331 } 332 } else { 333 throw new RuntimeException (); 334 } 335 } 337 338 344 public LinkedRemoteFile(RemoteFileInterface file, FtpConfig cfg) 345 throws IOException { 346 this(null, file, cfg); 347 } 348 349 352 public LinkedRemoteFile addFile(AbstractRemoteFile file) { 353 _lastModified = System.currentTimeMillis(); 354 return putFile(file); 355 } 356 357 protected synchronized void addSize(long size) { 358 _length += size; 359 try { 363 getParentFile().addSize(size); 364 } catch (FileNotFoundException done) { 365 } 366 } 367 368 public void addSlave(RemoteSlave slave) { 369 if (_slaves == null) throw new IllegalStateException ("Cannot addSlave() on a directory"); 371 if (slave == null) 372 throw new NullPointerException (); 373 374 if (_slaves.contains(slave)) { 377 return; 378 } 379 _slaves.add(slave); 380 } 381 382 387 public int compareTo(Object o) { 388 return getName().compareTo(((RemoteFileInterface) o).getName()); 389 } 390 391 public LinkedRemoteFile createDirectories(String path) { 392 NonExistingFile nef = lookupNonExistingFile(path); 393 if (!nef.hasPath()) 394 throw new RuntimeException ("createDirectories called on already existing directory"); 395 LinkedRemoteFile dir = nef.getFile(); 396 StringTokenizer st = new StringTokenizer (nef.getPath(), "/"); 397 while (st.hasMoreTokens()) { 398 try { 399 dir.createDirectory(st.nextToken()); 400 } catch (FileExistsException e) { 401 throw new RuntimeException (e); 402 } 403 } 404 return dir; 405 } 406 407 public LinkedRemoteFile createDirectory(String fileName) 408 throws FileExistsException { 409 return createDirectory(null, null, fileName); 410 } 411 412 public LinkedRemoteFile createDirectory( 413 String owner, 414 String group, 415 String fileName) 416 throws FileExistsException { 417 if (hasFile(fileName)) { 424 throw new FileExistsException( 425 fileName + " already exists in this directory"); 426 } 427 428 LinkedRemoteFile file = 429 addFile( 430 new StaticRemoteFile( 431 null, 432 fileName, 433 owner, 434 group, 435 0L, 436 System.currentTimeMillis())); 437 logger.info("Created directory " + file); 438 _lastModified = System.currentTimeMillis(); 439 return file; 440 } 441 442 451 public void delete() { 452 logger.debug("delete(" + getPath() + ")"); 453 _isDeleted = true; 454 _link = null; 455 if (isDirectory()) { 456 for (Iterator iter = getFiles().iterator(); iter.hasNext();) { 457 LinkedRemoteFileInterface myFile = 458 (LinkedRemoteFileInterface) iter.next(); 459 myFile.delete(); 460 } 461 try { 462 if (dirSize() == 0) { Object ret = getParentFile().getMap().remove(getName()); 464 if (ret == null) 465 throw new NullPointerException (); 466 } 467 } catch (FileNotFoundException ex) { 468 logger.log( 469 Level.FATAL, 470 "FileNotFoundException on getParentFile()", 471 ex); 472 } 473 return; 474 } else { 475 synchronized (_slaves) { 476 for (Iterator iter = _slaves.iterator(); iter.hasNext();) { 477 RemoteSlave rslave = (RemoteSlave) iter.next(); 478 Slave slave; 479 try { 480 slave = rslave.getSlave(); 481 } catch (SlaveUnavailableException ex) { 482 logger.info("slave not available for deletion"); 483 continue; 484 } 485 try { 486 System.out.println( 487 "DELETE: " + rslave.getName() + ": " + getPath()); 488 slave.delete(getPath()); 489 iter.remove(); 491 } catch (FileNotFoundException ex) { 492 iter.remove(); 493 logger.warn( 494 getPath() 495 + " missing on " 496 + rslave.getName() 497 + " during delete, assumed deleted", 498 ex); 499 } catch (RemoteException ex) { 500 rslave.handleRemoteException(ex); 501 continue; 502 } catch (IOException ex) { 503 logger.log( 504 Level.FATAL, 505 "IOException deleting file on slave " 506 + rslave.getName(), 507 ex); 508 continue; 509 } 510 } 511 } 512 513 if (_slaves.isEmpty()) { 514 try { 516 getParentFile().getMap().remove(getName()); 517 getParentFileNull().addSize(-length()); 518 } catch (FileNotFoundException ex) { 519 logger.log( 520 Level.FATAL, 521 "FileNotFoundException on getParentFile()", 522 ex); 523 } 524 } else { 525 logger.log( 526 Level.INFO, 527 getPath() 528 + " queued for deletion, remaining slaves:" 529 + _slaves); 530 } 531 } 532 } 533 534 public void deleteOthers(Set destSlaves) { 535 synchronized (_slaves) { 536 for (Iterator iter = _slaves.iterator(); iter.hasNext();) { 537 RemoteSlave tempSlave = (RemoteSlave) iter.next(); 538 if (destSlaves.contains(tempSlave)) 539 continue; try { 542 tempSlave.getSlave().delete(getPath()); 543 iter.remove(); 544 } catch (RemoteException e) { 545 tempSlave.handleRemoteException(e); 546 } catch (FileNotFoundException ex) { 547 logger.warn( 548 getPath() 549 + " missing on " 550 + tempSlave.getName() 551 + " during delete, assumed deleted", 552 ex); 553 iter.remove(); 554 } catch (SlaveUnavailableException e) { 555 logger.debug("Unable to delete file on offline slave", e); 556 } catch (IOException e) { 557 logger.debug("IOException deleting file from slave", e); 558 } 559 } 560 } 561 } 562 public long dirSize() { 563 if (_files == null) 564 throw new IllegalStateException ("Cannot be called on a non-directory"); 565 return _files.size(); 566 } 567 568 public boolean equals(Object obj) { 569 if (obj instanceof LinkedRemoteFileInterface 570 && ((LinkedRemoteFileInterface) obj).getPath().equals(getPath())) { 571 return true; 572 } 573 return false; 574 } 575 576 public Collection getAvailableSlaves() throws NoAvailableSlaveException { 577 ArrayList availableSlaves = new ArrayList (); 578 for (Iterator iter = getSlaves().iterator(); iter.hasNext();) { 579 RemoteSlave rslave = (RemoteSlave) iter.next(); 580 if (!rslave.isAvailable()) 581 continue; 582 availableSlaves.add(rslave); 583 } 584 if (availableSlaves.isEmpty()) { 585 throw new NoAvailableSlaveException( 586 getPath() + " has 0 slaves online"); 587 } 588 return availableSlaves; 589 } 590 591 594 public long getCheckSum() throws NoAvailableSlaveException { 595 if (_checkSum == 0 && _length != 0) { 596 _checkSum = getCheckSumFromSlave(); 597 if (_checkSum == 0) 598 throw new NoAvailableSlaveException( 599 "Could not find a slave to check crc of " + getPath()); 600 } 601 return _checkSum; 602 } 603 604 610 public long getCheckSumCached() { 611 return _checkSum; 612 } 613 614 617 public long getCheckSumFromSlave() { 618 try { 619 for (Iterator iter = getAvailableSlaves().iterator(); 620 iter.hasNext(); 621 ) { 622 RemoteSlave slave = (RemoteSlave) iter.next(); 623 try { 624 _checkSum = slave.getSlave().checkSum(getPath()); 625 } catch (RemoteException e) { 626 continue; 627 } catch (IOException e) { 628 continue; 629 } catch (SlaveUnavailableException e) { 630 continue; 631 } 632 return _checkSum; 633 } 634 } catch (NoAvailableSlaveException e) { 635 return 0; 636 } 637 return 0; 638 } 639 640 public Collection getDirectories() { 641 Collection temp = getFiles(); 642 for (Iterator iter = temp.iterator(); iter.hasNext();) { 643 if (((LinkedRemoteFileInterface) iter.next()).isFile()) 644 iter.remove(); 645 } 646 return temp; 647 } 648 649 656 public LinkedRemoteFileInterface getFile(String fileName) 657 throws FileNotFoundException { 658 LinkedRemoteFileInterface file = getFileDeleted(fileName); 659 if (file.isDeleted()) 660 throw new QueuedDeletionException("File is queued for deletion"); 661 return file; 662 } 663 664 public LinkedRemoteFileInterface getFileDeleted(String fileName) 665 throws FileNotFoundException { 666 LinkedRemoteFileInterface file = 667 (LinkedRemoteFileInterface) _files.get(fileName); 668 if (file == null) 669 throw new FileNotFoundException ( 670 "No such file or directory: " + fileName); 671 return file; 672 } 673 674 683 public Collection getFiles() { 684 if (_files == null) 685 throw new IllegalStateException ("Isn't a directory"); 686 return getFilesMap().values(); 687 } 688 689 699 private Map getFilesMap() { 700 Hashtable ret = new Hashtable (_files); 701 702 for (Iterator iter = ret.values().iterator(); iter.hasNext();) { 703 LinkedRemoteFileInterface file = 704 (LinkedRemoteFileInterface) iter.next(); 705 if (file.isDeleted()) 706 iter.remove(); 707 } 708 return ret; 709 } 710 711 public String getGroupname() { 712 if (_group == null || _group.equals("")) 713 return "drftpd"; 714 return _group; 715 } 716 717 public RemoteFileInterface getLink() throws FileNotFoundException { 718 return lookupFile(getLinkPath()); 719 } 720 721 public String getLinkPath() { 722 return _link; 723 } 724 725 734 public Map getMap() { 735 return _files; 736 } 737 738 public String getName() { 739 return _name; 740 } 741 742 public LinkedRemoteFileInterface getOldestFile() 743 throws ObjectNotFoundException { 744 Iterator iter = getFiles().iterator(); 745 if (!iter.hasNext()) 746 throw new ObjectNotFoundException(); 747 LinkedRemoteFile oldestFile = (LinkedRemoteFile) iter.next(); 748 for (; iter.hasNext();) { 749 LinkedRemoteFile file = (LinkedRemoteFile) iter.next(); 750 if (oldestFile.lastModified() > file.lastModified()) { 751 oldestFile = file; 752 } 753 } 754 return oldestFile; 755 } 756 757 public String getParent() throws FileNotFoundException { 758 return getParentFile().getPath(); 759 } 760 761 public LinkedRemoteFile getParentFile() throws FileNotFoundException { 762 if (_parent == null) 763 throw new FileNotFoundException ("root directory has no parent"); 764 return _parent; 765 } 766 767 public LinkedRemoteFile getParentFileNull() { 768 return _parent; 769 } 770 771 public String getPath() { 772 StringBuffer path = new StringBuffer (); 773 LinkedRemoteFileInterface parent = this; 774 775 while (true) { 776 if (parent.getName().length() == 0) 777 break; 778 path.insert(0, "/" + parent.getName()); 779 try { 780 parent = parent.getParentFile(); 781 } catch (FileNotFoundException ex) { 783 break; 784 } 785 } 786 if (path.length() == 0) 787 return "/"; 788 return path.toString(); 789 } 790 791 public LinkedRemoteFile getRoot() { 792 LinkedRemoteFile root = this; 793 try { 794 while (true) 795 root = root.getParentFile(); 796 } catch (FileNotFoundException ex) { 797 return root; 798 } 799 } 800 801 public synchronized SFVFile getSFVFile() 802 throws IOException , FileNotFoundException , NoAvailableSlaveException { 803 804 if (sfvFile == null) { 805 while (true) { 806 RemoteSlave rslave = 807 _ftpConfig 808 .getSlaveManager() 809 .getSlaveSelectionManager() 810 .getASlaveForMaster( 811 this, 812 _ftpConfig); 813 try { 814 sfvFile = rslave.getSlave().getSFVFile(getPath()); 815 sfvFile.setCompanion(this); 816 break; 817 } catch (RemoteException ex) { 818 rslave.handleRemoteException(ex); 819 } catch (SlaveUnavailableException e) { 820 continue; 821 } 822 } 823 } 824 if (sfvFile.size() == 0) { 825 throw new FileNotFoundException ("sfv file contains no checksum entries"); 826 } 827 return sfvFile; 828 } 829 830 833 public Collection getSlaves() { 834 if (_slaves == null) 835 throw new IllegalStateException ("getSlaves() called on a directory"); 836 return _slaves; 837 } 838 839 public String getUsername() { 840 if (_owner == null || _owner.equals("")) 841 return "nobody"; 842 return _owner; 843 } 844 845 public long getXferspeed() { 846 if (getXfertime() == 0) 847 return 0; 848 return (length() / getXfertime()); 849 } 850 851 854 public long getXfertime() { 855 return _xfertime; 856 } 857 858 867 public boolean hasFile(String filename) { 868 return _files.containsKey(filename); 869 } 870 871 public int hashCode() { 872 return getName().hashCode(); 873 } 874 875 882 public boolean hasOfflineSlaves() { 883 if (isFile()) { 884 for (Iterator iter = getSlaves().iterator(); iter.hasNext();) { 885 RemoteSlave rslave = (RemoteSlave) iter.next(); 886 if (rslave == null) 887 throw new NullPointerException (); 888 if (!rslave.isAvailable()) 889 return true; 890 } 891 } else if (isDirectory()) { 892 for (Iterator iter = getFiles().iterator(); iter.hasNext();) { 893 if (((LinkedRemoteFileInterface) iter.next()) 894 .hasOfflineSlaves()) 895 return true; 896 } 897 } 898 return false; 899 } 900 901 public boolean hasSlave(RemoteSlave slave) { 902 return _slaves.contains(slave); 903 } 904 905 910 public boolean isAvailable() { 911 if (isDirectory()) 912 return true; 913 for (Iterator iter = getSlaves().iterator(); iter.hasNext();) { 914 RemoteSlave rslave = (RemoteSlave) iter.next(); 915 if (rslave == null) 916 throw new RuntimeException (); 917 if (rslave.isAvailable()) 918 return true; 919 } 920 return false; 921 } 922 923 928 public boolean isDeleted() { 929 return _isDeleted; 930 } 931 932 public boolean isDirectory() { 933 return !isFile(); 934 } 935 936 939 private boolean isEmpty() { 940 if (_files == null) 941 throw new IllegalStateException (); 942 return _files.isEmpty(); 943 } 944 945 public boolean isFile() { 946 return _files == null && _slaves != null; 947 } 948 949 952 public boolean isLink() { 953 return _link != null; 954 } 955 956 public long lastModified() { 957 return _lastModified; 958 } 959 960 public long length() { 961 if (_length < 0) 980 return 0; 981 return _length; 982 } 983 984 public LinkedRemoteFile lookupFile(String path) 985 throws FileNotFoundException { 986 return lookupFile(path, false); 987 } 988 989 public LinkedRemoteFile lookupFile(String path, boolean includeDeleted) 990 throws FileNotFoundException { 991 992 NonExistingFile ret = lookupNonExistingFile(path, includeDeleted); 993 994 if (ret.hasPath()) 995 throw new FileNotFoundException (path + ": File not found"); 996 return (LinkedRemoteFile) ret.getFile(); 997 } 998 999 public NonExistingFile lookupNonExistingFile(String path) { 1000 return lookupNonExistingFile(path, false); 1001 } 1002 1003 1006 public NonExistingFile lookupNonExistingFile( 1007 String path, 1008 boolean includeDeleted) { 1009 if (path == null) 1010 throw new IllegalArgumentException ("null path not allowed"); 1011 LinkedRemoteFile currFile = this; 1012 1013 if (path.charAt(0) == '/') 1014 currFile = getRoot(); 1015 1016 if (path.length() == 1 && path.equals("~")) { 1018 currFile = getRoot(); 1019 path = ""; 1020 } else if (path.length() >= 2 && path.substring(0, 2).equals("~/")) { 1021 currFile = getRoot(); 1022 path = path.substring(2); 1023 } 1024 1025 StringTokenizer st = new StringTokenizer (path, "/"); 1026 while (st.hasMoreTokens()) { 1027 String currFileName = st.nextToken(); 1028 if (currFileName.equals(".")) 1029 continue; 1030 if (currFileName.equals("..")) { 1031 try { 1032 currFile = currFile.getParentFile(); 1033 } catch (FileNotFoundException ex) { 1034 } 1035 continue; 1036 } 1037 LinkedRemoteFile nextFile; 1038 try { 1039 if (includeDeleted) { 1040 nextFile = 1041 (LinkedRemoteFile) currFile.getFileDeleted( 1042 currFileName); 1043 } else { 1044 nextFile = 1045 (LinkedRemoteFile) currFile.getFileDeleted( 1046 currFileName); 1047 } 1048 } catch (FileNotFoundException ex) { 1049 StringBuffer remaining = new StringBuffer (currFileName); 1050 if (st.hasMoreElements()) { 1051 remaining.append('/').append(st.nextToken("")); 1052 } 1053 return new NonExistingFile(currFile, remaining.toString()); 1054 } 1055 currFile = nextFile; 1056 } 1057 return new NonExistingFile(currFile, null); 1058 } 1059 1060 1064 public String lookupPath(String path) { 1065 NonExistingFile ret = lookupNonExistingFile(path); 1066 if (!ret.hasPath()) { 1067 return ret.getFile().getPath(); 1068 } 1069 return ret.getFile().getPath() + '/' + ret.getPath(); 1070 } 1071 1072 public SFVFile lookupSFVFile() 1073 throws IOException , FileNotFoundException , NoAvailableSlaveException { 1074 if (!isDirectory()) 1075 throw new IllegalStateException ("lookupSFVFile must be called on a directory"); 1076 1077 for (Iterator iter = getFiles().iterator(); iter.hasNext();) { 1078 LinkedRemoteFileInterface myFile = 1079 (LinkedRemoteFileInterface) iter.next(); 1080 if (myFile.getName().toLowerCase().endsWith(".sfv")) { 1081 return myFile.getSFVFile(); 1082 } 1083 } 1084 throw new FileNotFoundException ("no sfv file in directory"); 1085 } 1086 1087 1090 public LinkedRemoteFile putFile(RemoteFileInterface file) { 1091 return putFile(file, file.getName()); 1092 } 1093 1094 1098 1132 1136 private LinkedRemoteFile putFile(RemoteFileInterface file, String toName) { 1137 if (_files.containsKey(toName)) { 1138 if (((LinkedRemoteFileInterface) _files.get(toName)).isDeleted()) { 1139 throw new IllegalStateException ( 1140 "Don't overwrite! " 1141 + getPath() 1142 + " " 1143 + toName 1144 + " (is queued for deletion)"); 1145 } else { 1146 throw new IllegalStateException ( 1147 "Don't overwrite! " + getPath() + " " + toName); 1148 } 1149 } 1150 if (file.isFile()) { 1152 if (file.getSlaves() == null) 1153 throw new RuntimeException (file.toString()); 1154 for (Iterator iter = file.getSlaves().iterator(); 1155 iter.hasNext(); 1156 ) { 1157 if (iter.next() == null) 1158 throw new RuntimeException (); 1159 } 1160 } 1161 1162 LinkedRemoteFile linkedfile = 1164 new LinkedRemoteFile(this, file, toName, _ftpConfig); 1165 _files.put(linkedfile.getName(), linkedfile); 1166 return linkedfile; 1167 } 1168 1169 private void queueRename(LinkedRemoteFile toFile) { 1170 _link = toFile.getPath(); 1171 _isDeleted = true; 1172 } 1173 1174 public TransferStatus receiveFile( 1175 Transfer transfer, 1176 char type, 1177 long offset) 1178 throws IOException { 1179 return transfer.receiveFile(getParent(), type, getName(), offset); 1180 } 1181 1182 1187 public void remerge(LinkedRemoteFile mergedir, RemoteSlave rslave) { 1188 if (_ftpConfig == null) 1189 throw new IllegalStateException ("_ftpConfig == null"); 1190 remergePass1(mergedir, rslave); 1191 remergePass2(mergedir, rslave); 1192 } 1193 1194 private void remergePass1(LinkedRemoteFile mergedir, RemoteSlave rslave) { 1195 if (!isDirectory()) 1196 throw new IllegalArgumentException ("merge() called on a non-directory"); 1197 1198 if (!mergedir.isDirectory()) 1199 throw new IllegalArgumentException ("argument is not a directory"); 1200 1201 for (Iterator i = mergedir.getFiles().iterator(); i.hasNext();) { 1203 LinkedRemoteFile slavefile = (LinkedRemoteFile) i.next(); 1204 if (slavefile.isDirectory() && slavefile.length() == 0) { 1205 logger.fatal( 1206 "Attempt to add empty directory: " 1207 + slavefile 1208 + " from " 1209 + rslave.getName()); 1210 continue; 1211 } 1212 LinkedRemoteFile localfile = 1217 (LinkedRemoteFile) _files.get(slavefile.getName()); 1218 if (localfile == null) { 1220 recursiveSetRSlaveAndConfig(slavefile, _ftpConfig, rslave); 1222 slavefile._parent = this; 1223 _files.put(slavefile.getName(), slavefile); 1224 logger.info( 1225 slavefile.getPath() + " added from " + rslave.getName()); 1226 } else { if (localfile.isDeleted()) { 1228 if (localfile.isLink()) { 1231 String linktarget = localfile.getLinkPath(); 1232 try { 1234 LinkedRemoteFileInterface renameTo = 1235 (LinkedRemoteFileInterface) localfile.getLink(); 1236 logger.debug( 1237 "queued rename for " 1238 + localfile.getPath() 1239 + " to " 1240 + renameTo.getPath()); 1241 try { 1242 rslave.getSlave().rename( 1243 localfile.getPath(), 1244 renameTo.getParent(), 1245 renameTo.getName()); 1246 if (localfile.isFile()) { 1249 recursiveRenameLoopFile( 1250 localfile, 1251 (LinkedRemoteFile) renameTo); 1252 } else { 1253 recursiveRenameLoop( 1254 localfile, 1255 (LinkedRemoteFile) renameTo); 1256 } 1257 1258 { 1264 NonExistingFile ret = 1265 slavefile.lookupNonExistingFile( 1266 linktarget); 1267 LinkedRemoteFile destDir = ret.getFile(); 1268 if (!ret.hasPath()) 1269 throw new RuntimeException ( 1270 ret 1271 + " - target already exists on the slave - ???"); 1272 StringTokenizer destst = 1273 new StringTokenizer (ret.getPath(), "/"); 1274 String desttok = null; 1275 if (!destst.hasMoreTokens()) 1276 throw new RuntimeException ("Invalid queued rename target"); 1277 while (destst.hasMoreTokens()) { 1278 desttok = destst.nextToken(); 1279 if (destst.hasMoreTokens()) { 1280 destDir = 1281 destDir.createDirectory( 1282 "drftpd", 1283 "drftpd", 1284 desttok); 1285 logger.debug( 1286 "Created " + destDir.getPath()); 1287 } 1288 } 1289 mergedir._files.remove(slavefile.getName()); 1290 slavefile._name = desttok; 1291 destDir.putFile(slavefile); 1292 slavefile._parent = destDir; 1293 logger.debug( 1294 "Renamed " 1295 + slavefile.getName() 1296 + " to " 1297 + destDir.getPath()); 1298 } 1300 1301 } catch (RemoteException e) { 1304 rslave.handleRemoteException(e); 1305 } catch (SlaveUnavailableException e) { 1306 throw new RuntimeException (e); 1307 } catch (IOException e) { 1308 logger.warn("", e); 1309 } 1310 continue; 1311 } catch (FileNotFoundException e) { 1312 logger.info( 1315 localfile.getPath() 1316 + " target didn't exist for queued rename, scheduling for deletion"); 1317 localfile._link = null; 1318 } 1319 } 1320 1321 if (!localfile.isLink()) { 1323 logger.log( 1324 Level.WARN, 1325 "Queued delete on " 1326 + rslave 1327 + " for file " 1328 + slavefile); 1329 if (!slavefile.isDirectory()) 1330 slavefile.addSlave(rslave); 1331 slavefile.delete(); 1332 localfile.delete(); 1333 continue; 1334 } 1336 } 1338 if (slavefile.isFile() 1339 && localfile.length() != slavefile.length()) { 1340 Collection filerslaves = slavefile.getSlaves(); 1342 1343 if ((filerslaves.size() == 1 1344 && filerslaves.contains(rslave)) 1345 || localfile.length() == 0) { 1346 localfile.setLength(slavefile.length()); 1348 localfile.setCheckSum(0L); 1349 localfile.setLastModified(slavefile.lastModified()); 1350 } else if (slavefile.length() == 0) { 1351 logger.log( 1352 Level.INFO, 1353 "Deleting conflicting 0byte " 1354 + slavefile 1355 + " on " 1356 + rslave); 1357 try { 1358 rslave.getSlave().delete(slavefile.getPath()); 1359 } catch (PermissionDeniedException ex) { 1360 logger.log( 1361 Level.FATAL, 1362 "Error deleting 0byte file on " + rslave, 1363 ex); 1364 } catch (Exception e) { 1365 throw new FatalException(e); 1366 } 1367 continue; 1368 } else { 1369 try { 1371 rslave.getSlave().rename( 1372 getPath() + "/" + slavefile.getName(), 1373 getPath(), 1374 slavefile.getName() 1375 + "." 1376 + rslave.getName() 1377 + ".conflict"); 1378 mergedir._files.remove(slavefile.getName()); 1379 slavefile._name = 1380 slavefile.getName() 1381 + "." 1382 + rslave.getName() 1383 + ".conflict"; 1384 mergedir._files.put(slavefile.getName(), slavefile); 1386 slavefile.addSlave(rslave); 1387 slavefile._parent = this; 1388 _files.put(slavefile.getName(), slavefile); 1389 logger.log( 1390 Level.WARN, 1391 "2 or more slaves contained same file with different sizes, renamed to " 1392 + slavefile.getName()); 1393 continue; 1394 } catch (Exception e) { 1395 throw new FatalException(e); 1396 } 1397 } 1398 } 1399 1400 if (slavefile.isDirectory()) { 1402 if (!localfile.isDirectory()) 1403 throw new RuntimeException ( 1404 "!!! ERROR: Directory/File conflict: " 1405 + slavefile 1406 + " and " 1407 + localfile 1408 + " from " 1409 + rslave.getName()); 1410 localfile.remergePass1(slavefile, rslave); 1412 } else { 1413 if (!slavefile.isFile()) 1414 throw new RuntimeException (); 1415 if (localfile.isDirectory()) 1416 throw new RuntimeException ( 1417 "!!! ERROR: File/Directory conflict: " 1418 + slavefile 1419 + " and " 1420 + localfile 1421 + " from " 1422 + rslave.getName()); 1423 localfile.addSlave(rslave); 1424 } 1425 } } 1427 1428 } 1429 1430 private void remergePass2(LinkedRemoteFile mergedir, RemoteSlave rslave) { 1431 synchronized (_files) { 1432 for (Iterator i = new ArrayList (_files.values()).iterator(); 1437 i.hasNext(); 1438 ) { 1439 LinkedRemoteFile file = (LinkedRemoteFile) i.next(); 1440 if (mergedir == null) { if (file.isFile()) { 1442 file.unmergeFile(rslave); 1443 } else { 1444 file.remergePass2(null, rslave); 1445 } 1446 continue; 1447 } 1448 if (!mergedir.hasFile(file.getName())) { 1449 if (file.isFile()) { 1450 file.unmergeFile(rslave); 1451 } else { 1452 file.remergePass2(null, rslave); 1453 } 1454 } else { 1455 if (file.isDirectory()) { 1456 try { 1457 file.remergePass2( 1458 (LinkedRemoteFile) mergedir.getFile( 1459 file.getName()), 1460 rslave); 1461 } catch (FileNotFoundException e) { 1462 throw new RuntimeException ( 1463 "inconsistent with hasFile() above", 1464 e); 1465 } 1466 } 1467 } 1469 } 1470 } 1471 } 1472 1473 1476 public boolean removeSlave(RemoteSlave slave) { 1477 if (_slaves == null) 1478 throw new IllegalStateException ("Cannot removeSlave() on directory"); 1479 boolean ret = _slaves.remove(slave); 1480 if (_slaves.isEmpty()) 1481 delete(); 1482 return ret; 1483 } 1484 1485 1488 public LinkedRemoteFile renameTo(String toDirPath, String toName) 1489 throws IOException , FileNotFoundException { 1490 if (toDirPath.charAt(0) != '/') 1491 throw new RuntimeException ("renameTo() must be given an absolute path as argument"); 1492 if (toName.indexOf('/') != -1) 1493 throw new RuntimeException ("Cannot rename to non-existing directory"); 1494 if (_ftpConfig == null) 1495 throw new RuntimeException ("_ftpConfig is null: " + this); 1496 1497 LinkedRemoteFile toDir = lookupFile(toDirPath); 1498 { 1500 LinkedRemoteFile tmpDir = toDir; 1501 do { 1502 if (tmpDir == this) { 1503 throw new IOException ("Cannot rename into a subdirectory of self"); 1504 } 1505 } while ((tmpDir = tmpDir.getParentFileNull()) != null); 1506 } 1507 1508 LinkedRemoteFile toFile = toDir.putFile(this, toName); 1510 1511 if (!toFile.isDirectory()) 1512 toFile._slaves = Collections.synchronizedList(new ArrayList ()); 1513 queueRename(toFile); 1514 if (isDirectory()) { 1515 for (Iterator iter = 1516 _ftpConfig.getSlaveManager().getSlaves().iterator(); 1517 iter.hasNext(); 1518 ) { 1519 RemoteSlave rslave = (RemoteSlave) iter.next(); 1520 Slave slave; 1521 try { 1522 slave = rslave.getSlave(); 1523 } catch (SlaveUnavailableException e) { 1524 continue; 1527 } 1528 try { 1529 slave.rename(getPath(), toDirPath, toName); 1530 } catch (RemoteException ex) { 1531 rslave.handleRemoteException(ex); 1532 } catch (IOException ex) { 1533 logger.log( 1534 Level.FATAL, 1535 "IOException in renameTo() for dir for " 1536 + rslave.getName(), 1537 ex); 1538 } 1539 } 1540 recursiveRenameLoop(this, toFile); 1541 } else { 1542 for (Iterator iter = new ArrayList (getSlaves()).iterator(); 1543 iter.hasNext(); 1544 ) { 1545 RemoteSlave rslave = (RemoteSlave) iter.next(); 1546 Slave slave; 1547 try { 1548 slave = rslave.getSlave(); 1549 } catch (SlaveUnavailableException ex) { 1550 continue; 1551 } 1552 try { 1553 slave.rename(getPath(), toDirPath, toName); 1554 removeSlave(rslave); 1555 toFile.addSlave(rslave); 1556 } catch (RemoteException ex) { 1558 rslave.handleRemoteException(ex); 1559 } catch (IOException ex) { 1560 logger.log( 1561 Level.FATAL, 1562 "IO error from " 1563 + rslave.getName() 1564 + " on a file in LinkedRemoteFile", 1565 ex); 1566 } 1567 } 1568 } 1569 1570 1576 1586 return toFile; 1591 } 1592 public TransferStatus sendFile(Transfer transfer, char type, long offset) 1593 throws IOException { 1594 return transfer.sendFile(getPath(), type, offset); 1595 } 1596 1597 public void setCheckSum(long checkSum) { 1598 _checkSum = checkSum; 1599 } 1600 1601 1604 public void setDeleted(boolean b) { 1605 _isDeleted = b; 1606 } 1607 public void setGroup(String group) { 1608 _group = group != null ? group.intern() : null; 1609 } 1610 1611 public void setLastModified(long lastModified) { 1612 _lastModified = lastModified; 1613 } 1614 1615 public void setLength(long length) { 1616 getParentFileNull().addSize(length - _length); 1617 _length = length; 1618 } 1619 public void setOwner(String owner) { 1620 _owner = owner != null ? owner.intern() : null; 1621 } 1622 1623 public void setXfertime(long xfertime) { 1624 _xfertime = xfertime; 1625 } 1626 1627 public String toString() { 1628 StringBuffer ret = new StringBuffer (); 1629 ret.append("LinkedRemoteFile[\"" + this.getName() + "\","); 1630 if (isFile()) { 1631 ret.append("xfertime:" + _xfertime + ","); 1632 } 1633 if (isDeleted()) 1634 ret.append("deleted,"); 1635 if (isLink()) 1636 ret.append("link:" + getLinkPath() + ","); 1637 if (_slaves != null) { 1639 Iterator i = _slaves.iterator(); 1640 ret.append("slaves:["); 1642 while (i.hasNext()) { 1645 RemoteSlave rslave = (RemoteSlave) i.next(); 1646 if (rslave == null) 1647 throw new FatalException("There's a null in rslaves"); 1648 ret.append(rslave.getName()); 1649 if (!rslave.isAvailable()) 1650 ret.append("-OFFLINE"); 1651 if (i.hasNext()) 1652 ret.append(","); 1653 } 1654 ret.append("]"); 1655 } 1656 if (isDirectory()) 1657 ret.append("[directory(" + _files.size() + ")]"); 1658 ret.append("]"); 1659 return ret.toString(); 1660 } 1661 1662 public void unmergeDir(RemoteSlave rslave) { 1663 if (!isDirectory()) 1664 throw new IllegalStateException (); 1665 1666 for (Iterator i = getFiles().iterator(); i.hasNext();) { 1667 LinkedRemoteFileInterface file = 1668 (LinkedRemoteFileInterface) i.next(); 1669 if (file.isDirectory()) { 1670 file.unmergeDir(rslave); 1671 if (file.isDeleted() && file.dirSize() == 0) { 1673 i.remove(); 1674 if (file.length() != 0) 1677 logger.warn( 1678 "file.length() == " 1679 + file.length() 1680 + " for unmerged directory"); 1681 addSize(-file.length()); 1682 } 1683 } else { 1684 file.unmergeFile(rslave); 1685 } 1686 } 1687 } 1688 1689 public void unmergeFile(RemoteSlave rslave) { 1690 if (!isFile()) 1691 throw new IllegalStateException (); 1692 1693 if (removeSlave(rslave)) { 1694 logger.warn(getPath() + " deleted from " + rslave.getName()); 1695 } 1696 } 1703 1704} 1705 | Popular Tags |