为什么软链接目标不存在时File.getCanonicalPath不会展开软链接?

从这个问题过来, 关于Java Symbolic link的问题? b -> a 如果a存在, b.canonicalPath == a, 如果a不存…
关注者
2
被浏览
1,525

1 个回答

这是一个关于Java_java_io_UnixFileSystem_canonicalize0函数实现的问题。题主已经贴出了具体实现的源码,我觉得题主主要纠结于函数:

int
canonicalize(char *original, char *resolved, int len)
    if (len < PATH_MAX) {
        errno = EINVAL;
        return -1;
    if (strlen(original) > PATH_MAX) {
        errno = ENAMETOOLONG;
        return -1;
    /* First try realpath() on the entire path */
    if (realpath(original, resolved)) {
        /* That worked, so return it */
        collapse(resolved);
        return 0;
    else {
        /* Something's bogus in the original path, so remove names from the end
           until either some subpath works or we run out of names */
        char *p, *end, *r = NULL;
        char path[PATH_MAX + 1];
        strncpy(path, original, sizeof(path));
        if (path[PATH_MAX] != '\0') {
            errno = ENAMETOOLONG;
            return -1;
        end = path + strlen(path);
        for (p = end; p > path;) {
            /* Skip last element */
            while ((--p > path) && (*p != '/'));
            if (p == path) break;
            /* Try realpath() on this subpath */
            *p = '\0';
            r = realpath(path, resolved);
            *p = (p == end) ? '\0' : '/';
            if (r != NULL) {
                /* The subpath has a canonical path */
                break;
            else if (errno == ENOENT || errno == ENOTDIR || errno == EACCES) {
                /* If the lookup of a particular subpath fails because the file
                   does not exist, because it is of the wrong type, or because
                   access is denied, then remove its last name and try again.
                   Other I/O problems cause an error return. */
                continue;
            else {
                return -1;
        if (r != NULL) {
            /* Append unresolved subpath to resolved subpath */
            int rn = strlen(r);
            if (rn + (int)strlen(p) >= len) {
                /* Buffer overflow */
                errno = ENAMETOOLONG;
                return -1;
            if ((rn > 0) && (r[rn - 1] == '/') && (*p == '/')) {
                /* Avoid duplicate slashes */
                p++;
            strcpy(r + rn, p);
            collapse(r);
            return 0;
        else {
            /* Nothing resolved, so just return the original path */
            strcpy(resolved, path);
            collapse(resolved);
            return 0;
}

中realpath(original, resolved)的调用结果,确实就算a不存在resolved也能返回b所链接的a的路径,但是a不存在时,该函数返回值是NULL,所以直接走的else分支。具体可以看看lldb下backtrace:

(lldb) bt