From 81b5ac20797d64d262b905e324cc401d01f58d57 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 13 Jun 2024 15:39:27 -0400 Subject: [PATCH] Added two checks when loading a file to determine if two cells are the same: (1) If the inodes of the filename are the same, then the cells are the same. This avoids treating symbolic links as different paths with different files; (2) If both layouts are in git repositories and the git repository commit hashes are the same, then the cells are considered to be the same. This allows projects to be cloned into other projects as dependencies and used in multiple places without magic treating them as different layouts. --- VERSION | 2 +- database/DBio.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 9734220e..5c84de62 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.485 +8.3.486 diff --git a/database/DBio.c b/database/DBio.c index 9635220f..a594764c 100644 --- a/database/DBio.c +++ b/database/DBio.c @@ -28,6 +28,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/ #include #include #include +#include +#include #ifdef HAVE_DIRENT_H #include @@ -1973,6 +1975,121 @@ badTransform: } else if (!strcmp(cwddir, pathptr)) pathOK = TRUE; + /* Apply same check as done in DBWprocs, which is to check the + * inode of the two files and declare the path okay if they are + * the same. This avoids conflicts in files that are referenced + * from two different places via different relative paths, or + * through symbolic links. + */ + + if ((pathOK == FALSE) && strcmp(subCellDef->cd_file, pathptr) + && (dereference == FALSE) && (firstUse == TRUE)) + { + struct stat statbuf; + ino_t inode; + + if (stat(subCellDef->cd_file, &statbuf) == 0) + { + inode = statbuf.st_ino; + + if (stat(pathptr, &statbuf) == 0) + { + if (inode == statbuf.st_ino) + pathOK = TRUE; + } + } + } + + if ((pathOK == FALSE) && strcmp(subCellDef->cd_file, pathptr) + && (dereference == FALSE) && (firstUse == TRUE)) + { + /* See if both paths are inside a git repository, and both + * git repositories have the same commit hash. Then the + * two layouts can be considered equivalent. If the "git" + * command fails for any reason, then ignore the error and + * continue. + */ + char *sl1ptr, *sl2ptr; + int link[2], nbytes, status; + pid_t pid; + char githash1[128]; + char githash2[128]; + char argstr[1024]; + + githash1[0] = '\0'; + + /* Remove the file component */ + sl1ptr = strrchr(pathptr, '/'); + if (sl1ptr != NULL) *sl1ptr = '\0'; + + /* Check first file for a git hash */ + if (pipe(link) != -1) + { + FORK(pid); + if (pid == 0) + { + dup2(link[1], STDOUT_FILENO); + close(link[0]); + close(link[1]); + sprintf(argstr, "-C %s", pathptr); + execlp("git", argstr, "rev-parse", "HEAD", NULL); + _exit(122); /* see vfork man page for reason for _exit() */ + } + else + { + close(link[1]); + nbytes = read(link[0], githash1, sizeof(githash1)); + waitpid(pid, &status, 0); + } + } + + if (sl1ptr != NULL) *sl1ptr = '/'; + + if (githash1[0] != '\0') + { + /* Check the second repository */ + + /* Remove the file component */ + sl2ptr = strrchr(subCellDef->cd_file, '/'); + if (sl2ptr != NULL) *sl2ptr = '\0'; + + /* Check first file for a git hash */ + if (pipe(link) != -1) + { + FORK(pid); + if (pid == 0) + { + dup2(link[1], STDOUT_FILENO); + close(link[0]); + close(link[1]); + sprintf(argstr, "-C %s", subCellDef->cd_file); + execlp("git", argstr, "rev-parse", "HEAD", NULL); + _exit(123); /* see vfork man page for reason for _exit() */ + } + else + { + close(link[1]); + nbytes = read(link[0], githash2, sizeof(githash2)); + waitpid(pid, &status, 0); + } + } + + if (sl2ptr != NULL) *sl2ptr = '/'; + + if (githash2[0] != '\0') + { + /* Check if the repositories have the same hash */ + if (!strcmp(githash1, githash2)) + { + TxPrintf("Cells %s in %s and %s have matching git repository" + " commits and can be considered equivalent.\n", + slashptr + 1, subCellDef->cd_file, pathptr); + pathOK = TRUE; + } + } + } + } + if ((pathOK == FALSE) && strcmp(subCellDef->cd_file, pathptr) && (dereference == FALSE) && (firstUse == TRUE)) {