Lines 45-60
Link Here
|
45 |
import java.awt.Image; |
45 |
import java.awt.Image; |
46 |
import java.awt.event.WindowEvent; |
46 |
import java.awt.event.WindowEvent; |
47 |
import java.awt.event.WindowFocusListener; |
47 |
import java.awt.event.WindowFocusListener; |
|
|
48 |
import java.io.BufferedReader; |
48 |
import java.io.ByteArrayInputStream; |
49 |
import java.io.ByteArrayInputStream; |
49 |
import java.io.ByteArrayOutputStream; |
50 |
import java.io.ByteArrayOutputStream; |
50 |
import java.io.File; |
51 |
import java.io.File; |
51 |
import java.io.FileInputStream; |
52 |
import java.io.FileInputStream; |
52 |
import java.io.FileNotFoundException; |
53 |
import java.io.FileNotFoundException; |
53 |
import java.io.FileOutputStream; |
54 |
import java.io.FileOutputStream; |
|
|
55 |
import java.io.FileReader; |
54 |
import java.io.IOException; |
56 |
import java.io.IOException; |
55 |
import java.io.InterruptedIOException; |
57 |
import java.io.InterruptedIOException; |
56 |
import java.io.ObjectInputStream; |
58 |
import java.io.ObjectInputStream; |
57 |
import java.io.ObjectOutputStream; |
59 |
import java.io.ObjectOutputStream; |
|
|
60 |
import java.io.OutputStream; |
61 |
import java.io.OutputStreamWriter; |
62 |
import java.io.PrintWriter; |
63 |
import java.io.UnsupportedEncodingException; |
58 |
import java.lang.ref.WeakReference; |
64 |
import java.lang.ref.WeakReference; |
59 |
import java.net.ConnectException; |
65 |
import java.net.ConnectException; |
60 |
import java.util.*; |
66 |
import java.util.*; |
Lines 70-81
Link Here
|
70 |
import org.netbeans.modules.dlight.libs.common.PathUtilities; |
76 |
import org.netbeans.modules.dlight.libs.common.PathUtilities; |
71 |
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment; |
77 |
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment; |
72 |
import org.netbeans.modules.nativeexecution.api.HostInfo; |
78 |
import org.netbeans.modules.nativeexecution.api.HostInfo; |
|
|
79 |
import org.netbeans.modules.nativeexecution.api.NativeProcessBuilder; |
73 |
import org.netbeans.modules.nativeexecution.api.util.CommonTasksSupport; |
80 |
import org.netbeans.modules.nativeexecution.api.util.CommonTasksSupport; |
74 |
import org.netbeans.modules.nativeexecution.api.util.ConnectionListener; |
81 |
import org.netbeans.modules.nativeexecution.api.util.ConnectionListener; |
75 |
import org.netbeans.modules.nativeexecution.api.util.ConnectionManager; |
82 |
import org.netbeans.modules.nativeexecution.api.util.ConnectionManager; |
76 |
import org.netbeans.modules.nativeexecution.api.util.ConnectionManager.CancellationException; |
83 |
import org.netbeans.modules.nativeexecution.api.util.ConnectionManager.CancellationException; |
77 |
import org.netbeans.modules.nativeexecution.api.util.FileInfoProvider; |
84 |
import org.netbeans.modules.nativeexecution.api.util.FileInfoProvider; |
78 |
import org.netbeans.modules.nativeexecution.api.util.HostInfoUtils; |
85 |
import org.netbeans.modules.nativeexecution.api.util.HostInfoUtils; |
|
|
86 |
import org.netbeans.modules.nativeexecution.api.util.ProcessUtils; |
79 |
import org.netbeans.modules.remote.actions.FastPasteAction; |
87 |
import org.netbeans.modules.remote.actions.FastPasteAction; |
80 |
import org.netbeans.modules.remote.api.ConnectionNotifier; |
88 |
import org.netbeans.modules.remote.api.ConnectionNotifier; |
81 |
import org.netbeans.modules.remote.impl.RemoteLogger; |
89 |
import org.netbeans.modules.remote.impl.RemoteLogger; |
Lines 140-146
Link Here
|
140 |
private final List<FileSystemProblemListener> problemListeners = |
148 |
private final List<FileSystemProblemListener> problemListeners = |
141 |
new ArrayList<>(globalProblemListeners); |
149 |
new ArrayList<>(globalProblemListeners); |
142 |
transient private final StatusImpl status = new StatusImpl(); |
150 |
transient private final StatusImpl status = new StatusImpl(); |
|
|
151 |
|
152 |
/** If the ALLOW_ALTERNATIVE_DELETE_ON_EXIT is ON and transport does not support delete-on-exit, |
153 |
* then alternative delete-on-exit will work */ |
154 |
public static final boolean ALLOW_ALTERNATIVE_DELETE_ON_EXIT = |
155 |
RemoteFileSystemUtils.getBoolean("remote.alternative.delete.on.exit", true); |
156 |
public static final String DELETE_ON_EXIT_FILE_NAME = ".rfs_delete_on_exit"; // NOI18N |
157 |
/** guarded by self */ |
143 |
private final LinkedHashSet<String> deleteOnExitFiles = new LinkedHashSet<>(); |
158 |
private final LinkedHashSet<String> deleteOnExitFiles = new LinkedHashSet<>(); |
|
|
159 |
/** |
160 |
* guarded by deleteOnExitFiles |
161 |
* The idea is to remove files only on 1-st connect; otherwise we'll get to complex sync */ |
162 |
boolean deleteOnExitFlag; |
163 |
|
144 |
private final ThreadLocal<RemoteFileObjectBase> beingRemoved = new ThreadLocal<>(); |
164 |
private final ThreadLocal<RemoteFileObjectBase> beingRemoved = new ThreadLocal<>(); |
145 |
private final ThreadLocal<RemoteFileObjectBase> beingCreated = new ThreadLocal<>(); |
165 |
private final ThreadLocal<RemoteFileObjectBase> beingCreated = new ThreadLocal<>(); |
146 |
private final ThreadLocal<RemoteFileObjectBase> externallyRemoved = new ThreadLocal<>(); |
166 |
private final ThreadLocal<RemoteFileObjectBase> externallyRemoved = new ThreadLocal<>(); |
Lines 186-191
Link Here
|
186 |
if (!cache.exists() && !cache.mkdirs()) { |
206 |
if (!cache.exists() && !cache.mkdirs()) { |
187 |
throw new IOException(NbBundle.getMessage(getClass(), "ERR_CreateDir", cache.getAbsolutePath())); // new IOException sic! (ctor) |
207 |
throw new IOException(NbBundle.getMessage(getClass(), "ERR_CreateDir", cache.getAbsolutePath())); // new IOException sic! (ctor) |
188 |
} |
208 |
} |
|
|
209 |
if (ALLOW_ALTERNATIVE_DELETE_ON_EXIT) { |
210 |
loadDeleteOnExit(); |
211 |
synchronized (deleteOnExitFiles) { |
212 |
deleteOnExitFlag = true; |
213 |
} |
214 |
} |
189 |
this.rootDelegate = new RootFileObject(this.root = new RemoteFileObject(this), this, execEnv, cache); // NOI18N |
215 |
this.rootDelegate = new RootFileObject(this.root = new RemoteFileObject(this), this, execEnv, cache); // NOI18N |
190 |
factory.register(rootDelegate); |
216 |
factory.register(rootDelegate); |
191 |
|
217 |
|
Lines 347-352
Link Here
|
347 |
fo.connectionChanged(); |
373 |
fo.connectionChanged(); |
348 |
} |
374 |
} |
349 |
} |
375 |
} |
|
|
376 |
if (ALLOW_ALTERNATIVE_DELETE_ON_EXIT) { |
377 |
if (ConnectionManager.getInstance().isConnectedTo(execEnv)) { |
378 |
deleteOnExitImpl(); |
379 |
} |
380 |
} |
350 |
} |
381 |
} |
351 |
|
382 |
|
352 |
private void maintainAutoMounts() { |
383 |
private void maintainAutoMounts() { |
Lines 420-425
Link Here
|
420 |
if (COLLECT_STATSISTICS) { |
451 |
if (COLLECT_STATSISTICS) { |
421 |
lockSupport.printStatistics(this); |
452 |
lockSupport.printStatistics(this); |
422 |
} |
453 |
} |
|
|
454 |
if (ALLOW_ALTERNATIVE_DELETE_ON_EXIT) { |
455 |
// right here: on IDE shutdown we otherwise won't be in time to store |
456 |
storeDeleteOnExit(); |
457 |
} |
423 |
} |
458 |
} |
424 |
|
459 |
|
425 |
public ExecutionEnvironment getExecutionEnvironment() { |
460 |
public ExecutionEnvironment getExecutionEnvironment() { |
Lines 949-984
Link Here
|
949 |
return status; |
984 |
return status; |
950 |
} |
985 |
} |
951 |
|
986 |
|
952 |
public void deleteOnExit(String path) { |
987 |
public void deleteOnExit(String... paths) { |
953 |
synchronized(deleteOnExitFiles) { |
988 |
synchronized(deleteOnExitFiles) { |
954 |
if (deleteOnExitFiles.isEmpty()) { |
989 |
for (String p : paths) { |
955 |
Runtime.getRuntime().addShutdownHook(new Thread() { |
990 |
deleteOnExitFiles.add(p); |
956 |
|
|
|
957 |
@Override |
958 |
public void run() { |
959 |
releaseResources(); |
960 |
} |
961 |
|
962 |
}); |
963 |
} |
991 |
} |
964 |
deleteOnExitFiles.add(path); |
|
|
965 |
} |
992 |
} |
966 |
} |
993 |
} |
967 |
|
994 |
|
968 |
private void releaseResources() { |
995 |
private void deleteOnExitImpl() { |
969 |
ArrayList<String> toBeDeleted; |
996 |
assert ALLOW_ALTERNATIVE_DELETE_ON_EXIT; |
|
|
997 |
List<String> toBeDeleted = Collections.emptyList(); |
970 |
synchronized(deleteOnExitFiles) { |
998 |
synchronized(deleteOnExitFiles) { |
971 |
toBeDeleted = new ArrayList<>(deleteOnExitFiles); |
999 |
if (deleteOnExitFlag && !deleteOnExitFiles.isEmpty()) { |
|
|
1000 |
deleteOnExitFlag = false; // delete only on 1-st connect, otherwize we get sync issues |
1001 |
toBeDeleted = new ArrayList<>(deleteOnExitFiles); |
1002 |
deleteOnExitFiles.clear(); |
1003 |
} |
1004 |
} |
1005 |
if (toBeDeleted.isEmpty()) { |
1006 |
return; |
972 |
} |
1007 |
} |
973 |
Collections.reverse(toBeDeleted); |
1008 |
Collections.reverse(toBeDeleted); |
974 |
for (String filename : toBeDeleted) { |
1009 |
StringBuilder sb = new StringBuilder(); |
975 |
if (!ConnectionManager.getInstance().isConnectedTo(execEnv)) { |
1010 |
for (String p : toBeDeleted) { |
976 |
return; |
1011 |
if (sb.length() > 0) { |
|
|
1012 |
sb.append(' '); |
977 |
} |
1013 |
} |
978 |
CommonTasksSupport.rmFile(execEnv, filename, null); |
1014 |
sb.append(p); |
|
|
1015 |
} |
1016 |
if (!ConnectionManager.getInstance().isConnectedTo(execEnv)) { |
1017 |
return; |
1018 |
} |
1019 |
ProcessUtils.execute(NativeProcessBuilder.newProcessBuilder(execEnv).setExecutable("xargs").setArguments("rm"), sb.toString().getBytes()); |
1020 |
|
1021 |
} |
1022 |
|
1023 |
private void storeDeleteOnExit() { |
1024 |
assert ALLOW_ALTERNATIVE_DELETE_ON_EXIT; |
1025 |
ArrayList<String> toStore; |
1026 |
synchronized (deleteOnExitFiles) { |
1027 |
toStore = new ArrayList<>(deleteOnExitFiles); |
1028 |
} |
1029 |
File f = new File(getCache(), DELETE_ON_EXIT_FILE_NAME); |
1030 |
// the existence of cache root ensured in ctor |
1031 |
try (PrintWriter pw = new PrintWriter(f, "UTF8")) { // NOI18N |
1032 |
if (!toStore.isEmpty()) { |
1033 |
for (String path : toStore) { |
1034 |
pw.append(path).append('\n'); |
1035 |
} |
1036 |
pw.close(); |
1037 |
} |
1038 |
} catch (FileNotFoundException | UnsupportedEncodingException ex) { |
1039 |
Exceptions.printStackTrace(ex); // should never occur |
979 |
} |
1040 |
} |
980 |
} |
1041 |
} |
981 |
|
1042 |
|
|
|
1043 |
private void loadDeleteOnExit() { |
1044 |
assert ALLOW_ALTERNATIVE_DELETE_ON_EXIT; |
1045 |
File f = new File(getCache(), DELETE_ON_EXIT_FILE_NAME); |
1046 |
// the existence of cache root ensured in ctor |
1047 |
synchronized (deleteOnExitFiles) { |
1048 |
// this is called from ctor only, so it's OK to do file ops in sync block |
1049 |
try (BufferedReader br = new BufferedReader(new FileReader(f))) { |
1050 |
for (String path; (path = br.readLine()) != null;) { |
1051 |
if (!path.isEmpty()) { |
1052 |
deleteOnExitFiles.add(path); |
1053 |
} |
1054 |
} |
1055 |
// line is not visible here. |
1056 |
} catch (FileNotFoundException ex) { |
1057 |
// nothing to do: no file is quite normal |
1058 |
} catch (IOException ex) { |
1059 |
ex.printStackTrace(System.err); |
1060 |
} |
1061 |
} |
1062 |
} |
1063 |
|
982 |
/*package*/ void setBeingRemoved(RemoteFileObjectBase fo) { |
1064 |
/*package*/ void setBeingRemoved(RemoteFileObjectBase fo) { |
983 |
beingRemoved.set(fo); |
1065 |
beingRemoved.set(fo); |
984 |
} |
1066 |
} |