int main () { static char const *const tests[][3] = { {"a", "b", "a/b"}, {"a/", "b", "a/b"}, {"a/", "/b", "a/b"}, {"a", "/b", "a/b"}, {"/", "b", "/b"}, {"/", "/b", "/b"}, {"/", "/", "/"}, {"a", "/", "a/"}, /* this might deserve a diagnostic */ {"/a", "/", "/a/"}, /* this might deserve a diagnostic */ {"a", "//b", "a/b"}, }; size_t i; bool fail = false; for (i = 0; i < sizeof tests / sizeof tests[0]; i++) { char *base_in_result; char const *const *t = tests[i]; char *res = file_name_concat (t[0], t[1], &base_in_result); if (strcmp (res, t[2]) != 0) { printf ("got %s, expected %s\n", res, t[2]); fail = true; } } exit (fail ? EXIT_FAILURE : EXIT_SUCCESS); }
char * find_dir_file_pathname (char const *dir, char const *file) { /* The 'IF_LINT (volatile)' works around what appears to be a bug in gcc 4.8.0 20120825; see <http://lists.gnu.org/archive/html/bug-diffutils/2012-08/msg00007.html>. */ char const * IF_LINT (volatile) match = file; char *val; struct dirdata dirdata; dirdata.names = NULL; dirdata.data = NULL; if (ignore_file_name_case) { struct file_data filedata; filedata.name = dir; filedata.desc = 0; if (dir_read (&filedata, &dirdata)) { locale_specific_sorting = true; if (setjmp (failed_locale_specific_sorting)) match = file; /* longjmp may mess up MATCH. */ else { for (char const **p = dirdata.names; *p; p++) if (compare_names (*p, file) == 0) { if (file_name_cmp (*p, file) == 0) { match = *p; break; } if (match == file) match = *p; } } } } val = file_name_concat (dir, match, NULL); free (dirdata.names); free (dirdata.data); return val; }
int main (int argc, char *argv[]) { static char const *const tests[][3] = { {"a", "b", "a/b"}, {"a/", "b", "a/b"}, {"a/", "/b", "a/b"}, {"a", "/b", "a/b"}, {"/", "b", "/b"}, {"/", "/b", "/b"}, {"/", "/", "/"}, {"a", "/", "a/"}, /* this might deserve a diagnostic */ {"/a", "/", "/a/"}, /* this might deserve a diagnostic */ {"a", "//b", "a/b"}, {"", "a", "a"}, /* this might deserve a diagnostic */ }; unsigned int i; bool fail = false; set_program_name (argv[0]); for (i = 0; i < sizeof tests / sizeof tests[0]; i++) { char *base_in_result; char const *const *t = tests[i]; char *res = file_name_concat (t[0], t[1], &base_in_result); if (strcmp (res, t[2]) != 0) { fprintf (stderr, "test #%u: got %s, expected %s\n", i, res, t[2]); fail = true; } } exit (fail ? EXIT_FAILURE : EXIT_SUCCESS); }
int main () { int i; int dfd; char *cwd; int result; /* Clean up any trash from prior testsuite runs. */ ASSERT (system ("rm -rf " BASE "*") == 0); /* Test basic link functionality, without mentioning symlinks. */ result = test_link (do_link, false); dfd1 = open (".", O_RDONLY); ASSERT (0 <= dfd1); ASSERT (test_link (do_link, false) == result); dfd2 = dfd1; ASSERT (test_link (do_link, false) == result); dfd1 = AT_FDCWD; ASSERT (test_link (do_link, false) == result); flag = 0; ASSERT (test_link (do_link, false) == result); dfd1 = dfd2; ASSERT (test_link (do_link, false) == result); dfd2 = AT_FDCWD; ASSERT (test_link (do_link, false) == result); ASSERT (close (dfd1) == 0); dfd1 = AT_FDCWD; ASSERT (test_link (do_link, false) == result); /* Create locations to manipulate. */ ASSERT (mkdir (BASE "sub1", 0700) == 0); ASSERT (mkdir (BASE "sub2", 0700) == 0); ASSERT (close (creat (BASE "00", 0600)) == 0); cwd = xgetcwd (); dfd = open (BASE "sub1", O_RDONLY); ASSERT (0 <= dfd); ASSERT (chdir (BASE "sub2") == 0); /* There are 16 possible scenarios, based on whether an fd is AT_FDCWD or real, whether a file is absolute or relative, coupled with whether flag is set for 32 iterations. To ensure that we test all of the code paths (rather than triggering early normalization optimizations), we use a loop to repeatedly rename a file in the parent directory, use an fd open on subdirectory 1, all while executing in subdirectory 2; all relative names are thus given with a leading "../". Finally, the last scenario (two relative paths given, neither one AT_FDCWD) has two paths, based on whether the two fds are equivalent, so we do the other variant after the loop. */ for (i = 0; i < 32; i++) { int flag = (i & 0x10 ? AT_SYMLINK_FOLLOW : 0); int fd1 = (i & 8) ? dfd : AT_FDCWD; char *file1 = file_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL); int fd2 = (i & 2) ? dfd : AT_FDCWD; char *file2 = file_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL); ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2); ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2); ASSERT (linkat (fd1, file1, fd2, file2, flag) == 0); ASSERT (unlinkat (fd1, file1, 0) == 0); free (file1); free (file2); } dfd2 = open ("..", O_RDONLY); ASSERT (0 <= dfd2); ASSERT (linkat (dfd, "../" BASE "32", dfd2, BASE "33", 0) == 0); ASSERT (linkat (dfd, "../" BASE "33", dfd2, BASE "34", AT_SYMLINK_FOLLOW) == 0); ASSERT (close (dfd2) == 0); /* Now we change back to the parent directory, and set dfd to ".", in order to test behavior on symlinks. */ ASSERT (chdir ("..") == 0); ASSERT (close (dfd) == 0); if (symlink (BASE "sub1", BASE "link1")) { ASSERT (unlink (BASE "32") == 0); ASSERT (unlink (BASE "33") == 0); ASSERT (unlink (BASE "34") == 0); ASSERT (rmdir (BASE "sub1") == 0); ASSERT (rmdir (BASE "sub2") == 0); free (cwd); fputs ("skipping test: symlinks not supported on this filesystem\n", stderr); return result; } dfd = open (".", O_RDONLY); ASSERT (0 <= dfd); ASSERT (symlink (BASE "34", BASE "link2") == 0); ASSERT (symlink (BASE "link3", BASE "link3") == 0); ASSERT (symlink (BASE "nowhere", BASE "link4") == 0); /* Link cannot overwrite existing files. */ errno = 0; ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1", 0) == -1); ASSERT (errno == EEXIST); errno = 0; ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1", 0) == -1); ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES); errno = 0; ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/", 0) == -1); ASSERT (errno == EEXIST); errno = 0; ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1", AT_SYMLINK_FOLLOW) == -1); ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES); errno = 0; ASSERT (linkat (dfd, BASE "link1/", dfd, BASE "sub1", AT_SYMLINK_FOLLOW) == -1); ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES); errno = 0; ASSERT (linkat (dfd, BASE "link1", dfd, BASE "sub1/", AT_SYMLINK_FOLLOW) == -1); ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES); errno = 0; ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2", 0) == -1); ASSERT (errno == EEXIST); errno = 0; ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link2", AT_SYMLINK_FOLLOW) == -1); ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES); errno = 0; ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3", 0) == -1); ASSERT (errno == EEXIST || errno == ELOOP); errno = 0; ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link3", AT_SYMLINK_FOLLOW) == -1); ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES || errno == ELOOP); errno = 0; ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3", 0) == -1); ASSERT (errno == EEXIST || errno == ELOOP); errno = 0; ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link3", AT_SYMLINK_FOLLOW) == -1); ASSERT (errno == EEXIST || errno == ELOOP); /* AT_SYMLINK_FOLLOW only follows first argument, not second. */ errno = 0; ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4", 0) == -1); ASSERT (errno == EEXIST); ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link4", AT_SYMLINK_FOLLOW) == -1); ASSERT (errno == EEXIST || errno == EPERM || errno == EACCES); errno = 0; ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", 0) == -1); ASSERT (errno == EEXIST); errno = 0; ASSERT (linkat (dfd, BASE "34", dfd, BASE "link4", AT_SYMLINK_FOLLOW) == -1); ASSERT (errno == EEXIST); /* Trailing slash handling. */ errno = 0; ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5", 0) == -1); ASSERT (errno == ENOTDIR); errno = 0; ASSERT (linkat (dfd, BASE "link2/", dfd, BASE "link5", AT_SYMLINK_FOLLOW) == -1); ASSERT (errno == ENOTDIR); errno = 0; ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5", 0) == -1); ASSERT (errno == ELOOP); errno = 0; ASSERT (linkat (dfd, BASE "link3/", dfd, BASE "link5", AT_SYMLINK_FOLLOW) == -1); ASSERT (errno == ELOOP); errno = 0; ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5", 0) == -1); ASSERT (errno == ENOENT); errno = 0; ASSERT (linkat (dfd, BASE "link4/", dfd, BASE "link5", AT_SYMLINK_FOLLOW) == -1); ASSERT (errno == ENOENT); /* Check for hard links to symlinks. */ ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5", 0) == 0); check_same_link (BASE "link1", BASE "link5"); ASSERT (unlink (BASE "link5") == 0); errno = 0; ASSERT (linkat (dfd, BASE "link1", dfd, BASE "link5", AT_SYMLINK_FOLLOW) == -1); ASSERT (errno == EPERM || errno == EACCES); ASSERT (linkat (dfd, BASE "link2", dfd, BASE "link5", 0) == 0); check_same_link (BASE "link2", BASE "link5"); ASSERT (unlink (BASE "link5") == 0); ASSERT (linkat (dfd, BASE "link2", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0); errno = 0; ASSERT (areadlink (BASE "file") == NULL); ASSERT (errno == EINVAL); ASSERT (unlink (BASE "file") == 0); ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5", 0) == 0); check_same_link (BASE "link3", BASE "link5"); ASSERT (unlink (BASE "link5") == 0); errno = 0; ASSERT (linkat (dfd, BASE "link3", dfd, BASE "link5", AT_SYMLINK_FOLLOW) == -1); ASSERT (errno == ELOOP); ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5", 0) == 0); check_same_link (BASE "link4", BASE "link5"); ASSERT (unlink (BASE "link5") == 0); errno = 0; ASSERT (linkat (dfd, BASE "link4", dfd, BASE "link5", AT_SYMLINK_FOLLOW) == -1); ASSERT (errno == ENOENT); /* Check that symlink to symlink to file is followed all the way. */ ASSERT (symlink (BASE "link2", BASE "link5") == 0); ASSERT (linkat (dfd, BASE "link5", dfd, BASE "link6", 0) == 0); check_same_link (BASE "link5", BASE "link6"); ASSERT (unlink (BASE "link6") == 0); ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file", AT_SYMLINK_FOLLOW) == 0); errno = 0; ASSERT (areadlink (BASE "file") == NULL); ASSERT (errno == EINVAL); ASSERT (unlink (BASE "file") == 0); ASSERT (unlink (BASE "link5") == 0); ASSERT (symlink (BASE "link3", BASE "link5") == 0); errno = 0; ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file", AT_SYMLINK_FOLLOW) == -1); ASSERT (errno == ELOOP); ASSERT (unlink (BASE "link5") == 0); ASSERT (symlink (BASE "link4", BASE "link5") == 0); errno = 0; ASSERT (linkat (dfd, BASE "link5", dfd, BASE "file", AT_SYMLINK_FOLLOW) == -1); ASSERT (errno == ENOENT); /* Now for some real fun with directory crossing. */ ASSERT (symlink (cwd, BASE "sub1/link") == 0); ASSERT (symlink (".././/" BASE "sub1/link/" BASE "link2", BASE "sub2/link") == 0); ASSERT (close (dfd) == 0); dfd = open (BASE "sub1", O_RDONLY); ASSERT (0 <= dfd); dfd2 = open (BASE "sub2", O_RDONLY); ASSERT (0 < dfd2); ASSERT (linkat (dfd, "../" BASE "sub2/link", dfd2, "./..//" BASE "sub1/file", AT_SYMLINK_FOLLOW) == 0); errno = 0; ASSERT (areadlink (BASE "sub1/file") == NULL); ASSERT (errno == EINVAL); /* Cleanup. */ ASSERT (close (dfd) == 0); ASSERT (close (dfd2) == 0); ASSERT (unlink (BASE "sub1/file") == 0); ASSERT (unlink (BASE "sub1/link") == 0); ASSERT (unlink (BASE "sub2/link") == 0); ASSERT (unlink (BASE "32") == 0); ASSERT (unlink (BASE "33") == 0); ASSERT (unlink (BASE "34") == 0); ASSERT (rmdir (BASE "sub1") == 0); ASSERT (rmdir (BASE "sub2") == 0); ASSERT (unlink (BASE "link1") == 0); ASSERT (unlink (BASE "link2") == 0); ASSERT (unlink (BASE "link3") == 0); ASSERT (unlink (BASE "link4") == 0); ASSERT (unlink (BASE "link5") == 0); free (cwd); return result; }
int main (void) { int i; int dfd; char *cwd; int result; /* Clean up any trash from prior testsuite runs. */ ignore_value (system ("rm -rf " BASE "*")); /* Test behaviour for invalid file descriptors. */ { errno = 0; ASSERT (renameat (-1, "foo", AT_FDCWD, "bar") == -1); ASSERT (errno == EBADF); } { errno = 0; ASSERT (renameat (99, "foo", AT_FDCWD, "bar") == -1); ASSERT (errno == EBADF); } ASSERT (close (creat (BASE "oo", 0600)) == 0); { errno = 0; ASSERT (renameat (AT_FDCWD, BASE "oo", -1, "bar") == -1); ASSERT (errno == EBADF); } { errno = 0; ASSERT (renameat (AT_FDCWD, BASE "oo", 99, "bar") == -1); ASSERT (errno == EBADF); } ASSERT (unlink (BASE "oo") == 0); /* Test basic rename functionality, using current directory. */ result = test_rename (do_rename, false); dfd1 = open (".", O_RDONLY); ASSERT (0 <= dfd1); ASSERT (test_rename (do_rename, false) == result); dfd2 = dfd1; ASSERT (test_rename (do_rename, false) == result); dfd1 = AT_FDCWD; ASSERT (test_rename (do_rename, false) == result); ASSERT (close (dfd2) == 0); /* Create locations to manipulate. */ ASSERT (mkdir (BASE "sub1", 0700) == 0); ASSERT (mkdir (BASE "sub2", 0700) == 0); dfd = creat (BASE "00", 0600); ASSERT (0 <= dfd); ASSERT (close (dfd) == 0); cwd = getcwd (NULL, 0); ASSERT (cwd); dfd = open (BASE "sub1", O_RDONLY); ASSERT (0 <= dfd); ASSERT (chdir (BASE "sub2") == 0); /* There are 16 possible scenarios, based on whether an fd is AT_FDCWD or real, and whether a file is absolute or relative. To ensure that we test all of the code paths (rather than triggering early normalization optimizations), we use a loop to repeatedly rename a file in the parent directory, use an fd open on subdirectory 1, all while executing in subdirectory 2; all relative names are thus given with a leading "../". Finally, the last scenario (two relative paths given, neither one AT_FDCWD) has two paths, based on whether the two fds are equivalent, so we do the other variant after the loop. */ for (i = 0; i < 16; i++) { int fd1 = (i & 8) ? dfd : AT_FDCWD; char *file1 = file_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL); int fd2 = (i & 2) ? dfd : AT_FDCWD; char *file2 = file_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL); ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2); ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2); ASSERT (renameat (fd1, file1, fd2, file2) == 0); free (file1); free (file2); } dfd2 = open ("..", O_RDONLY); ASSERT (0 <= dfd2); ASSERT (renameat (dfd, "../" BASE "16", dfd2, BASE "17") == 0); ASSERT (close (dfd2) == 0); /* Now we change back to the parent directory, and set dfd to "."; using dfd in remaining tests will expose any bugs if emulation via /proc/self/fd doesn't check for empty names. */ ASSERT (chdir ("..") == 0); ASSERT (close (dfd) == 0); dfd = open (".", O_RDONLY); ASSERT (0 <= dfd); ASSERT (close (creat (BASE "sub2/file", 0600)) == 0); errno = 0; ASSERT (renameat (dfd, BASE "sub1", dfd, BASE "sub2") == -1); ASSERT (errno == EEXIST || errno == ENOTEMPTY); ASSERT (unlink (BASE "sub2/file") == 0); errno = 0; ASSERT (renameat (dfd, BASE "sub2", dfd, BASE "sub1/.") == -1); ASSERT (errno == EINVAL || errno == EISDIR || errno == EBUSY || errno == ENOTEMPTY || errno == EEXIST); errno = 0; ASSERT (renameat (dfd, BASE "sub2/.", dfd, BASE "sub1") == -1); ASSERT (errno == EINVAL || errno == EBUSY || errno == EEXIST); errno = 0; ASSERT (renameat (dfd, BASE "17", dfd, BASE "sub1") == -1); ASSERT (errno == EISDIR); errno = 0; ASSERT (renameat (dfd, BASE "nosuch", dfd, BASE "18") == -1); ASSERT (errno == ENOENT); errno = 0; ASSERT (renameat (dfd, "", dfd, BASE "17") == -1); ASSERT (errno == ENOENT); errno = 0; ASSERT (renameat (dfd, BASE "17", dfd, "") == -1); ASSERT (errno == ENOENT); errno = 0; ASSERT (renameat (dfd, BASE "sub2", dfd, BASE "17") == -1); ASSERT (errno == ENOTDIR); errno = 0; ASSERT (renameat (dfd, BASE "17/", dfd, BASE "18") == -1); ASSERT (errno == ENOTDIR); errno = 0; ASSERT (renameat (dfd, BASE "17", dfd, BASE "18/") == -1); ASSERT (errno == ENOTDIR || errno == ENOENT); /* Finally, make sure we can overwrite existing files. */ ASSERT (close (creat (BASE "sub2/file", 0600)) == 0); errno = 0; ASSERT (renameat (dfd, BASE "sub2", dfd, BASE "sub1") == 0); ASSERT (renameat (dfd, BASE "sub1/file", dfd, BASE "17") == 0); /* Cleanup. */ ASSERT (close (dfd) == 0); errno = 0; ASSERT (unlink (BASE "sub1/file") == -1); ASSERT (errno == ENOENT); ASSERT (unlink (BASE "17") == 0); ASSERT (rmdir (BASE "sub1") == 0); errno = 0; ASSERT (rmdir (BASE "sub2") == -1); ASSERT (errno == ENOENT); free (cwd); if (result) fputs ("skipping test: symlinks not supported on this file system\n", stderr); return result; }
/* Search for FILENAME according to -B options, `.', -I options, then M4PATH environment. If successful, return the open file, and if RESULT is not NULL, set *RESULT to a malloc'd string that represents the file found with respect to the current working directory. Otherwise, return NULL, and errno reflects the failure from searching `.' (regardless of what else was searched). */ char * m4_path_search (m4 *context, const char *filename, const char **suffixes) { m4__search_path *incl; char *filepath; /* buffer for constructed name */ size_t max_suffix_len = 0; int i, e = 0; /* Reject empty file. */ if (*filename == '\0') { errno = ENOENT; return NULL; } /* Use no suffixes by default. */ if (suffixes == NULL) suffixes = NO_SUFFIXES; /* Find the longest suffix, so that we will always allocate enough memory for a filename with suffix. */ for (i = 0; suffixes && suffixes[i]; ++i) { size_t len = strlen (suffixes[i]); if (len > max_suffix_len) max_suffix_len = len; } /* If file is absolute, or if we are not searching a path, a single lookup will do the trick. */ if (IS_ABSOLUTE_FILE_NAME (filename)) { size_t mem = strlen (filename); /* Try appending each of the suffixes we were given. */ filepath = strncpy (xmalloc (mem + max_suffix_len +1), filename, mem +1); #if TRUNCATE_FILENAME filepath = path_truncate (filepath); mem = strlen (filepath); /* recalculate length after truncation */ #endif for (i = 0; suffixes && suffixes[i]; ++i) { strcpy (filepath + mem, suffixes[i]); if (access (filepath, R_OK) == 0) return filepath; /* If search fails, we'll use the error we got from the first access (usually with no suffix). */ if (i == 0) e = errno; } free (filepath); /* No such file. */ errno = e; return NULL; } for (incl = m4__get_search_path (context)->list; incl != NULL; incl = incl->next) { char *pathname = file_name_concat (incl->dir, filename, NULL); size_t mem = strlen (pathname); #ifdef DEBUG_INCL xfprintf (stderr, "path_search (%s) -- trying %s\n", filename, pathname); #endif if (access (pathname, R_OK) == 0) { m4_debug_message (context, M4_DEBUG_TRACE_PATH, _("path search for %s found %s"), quotearg_style (locale_quoting_style, filename), quotearg_n_style (1, locale_quoting_style, pathname)); return pathname; } else if (!incl->len) /* Capture errno only when searching `.'. */ e = errno; filepath = strncpy (xmalloc (mem + max_suffix_len +1), pathname, mem +1); free (pathname); #if TRUNCATE_FILENAME filepath = path_truncate (filepath); mem = strlen (filepath); /* recalculate length after truncation */ #endif for (i = 0; suffixes && suffixes[i]; ++i) { strcpy (filepath + mem, suffixes[i]); if (access (filepath, R_OK) == 0) return filepath; } free (filepath); } errno = e; return NULL; }
char * canonicalize_file_name (const char *name) { # if HAVE_RESOLVEPATH char *resolved, *extra_buf = NULL; size_t resolved_size; ssize_t resolved_len; if (name == NULL) { __set_errno (EINVAL); return NULL; } if (name[0] == '\0') { __set_errno (ENOENT); return NULL; } /* All known hosts with resolvepath (e.g. Solaris 7) don't turn relative names into absolute ones, so prepend the working directory if the file name is not absolute. */ if (name[0] != '/') { char *wd; if (!(wd = xgetcwd ())) return NULL; extra_buf = file_name_concat (wd, name, NULL); name = extra_buf; free (wd); } resolved_size = strlen (name); while (1) { resolved_size = 2 * resolved_size + 1; resolved = xmalloc (resolved_size); resolved_len = resolvepath (name, resolved, resolved_size); if (resolved_len < 0) { free (resolved); free (extra_buf); return NULL; } if (resolved_len < resolved_size) break; free (resolved); } free (extra_buf); /* NUL-terminate the resulting name. */ resolved[resolved_len] = '\0'; return resolved; # else return canonicalize_filename_mode (name, CAN_EXISTING); # endif /* !HAVE_RESOLVEPATH */ }