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.
This commit is contained in:
Tim Edwards 2024-06-13 15:39:27 -04:00
parent e9db9ecbc9
commit 81b5ac2079
2 changed files with 118 additions and 1 deletions

View File

@ -1 +1 @@
8.3.485
8.3.486

View File

@ -28,6 +28,8 @@ static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/
#include <errno.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/wait.h>
#ifdef HAVE_DIRENT_H
#include <dirent.h>
@ -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))
{