This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 268926
Collapse All | Expand All

(-)13ee6f16f094 (+197 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 */
40
package org.netbeans.modules.remote.impl.fs;
41
42
import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment;
43
import java.io.BufferedReader;
44
import java.io.File;
45
import java.io.FileNotFoundException;
46
import java.io.FileReader;
47
import java.io.IOException;
48
import java.io.PrintWriter;
49
import java.io.UnsupportedEncodingException;
50
import java.util.ArrayList;
51
import java.util.Collection;
52
import java.util.LinkedHashSet;
53
import java.util.List;
54
import org.netbeans.modules.nativeexecution.api.NativeProcessBuilder;
55
import org.netbeans.modules.nativeexecution.api.util.ConnectionManager;
56
import org.netbeans.modules.nativeexecution.api.util.ProcessUtils;
57
import org.openide.util.Exceptions;
58
59
/**
60
 * Manages paths that are marked as "delete on exit".
61
 * @author vkvashin
62
 */
63
public class DeleteOnExitSupport {
64
65
    private final ExecutionEnvironment execEnv;
66
    private final File cache;
67
68
    /** If the ALLOW_ALTERNATIVE_DELETE_ON_EXIT is ON and transport does not support delete-on-exit, 
69
     *  then alternative delete-on-exit will work */
70
    private static final boolean ALLOW_ALTERNATIVE_DELETE_ON_EXIT = 
71
            RemoteFileSystemUtils.getBoolean("remote.alternative.delete.on.exit", true);
72
73
    private static final String DELETE_ON_EXIT_FILE_NAME = ".rfs_delete_on_exit"; // NOI18N
74
75
    private static final Object lock = new Object();
76
    
77
    // The idea about filesToDelete and filesToRemember is as follows:
78
    // When a file is marked as "delete on exit", it is added to filesToRemember
79
    // When a disconnect occurs, we move all files from filesToRemember into filesToDelete
80
    // (and also store them on disk)
81
    // When connnect occurs, filesToDelete are deleted.
82
    // This prevents sync issues 
83
    
84
    /** guarded by lock */
85
    private final LinkedHashSet<String> filesToDelete = new LinkedHashSet<>();
86
87
    /** guarded by lock */
88
    private final LinkedHashSet<String> filesToRemember = new LinkedHashSet<>();
89
90
    
91
    public DeleteOnExitSupport(ExecutionEnvironment execEnv, File cacheRoot) {
92
        this.execEnv = execEnv;
93
        this.cache = new File(cacheRoot, DELETE_ON_EXIT_FILE_NAME);
94
        if (ALLOW_ALTERNATIVE_DELETE_ON_EXIT) {
95
            synchronized (lock) {
96
                loadDeleteOnExit(cache, filesToDelete);
97
            }
98
        }
99
    }
100
    
101
    /** Called directly from ConnectionListener.connected */
102
    public void notifyConnected() {        
103
    }
104
105
    /** Called directly from ConnectionListener.disconnected */
106
    public void notifyDisconnected() {        
107
        if (ALLOW_ALTERNATIVE_DELETE_ON_EXIT) {
108
            List<String> paths;
109
            synchronized (lock) {
110
                filesToDelete.addAll(filesToRemember);
111
                filesToRemember.clear();
112
                paths = new ArrayList<>(filesToDelete);
113
            }
114
            storeDeleteOnExit(cache, paths);
115
        }
116
    }
117
    /**
118
     * Is called from the request processor 
119
     * in reaction on connect OR disconnect
120
     */
121
    public void processConnectionChange() {
122
        if (ALLOW_ALTERNATIVE_DELETE_ON_EXIT) {
123
            if (ConnectionManager.getInstance().isConnectedTo(execEnv)) {
124
                List<String> paths;
125
                synchronized (lock) {
126
                    paths = new ArrayList<>(filesToDelete);
127
                    filesToDelete.clear();
128
                }
129
                if (!paths.isEmpty()) {
130
                    deleteImpl(execEnv, paths);
131
                }
132
            }
133
        }
134
    }
135
    
136
    public void deleteOnExit(String... paths) {
137
        if (ALLOW_ALTERNATIVE_DELETE_ON_EXIT) {
138
            synchronized (lock) {
139
                for (String p : paths) {
140
                    filesToRemember.add(p);
141
                }
142
            }
143
        }
144
    }
145
146
    private static void deleteImpl(ExecutionEnvironment execEnv, Collection<String> paths) {
147
        assert ALLOW_ALTERNATIVE_DELETE_ON_EXIT;
148
        if (paths.isEmpty()) {
149
            return;
150
        }
151
        StringBuilder sb = new StringBuilder();
152
        for (String p : paths) {
153
            if (sb.length() > 0) {
154
                sb.append(' ');
155
            }
156
            sb.append(p);
157
        }
158
        if (!ConnectionManager.getInstance().isConnectedTo(execEnv)) {
159
            return;
160
        }
161
        ProcessUtils.execute(NativeProcessBuilder.newProcessBuilder(execEnv).setExecutable("xargs").setArguments("rm"), sb.toString().getBytes());
162
163
    }
164
165
    private static void storeDeleteOnExit(File file, Collection<String> paths) {
166
        assert ALLOW_ALTERNATIVE_DELETE_ON_EXIT;
167
        // the existence of cache root ensured in ctor
168
        try (PrintWriter pw = new PrintWriter(file, "UTF8")) { // NOI18N
169
            if (!paths.isEmpty()) {
170
                for (String path : paths) {
171
                    pw.append(path).append('\n');
172
                }
173
                pw.close();
174
            }
175
        } catch (FileNotFoundException | UnsupportedEncodingException ex) {
176
            Exceptions.printStackTrace(ex); // should never occur
177
        }
178
    }
179
180
    private static void loadDeleteOnExit(File file, Collection<String> pathsToAdd) {
181
        assert ALLOW_ALTERNATIVE_DELETE_ON_EXIT;
182
        // the existence of cache root ensured in ctor
183
        // this is called from ctor only, so it's OK to do file ops in sync block
184
        try (BufferedReader br = new BufferedReader(new FileReader(file))) {
185
            for (String path; (path = br.readLine()) != null;) {
186
                if (!path.isEmpty()) {
187
                    pathsToAdd.add(path);
188
                }
189
            }
190
            // line is not visible here.
191
        } catch (FileNotFoundException ex) {
192
            // nothing to do: no file is quite normal
193
        } catch (IOException ex) {
194
            ex.printStackTrace(System.err);
195
        }
196
    }
197
}
(-)a/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/RemoteFileSystem.java (-32 / +22 lines)
Lines 55-61 Link Here
55
import java.io.InterruptedIOException;
55
import java.io.InterruptedIOException;
56
import java.io.ObjectInputStream;
56
import java.io.ObjectInputStream;
57
import java.io.ObjectOutputStream;
57
import java.io.ObjectOutputStream;
58
import java.lang.ref.WeakReference;
59
import java.net.ConnectException;
58
import java.net.ConnectException;
60
import java.util.*;
59
import java.util.*;
61
import java.util.concurrent.CopyOnWriteArrayList;
60
import java.util.concurrent.CopyOnWriteArrayList;
Lines 140-146 Link Here
140
    private final List<FileSystemProblemListener> problemListeners =
139
    private final List<FileSystemProblemListener> problemListeners =
141
            new ArrayList<>(globalProblemListeners);
140
            new ArrayList<>(globalProblemListeners);
142
    transient private final StatusImpl status = new StatusImpl();
141
    transient private final StatusImpl status = new StatusImpl();
143
    private final LinkedHashSet<String> deleteOnExitFiles = new LinkedHashSet<>();
142
    private final DeleteOnExitSupport deleteOnExitSupport;
144
    private final ThreadLocal<RemoteFileObjectBase> beingRemoved = new ThreadLocal<>();
143
    private final ThreadLocal<RemoteFileObjectBase> beingRemoved = new ThreadLocal<>();
145
    private final ThreadLocal<RemoteFileObjectBase> beingCreated = new ThreadLocal<>();
144
    private final ThreadLocal<RemoteFileObjectBase> beingCreated = new ThreadLocal<>();
146
    private final ThreadLocal<RemoteFileObjectBase> externallyRemoved = new ThreadLocal<>();
145
    private final ThreadLocal<RemoteFileObjectBase> externallyRemoved = new ThreadLocal<>();
Lines 169-174 Link Here
169
     * @guarded by autoMounts 
168
     * @guarded by autoMounts 
170
     */
169
     */
171
    private boolean autoMountsAnalyzed = false;
170
    private boolean autoMountsAnalyzed = false;
171
    private volatile boolean disposed = false;
172
172
173
    /*package*/ RemoteFileSystem(ExecutionEnvironment execEnv) throws IOException {
173
    /*package*/ RemoteFileSystem(ExecutionEnvironment execEnv) throws IOException {
174
        RemoteLogger.assertTrue(execEnv.isRemote());
174
        RemoteLogger.assertTrue(execEnv.isRemote());
Lines 186-191 Link Here
186
        if (!cache.exists() && !cache.mkdirs()) {
186
        if (!cache.exists() && !cache.mkdirs()) {
187
            throw new IOException(NbBundle.getMessage(getClass(), "ERR_CreateDir", cache.getAbsolutePath())); // new IOException sic! (ctor)
187
            throw new IOException(NbBundle.getMessage(getClass(), "ERR_CreateDir", cache.getAbsolutePath())); // new IOException sic! (ctor)
188
        }
188
        }
189
        deleteOnExitSupport = new DeleteOnExitSupport(execEnv, cache);
189
        this.rootDelegate = new RootFileObject(this.root = new RemoteFileObject(this), this, execEnv, cache); // NOI18N
190
        this.rootDelegate = new RootFileObject(this.root = new RemoteFileObject(this), this, execEnv, cache); // NOI18N
190
        factory.register(rootDelegate);
191
        factory.register(rootDelegate);
191
192
Lines 326-331 Link Here
326
    }
327
    }
327
    
328
    
328
    /*package*/ void dispose() {
329
    /*package*/ void dispose() {
330
        disposed = true;
329
        ConnectionManager.getInstance().removeConnectionListener(this);
331
        ConnectionManager.getInstance().removeConnectionListener(this);
330
    }
332
    }
331
333
Lines 339-345 Link Here
339
            if (ConnectionManager.getInstance().isConnectedTo(execEnv)) {
341
            if (ConnectionManager.getInstance().isConnectedTo(execEnv)) {
340
                maintainAutoMounts();
342
                maintainAutoMounts();
341
            }
343
            }
342
            if (connectionChanged) {
344
            if (connectionChanged && !disposed) {
343
                if (ConnectionManager.getInstance().isConnectedTo(execEnv)) {
345
                if (ConnectionManager.getInstance().isConnectedTo(execEnv)) {
344
                    refreshManager.scheduleRefreshOnConnect();
346
                    refreshManager.scheduleRefreshOnConnect();
345
                }
347
                }
Lines 347-352 Link Here
347
                    fo.connectionChanged();
349
                    fo.connectionChanged();
348
                }
350
                }
349
            }
351
            }
352
            if (!disposed) {
353
                deleteOnExitSupport.processConnectionChange();
354
            }
350
        }
355
        }
351
356
352
        private void maintainAutoMounts() {
357
        private void maintainAutoMounts() {
Lines 405-410 Link Here
405
        if (execEnv.equals(env)) {
410
        if (execEnv.equals(env)) {
406
            readOnlyConnectNotification.compareAndSet(true, false);
411
            readOnlyConnectNotification.compareAndSet(true, false);
407
            connectionChanged = true; // volatile
412
            connectionChanged = true; // volatile
413
            deleteOnExitSupport.notifyConnected();
408
            connectionTask.schedule(0);
414
            connectionTask.schedule(0);
409
        }
415
        }
410
    }
416
    }
Lines 420-425 Link Here
420
        if (COLLECT_STATSISTICS) {
426
        if (COLLECT_STATSISTICS) {
421
            lockSupport.printStatistics(this);
427
            lockSupport.printStatistics(this);
422
        }
428
        }
429
        deleteOnExitSupport.notifyDisconnected();
423
    }
430
    }
424
    
431
    
425
    public ExecutionEnvironment getExecutionEnvironment() {
432
    public ExecutionEnvironment getExecutionEnvironment() {
Lines 949-984 Link Here
949
        return status;
956
        return status;
950
    }
957
    }
951
    
958
    
952
    public void deleteOnExit(String path) {
959
    public void deleteOnExit(String... paths) {
953
        synchronized(deleteOnExitFiles) {
960
        if (RemoteFileSystemTransport.canDeleteOnDisconnect(execEnv)) {
954
            if (deleteOnExitFiles.isEmpty()) {
961
            try {
955
                Runtime.getRuntime().addShutdownHook(new Thread() {
962
                RemoteFileSystemTransport.deleteOnDisconnect(execEnv, paths);
963
                return;
964
            } // else
965
            catch (IOException | java.util.concurrent.CancellationException | InterruptedException | ExecutionException ex) {
966
                ex.printStackTrace(System.err);
967
            }
968
        }
969
        deleteOnExitSupport.deleteOnExit(paths);
970
    }
956
971
957
                    @Override
958
                    public void run() {
959
                        releaseResources();
960
                    }
961
962
                });
963
            }
964
            deleteOnExitFiles.add(path);
965
        }
966
    }
967
    
968
    private void releaseResources() {
969
    	ArrayList<String> toBeDeleted;
970
        synchronized(deleteOnExitFiles) {
971
        	toBeDeleted = new ArrayList<>(deleteOnExitFiles);
972
        }
973
    	Collections.reverse(toBeDeleted);
974
        for (String filename : toBeDeleted) {
975
            if (!ConnectionManager.getInstance().isConnectedTo(execEnv)) {
976
                 return;
977
            }
978
            CommonTasksSupport.rmFile(execEnv, filename, null);
979
        }
980
    }
981
    
982
    /*package*/ void setBeingRemoved(RemoteFileObjectBase fo) {
972
    /*package*/ void setBeingRemoved(RemoteFileObjectBase fo) {
983
        beingRemoved.set(fo);
973
        beingRemoved.set(fo);
984
    }
974
    }
(-)a/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/RemoteFileSystemTransport.java (+14 lines)
Lines 83-88 Link Here
83
    public static boolean canSetAccessCheckType(ExecutionEnvironment execEnv) {
83
    public static boolean canSetAccessCheckType(ExecutionEnvironment execEnv) {
84
        return getInstanceFast(execEnv).canSetAccessCheckType();
84
        return getInstanceFast(execEnv).canSetAccessCheckType();
85
    }
85
    }
86
    
87
    public static boolean canDeleteOnDisconnect(ExecutionEnvironment execEnv) {
88
        return getInstanceFast(execEnv).canDeleteOnDisconnect();
89
    }
90
    
91
    public static void deleteOnDisconnect(ExecutionEnvironment execEnv, String... paths)
92
        throws IOException, CancellationException, InterruptedException, ExecutionException {
93
        getInstanceFast(execEnv).deleteOnDisconnect(paths);
94
    }
86
95
87
    public static void setAccessCheckType(ExecutionEnvironment execEnv, FileSystemProvider.AccessCheckType accessCheckType) {
96
    public static void setAccessCheckType(ExecutionEnvironment execEnv, FileSystemProvider.AccessCheckType accessCheckType) {
88
        getInstanceFast(execEnv).setAccessCheckType(accessCheckType);
97
        getInstanceFast(execEnv).setAccessCheckType(accessCheckType);
Lines 344-349 Link Here
344
353
345
    protected abstract boolean canSetAccessCheckType();
354
    protected abstract boolean canSetAccessCheckType();
346
355
356
    protected abstract boolean canDeleteOnDisconnect();
357
358
    protected abstract void deleteOnDisconnect(String[] paths) 
359
            throws IOException, CancellationException, InterruptedException, ExecutionException;
360
347
    protected abstract void setAccessCheckType(FileSystemProvider.AccessCheckType accessCheckType);
361
    protected abstract void setAccessCheckType(FileSystemProvider.AccessCheckType accessCheckType);
348
362
349
    /** can be null */
363
    /** can be null */
(-)a/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/SftpTransport.java (+9 lines)
Lines 296-299 Link Here
296
    protected FileSystemProvider.AccessCheckType getAccessCheckType() {
296
    protected FileSystemProvider.AccessCheckType getAccessCheckType() {
297
        return null;
297
        return null;
298
    }
298
    }
299
300
    @Override
301
    protected boolean canDeleteOnDisconnect() {
302
        return false;
303
    }
304
305
    @Override
306
    protected void deleteOnDisconnect(String[] paths) {
307
    }
299
}
308
}
(-)a/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/server/FSSDispatcher.java (-1 / +1 lines)
Lines 146-152 Link Here
146
                Exceptions.printStackTrace(ex);
146
                Exceptions.printStackTrace(ex);
147
            }
147
            }
148
        }
148
        }
149
        return "1.10.2"; // NOI18N
149
        return "1.11.0"; // NOI18N
150
    }
150
    }
151
    
151
    
152
    private FSSDispatcher(ExecutionEnvironment env) {
152
    private FSSDispatcher(ExecutionEnvironment env) {
(-)a/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/server/FSSRequestKind.java (+1 lines)
Lines 56-61 Link Here
56
    FS_REQ_REMOVE_WATCH('w'),
56
    FS_REQ_REMOVE_WATCH('w'),
57
    FS_REQ_REFRESH('R'),
57
    FS_REQ_REFRESH('R'),
58
    FS_REQ_DELETE('d'),
58
    FS_REQ_DELETE('d'),
59
    FS_REQ_DELETE_ON_DISCONNECT('D'),
59
    FS_REQ_COPY('C'),
60
    FS_REQ_COPY('C'),
60
    FS_REQ_MOVE('m'),
61
    FS_REQ_MOVE('m'),
61
    FS_REQ_SERVER_INFO('i'),
62
    FS_REQ_SERVER_INFO('i'),
(-)a/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/server/FSSTransport.java (+14 lines)
Lines 657-662 Link Here
657
    protected FileSystemProvider.AccessCheckType getAccessCheckType() {
657
    protected FileSystemProvider.AccessCheckType getAccessCheckType() {
658
        return dispatcher.getAccessCheckType();
658
        return dispatcher.getAccessCheckType();
659
    }
659
    }
660
    
661
    @Override
662
    protected boolean canDeleteOnDisconnect() {
663
        return true;
664
    }
665
666
    @Override
667
    protected void deleteOnDisconnect(String[] paths) 
668
        throws IOException, CancellationException, InterruptedException, ExecutionException {
669
        for (String p : paths) {
670
            FSSRequest request = new FSSRequest(FSSRequestKind.FS_REQ_DELETE_ON_DISCONNECT, p, true);
671
            dispatcher.dispatch(request);
672
        }
673
    }    
660
674
661
    private class WarmupImpl implements Warmup, FSSResponse.Listener, Runnable {
675
    private class WarmupImpl implements Warmup, FSSResponse.Listener, Runnable {
662
676
(-)a/dlight.remote.impl/test/unit/src/org/netbeans/modules/remote/impl/fs/DeleteOnExitTestCase.java (-8 / +18 lines)
Lines 80-89 Link Here
80
            dirFO.getFileSystem().deleteOnExit(path1);
80
            dirFO.getFileSystem().deleteOnExit(path1);
81
            dirFO.getFileSystem().deleteOnExit(path2);
81
            dirFO.getFileSystem().deleteOnExit(path2);
82
82
83
            reconnect();
83
            //RemoteFileSystemManager.getInstance().resetFileSystem(execEnv, false);
84
            
84
            reconnect(true);
85
            sleep(200);
85
            status = ProcessUtils.execute(execEnv, "ls", path1, path2);
86
            status = ProcessUtils.execute(execEnv, "ls", path1, path2);
86
            assertFalse("Files should be removed", status.isOK());
87
            assertExec("Files should be removed", false, 100, 5, "ls", path1, path2);
87
        } finally {
88
        } finally {
88
            removeRemoteDirIfNotNull(dir);
89
            removeRemoteDirIfNotNull(dir);
89
        }
90
        }
Lines 97-111 Link Here
97
            RemoteFileObject dirFO = (RemoteFileObject) getFileObject(dir);
98
            RemoteFileObject dirFO = (RemoteFileObject) getFileObject(dir);
98
            FileObject tmpFO = dirFO.getFileSystem().createTempFile(dirFO, "tmp", "tmp", true);            
99
            FileObject tmpFO = dirFO.getFileSystem().createTempFile(dirFO, "tmp", "tmp", true);            
99
            String path1 = tmpFO.getPath();            
100
            String path1 = tmpFO.getPath();            
100
            //ProcessUtils.ExitStatus status = ProcessUtils.execute(execEnv, "ls", path1);
101
            //RemoteFileSystemManager.getInstance().resetFileSystem(execEnv, false);            
101
            //assertTrue("Error creating temp files", status.isOK());
102
            reconnect(true);
102
            reconnect();
103
            assertExec("Files should be removed", false, 100, 5, "ls", path1);
103
            final ProcessUtils.ExitStatus status = ProcessUtils.execute(execEnv, "ls", path1);
104
            assertFalse("Files should be removed", status.isOK());
105
        } finally {
104
        } finally {
106
            removeRemoteDirIfNotNull(dir);
105
            removeRemoteDirIfNotNull(dir);
107
        }
106
        }
108
    }
107
    }
108
    
109
    private void assertExec(String failureMessage, boolean expectSuccess, int timeout, int attempts, String cmd, String...args) {
110
        for (int i = 0; i < attempts; i++) {
111
            ProcessUtils.ExitStatus status = ProcessUtils.execute(execEnv, cmd, args);
112
            if (status.isOK() == expectSuccess) {
113
                return;
114
            }
115
            sleep(timeout);
116
        }        
117
        assertTrue(failureMessage, false);
118
    }
109
119
110
    public static Test suite() {
120
    public static Test suite() {
111
        return RemoteApiTest.createSuite(DeleteOnExitTestCase.class);
121
        return RemoteApiTest.createSuite(DeleteOnExitTestCase.class);
(-)a/dlight.remote.impl/test/unit/src/org/netbeans/modules/remote/impl/fs/RemoteFileTestBase.java (-3 / +4 lines)
Lines 106-117 Link Here
106
        this.execEnv = execEnv;
106
        this.execEnv = execEnv;
107
    }
107
    }
108
    
108
    
109
    protected void reconnect() throws Exception {
109
    protected void reconnect(boolean resetFileSystem) throws Exception {
110
        char[] paswd = PasswordManager.getInstance().getPassword(execEnv);
110
        char[] paswd = PasswordManager.getInstance().getPassword(execEnv);
111
        ConnectionManager.getInstance().disconnect(execEnv);
111
        ConnectionManager.getInstance().disconnect(execEnv);
112
        sleep(250);
112
        sleep(100);
113
        assertFalse("Failure disconnecting from " + execEnv, ConnectionManager.getInstance().isConnectedTo(execEnv));
113
        assertFalse("Failure disconnecting from " + execEnv, ConnectionManager.getInstance().isConnectedTo(execEnv));
114
        sleep(250);
114
        sleep(100);
115
        RemoteFileSystemManager.getInstance().resetFileSystem(execEnv, false);
115
        PasswordManager.getInstance().storePassword(execEnv, paswd, true);
116
        PasswordManager.getInstance().storePassword(execEnv, paswd, true);
116
        ConnectionManager.getInstance().connectTo(execEnv);
117
        ConnectionManager.getInstance().connectTo(execEnv);
117
        assertTrue("Failure reconnecting to " + execEnv, ConnectionManager.getInstance().isConnectedTo(execEnv));
118
        assertTrue("Failure reconnecting to " + execEnv, ConnectionManager.getInstance().isConnectedTo(execEnv));
(-)a/dlight.remote.impl/tools/fs_server/src/fs_server.c (-2 / +52 lines)
Lines 96-103 Link Here
96
//static bool shutting_down = false;
96
//static bool shutting_down = false;
97
97
98
#define FS_SERVER_MAJOR_VERSION 1
98
#define FS_SERVER_MAJOR_VERSION 1
99
#define FS_SERVER_MID_VERSION 10
99
#define FS_SERVER_MID_VERSION 11
100
#define FS_SERVER_MINOR_VERSION 3
100
#define FS_SERVER_MINOR_VERSION 0
101
101
102
typedef struct fs_entry {
102
typedef struct fs_entry {
103
    int /*short?*/ name_len;
103
    int /*short?*/ name_len;
Lines 130-138 Link Here
130
    char* strerr;
130
    char* strerr;
131
} err_info;
131
} err_info;
132
132
133
static struct {
134
    queue queue;
135
    pthread_mutex_t mutex;
136
} delete_on_exit_list;
137
133
static const int thread_emsg_bufsize = PATH_MAX * 2 + 128; // should it be less?
138
static const int thread_emsg_bufsize = PATH_MAX * 2 + 128; // should it be less?
134
static const int strerr_bufsize = PATH_MAX * 2 + 128; // should it be less?
139
static const int strerr_bufsize = PATH_MAX * 2 + 128; // should it be less?
135
140
141
static void delete_on_exit_list_init() {
142
    pthread_mutex_init(&delete_on_exit_list.mutex, NULL);
143
    mutex_lock_wrapper(&delete_on_exit_list.mutex);
144
    queue_init(&delete_on_exit_list.queue);
145
    mutex_unlock_wrapper(&delete_on_exit_list.mutex);
146
}
147
148
static void delete_on_exit_list_add(const char* p) {
149
    mutex_lock_wrapper(&delete_on_exit_list.mutex);
150
    const char* p2 = strdup_wrapper(p);
151
    queue_add(&delete_on_exit_list.queue, (void*) p2);
152
    mutex_unlock_wrapper(&delete_on_exit_list.mutex);
153
}
154
155
static void delete_on_exit_impl() {
156
    trace(TRACE_INFO, "Processing files that should be deleted on exit\n");
157
    mutex_lock_wrapper(&delete_on_exit_list.mutex);
158
    int cnt = 0;
159
    void* p;
160
    while((p = queue_poll(&delete_on_exit_list.queue))) {
161
        const char* path = (const char*) p;
162
        trace(TRACE_FINEST, "  removing %s...", path);
163
        unlink(path);
164
        free(p);
165
        cnt++;
166
        free(p);
167
    }
168
    mutex_unlock_wrapper(&delete_on_exit_list.mutex);    
169
    trace(TRACE_INFO, "Removed %d files\n", cnt);
170
}
171
136
static void err_init() {
172
static void err_init() {
137
    err_info.err_no = 0;
173
    err_info.err_no = 0;
138
    err_info.errmsg = malloc_wrapper(thread_emsg_bufsize);
174
    err_info.errmsg = malloc_wrapper(thread_emsg_bufsize);
Lines 303-308 Link Here
303
        case FS_REQ_REMOVE_WATCH:
339
        case FS_REQ_REMOVE_WATCH:
304
        case FS_REQ_REFRESH:
340
        case FS_REQ_REFRESH:
305
        case FS_REQ_DELETE:
341
        case FS_REQ_DELETE:
342
        case FS_REQ_DELETE_ON_DISCONNECT:
306
        case FS_REQ_SERVER_INFO:
343
        case FS_REQ_SERVER_INFO:
307
        case FS_REQ_HELP:
344
        case FS_REQ_HELP:
308
        case FS_REQ_OPTION:
345
        case FS_REQ_OPTION:
Lines 849-854 Link Here
849
    my_fflush(STDOUT);
886
    my_fflush(STDOUT);
850
}
887
}
851
888
889
static void response_delete_on_disconnect(int request_id, const char* path) {
890
    if (request_id != 0) {
891
        response_error(request_id, path, 0, "FS_REQ_DELETE_ON_DISCONNECT request should have zero ID!");
892
    }
893
    delete_on_exit_list_add(path);
894
}
895
852
static void response_delete(int request_id, const char* path, const settings_str* settings) {
896
static void response_delete(int request_id, const char* path, const settings_str* settings) {
853
897
854
    const char* last_slash = strrchr(path, '/');
898
    const char* last_slash = strrchr(path, '/');
Lines 1354-1359 Link Here
1354
1398
1355
static void thread_init() {
1399
static void thread_init() {
1356
    err_init();
1400
    err_init();
1401
    delete_on_exit_list_init();
1357
    sigset_t set;
1402
    sigset_t set;
1358
    sigfillset(&set);
1403
    sigfillset(&set);
1359
    sigdelset(&set, SIGUSR1);
1404
    sigdelset(&set, SIGUSR1);
Lines 1524-1529 Link Here
1524
    help_req_kind(FS_REQ_REMOVE_WATCH);
1569
    help_req_kind(FS_REQ_REMOVE_WATCH);
1525
    help_req_kind(FS_REQ_REFRESH);
1570
    help_req_kind(FS_REQ_REFRESH);
1526
    help_req_kind(FS_REQ_DELETE);
1571
    help_req_kind(FS_REQ_DELETE);
1572
    help_req_kind(FS_REQ_DELETE_ON_DISCONNECT);
1527
    help_req_kind(FS_REQ_SERVER_INFO);
1573
    help_req_kind(FS_REQ_SERVER_INFO);
1528
    help_req_kind(FS_REQ_OPTION);
1574
    help_req_kind(FS_REQ_OPTION);
1529
    help_req_kind(FS_REQ_HELP);
1575
    help_req_kind(FS_REQ_HELP);
Lines 1537-1542 Link Here
1537
        case FS_REQ_DELETE:
1583
        case FS_REQ_DELETE:
1538
            response_delete(request->id, request->path, &settings);
1584
            response_delete(request->id, request->path, &settings);
1539
            break;
1585
            break;
1586
        case FS_REQ_DELETE_ON_DISCONNECT:
1587
            response_delete_on_disconnect(request->id, request->path);
1588
            break;
1540
        case FS_REQ_SERVER_INFO:
1589
        case FS_REQ_SERVER_INFO:
1541
            response_info(request->id);
1590
            response_info(request->id);
1542
            break;
1591
            break;
Lines 1957-1962 Link Here
1957
2006
1958
static void shutdown() {
2007
static void shutdown() {
1959
    state_set_proceed(false);
2008
    state_set_proceed(false);
2009
    delete_on_exit_impl();
1960
    blocking_queue_shutdown(&req_queue);
2010
    blocking_queue_shutdown(&req_queue);
1961
    trace(TRACE_INFO, "Max. requests queue size: %d\n", blocking_queue_max_size(&req_queue));
2011
    trace(TRACE_INFO, "Max. requests queue size: %d\n", blocking_queue_max_size(&req_queue));
1962
    if (statistics) {
2012
    if (statistics) {
(-)a/dlight.remote.impl/tools/fs_server/src/fs_server.h (+1 lines)
Lines 62-67 Link Here
62
    FS_REQ_REMOVE_WATCH = 'w',
62
    FS_REQ_REMOVE_WATCH = 'w',
63
    FS_REQ_REFRESH = 'R',
63
    FS_REQ_REFRESH = 'R',
64
    FS_REQ_DELETE = 'd',
64
    FS_REQ_DELETE = 'd',
65
    FS_REQ_DELETE_ON_DISCONNECT = 'D',
65
    FS_REQ_SERVER_INFO = 'i',
66
    FS_REQ_SERVER_INFO = 'i',
66
    FS_REQ_HELP = '?',
67
    FS_REQ_HELP = '?',
67
    FS_REQ_OPTION = 'o'
68
    FS_REQ_OPTION = 'o'
(-)a/dlight.remote.impl/tools/fs_server/src/util.c (+8 lines)
Lines 146-151 Link Here
146
        va_end(args);
146
        va_end(args);
147
    }
147
    }
148
}
148
}
149
char *strdup_wrapper(const char* str) {
150
    char* p = strdup(str);
151
    if (!p) {
152
        report_error("out of memory\n");
153
        exit(FAILURE_ALLOCATE_MEMORY);
154
    }
155
    return p;
156
}
149
157
150
void *malloc_wrapper(size_t size) {
158
void *malloc_wrapper(size_t size) {
151
    void *p = malloc(size);
159
    void *p = malloc(size);
(-)a/dlight.remote.impl/tools/fs_server/src/util.h (+1 lines)
Lines 89-94 Link Here
89
void mutex_lock_wrapper(pthread_mutex_t *mutex);
89
void mutex_lock_wrapper(pthread_mutex_t *mutex);
90
void *malloc_wrapper(size_t size);
90
void *malloc_wrapper(size_t size);
91
void *realloc_wrapper(void *ptr, size_t size);
91
void *realloc_wrapper(void *ptr, size_t size);
92
char *strdup_wrapper(const char* str);
92
93
93
bool get_home_dir(char* home, int size);
94
bool get_home_dir(char* home, int size);
94
bool file_exists(const char* path);
95
bool file_exists(const char* path);

Return to bug 268926