Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: a696e8c15e1d3fcd349739890d52fce8852a5a4d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
/*******************************************************************************
 * Copyright (c) 2011 Wind River Systems, Inc. and others. All rights reserved.
 * This program and the accompanying materials are made available under the terms
 * of the Eclipse Public License v1.0 which accompanies this distribution, and is
 * available at http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * Wind River Systems - initial API and implementation
 * William Chen (Wind River) - [345384] Provide property pages for remote file system nodes
 * William Chen (Wind River) - [352302]Opening a file in an editor depending on
 *                             the client's permissions.
 * William Chen (Wind River) - [361324] Add more file operations in the file system
 * 												of Target Explorer.
 *******************************************************************************/
package org.eclipse.tcf.te.tcf.filesystem.model;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.PlatformObject;
import org.eclipse.tcf.protocol.Protocol;
import org.eclipse.tcf.services.IFileSystem;
import org.eclipse.tcf.te.tcf.filesystem.interfaces.IWindowsFileAttributes;
import org.eclipse.tcf.te.tcf.filesystem.internal.UserAccount;
import org.eclipse.tcf.te.tcf.filesystem.internal.handlers.UserManager;
import org.eclipse.tcf.te.tcf.filesystem.internal.url.TcfURLConnection;
import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerModel;

/**
 * Representation of a file system tree node.
 * <p>
 * <b>Note:</b> Node construction and child list access is limited to the TCF
 * event dispatch thread.
 */
public final class FSTreeNode extends PlatformObject implements Cloneable{

	private static final String KEY_WIN32_ATTRS = "Win32Attrs"; //$NON-NLS-1$

	private final UUID uniqueId = UUID.randomUUID();

	/**
	 * The tree node name.
	 */
	public String name = null;

	/**
	 * The tree node type.
	 */
	public String type = null;

	/**
	 * The tree node file system attributes
	 */
	public IFileSystem.FileAttrs attr = null;

	/**
	 * The peer node the file system tree node is associated with.
	 */
	public IPeerModel peerNode = null;

	/**
	 * The tree node parent.
	 */
	public FSTreeNode parent = null;

	/**
	 * The tree node children.
	 */
	private List<FSTreeNode> children;

	/**
	 * Flag to mark once the children of the node got queried
	 */
	public boolean childrenQueried = false;

	/**
	 * Flag to mark once the children query is running
	 */
	public boolean childrenQueryRunning = false;

	/**
	 * Constructor.
	 */
	public FSTreeNode() {
		super();
		children = Collections.synchronizedList(new ArrayList<FSTreeNode>());
		Assert.isTrue(Protocol.isDispatchThread());
	}

	/*
	 * (non-Javadoc)
	 * @see java.lang.Object#clone()
	 */
	@Override
	public Object clone() {
		if (Protocol.isDispatchThread()) {
			FSTreeNode clone = new FSTreeNode();
			clone.childrenQueried = childrenQueried;
			clone.childrenQueryRunning = childrenQueryRunning;
			clone.name = name;
			clone.parent = parent;
			clone.peerNode = peerNode;
			clone.type = type;
			Map<String, Object> attributes = new HashMap<String, Object>(attr.attributes);
			clone.attr = new IFileSystem.FileAttrs(attr.flags, attr.size, attr.uid, attr.gid, attr.permissions, attr.atime, attr.mtime, attributes);
			return clone;
		}
		final Object[] objects = new Object[1];
		Protocol.invokeAndWait(new Runnable() {

			@Override
			public void run() {
				objects[0] = FSTreeNode.this.clone();
			}
		});
		return objects[0];
	}

	/**
	 * Change the file/folder's write permission.
	 * @param b true if the agent is granted with its write permission.
	 */
	public void setWritable(boolean b) {
		UserAccount account = UserManager.getInstance().getUserAccount(peerNode);
		if (account != null && attr != null) {
			int bit;
			if (attr.uid == account.getEUID()) {
				bit = IFileSystem.S_IWUSR;
			} else if (attr.gid == account.getEGID()) {
				bit = IFileSystem.S_IWGRP;
			} else {
				bit = IFileSystem.S_IWOTH;
			}
			int permissions = attr.permissions;
			setPermissions(b ? (permissions | bit):(permissions & ~ bit));
		}
    }

	/**
	 * Set the file's permissions.
	 * @param permissions The new permissions.
	 */
	public void setPermissions(int permissions) {
		attr = new IFileSystem.FileAttrs(attr.flags, attr.size, attr.uid, attr.gid, permissions, attr.atime, attr.mtime, attr.attributes);
    }

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public final int hashCode() {
		return uniqueId.hashCode();
	}

	/**
	 * Returns the children list storage object.
	 * <p>
	 * <b>Note:</b> This method must be called from within the TCF event
	 * dispatch thread only!
	 * 
	 * @return The children list storage object.
	 */
	public final List<FSTreeNode> getChildren() {
		Assert.isTrue(Protocol.isDispatchThread());
		return children;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public final boolean equals(Object obj) {
		if(this == obj)
			return true;
		if (obj instanceof FSTreeNode) {
			return uniqueId.equals(((FSTreeNode) obj).uniqueId);
		}
		return super.equals(obj);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		StringBuilder buffer = new StringBuilder(getClass().getSimpleName());
		buffer.append(": name=" + (name != null ? name : super.toString())); //$NON-NLS-1$
		buffer.append(", UUID=" + uniqueId.toString()); //$NON-NLS-1$
		return buffer.toString();
	}

	/**
	 * Return if the node is a Windows file/folder node.
	 * 
	 * @return true if it is a Windows node, or else false.
	 */
	public boolean isWindowsNode() {
		return attr != null && attr.attributes != null && attr.attributes.containsKey(KEY_WIN32_ATTRS);
	}

	/**
	 * Return if the node is a file.
	 * 
	 * @return true if it is a file, or else false.
	 */
	public boolean isFile() {
		return attr != null && attr.isFile();
	}

	/**
	 * Return if the node is a directory.
	 * 
	 * @return true if it is a directory, or else false.
	 */
	public boolean isDirectory() {
		return attr != null && attr.isDirectory();
	}

	/**
	 * Return if the attribute specified by the mask bit is turned on.
	 * 
	 * @param bit
	 *            The attribute's mask bit.
	 * @return true if it is on, or else false.
	 */
	public boolean isWin32AttrOn(int bit) {
		if (attr != null && attr.attributes.get(KEY_WIN32_ATTRS) instanceof Integer) {
			Integer win32Attrs = (Integer) attr.attributes.get(KEY_WIN32_ATTRS);
			return (win32Attrs.intValue() & bit) != 0;
		}
		return false;
	}
	
	/**
	 * Set the attribute specified by the mask bit to on or off.
	 * @param bit The attribute's mask bit.
	 * @param on The flag if the bit should be turned on or off.
	 */
	public void setWin32Attr(int bit, boolean on) {
		if (attr != null && attr.attributes.get(KEY_WIN32_ATTRS) instanceof Integer) {
			int win32attr = ((Integer) attr.attributes.get(KEY_WIN32_ATTRS)).intValue();
			win32attr = on ? (win32attr | bit) : (win32attr & ~bit);
			attr.attributes.put(KEY_WIN32_ATTRS, Integer.valueOf(win32attr));
		}
	}

	/**
	 * Get the file's win32 attributes.
	 * @return The file's win32 attributes.
	 */
	public int getWin32Attrs() {
		if (attr != null && attr.attributes.get(KEY_WIN32_ATTRS) instanceof Integer) {
			return ((Integer) attr.attributes.get(KEY_WIN32_ATTRS)).intValue();
		}
	    return 0;
    }

	/**
	 * Return if this file/folder is hidden.
	 * 
	 * @return true if it is hidden, or else false.
	 */
	public boolean isHidden() {
		return isWin32AttrOn(IWindowsFileAttributes.FILE_ATTRIBUTE_HIDDEN);
	}

	/**
	 * Set the file/folder hidden attribute's value.
	 * @param hidden The new value.
	 */
	public void setHidden(boolean hidden) {
		setWin32Attr(IWindowsFileAttributes.FILE_ATTRIBUTE_HIDDEN, hidden);
    }

	/**
	 * Return if this file/folder is read-only.
	 * 
	 * @return true if it is read-only, or else false.
	 */
	public boolean isReadOnly() {
		return isWin32AttrOn(IWindowsFileAttributes.FILE_ATTRIBUTE_READONLY);
	}

	/**
	 * Set the file/folder read-only attribute's value.
	 * @param readOnly The new value.
	 */
	public void setReadOnly(boolean readOnly) {
		setWin32Attr(IWindowsFileAttributes.FILE_ATTRIBUTE_READONLY, readOnly);
    }

	/**
	 * Get the location of a file/folder node using the format of the file
	 * system's platform.
	 * 
	 * @param node
	 *            The file/folder node.
	 * @return The location of the file/folder.
	 */
	public String getLocation() {
		return getLocation(false);
	}

	/**
	 * Get the location of a file/folder.
	 * 
	 * @param cross
	 *            If the format is cross-platform.
	 * @return The path to the file/folder.
	 */
	public String getLocation(boolean cross) {
		if(isRoot()) {
			if(cross) {
				if(isWindowsNode()) {
					return name.substring(0, name.length() - 1) + "/"; //$NON-NLS-1$
				}
			}
			return name;
		}
		String pLoc = parent.getLocation(cross);
		if(parent.isRoot()) {
			return pLoc + name; 
		}
		String pathSep = (!cross && isWindowsNode()) ? "\\" : "/"; //$NON-NLS-1$ //$NON-NLS-2$
		return pLoc + pathSep + name;
	}

	/**
	 * Get the URL of the file or folder. The URL's format is created in the
	 * following way: tcf:///<TCF_AGENT_ID>/remote/path/to/the/resource... See
	 * {@link TcfURLConnection#TcfURLConnection(URL)}
	 * 
	 * @return The URL of the file/folder.
	 * @throws MalformedURLException
	 */
	public URL getLocationURL() {
		try {
			String id = peerNode.getPeer().getID();
			String path = getLocation(true);
			String location = TcfURLConnection.PROTOCOL_SCHEMA + ":/" + id + (isWindowsNode() ? "/" + path : path); //$NON-NLS-1$ //$NON-NLS-2$
			return new URL(location);
		} catch (MalformedURLException e) {
			assert false;
			return null;
		}
	}

	/**
	 * If this node is a root node.
	 * 
	 * @return true if this node is a root node.
	 */
	public boolean isRoot() {
		return type.endsWith("FSRootDirNode"); //$NON-NLS-1$
	}

	/**
	 * If this file is readable.
	 * 
	 * @return true if it is readable.
	 */
	public boolean isReadable() {
		UserAccount account = UserManager.getInstance().getUserAccount(peerNode);
		if (account != null && attr != null) {
			if (attr.uid == account.getEUID()) {
				return (attr.permissions & IFileSystem.S_IRUSR) != 0;
			} else if (attr.gid == account.getEGID()) {
				return (attr.permissions & IFileSystem.S_IRGRP) != 0;
			} else {
				return (attr.permissions & IFileSystem.S_IROTH) != 0;
			}
		}
		return false;
	}

	/**
	 * If the agent is the owner of this file/folder.
	 * 
	 * @return true if the agent is the owner of this file/folder.
	 */
	public boolean isAgentOwner() {
		UserAccount account = UserManager.getInstance().getUserAccount(peerNode);
		if (account != null && attr != null) {
			return attr.uid == account.getEUID();
		}
		return false;
	}

	/**
	 * If this file is writable.
	 * 
	 * @return true if it is writable.
	 */
	public boolean isWritable() {
		UserAccount account = UserManager.getInstance().getUserAccount(peerNode);
		if (account != null && attr != null) {
			if (attr.uid == account.getEUID()) {
				return (attr.permissions & IFileSystem.S_IWUSR) != 0;
			} else if (attr.gid == account.getEGID()) {
				return (attr.permissions & IFileSystem.S_IWGRP) != 0;
			} else {
				return (attr.permissions & IFileSystem.S_IWOTH) != 0;
			}
		}
		return false;
	}

	/**
	 * If this file is executable.
	 * 
	 * @return true if it is executable.
	 */
	public boolean isExecutable() {
		UserAccount account = UserManager.getInstance().getUserAccount(peerNode);
		if (account != null && attr != null) {
			if (attr.uid == account.getEUID()) {
				return (attr.permissions & IFileSystem.S_IXUSR) != 0;
			} else if (attr.gid == account.getEGID()) {
				return (attr.permissions & IFileSystem.S_IXGRP) != 0;
			} else {
				return (attr.permissions & IFileSystem.S_IXOTH) != 0;
			}
		}
		return false;
	}

	/**
	 * If this node is ancestor of the specified node.
	 * @return true if it is.
	 */
	public boolean isAncestorOf(FSTreeNode node) {
		if (node == null) return false;
		if (node.parent == this) return true;
		return isAncestorOf(node.parent);
	}
}

Back to the top