1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-03 22:35:43 +02:00

[216343][ssh] Return immediate symbolic link target for broken links, and correct canonical path for symbolic links that point to directories

This commit is contained in:
Martin Oberhuber 2008-01-23 21:13:30 +00:00
parent 3bc0f8aa92
commit 83578a63fa
3 changed files with 73 additions and 14 deletions

View file

@ -43,6 +43,7 @@ import java.util.regex.Pattern;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.osgi.util.NLS;
import com.jcraft.jsch.Channel;
@ -348,6 +349,15 @@ public class SftpFileService extends AbstractFileService implements IFileService
return fChannelSftp;
}
protected void progressTick(IProgressMonitor monitor, int ticks) throws RemoteFileCancelledException {
if (monitor!=null) {
if (monitor.isCanceled()) {
throw new RemoteFileCancelledException();
}
monitor.worked(ticks);
}
}
public void disconnect() {
//disconnect-service may be called after the session is already
//disconnected (due to event handling). Therefore, don't try to
@ -457,8 +467,14 @@ public class SftpFileService extends AbstractFileService implements IFileService
}
List results = new ArrayList();
if (fDirChannelMutex.waitForLock(monitor, fDirChannelTimeout)) {
boolean haveSubMonitor = false;
try {
Vector vv=getChannel("SftpFileService.internalFetch: "+parentPath).ls(recodeSafe(parentPath)); //$NON-NLS-1$
progressTick(monitor, 40);
if (vv.size()>1 && monitor!=null) {
monitor = new SubProgressMonitor(monitor, 40);
monitor.beginTask(null, vv.size());
}
for(int ii=0; ii<vv.size(); ii++) {
Object obj=vv.elementAt(ii);
if(obj instanceof ChannelSftp.LsEntry){
@ -471,6 +487,7 @@ public class SftpFileService extends AbstractFileService implements IFileService
if (filematcher.matches(fileName) || (lsEntry.getAttrs().isDir() && fileType!=IFileService.FILE_TYPE_FOLDERS)) {
//get ALL directory names (unless looking for folders only)
SftpHostFile node = makeHostFile(parentPath, fileName, lsEntry.getAttrs());
progressTick(monitor, 1);
if (isRightType(fileType, node)) {
results.add(node);
}
@ -492,6 +509,7 @@ public class SftpFileService extends AbstractFileService implements IFileService
//Probably not, since the session is going down anyways.
} finally {
fDirChannelMutex.release();
if (haveSubMonitor) monitor.done(); else progressTick(monitor, 40);
}
} else {
throw new RemoteFileCancelledException();
@ -502,27 +520,51 @@ public class SftpFileService extends AbstractFileService implements IFileService
private SftpHostFile makeHostFile(String parentPath, String fileName, SftpATTRS attrs) {
SftpATTRS attrsTarget = attrs;
String linkTarget=null;
String canonicalPath = null;
if (attrs.isLink()) {
//TODO remove comments as soon as jsch-0.1.29 is available
// try {
// //Note: readlink() is supported only with jsch-0.1.29 or higher.
// //By catching the exception we remain backward compatible.
// linkTarget=getChannel("makeHostFile.readlink").readlink(recode(node.getAbsolutePath())); //$NON-NLS-1$
// //TODO: Classify the type of resource linked to as file, folder or broken link
// } catch(Exception e) {}
//check if the link points to a directory
try {
getChannel("makeHostFile.chdir").cd(recode(concat(parentPath, fileName))); //$NON-NLS-1$
linkTarget=decode(getChannel("makeHostFile.chdir").pwd()); //$NON-NLS-1$
boolean readlinkDone = false;
try {
linkTarget=decode(getChannel("makeHostFile.readlink").readlink(recode(concat(parentPath, fileName)))); //$NON-NLS-1$
readlinkDone = true;
} catch(Exception e) {
//readlink() is only supported on sftpv3 and later servers, and jsch-0.1.29 or higher.
//By catching the exception we remain backward compatible.
//Disadvantages of the cd/pwd approach:
// * _realpath() followed by _stat() might be one extra roundtrip compared to the readlink() approach
// * Immediate link target is not available, only the fully resolved link target (might be an advantage too!)
// * -- but clients can also resolve the path with the
// * Immediate link target is not available for broken symbolic links
getChannel("makeHostFile.chdir").cd(recode(concat(parentPath, fileName))); //$NON-NLS-1$
linkTarget=decode(getChannel("makeHostFile.pwd").pwd()); //$NON-NLS-1$
canonicalPath=linkTarget;
}
if (linkTarget!=null && !linkTarget.equals(concat(parentPath, fileName))) {
if (readlinkDone) {
//linkTarget may be a relative path name that needs to be resolved for stat() to work properly
String curdir=decode(getChannel("makeHostFile.pwd").pwd()); //$NON-NLS-1$
if (!parentPath.equals(curdir)) {
getChannel("makeHostFile.chdir").cd(recode(parentPath)); //$NON-NLS-1$
}
}
attrsTarget = getChannel("SftpFileService.getFile").stat(recode(linkTarget)); //$NON-NLS-1$
if (readlinkDone && attrsTarget.isDir()) {
//TODO JSch should have realpath() API
getChannel("makeHostFile.chdir").cd(recode(concat(parentPath, fileName))); //$NON-NLS-1$
canonicalPath=decode(getChannel("makeHostFile.pwd").pwd()); //$NON-NLS-1$
}
} else {
linkTarget=null;
}
} catch(Exception e) {
//dangling link?
if (e instanceof SftpException && ((SftpException)e).id==ChannelSftp.SSH_FX_NO_SUCH_FILE) {
linkTarget=":dangling link"; //$NON-NLS-1$
if (linkTarget==null) {
linkTarget=":dangling link"; //$NON-NLS-1$
} else {
linkTarget=":dangling link:" + linkTarget; //$NON-NLS-1$
}
}
}
}
@ -532,6 +574,9 @@ public class SftpFileService extends AbstractFileService implements IFileService
if (linkTarget!=null) {
node.setLinkTarget(linkTarget);
}
if (canonicalPath!=null) {
node.setCanonicalPath(canonicalPath);
}
//Permissions: expect the current user to be the owner
String perms = attrsTarget.getPermissionsString();
if (perms.indexOf('r',1)<=0) {
@ -555,7 +600,7 @@ public class SftpFileService extends AbstractFileService implements IFileService
// permissions
// TODO get the user and owner from the uid and gid
HostFilePermissions permissions = new HostFilePermissions(perms, "" + attrs.getUId(), "" + attrs.getGId());
HostFilePermissions permissions = new HostFilePermissions(perms, "" + attrs.getUId(), "" + attrs.getGId()); //$NON-NLS-1$ //$NON-NLS-2$
node.setPermissions(permissions);
return node;

View file

@ -40,6 +40,7 @@ public class SftpHostFile implements IHostFile, IHostFilePermissionsContainer {
private long fSize = 0;
private boolean fIsLink = false;
private String fLinkTarget;
private String fCanonicalPath;
private String[] fExtended = null;
private IHostFilePermissions _permissions = null;
@ -144,6 +145,18 @@ public class SftpHostFile implements IHostFile, IHostFilePermissionsContainer {
return fLinkTarget;
}
public void setCanonicalPath(String canonicalPath) {
fCanonicalPath = canonicalPath;
}
public String getCanonicalPath() {
if (fCanonicalPath==null) {
return getAbsolutePath();
} else {
return fCanonicalPath;
}
}
/**
* Set Extended data as key,value pairs.
*
@ -177,8 +190,9 @@ public class SftpHostFile implements IHostFile, IHostFilePermissionsContainer {
if (isLink()) {
result = "symbolic link"; //$NON-NLS-1$
if (fLinkTarget!=null) {
if (fLinkTarget.equals(":dangling link")) { //$NON-NLS-1$
result = "broken symbolic link to `unknown'"; //$NON-NLS-1$
if (fLinkTarget.startsWith(":dangling link")) { //$NON-NLS-1$
String linkTarget = (fLinkTarget.length()<=15) ? "unknown" : fLinkTarget.substring(15); //$NON-NLS-1$
result = "broken symbolic link to `" + linkTarget + "'"; //$NON-NLS-1$ //$NON-NLS-2$
} else if(isDirectory()) {
result += "(directory):" + fLinkTarget; //$NON-NLS-1$
} else if(canExecute()) {

View file

@ -38,7 +38,7 @@ public class SftpRemoteFile extends AbstractRemoteFile {
}
public String getCanonicalPath() {
return getAbsolutePath();
return getSftpHostFile().getCanonicalPath();
}
public String getClassification() {