001: /*
002: * This file is part of DrFTPD, Distributed FTP Daemon.
003: *
004: * DrFTPD is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * DrFTPD is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with DrFTPD; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */
018: package org.drftpd.slave;
019:
020: import org.apache.log4j.Logger;
021:
022: import se.mog.io.File;
023: import se.mog.io.PermissionDeniedException;
024:
025: import java.io.FileNotFoundException;
026: import java.io.IOException;
027:
028: import java.util.ArrayList;
029: import java.util.Collection;
030: import java.util.Collections;
031: import java.util.Comparator;
032: import java.util.Hashtable;
033: import java.util.Iterator;
034: import java.util.List;
035:
036: //TODO SECURITY: verify so that we never get outside of a rootbasket root
037:
038: /**
039: * @author mog
040: * @version $Id: RootCollection.java 1562 2007-01-05 12:37:07Z zubov $
041: */
042: public class RootCollection {
043: private static final Logger logger = Logger
044: .getLogger(RootCollection.class);
045: private Collection _roots;
046:
047: public RootCollection(Collection roots) throws IOException {
048: /** sanity checks **/
049: validateRoots(roots);
050: _roots = new ArrayList(roots);
051: }
052:
053: public Root getARoot() {
054: long mostFree = 0;
055: Root mostFreeRoot = null;
056:
057: for (Iterator iter = _roots.iterator(); iter.hasNext();) {
058: Root root = (Root) iter.next();
059: long diskSpaceAvailable = root.getDiskSpaceAvailable();
060:
061: if (diskSpaceAvailable > mostFree) {
062: mostFree = diskSpaceAvailable;
063: mostFreeRoot = root;
064: }
065: }
066:
067: if (mostFreeRoot == null) {
068: throw new RuntimeException("NoAvailableRootsException");
069: }
070:
071: return mostFreeRoot;
072: }
073:
074: /**
075: * Get a directory specified by dir under an approperiate root for storing storing files in.
076: * @param directory to store file in
077: * @throws PermissionDeniedException If creation of dir failed in the slave root selected by getARootFileDir().
078: */
079: public File getARootFileDir(String dir)
080: throws PermissionDeniedException {
081: Iterator iter = _roots.iterator();
082: Root bestRoot = (Root) iter.next();
083:
084: while (iter.hasNext()) {
085: Root root = (Root) iter.next();
086:
087: if (bestRoot.isFull()) {
088: bestRoot = root;
089:
090: continue;
091: }
092:
093: if (root.lastModified() > bestRoot.lastModified()) {
094: if (root.isFull() && !bestRoot.isFull()) {
095: continue;
096: }
097:
098: bestRoot = root;
099: }
100: }
101:
102: bestRoot.touch();
103:
104: File file = bestRoot.getFile(dir);
105:
106: file.mkdirs2();
107:
108: return file;
109: }
110:
111: //Get root which has most of the tree structure that we have.
112: public File getFile(String path) throws FileNotFoundException {
113: return new File(getRootForFile(path).getPath()
114: + File.separatorChar + path);
115: }
116:
117: /**
118: * Returns an ArrayList containing se.mog.io.File objects
119: */
120: public List getMultipleFiles(String path)
121: throws FileNotFoundException {
122: ArrayList files = new ArrayList();
123:
124: for (Iterator iter = getMultipleRootsForFile(path).iterator(); iter
125: .hasNext();) {
126: files.add(((Root) iter.next()).getFile(path));
127: }
128:
129: return files;
130: }
131:
132: public List getMultipleRootsForFile(String path)
133: throws FileNotFoundException {
134: ArrayList roots = new ArrayList();
135:
136: for (Iterator iter = _roots.iterator(); iter.hasNext();) {
137: Root root = (Root) iter.next();
138:
139: if (root.getFile(path).exists()) {
140: roots.add(root);
141: }
142: }
143:
144: if (roots.size() == 0) {
145: throw new FileNotFoundException(
146: "Unable to find suitable root: " + path);
147: }
148:
149: return roots;
150: }
151:
152: public Root getRootForFile(String path)
153: throws FileNotFoundException {
154: for (Iterator iter = _roots.iterator(); iter.hasNext();) {
155: Root root = (Root) iter.next();
156: File file = new File(root.getPath() + File.separatorChar
157: + path);
158: System.out.println(file.getPath());
159: if (file.exists()) {
160: return root;
161: }
162: }
163: throw new FileNotFoundException(path
164: + " wasn't found in any root");
165: }
166:
167: public long getTotalDiskSpaceAvailable() {
168: long totalDiskSpaceAvailable = 0;
169:
170: for (Iterator iter = _roots.iterator(); iter.hasNext();) {
171: Root root = (Root) iter.next();
172: File rootFile = root.getFile();
173: totalDiskSpaceAvailable += rootFile.getDiskSpaceAvailable();
174: }
175:
176: return totalDiskSpaceAvailable;
177: }
178:
179: public long getTotalDiskSpaceCapacity() {
180: long totalDiskSpaceCapacity = 0;
181:
182: for (Iterator iter = _roots.iterator(); iter.hasNext();) {
183: Root root = (Root) iter.next();
184: File rootFile = root.getFile();
185: totalDiskSpaceCapacity += rootFile.getDiskSpaceCapacity();
186: }
187:
188: return totalDiskSpaceCapacity;
189: }
190:
191: public Iterator iterator() {
192: return _roots.iterator();
193: }
194:
195: private static void validateRoots(Collection roots)
196: throws IOException {
197: File[] mountsArr = File.listMounts();
198: ArrayList mounts = new ArrayList(mountsArr.length);
199:
200: for (int i = 0; i < mountsArr.length; i++) {
201: mounts.add(mountsArr[i]);
202: }
203:
204: Collections.sort(mounts, new Comparator() {
205: public boolean equals(Object obj) {
206: if (obj == null)
207: return false;
208: return obj.getClass() == getClass();
209: }
210:
211: public int hashCode() {
212: return getClass().hashCode();
213: }
214:
215: public int compare(Object o1, Object o2) {
216: return compare((File) o1, (File) o2);
217: }
218:
219: public int compare(File o1, File o2) {
220: int this Val = o1.getPath().length();
221: int anotherVal = o2.getPath().length();
222:
223: return ((this Val < anotherVal) ? 1
224: : ((this Val == anotherVal) ? 0 : (-1)));
225: }
226: });
227:
228: Hashtable usedMounts = new Hashtable();
229:
230: for (Iterator iter = roots.iterator(); iter.hasNext();) {
231: Object o = iter.next();
232:
233: if (!(o instanceof Root)) {
234: throw new RuntimeException();
235: }
236:
237: Root root = (Root) o;
238: File rootFile = root.getFile();
239:
240: if (!rootFile.exists()) {
241: if (!rootFile.mkdirs()) {
242: throw new IOException("mkdirs() failed on "
243: + rootFile.getPath());
244: }
245: }
246:
247: if (!rootFile.exists()) {
248: throw new FileNotFoundException("Invalid root: "
249: + rootFile);
250: }
251:
252: String fullpath = rootFile.getAbsolutePath();
253:
254: for (Iterator iterator = mounts.iterator(); iterator
255: .hasNext();) {
256: File mount = (File) iterator.next();
257:
258: if (fullpath.startsWith(mount.getPath())) {
259: logger.info(fullpath + " in mount "
260: + mount.getPath());
261:
262: if (usedMounts.get(mount.getPath()) != null) {
263: throw new IOException(
264: "Multiple roots in mount "
265: + mount.getPath());
266: }
267:
268: usedMounts.put(mount.getPath(), new Object());
269:
270: break;
271: }
272: }
273:
274: for (Iterator iterator = roots.iterator(); iterator
275: .hasNext();) {
276: Root root2 = (Root) iterator.next();
277:
278: if (root == root2) {
279: continue;
280: }
281:
282: if ((root2.getPath() + File.pathSeparator)
283: .startsWith(root.getPath() + File.pathSeparator)) {
284: throw new RuntimeException("Overlapping roots: "
285: + root.getPath() + " and "
286: + root2.getPath());
287: }
288: }
289: }
290: }
291:
292: public int getMaxPath() {
293: if (Slave.isWin32) {
294: int maxPath = 0;
295:
296: for (Iterator iter = iterator(); iter.hasNext();) {
297: Root root = (Root) iter.next();
298: maxPath = Math.max(root.getPath().length(), maxPath);
299: } //constant for win32, see
300:
301: //http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/Q177/6/65.ASP&NoWebContent=1
302: // for more info
303: return 256 - maxPath;
304: }
305:
306: return -1;
307: }
308: }
|