# HG changeset patch # User Vladimir Kvashin # Date 1472337200 -10800 # Node ID 274829a854918bf972fb64705b299a519d42d7b5 # Parent ebee7717226edb2ba3a79db70d34881aff005bc5 Fixing #267715 (Tests can't add remote host, because "New Remote Host Setup" wizard fails) diff -r ebee7717226e -r 274829a85491 dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/RemoteDirectory.java --- a/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/RemoteDirectory.java Sat Aug 27 13:36:45 2016 +0300 +++ b/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/RemoteDirectory.java Sun Aug 28 01:33:20 2016 +0300 @@ -554,26 +554,6 @@ } } - private boolean isProhibited() { - final String path = getPath(); - if (path.equals("/proc") || getPath().equals("/dev")) { //NOI18N - return true; - } - if (path.equals("/run")) { //NOI18N - if (HostInfoUtils.isHostInfoAvailable(getExecutionEnvironment())) { - try { - HostInfo hi = HostInfoUtils.getHostInfo(getExecutionEnvironment()); - if (hi.getOSFamily() == HostInfo.OSFamily.LINUX) { - return true; - } - } catch (IOException | ConnectionManager.CancellationException ex) { - Exceptions.printStackTrace(ex); // should never be the case if isHostInfoAvailable retured true - } - } - } - return false; - } - private void warmupDirs() { if (RemoteFileSystemUtils.getBoolean("remote.warmup", true)) { setFlag(MASK_WARMUP, true); @@ -627,7 +607,7 @@ private Map readEntries(DirectoryStorage oldStorage, boolean forceRefresh, String childName) throws TimeoutException, IOException, InterruptedException, ExecutionException, CancellationException { - if (isProhibited()) { + if (getFileSystem().isProhibitedToEnter(getPath())) { return Collections.emptyMap(); } readEntryReqs.incrementAndGet(); diff -r ebee7717226e -r 274829a85491 dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/RemoteFileSystem.java --- a/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/RemoteFileSystem.java Sat Aug 27 13:36:45 2016 +0300 +++ b/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/RemoteFileSystem.java Sun Aug 28 01:33:20 2016 +0300 @@ -69,6 +69,7 @@ import org.netbeans.api.annotations.common.NonNull; import org.netbeans.modules.dlight.libs.common.PathUtilities; import org.netbeans.modules.nativeexecution.api.ExecutionEnvironment; +import org.netbeans.modules.nativeexecution.api.HostInfo; import org.netbeans.modules.nativeexecution.api.util.CommonTasksSupport; import org.netbeans.modules.nativeexecution.api.util.ConnectionListener; import org.netbeans.modules.nativeexecution.api.util.ConnectionManager; @@ -230,6 +231,31 @@ } } + public List getDirsProhibitedToStat(String path) { + synchronized (autoMounts) { + return Collections.unmodifiableList(autoMounts); + } + } + + public boolean isProhibitedToEnter(String path) { + if (path.equals("/proc") || path.equals("/dev")) { //NOI18N + return true; + } + if (path.equals("/run")) { //NOI18N + if (HostInfoUtils.isHostInfoAvailable(getExecutionEnvironment())) { + try { + HostInfo hi = HostInfoUtils.getHostInfo(getExecutionEnvironment()); + if (hi.getOSFamily() == HostInfo.OSFamily.LINUX) { + return true; + } + } catch (IOException | ConnectionManager.CancellationException ex) { + Exceptions.printStackTrace(ex); // should never be the case if isHostInfoAvailable retured true + } + } + } + return false; + } + public boolean isDirectAutoMountChild(String path) { String parent = PathUtilities.getDirName(path); if (parent != null && ! parent.isEmpty()) { diff -r ebee7717226e -r 274829a85491 dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/server/FSSDispatcher.java --- a/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/server/FSSDispatcher.java Sat Aug 27 13:36:45 2016 +0300 +++ b/dlight.remote.impl/src/org/netbeans/modules/remote/impl/fs/server/FSSDispatcher.java Sun Aug 28 01:33:20 2016 +0300 @@ -82,6 +82,7 @@ import org.netbeans.modules.remote.impl.RemoteLogger; import org.netbeans.modules.remote.impl.fs.RefreshManager; import org.netbeans.modules.remote.impl.fs.RemoteExceptions; +import org.netbeans.modules.remote.impl.fs.RemoteFileSystem; import org.netbeans.modules.remote.impl.fs.RemoteFileSystemManager; import org.netbeans.modules.remote.impl.fs.RemoteFileSystemUtils; import org.netbeans.modules.remote.impl.fs.ui.RemoteNotifier; @@ -134,7 +135,7 @@ private volatile FileSystemProvider.AccessCheckType accessCheckType; - private static final String MIN_SERVER_VERSION = "1.7.0"; // NOI18N + private static final String MIN_SERVER_VERSION = "1.10.0"; // NOI18N private FSSDispatcher(ExecutionEnvironment env) { this.env = env; @@ -147,10 +148,14 @@ } private void addToRefresh(String path) { - RefreshManager refreshManager = RemoteFileSystemManager.getInstance().getFileSystem(env).getRefreshManager(); + RefreshManager refreshManager = getFileSystem().getRefreshManager(); refreshManager.scheduleRefreshExistent(Arrays.asList(path), false); } - + + private RemoteFileSystem getFileSystem() { + return RemoteFileSystemManager.getInstance().getFileSystem(env); + } + public static FSSDispatcher getInstance(ExecutionEnvironment env) { synchronized (instanceLock) { FSSDispatcher instance = instances.get(env); @@ -169,7 +174,7 @@ public void connected() { boolean wasValid = valid; valid = true; - if (wasValid && RemoteFileSystemManager.getInstance().getFileSystem(env).getRoot().getImplementor().hasCache()) { + if (wasValid && getFileSystem().getRoot().getImplementor().hasCache()) { RP.post(new ConnectTask()); } } @@ -597,6 +602,7 @@ RP.post(new ErrorReader(server.getProcess().getErrorStream())); try { handShake(); + setupProhibitedToLstat(); } catch (InitializationException ex) { server = null; setInvalid(true); @@ -608,6 +614,25 @@ } } + private void setupProhibitedToLstat() { + List forbiddenPaths = getFileSystem().getDirsProhibitedToStat(traceName); + if(forbiddenPaths == null || forbiddenPaths.isEmpty()) { + return; + } + FsServer srv = server; + if (srv == null) { + return; // this should not happen, but server is not final => need to check + } + StringBuilder sb = new StringBuilder("dirs-forbidden-to-stat="); + boolean first = true; + for (String path : forbiddenPaths) { + sb.append(path).append(first ? "" : ":"); + first = false; + } + FSSRequest req = new FSSRequest(FSSRequestKind.FS_REQ_OPTION, sb.toString()); + sendRequest(server.getWriter(), req); + } + private void handShake() throws IOException, InitializationException, InterruptedException { FSSRequest infoReq = new FSSRequest(FSSRequestKind.FS_REQ_SERVER_INFO, ""); sendRequest(server.getWriter(), infoReq); @@ -770,7 +795,7 @@ if (cleanupUponStart) { argsList.add("-c"); // NOI18N } else { - if (!RemoteFileSystemManager.getInstance().getFileSystem(env).getRoot().getImplementor().hasCache()) { + if (!getFileSystem().getRoot().getImplementor().hasCache()) { // there is no cache locally => clean remote cache as well argsList.add("-c"); // NOI18N } diff -r ebee7717226e -r 274829a85491 dlight.remote.impl/tools/fs_server/nbproject/configurations.xml --- a/dlight.remote.impl/tools/fs_server/nbproject/configurations.xml Sat Aug 27 13:36:45 2016 +0300 +++ b/dlight.remote.impl/tools/fs_server/nbproject/configurations.xml Sun Aug 28 01:33:20 2016 +0300 @@ -38,7 +38,7 @@ Contributor(s): --> - + @@ -134,7 +134,7 @@ - OracleSolarisStudio|OracleSolarisStudio + OracleDeveloperStudio|OracleDeveloperStudio 1 false false @@ -344,7 +344,7 @@ - OracleSolarisStudio|OracleSolarisStudio + OracleDeveloperStudio|OracleDeveloperStudio 0 false false @@ -535,12 +535,9 @@ LINUX - NDEBUG _GNU_SOURCE - _POSIX_PTHREAD_SEMANTICS _REENTRANT _XOPEN_SOURCE=700 - __EXTENSIONS__ diff -r ebee7717226e -r 274829a85491 dlight.remote.impl/tools/fs_server/src/fs_server.c --- a/dlight.remote.impl/tools/fs_server/src/fs_server.c Sat Aug 27 13:36:45 2016 +0300 +++ b/dlight.remote.impl/tools/fs_server/src/fs_server.c Sun Aug 28 01:33:20 2016 +0300 @@ -95,7 +95,7 @@ //static bool shutting_down = false; #define FS_SERVER_MAJOR_VERSION 1 -#define FS_SERVER_MID_VERSION 9 +#define FS_SERVER_MID_VERSION 10 #define FS_SERVER_MINOR_VERSION 0 typedef struct fs_entry { @@ -221,6 +221,100 @@ return result; } +/// a mutex that guards both dirs_forbidden_to_stat and dirs_forbidden_to_stat_data +static pthread_mutex_t forbidden_dirs_mutex = PTHREAD_MUTEX_INITIALIZER; + +/// directories that are forbidden to stat; the last element is null +static const char** dirs_forbidden_to_stat = NULL; + +/// just a buffer to keep strings in dirs_forbidden_to_stat +static char* dirs_forbidden_to_stat_buffer = NULL; + +static void free_dirs_forbidden_to_stat() { + mutex_lock_wrapper(&forbidden_dirs_mutex); + if (dirs_forbidden_to_stat) { + free(dirs_forbidden_to_stat); + } + if (dirs_forbidden_to_stat_buffer) { + free(dirs_forbidden_to_stat_buffer); + } + mutex_unlock_wrapper(&forbidden_dirs_mutex); +} + +static bool is_dir_forbidden_to_stat(const char* path2check) { + bool forbidden = false; + mutex_lock_wrapper(&forbidden_dirs_mutex); + if (dirs_forbidden_to_stat) { + for(const char** path = dirs_forbidden_to_stat; *path; path++) { + if (strcmp(path2check, *path) == 0) { + forbidden = true; + } + } + } + mutex_unlock_wrapper(&forbidden_dirs_mutex); + return forbidden; +} + +static void set_dirs_forbidden_to_stat(const char* dir_list) { + mutex_lock_wrapper(&forbidden_dirs_mutex); + dirs_forbidden_to_stat_buffer = strdup(dir_list); + int cnt = 1; + for(const char* p = dirs_forbidden_to_stat_buffer; *p; p++) { + if (*p == ':') { + cnt++; + } + } + dirs_forbidden_to_stat = calloc(cnt+1, sizeof(char*)); // cnt+1 reserves space for trailing null + const char** curr_path = dirs_forbidden_to_stat; + *curr_path = dirs_forbidden_to_stat_buffer; + for(char* p = dirs_forbidden_to_stat_buffer; *p; p++) { + if (*p == ':') { + *p = '\0'; + curr_path++; + *curr_path = p+1; + } + } + mutex_unlock_wrapper(&forbidden_dirs_mutex); +} + +static void dump_dirs_forbidden_to_stat(TraceLevel level) { + if (is_traceable(level)) { + trace(level, "Directories forbidden to stat:\n"); + mutex_lock_wrapper(&forbidden_dirs_mutex); + for(const char** path = dirs_forbidden_to_stat; *path; path++) { + trace(level, "%s\n", *path); + } + mutex_unlock_wrapper(&forbidden_dirs_mutex); + } +} + +static void fill_dummy_stat(struct stat *stat_buf) { + memset(stat_buf, '\0', sizeof(struct stat)); + stat_buf->st_uid = 0; + stat_buf->st_mode = __S_IFDIR; + stat_buf->st_size = 0; + stat_buf->st_dev = 0; + stat_buf->st_ino = 0; +} + +static int lstat_wrapper(const char *path, struct stat *stat_buf) { + if (is_dir_forbidden_to_stat(path)) { + fill_dummy_stat(stat_buf); + return 0; + } else { + return lstat(path, stat_buf); + } +} + +static int stat_wrapper(const char *path, struct stat *stat_buf) { + if (is_dir_forbidden_to_stat(path)) { + fill_dummy_stat(stat_buf); + return 0; + } else { + return stat(path, stat_buf); + } +} + #define DECLARE_DECODE(type, type_name, maxlen) \ static const char* decode_##type_name (const char* text, type* result) { \ *result = 0; \ @@ -711,7 +805,7 @@ const char *abspath, const char *basename, buffer work_buf) { struct stat stat_buf; - if (lstat(abspath, &stat_buf) == 0) { + if (lstat_wrapper(abspath, &stat_buf) == 0) { //int escaped_name_size = escape_strlen(entry->d_name); escape_strcpy(work_buf.data, basename); @@ -882,7 +976,7 @@ } struct stat stat_buf; - if (lstat(path, &stat_buf) == 0) { + if (lstat_wrapper(path, &stat_buf) == 0) { if (S_ISDIR(stat_buf.st_mode)) { if (!clean_dir(path)) { response_error(request_id, path, errno, "can't remote directory content"); @@ -942,7 +1036,7 @@ static void response_stat(int request_id, const char* path) { struct stat stat_buf; - if (stat(path, &stat_buf) == 0) { + if (stat_wrapper(path, &stat_buf) == 0) { int buf_size = MAXNAMLEN * 2 + 80; // *2 because of escaping. TODO: accurate size calculation char* escaped_name = malloc_wrapper(buf_size); const char* basename = get_basename(path); @@ -984,12 +1078,12 @@ // if file exists, return error struct stat stat_buf; - if (lstat(request->path2, &stat_buf) == 0) { + if (lstat_wrapper(request->path2, &stat_buf) == 0) { response_error(request->id, request->path2, 0, "file already exists"); response_end(request->id, request->path2); return; } - if (lstat(request->path, &stat_buf) == -1) { + if (lstat_wrapper(request->path, &stat_buf) == -1) { response_error(request->id, request->path, errno, err_to_string(errno)); response_end(request->id, request->path2); return; @@ -1170,7 +1264,7 @@ // check whether it is directory and print clear error message // (copy_plain_file will print unclear "Operation not permitted" in this case) struct stat stat_buf; - if (lstat(request->path, &stat_buf) == -1) { + if (lstat_wrapper(request->path, &stat_buf) == -1) { response_error(request->id, request->path, errno, err_to_string(errno)); return; } @@ -1472,6 +1566,9 @@ } else { report_error("Unexpected option value: %s=%s\n", option, value); } + } else if (strcmp(option, "dirs-forbidden-to-stat") == 0) { + set_dirs_forbidden_to_stat(value); + dump_dirs_forbidden_to_stat(TRACE_FINER); } else { report_error("Unexpected option key: %s\n", option); } @@ -1983,6 +2080,7 @@ dirtab_free(); log_close(); err_shutdown(); + free_dirs_forbidden_to_stat(); trace(TRACE_INFO, "Shut down.\n"); exit(0); } diff -r ebee7717226e -r 274829a85491 dlight.remote.impl/tools/fs_server/src/util.c --- a/dlight.remote.impl/tools/fs_server/src/util.c Sat Aug 27 13:36:45 2016 +0300 +++ b/dlight.remote.impl/tools/fs_server/src/util.c Sun Aug 28 01:33:20 2016 +0300 @@ -477,9 +477,13 @@ int buf_size = PATH_MAX; char *abspath = malloc_wrapper(buf_size); char *link = malloc_wrapper(buf_size); - // TODO: error processing (malloc() can return null) - int base_len = strlen(path); - strcpy(abspath, path); + int base_len; + if (path[0] == '/' && path[1] == '\0') { + base_len = 0; + } else { + base_len = strlen(path); + strcpy(abspath, path); + } abspath[base_len] = '/'; struct dirent *entry; while (true) {