1 /* Copyright 2014-present Facebook, Inc.
2  * Licensed under the Apache License, Version 2.0 */
3 
4 #include "watchman.h"
5 #ifdef HAVE_SYS_VFS_H
6 # include <sys/vfs.h>
7 #endif
8 #ifdef HAVE_SYS_STATVFS_H
9 # include <sys/statvfs.h>
10 #endif
11 #ifdef HAVE_SYS_PARAM_H
12 # include <sys/param.h>
13 #endif
14 #ifdef HAVE_SYS_MOUNT_H
15 # include <sys/mount.h>
16 #endif
17 #ifdef __linux__
18 #include <linux/magic.h>
19 #endif
20 #include "FileDescriptor.h"
21 
22 // The primary purpose of checking the filesystem type is to prevent
23 // watching filesystems that are known to be problematic, such as
24 // network or remote mounted filesystems.  As such, we don't strictly
25 // need to have a fully comprehensive mapping of the underlying filesystem
26 // type codes to names, just the known problematic types
27 
w_fstype(const char * path)28 w_string w_fstype(const char *path)
29 {
30 #ifdef __linux__
31   struct statfs sfs;
32   const char *name = "unknown";
33 
34   if (statfs(path, &sfs) == 0) {
35     switch (sfs.f_type) {
36 #ifdef CIFS_MAGIC_NUMBER
37       case CIFS_MAGIC_NUMBER:
38         name = "cifs";
39         break;
40 #endif
41 #ifdef NFS_SUPER_MAGIC
42       case NFS_SUPER_MAGIC:
43         name = "nfs";
44         break;
45 #endif
46 #ifdef SMB_SUPER_MAGIC
47       case SMB_SUPER_MAGIC:
48         name = "smb";
49         break;
50 #endif
51       default:
52         name = "unknown";
53     }
54   }
55 
56   return w_string(name, W_STRING_UNICODE);
57 #elif STATVFS_HAS_FSTYPE_AS_STRING
58   struct statvfs sfs;
59 
60   if (statvfs(path, &sfs) == 0) {
61 #ifdef HAVE_STRUCT_STATVFS_F_FSTYPENAME
62     return w_string(sfs.f_fstypename, W_STRING_UNICODE);
63 #endif
64 #ifdef HAVE_STRUCT_STATVFS_F_BASETYPE
65     return w_string(sfs.f_basetype, W_STRING_UNICODE);
66 #endif
67   }
68 #elif HAVE_STATFS
69   struct statfs sfs;
70 
71   if (statfs(path, &sfs) == 0) {
72     return w_string(sfs.f_fstypename, W_STRING_UNICODE);
73   }
74 #endif
75 #ifdef _WIN32
76   auto wpath = w_string_piece(path).asWideUNC();
77   WCHAR fstype[MAX_PATH + 1];
78   watchman::FileDescriptor h(intptr_t(CreateFileW(
79       wpath.c_str(),
80       GENERIC_READ,
81       FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
82       nullptr,
83       OPEN_EXISTING,
84       FILE_FLAG_BACKUP_SEMANTICS,
85       nullptr)));
86   if (h && GetVolumeInformationByHandleW(
87                (HANDLE)h.handle(), nullptr, 0, 0, 0, 0, fstype, MAX_PATH + 1)) {
88     return w_string(fstype, wcslen(fstype));
89   }
90   return w_string("unknown", W_STRING_UNICODE);
91 #else
92   unused_parameter(path);
93   return w_string("unknown", W_STRING_UNICODE);
94 #endif
95 }
96 
97 /* vim:ts=2:sw=2:et:
98  */
99