1 /*
2  * File    : ShareResourceDirContentsImpl.java
3  * Created : 02-Jan-2004
4  * By      : parg
5  *
6  * Azureus - a Java Bittorrent client
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details ( see the LICENSE file ).
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 
23 package org.gudy.azureus2.pluginsimpl.local.sharing;
24 
25 /**
26  * @author parg
27  *
28  */
29 
30 import java.io.*;
31 import java.util.*;
32 
33 import org.gudy.azureus2.plugins.sharing.*;
34 import org.gudy.azureus2.plugins.torrent.TorrentAttribute;
35 import org.gudy.azureus2.core3.util.*;
36 import org.gudy.azureus2.core3.internat.*;
37 
38 public class
39 ShareResourceDirContentsImpl
40 	extends		ShareResourceImpl
41 	implements 	ShareResourceDirContents
42 {
43 	private final File					root;
44 	private final boolean				recursive;
45 	private final Map<String,String>	properties;
46 	private final byte[]				personal_key;
47 
48 	protected ShareResource[]		children	= new ShareResource[0];
49 
50 	protected
ShareResourceDirContentsImpl( ShareManagerImpl _manager, File _dir, boolean _recursive, boolean _personal, Map<String,String> _properties, boolean _async_check )51 	ShareResourceDirContentsImpl(
52 		ShareManagerImpl	_manager,
53 		File				_dir,
54 		boolean				_recursive,
55 		boolean				_personal,
56 		Map<String,String>	_properties,
57 		boolean				_async_check )
58 
59 		throws ShareException
60 	{
61 		super( _manager, ST_DIR_CONTENTS );
62 
63 		root 		= _dir;
64 		recursive	= _recursive;
65 		properties	= _properties;
66 
67 		if ( !root.exists()){
68 
69 			throw( new ShareException( "Dir '" + root.getName() + "' not found"));
70 		}
71 
72 		if ( root.isFile()){
73 
74 			throw( new ShareException( "Not a directory"));
75 		}
76 
77 		personal_key = _personal?RandomUtils.nextSecureHash():null;
78 
79 			// new resource, trigger processing
80 
81 		if ( _async_check ){
82 
83 			new AEThread2( "SM:asyncCheck", true )
84 			{
85 				public void
86 				run()
87 				{
88 					try{
89 						checkConsistency();
90 
91 					}catch( Throwable e ){
92 
93 						Debug.out( "Failed to update consistency", e );
94 					}
95 				}
96 			}.start();
97 
98 		}else{
99 
100 		      checkConsistency();
101 		}
102 	}
103 
104 	protected
ShareResourceDirContentsImpl( ShareManagerImpl _manager, File _dir, boolean _recursive, Map _map )105 	ShareResourceDirContentsImpl(
106 		ShareManagerImpl	_manager,
107 		File				_dir,
108 		boolean				_recursive,
109 		Map					_map )
110 
111 		throws ShareException
112 	{
113 		super( _manager, ST_DIR_CONTENTS, _map );
114 
115 		root 		= _dir;
116 		recursive	= _recursive;
117 
118 			// recovery - see comment below about not failing if dir doesn't exist...
119 
120 		if ( !root.exists()){
121 
122 			Debug.out( "Dir '" + root.getName() + "' not found");
123 
124 			// throw( new ShareException( "Dir '".concat(root.getName()).concat("' not found")));
125 
126 		}else{
127 
128 			if ( root.isFile()){
129 
130 				throw( new ShareException( "Not a directory"));
131 			}
132 		}
133 
134 		personal_key = (byte[])_map.get( "per_key" );
135 
136 		properties = BDecoder.decodeStrings((Map)_map.get( "props" ));
137 
138 			// deserialised resource, checkConsistency will be called later to trigger sub-share adding
139 	}
140 
141 	public boolean
canBeDeleted()142 	canBeDeleted()
143 
144 		throws ShareResourceDeletionVetoException
145 	{
146 		for (int i=0;i<children.length;i++){
147 
148 			if ( !children[i].canBeDeleted()){
149 
150 				return( false );
151 			}
152 		}
153 
154 		return( true );
155 	}
156 
157 	protected void
checkConsistency()158 	checkConsistency()
159 
160 		throws ShareException
161 	{
162 		// ensure all shares are defined as per dir contents and recursion flag
163 
164 		List	kids = checkConsistency(root);
165 
166 		if ( kids != null ){
167 
168 			children = new ShareResource[kids.size()];
169 
170 			kids.toArray( children );
171 
172 		}else{
173 
174 			children = new ShareResource[0];
175 		}
176 	}
177 
178 	protected List
checkConsistency( File dir )179 	checkConsistency(
180 		File		dir )
181 
182 		throws ShareException
183 	{
184 		List	kids = new ArrayList();
185 
186 		File[]	files = dir.listFiles();
187 
188 		if ( files == null || !dir.exists() ){
189 
190 				// dir has been deleted
191 
192 			if ( !isPersistent()){
193 
194 					// actually, this can be bad as some os errors (e.g. "too many open files") can cause the dir
195 					// to appear to have been deleted. However, we don't want to delete the share. So let's just
196 					// leave it around, manual delete required if deletion required.
197 
198 				if ( dir == root ){
199 
200 					return( null );
201 
202 				}else{
203 
204 					manager.delete( this, true );
205 				}
206 			}
207 		}else{
208 
209 			for (int i=0;i<files.length;i++){
210 
211 				File	file = files[i];
212 
213 				String	file_name = file.getName();
214 
215 				if (!(file_name.equals(".") || file_name.equals(".." ))){
216 
217 					if ( file.isDirectory()){
218 
219 						if ( recursive ){
220 
221 							List	child = checkConsistency( file );
222 
223 							kids.add( new shareNode( this, file, child ));
224 
225 						}else{
226 
227 							try{
228 								ShareResource res = manager.getDir( file );
229 
230 								if ( res == null ){
231 
232 									res = manager.addDir( this, file, personal_key != null, properties );
233 								}
234 
235 								kids.add( res );
236 
237 							}catch( Throwable e ){
238 
239 								Debug.printStackTrace( e );
240 							}
241 						}
242 					}else{
243 
244 						try{
245 							ShareResource res = manager.getFile( file );
246 
247 							if ( res == null ){
248 
249 								res = manager.addFile( this, file, personal_key != null, properties );
250 							}
251 
252 							kids.add( res );
253 
254 						}catch( Throwable e ){
255 
256 							Debug.printStackTrace( e );
257 						}
258 					}
259 				}
260 			}
261 
262 			for (int i=0;i<kids.size();i++){
263 
264 				Object	o = kids.get(i);
265 
266 				if ( o instanceof ShareResourceImpl ){
267 
268 					((ShareResourceImpl)o).setParent(this);
269 				}else{
270 
271 					((shareNode)o).setParent(this);
272 				}
273 			}
274 		}
275 
276 		return( kids );
277 	}
278 
279 	protected void
deleteInternal()280 	deleteInternal()
281 	{
282 		for (int i=0;i<children.length;i++){
283 
284 			try{
285 				if ( children[i] instanceof ShareResourceImpl ){
286 
287 					((ShareResourceImpl)children[i]).delete(true);
288 				}else{
289 
290 					((shareNode)children[i]).delete(true);
291 
292 				}
293 			}catch( Throwable e ){
294 
295 				Debug.printStackTrace( e );
296 			}
297 		}
298 	}
299 
300 	protected void
serialiseResource( Map map )301 	serialiseResource(
302 		Map		map )
303 	{
304 		super.serialiseResource( map );
305 
306 		map.put( "type", new Long(getType()));
307 
308 		map.put( "recursive", new Long(recursive?1:0));
309 
310 		try{
311 			map.put( "file", root.toString().getBytes( Constants.DEFAULT_ENCODING));
312 
313 		}catch( UnsupportedEncodingException e ){
314 
315 			Debug.printStackTrace( e );
316 		}
317 
318 		if ( personal_key != null ){
319 
320 			map.put( "per_key", personal_key );
321 		}
322 
323 		if ( properties != null ){
324 
325 			map.put( "props", properties );
326 		}
327 	}
328 
329 	protected static ShareResourceImpl
deserialiseResource( ShareManagerImpl manager, Map map )330 	deserialiseResource(
331 		ShareManagerImpl	manager,
332 		Map					map )
333 
334 		throws ShareException
335 	{
336 		try{
337 			File root = new File(new String((byte[])map.get("file"), Constants.DEFAULT_ENCODING));
338 
339 			boolean	recursive = ((Long)map.get("recursive")).longValue() == 1;
340 
341 			ShareResourceImpl res  = new ShareResourceDirContentsImpl( manager, root, recursive, map );
342 
343 			return( res );
344 
345 		}catch( UnsupportedEncodingException e ){
346 
347 			throw( new ShareException( "internal error", e ));
348 		}
349 	}
350 
351 	public String
getName()352 	getName()
353 	{
354 		return( root.toString());
355 	}
356 
357 	public File
getRoot()358 	getRoot()
359 	{
360 		return( root );
361 	}
362 
363 	public boolean
isRecursive()364 	isRecursive()
365 	{
366 		return( recursive );
367 	}
368 
369 	public ShareResource[]
getChildren()370 	getChildren()
371 	{
372 		return( children );
373 	}
374 
375 	public Map<String, String>
getProperties()376 	getProperties()
377 	{
378 		return( properties );
379 	}
380 
381 	protected class
382 	shareNode
383 		implements ShareResourceDirContents
384 	{
385 		protected ShareResourceDirContents	node_parent;
386 		protected File						node;
387 		protected ShareResource[]			node_children;
388 
389 		protected
shareNode( ShareResourceDirContents _parent, File _node, List kids )390 		shareNode(
391 			ShareResourceDirContents	_parent,
392 			File						_node,
393 			List						kids )
394 		{
395 			node_parent	= _parent;
396 			node		=_node;
397 
398 			node_children = new ShareResource[kids.size()];
399 
400 			kids.toArray( node_children );
401 
402 			for (int i=0;i<node_children.length;i++){
403 
404 				Object	o = node_children[i];
405 
406 				if ( o instanceof ShareResourceImpl ){
407 
408 					((ShareResourceImpl)o).setParent( this );
409 				}else{
410 
411 					((shareNode)o).setParent( this );
412 
413 				}
414 			}
415 		}
416 
417 		public ShareResourceDirContents
getParent()418 		getParent()
419 		{
420 			return( node_parent );
421 		}
422 
423 		protected void
setParent( ShareResourceDirContents _parent )424 		setParent(
425 			ShareResourceDirContents	_parent )
426 		{
427 			node_parent	= _parent;
428 		}
429 
430 		public int
getType()431 		getType()
432 		{
433 			return( ShareResource.ST_DIR_CONTENTS );
434 		}
435 
436 		public String
getName()437 		getName()
438 		{
439 			return( node.toString());
440 		}
441 
442 		public void
setAttribute( TorrentAttribute attribute, String value )443 		setAttribute(
444 			TorrentAttribute		attribute,
445 			String					value )
446 		{
447 			for (int i=0;i<node_children.length;i++){
448 
449 				node_children[i].setAttribute( attribute, value );
450 			}
451 		}
452 
453 		public String
getAttribute( TorrentAttribute attribute )454 		getAttribute(
455 			TorrentAttribute		attribute )
456 		{
457 			return( null );
458 		}
459 
460 		public TorrentAttribute[]
getAttributes()461 		getAttributes()
462 		{
463 			return( new TorrentAttribute[0]);
464 		}
465 
466 		public void
delete()467 		delete()
468 
469 			throws ShareResourceDeletionVetoException
470 		{
471 			throw( new ShareResourceDeletionVetoException( MessageText.getString("plugin.sharing.remove.veto")));
472 		}
473 
474 		public void
delete( boolean force )475 		delete(
476 			boolean	force )
477 
478 			throws ShareException, ShareResourceDeletionVetoException
479 		{
480 			for (int i=0;i<node_children.length;i++){
481 
482 				Object	o = node_children[i];
483 
484 				if ( o instanceof ShareResourceImpl ){
485 
486 					((ShareResourceImpl)o).delete(force);
487 				}else{
488 
489 					((shareNode)o).delete(force);
490 				}
491 			}
492 		}
493 
494 
495 		public boolean
canBeDeleted()496 		canBeDeleted()
497 
498 			throws ShareResourceDeletionVetoException
499 		{
500 			for (int i=0;i<node_children.length;i++){
501 
502 				node_children[i].canBeDeleted();
503 			}
504 
505 			return( true );
506 		}
507 
508 		public File
getRoot()509 		getRoot()
510 		{
511 			return( node );
512 		}
513 
514 		public boolean
isRecursive()515 		isRecursive()
516 		{
517 			return( recursive );
518 		}
519 
520 		public ShareResource[]
getChildren()521 		getChildren()
522 		{
523 			return( node_children );
524 		}
525 
526 		public Map<String, String>
getProperties()527 		getProperties()
528 		{
529 			return( null );
530 		}
531 
532 		public boolean
isPersistent()533 		isPersistent()
534 		{
535 			return( false );
536 		}
537 
538 		public void
addChangeListener( ShareResourceListener l )539 		addChangeListener(
540 			ShareResourceListener	l )
541 		{
542 		}
543 
544 		public void
removeChangeListener( ShareResourceListener l )545 		removeChangeListener(
546 			ShareResourceListener	l )
547 		{
548 		}
549 
550 		public void
addDeletionListener( ShareResourceWillBeDeletedListener l )551 		addDeletionListener(
552 			ShareResourceWillBeDeletedListener	l )
553 		{
554 		}
555 
556 		public void
removeDeletionListener( ShareResourceWillBeDeletedListener l )557 		removeDeletionListener(
558 			ShareResourceWillBeDeletedListener	l )
559 		{
560 		}
561 	}
562 }
563