1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
|
#include "git-compat-util.h"
#include "fsmonitor-ll.h"
#include "fsmonitor-path-utils.h"
#include "gettext.h"
#include "trace.h"
#include <sys/statfs.h>
#ifdef HAVE_LINUX_MAGIC_H
#include <linux/magic.h>
#endif
/*
* Filesystem magic numbers for remote filesystems.
* Defined here if not available in linux/magic.h.
*/
#ifndef CIFS_SUPER_MAGIC
#define CIFS_SUPER_MAGIC 0xff534d42
#endif
#ifndef SMB_SUPER_MAGIC
#define SMB_SUPER_MAGIC 0x517b
#endif
#ifndef SMB2_SUPER_MAGIC
#define SMB2_SUPER_MAGIC 0xfe534d42
#endif
#ifndef NFS_SUPER_MAGIC
#define NFS_SUPER_MAGIC 0x6969
#endif
#ifndef AFS_SUPER_MAGIC
#define AFS_SUPER_MAGIC 0x5346414f
#endif
#ifndef CODA_SUPER_MAGIC
#define CODA_SUPER_MAGIC 0x73757245
#endif
#ifndef FUSE_SUPER_MAGIC
#define FUSE_SUPER_MAGIC 0x65735546
#endif
/*
* Check if filesystem type is a remote filesystem.
*/
static int is_remote_fs(unsigned long f_type)
{
switch (f_type) {
case CIFS_SUPER_MAGIC:
case SMB_SUPER_MAGIC:
case SMB2_SUPER_MAGIC:
case NFS_SUPER_MAGIC:
case AFS_SUPER_MAGIC:
case CODA_SUPER_MAGIC:
case FUSE_SUPER_MAGIC:
return 1;
default:
return 0;
}
}
/*
* Map filesystem magic numbers to human-readable names as a fallback
* when /proc/mounts is unavailable. This only covers the remote and
* special filesystems in is_remote_fs() above; local filesystems are
* never flagged as incompatible, so we do not need their names here.
*/
static const char *get_fs_typename(unsigned long f_type)
{
switch (f_type) {
case CIFS_SUPER_MAGIC:
return "cifs";
case SMB_SUPER_MAGIC:
return "smb";
case SMB2_SUPER_MAGIC:
return "smb2";
case NFS_SUPER_MAGIC:
return "nfs";
case AFS_SUPER_MAGIC:
return "afs";
case CODA_SUPER_MAGIC:
return "coda";
case FUSE_SUPER_MAGIC:
return "fuse";
default:
return "unknown";
}
}
/*
* Find the mount point for a given path by reading /proc/mounts.
*
* statfs(2) gives us f_type (the magic number) but not the human-readable
* filesystem type string. We scan /proc/mounts to find the mount entry
* whose path is the longest prefix of ours and whose f_fsid matches,
* which gives us the fstype string (e.g. "nfs", "ext4") for logging.
*/
static char *find_mount(const char *path, const struct statfs *path_fs)
{
FILE *fp;
struct strbuf line = STRBUF_INIT;
struct strbuf match = STRBUF_INIT;
struct strbuf fstype = STRBUF_INIT;
char *result = NULL;
fp = fopen("/proc/mounts", "r");
if (!fp)
return NULL;
while (strbuf_getline(&line, fp) != EOF) {
char *fields[6];
char *p = line.buf;
int i;
/* Parse mount entry: device mountpoint fstype options dump pass */
for (i = 0; i < 6 && p; i++) {
fields[i] = p;
p = strchr(p, ' ');
if (p)
*p++ = '\0';
}
if (i >= 3) {
const char *mountpoint = fields[1];
const char *type = fields[2];
struct statfs mount_fs;
/* Check if this mount point is a prefix of our path */
if (starts_with(path, mountpoint) &&
(path[strlen(mountpoint)] == '/' ||
path[strlen(mountpoint)] == '\0')) {
/* Check if filesystem ID matches */
if (statfs(mountpoint, &mount_fs) == 0 &&
!memcmp(&mount_fs.f_fsid, &path_fs->f_fsid,
sizeof(mount_fs.f_fsid))) {
/* Keep the longest matching mount point */
if (strlen(mountpoint) > match.len) {
strbuf_reset(&match);
strbuf_addstr(&match, mountpoint);
strbuf_reset(&fstype);
strbuf_addstr(&fstype, type);
}
}
}
}
}
fclose(fp);
strbuf_release(&line);
strbuf_release(&match);
if (fstype.len)
result = strbuf_detach(&fstype, NULL);
else
strbuf_release(&fstype);
return result;
}
int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
{
struct statfs fs;
if (statfs(path, &fs) == -1) {
int saved_errno = errno;
trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
path, strerror(saved_errno));
errno = saved_errno;
return -1;
}
trace_printf_key(&trace_fsmonitor,
"statfs('%s') [type 0x%08lx]",
path, (unsigned long)fs.f_type);
fs_info->is_remote = is_remote_fs(fs.f_type);
/*
* Try to get filesystem type from /proc/mounts for a more
* descriptive name.
*/
fs_info->typename = find_mount(path, &fs);
if (!fs_info->typename)
fs_info->typename = xstrdup(get_fs_typename(fs.f_type));
trace_printf_key(&trace_fsmonitor,
"'%s' is_remote: %d, typename: %s",
path, fs_info->is_remote, fs_info->typename);
return 0;
}
int fsmonitor__is_fs_remote(const char *path)
{
struct fs_info fs;
if (fsmonitor__get_fs_info(path, &fs))
return -1;
free(fs.typename);
return fs.is_remote;
}
/*
* No-op for Linux - we don't have firmlinks like macOS.
*/
int fsmonitor__get_alias(const char *path UNUSED,
struct alias_info *info UNUSED)
{
return 0;
}
/*
* No-op for Linux - we don't have firmlinks like macOS.
*/
char *fsmonitor__resolve_alias(const char *path UNUSED,
const struct alias_info *info UNUSED)
{
return NULL;
}
|