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)) {