git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Eric DeCosta via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: "Eric Sunshine [ ]" <sunshine@sunshineco.com>,
	"Ævar Arnfjörð Bjarmason [ ]" <avarab@gmail.com>,
	"Glen Choo [ ]" <chooglen@google.com>,
	"Johannes Schindelin [ ]" <Johannes.Schindelin@gmx.de>,
	"Taylor Blau [ ]" <me@ttaylorr.com>, marzi <m.ispare63@gmail.com>,
	"Eric DeCosta" <edecosta@mathworks.com>
Subject: [PATCH 2/7] fsmonitor: determine if filesystem is local or remote
Date: Thu, 15 Feb 2024 10:29:33 +0000	[thread overview]
Message-ID: <d26de10866662a5bcd16d562cd1063dedd21cf02.1707992978.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.1667.git.git.1707992978.gitgitgadget@gmail.com>

From: Eric DeCosta <edecosta@mathworks.com>

Compare the given path to the mounted filesystems. Find the mount that is
the longest prefix of the path (if any) and determine if that mount is on a
local or remote filesystem.

Signed-off-by: Eric DeCosta <edecosta@mathworks.com>
---
 Makefile                                |   4 +
 compat/fsmonitor/fsm-path-utils-linux.c | 195 ++++++++++++++++++++++++
 compat/fsmonitor/fsm-path-utils-linux.h |  91 +++++++++++
 config.mak.uname                        |  11 ++
 4 files changed, 301 insertions(+)
 create mode 100644 compat/fsmonitor/fsm-path-utils-linux.c
 create mode 100644 compat/fsmonitor/fsm-path-utils-linux.h

diff --git a/Makefile b/Makefile
index 78e874099d9..0f36a0fd83a 100644
--- a/Makefile
+++ b/Makefile
@@ -2088,6 +2088,10 @@ ifdef HAVE_CLOCK_GETTIME
 	BASIC_CFLAGS += -DHAVE_CLOCK_GETTIME
 endif
 
+ifdef HAVE_LINUX_MAGIC_H
+	BASIC_CFLAGS += -DHAVE_LINUX_MAGIC_H
+endif
+
 ifdef HAVE_CLOCK_MONOTONIC
 	BASIC_CFLAGS += -DHAVE_CLOCK_MONOTONIC
 endif
diff --git a/compat/fsmonitor/fsm-path-utils-linux.c b/compat/fsmonitor/fsm-path-utils-linux.c
new file mode 100644
index 00000000000..c21d1349532
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-linux.c
@@ -0,0 +1,195 @@
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "fsmonitor.h"
+#include "fsmonitor-path-utils.h"
+#include "fsm-path-utils-linux.h"
+#include <errno.h>
+#include <mntent.h>
+#include <sys/mount.h>
+#include <sys/vfs.h>
+#include <sys/statvfs.h>
+
+static int is_remote_fs(const char *path)
+{
+	struct statfs fs;
+
+	if (statfs(path, &fs))
+		return error_errno(_("statfs('%s') failed"), path);
+
+	switch (fs.f_type) {
+	case ACFS_SUPER_MAGIC:
+	case AFS_SUPER_MAGIC:
+	case CEPH_SUPER_MAGIC:
+	case CIFS_SUPER_MAGIC:
+	case CODA_SUPER_MAGIC:
+	case FHGFS_SUPER_MAGIC:
+	case GFS_SUPER_MAGIC:
+	case GPFS_SUPER_MAGIC:
+	case IBRIX_SUPER_MAGIC:
+	case KAFS_SUPER_MAGIC:
+	case LUSTRE_SUPER_MAGIC:
+	case NCP_SUPER_MAGIC:
+	case NFS_SUPER_MAGIC:
+	case NFSD_SUPER_MAGIC:
+	case OCFS2_SUPER_MAGIC:
+	case PANFS_SUPER_MAGIC:
+	case SMB_SUPER_MAGIC:
+	case SMB2_SUPER_MAGIC:
+	case SNFS_SUPER_MAGIC:
+	case VMHGFS_SUPER_MAGIC:
+	case VXFS_SUPER_MAGIC:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static int find_mount(const char *path, const struct statvfs *fs,
+			struct mntent *entry)
+{
+	const char *const mounts = "/proc/mounts";
+	char *rp = real_pathdup(path, 1);
+	struct mntent *ment = NULL;
+	struct statvfs mntfs;
+	FILE *fp;
+	int found = 0;
+	int ret = 0;
+	size_t dlen, plen, flen = 0;
+
+	entry->mnt_fsname = NULL;
+	entry->mnt_dir = NULL;
+	entry->mnt_type = NULL;
+
+	fp = setmntent(mounts, "r");
+	if (!fp) {
+		free(rp);
+		return error_errno(_("setmntent('%s') failed"), mounts);
+	}
+
+	plen = strlen(rp);
+
+	/* read all the mount information and compare to path */
+	while ((ment = getmntent(fp))) {
+		if (statvfs(ment->mnt_dir, &mntfs)) {
+			switch (errno) {
+			case EPERM:
+			case ESRCH:
+			case EACCES:
+				continue;
+			default:
+				error_errno(_("statvfs('%s') failed"), ment->mnt_dir);
+				ret = -1;
+				goto done;
+			}
+		}
+
+		/* is mount on the same filesystem and is a prefix of the path */
+		if ((fs->f_fsid == mntfs.f_fsid) &&
+			!strncmp(ment->mnt_dir, rp, strlen(ment->mnt_dir))) {
+			dlen = strlen(ment->mnt_dir);
+			if (dlen > plen)
+				continue;
+			/*
+			 * look for the longest prefix (including root)
+			 */
+			if (dlen > flen &&
+				((dlen == 1 && ment->mnt_dir[0] == '/') ||
+				 (!rp[dlen] || rp[dlen] == '/'))) {
+				flen = dlen;
+				found = 1;
+
+				/*
+				 * https://man7.org/linux/man-pages/man3/getmntent.3.html
+				 *
+				 * The pointer points to a static area of memory which is
+				 * overwritten by subsequent calls to getmntent().
+				 */
+				free(entry->mnt_fsname);
+				free(entry->mnt_dir);
+				free(entry->mnt_type);
+				entry->mnt_fsname = xstrdup(ment->mnt_fsname);
+				entry->mnt_dir = xstrdup(ment->mnt_dir);
+				entry->mnt_type = xstrdup(ment->mnt_type);
+			}
+		}
+	}
+
+done:
+	free(rp);
+	endmntent(fp);
+
+	if (!found)
+		return -1;
+
+	return ret;
+}
+
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+	int ret = 0;
+	struct mntent entry;
+	struct statvfs fs;
+
+	fs_info->is_remote = -1;
+	fs_info->typename = NULL;
+
+	if (statvfs(path, &fs))
+		return error_errno(_("statvfs('%s') failed"), path);
+
+	if (find_mount(path, &fs, &entry) < 0) {
+		ret = -1;
+		goto done;
+	}
+
+	trace_printf_key(&trace_fsmonitor,
+			 "statvfs('%s') [flags 0x%08lx] '%s' '%s'",
+			 path, fs.f_flag, entry.mnt_type, entry.mnt_fsname);
+
+	fs_info->is_remote = is_remote_fs(entry.mnt_dir);
+	fs_info->typename = xstrdup(entry.mnt_fsname);
+
+	if (fs_info->is_remote < 0)
+		ret = -1;
+
+	trace_printf_key(&trace_fsmonitor,
+				"'%s' is_remote: %d",
+				path, fs_info->is_remote);
+
+done:
+	free(entry.mnt_fsname);
+	free(entry.mnt_dir);
+	free(entry.mnt_type);
+	return ret;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+	int ret = 0;
+	struct fs_info fs;
+
+	if (fsmonitor__get_fs_info(path, &fs))
+		ret = -1;
+	else
+		ret = fs.is_remote;
+
+	free(fs.typename);
+
+	return ret;
+}
+
+/*
+ * No-op for now.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+	return 0;
+}
+
+/*
+ * No-op for now.
+ */
+char *fsmonitor__resolve_alias(const char *path,
+		const struct alias_info *info)
+{
+	return NULL;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-linux.h b/compat/fsmonitor/fsm-path-utils-linux.h
new file mode 100644
index 00000000000..49bdb3c4728
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-linux.h
@@ -0,0 +1,91 @@
+#ifndef FSM_PATH_UTILS_LINUX_H
+#define FSM_PATH_UTILS_LINUX_H
+#endif
+
+#ifdef HAVE_LINUX_MAGIC_H
+#include <linux/magic.h>
+#endif
+
+#ifndef ACFS_SUPER_MAGIC
+#define ACFS_SUPER_MAGIC 0x61636673
+#endif
+
+#ifndef AFS_SUPER_MAGIC
+#define AFS_SUPER_MAGIC 0x5346414f
+#endif
+
+#ifndef CEPH_SUPER_MAGIC
+#define CEPH_SUPER_MAGIC 0x00c36400
+#endif
+
+#ifndef CIFS_SUPER_MAGIC
+#define CIFS_SUPER_MAGIC 0xff534d42
+#endif
+
+#ifndef CODA_SUPER_MAGIC
+#define CODA_SUPER_MAGIC 0x73757245
+#endif
+
+#ifndef FHGFS_SUPER_MAGIC
+#define FHGFS_SUPER_MAGIC 0x19830326
+#endif
+
+#ifndef GFS_SUPER_MAGIC
+#define GFS_SUPER_MAGIC 0x1161970
+#endif
+
+#ifndef GPFS_SUPER_MAGIC
+#define GPFS_SUPER_MAGIC 0x47504653
+#endif
+
+#ifndef IBRIX_SUPER_MAGIC
+#define IBRIX_SUPER_MAGIC 0x013111a8
+#endif
+
+#ifndef KAFS_SUPER_MAGIC
+#define KAFS_SUPER_MAGIC 0x6b414653
+#endif
+
+#ifndef LUSTRE_SUPER_MAGIC
+#define LUSTRE_SUPER_MAGIC 0x0bd00bd0
+#endif
+
+#ifndef NCP_SUPER_MAGIC
+#define NCP_SUPER_MAGIC 0x564c
+#endif
+
+#ifndef NFS_SUPER_MAGIC
+#define NFS_SUPER_MAGIC 0x6969
+#endif
+
+#ifndef NFSD_SUPER_MAGIC
+#define NFSD_SUPER_MAGIC 0x6e667364
+#endif
+
+#ifndef OCFS2_SUPER_MAGIC
+#define OCFS2_SUPER_MAGIC 0x7461636f
+#endif
+
+#ifndef PANFS_SUPER_MAGIC
+#define PANFS_SUPER_MAGIC 0xaad7aaea
+#endif
+
+#ifndef SMB_SUPER_MAGIC
+#define SMB_SUPER_MAGIC 0x517b
+#endif
+
+#ifndef SMB2_SUPER_MAGIC
+#define SMB2_SUPER_MAGIC 0xfe534d42
+#endif
+
+#ifndef SNFS_SUPER_MAGIC
+#define SNFS_SUPER_MAGIC 0xbeefdead
+#endif
+
+#ifndef VMHGFS_SUPER_MAGIC
+#define VMHGFS_SUPER_MAGIC 0xbacbacbc
+#endif
+
+#ifndef VXFS_SUPER_MAGIC
+#define VXFS_SUPER_MAGIC 0xa501fcf5
+#endif
diff --git a/config.mak.uname b/config.mak.uname
index dacc95172dc..80d7e2a2e68 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -68,6 +68,17 @@ ifeq ($(uname_S),Linux)
 	ifneq ($(findstring .el7.,$(uname_R)),)
 		BASIC_CFLAGS += -std=c99
 	endif
+	ifeq ($(shell test -f /usr/include/linux/magic.h && echo y),y)
+		HAVE_LINUX_MAGIC_H = YesPlease
+	endif
+	# The builtin FSMonitor on Linux builds upon Simple-IPC.  Both require
+	# Unix domain sockets and PThreads.
+	ifndef NO_PTHREADS
+	ifndef NO_UNIX_SOCKETS
+	FSMONITOR_DAEMON_BACKEND = linux
+	FSMONITOR_OS_SETTINGS = linux
+	endif
+	endif
 endif
 ifeq ($(uname_S),GNU/kFreeBSD)
 	HAVE_ALLOCA_H = YesPlease
-- 
gitgitgadget


  parent reply	other threads:[~2024-02-15 10:29 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-02-15 10:29 [PATCH 0/7] fsmonitor: completing a stale patch that Implements fsmonitor for Linux marzi via GitGitGadget
2024-02-15 10:29 ` [PATCH 1/7] fsmonitor: rebase with master Eric DeCosta via GitGitGadget
2024-02-15 13:49   ` Patrick Steinhardt
2024-02-15 10:29 ` Eric DeCosta via GitGitGadget [this message]
2024-02-15 11:24   ` [PATCH 2/7] fsmonitor: determine if filesystem is local or remote Jean-Noël Avila
2024-02-15 13:49   ` Patrick Steinhardt
2024-02-15 10:29 ` [PATCH 3/7] fsmonitor: implement filesystem change listener for Linux Eric DeCosta via GitGitGadget
2024-02-15 13:49   ` Patrick Steinhardt
2024-02-15 10:29 ` [PATCH 4/7] fsmonitor: enable fsmonitor " Eric DeCosta via GitGitGadget
2024-02-15 10:29 ` [PATCH 5/7] fsmonitor: test updates Eric DeCosta via GitGitGadget
2024-02-15 10:29 ` [PATCH 6/7] fsmonitor: update doc for Linux Eric DeCosta via GitGitGadget
2024-02-15 10:29 ` [PATCH 7/7] fsmonitor: addressed comments for patch 1352 marzi.esipreh via GitGitGadget
2024-02-15 13:49   ` Patrick Steinhardt
2025-01-31  3:28 ` [PATCH 0/7] fsmonitor: completing a stale patch that Implements fsmonitor for Linux Manoraj K

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d26de10866662a5bcd16d562cd1063dedd21cf02.1707992978.git.gitgitgadget@gmail.com \
    --to=gitgitgadget@gmail.com \
    --cc=Johannes.Schindelin@gmx.de \
    --cc=avarab@gmail.com \
    --cc=chooglen@google.com \
    --cc=edecosta@mathworks.com \
    --cc=git@vger.kernel.org \
    --cc=m.ispare63@gmail.com \
    --cc=me@ttaylorr.com \
    --cc=sunshine@sunshineco.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).