s3: libsmb: In cli_ntrename_internal_send() (SMBntrename) check for DFS dst pathname.
[Samba.git] / source3 / modules / vfs_glusterfs_fuse.c
blob3eb4dc27d548762aac94da6990a69c6301e96ccc
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (c) 2019 Guenther Deschner <gd@samba.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "smbd/smbd.h"
22 #include "system/filesys.h"
24 #define GLUSTER_NAME_MAX 255
26 static NTSTATUS vfs_gluster_fuse_get_real_filename_at(
27 struct vfs_handle_struct *handle,
28 struct files_struct *dirfsp,
29 const char *name,
30 TALLOC_CTX *mem_ctx,
31 char **_found_name)
33 int ret, dirfd;
34 char key_buf[GLUSTER_NAME_MAX + 64];
35 char val_buf[GLUSTER_NAME_MAX + 1];
36 char *found_name = NULL;
38 if (strlen(name) >= GLUSTER_NAME_MAX) {
39 return NT_STATUS_OBJECT_NAME_INVALID;
42 snprintf(key_buf, GLUSTER_NAME_MAX + 64,
43 "glusterfs.get_real_filename:%s", name);
45 dirfd = openat(fsp_get_pathref_fd(dirfsp), ".", O_RDONLY);
46 if (dirfd == -1) {
47 NTSTATUS status = map_nt_error_from_unix(errno);
48 DBG_DEBUG("Could not open '.' in %s: %s\n",
49 fsp_str_dbg(dirfsp),
50 strerror(errno));
51 return status;
54 ret = fgetxattr(dirfd, key_buf, val_buf, GLUSTER_NAME_MAX + 1);
55 close(dirfd);
56 if (ret == -1) {
57 if (errno == ENOATTR) {
58 errno = ENOENT;
60 return map_nt_error_from_unix(errno);
63 found_name = talloc_strdup(mem_ctx, val_buf);
64 if (found_name == NULL) {
65 return NT_STATUS_NO_MEMORY;
67 *_found_name = found_name;
68 return NT_STATUS_OK;
71 struct device_mapping_entry {
72 SMB_DEV_T device; /* the local device, for reference */
73 uint64_t mapped_device; /* the mapped device */
76 struct vfs_glusterfs_fuse_handle_data {
77 unsigned num_mapped_devices;
78 struct device_mapping_entry *mapped_devices;
81 /* a 64 bit hash, based on the one in tdb, copied from vfs_fileied */
82 static uint64_t vfs_glusterfs_fuse_uint64_hash(const uint8_t *s, size_t len)
84 uint64_t value; /* Used to compute the hash value. */
85 uint32_t i; /* Used to cycle through random values. */
87 /* Set the initial value from the key size. */
88 for (value = 0x238F13AFLL * len, i=0; i < len; i++)
89 value = (value + (((uint64_t)s[i]) << (i*5 % 24)));
91 return (1103515243LL * value + 12345LL);
94 static void vfs_glusterfs_fuse_load_devices(
95 struct vfs_glusterfs_fuse_handle_data *data)
97 FILE *f;
98 struct mntent *m;
100 data->num_mapped_devices = 0;
101 TALLOC_FREE(data->mapped_devices);
103 f = setmntent("/etc/mtab", "r");
104 if (!f) {
105 return;
108 while ((m = getmntent(f))) {
109 struct stat st;
110 char *p;
111 uint64_t mapped_device;
113 if (stat(m->mnt_dir, &st) != 0) {
114 /* TODO: log? */
115 continue;
118 /* strip the host part off of the fsname */
119 p = strrchr(m->mnt_fsname, ':');
120 if (p == NULL) {
121 p = m->mnt_fsname;
122 } else {
123 /* TODO: consider the case of '' ? */
124 p++;
127 mapped_device = vfs_glusterfs_fuse_uint64_hash(
128 (const uint8_t *)p,
129 strlen(p));
131 data->mapped_devices = talloc_realloc(data,
132 data->mapped_devices,
133 struct device_mapping_entry,
134 data->num_mapped_devices + 1);
135 if (data->mapped_devices == NULL) {
136 goto nomem;
139 data->mapped_devices[data->num_mapped_devices].device =
140 st.st_dev;
141 data->mapped_devices[data->num_mapped_devices].mapped_device =
142 mapped_device;
144 data->num_mapped_devices++;
147 endmntent(f);
148 return;
150 nomem:
151 data->num_mapped_devices = 0;
152 TALLOC_FREE(data->mapped_devices);
154 endmntent(f);
155 return;
158 static int vfs_glusterfs_fuse_map_device_cached(
159 struct vfs_glusterfs_fuse_handle_data *data,
160 SMB_DEV_T device,
161 uint64_t *mapped_device)
163 unsigned i;
165 for (i = 0; i < data->num_mapped_devices; i++) {
166 if (data->mapped_devices[i].device == device) {
167 *mapped_device = data->mapped_devices[i].mapped_device;
168 return 0;
172 return -1;
175 static int vfs_glusterfs_fuse_map_device(
176 struct vfs_glusterfs_fuse_handle_data *data,
177 SMB_DEV_T device,
178 uint64_t *mapped_device)
180 int ret;
182 ret = vfs_glusterfs_fuse_map_device_cached(data, device, mapped_device);
183 if (ret == 0) {
184 return 0;
187 vfs_glusterfs_fuse_load_devices(data);
189 ret = vfs_glusterfs_fuse_map_device_cached(data, device, mapped_device);
191 return ret;
194 static struct file_id vfs_glusterfs_fuse_file_id_create(
195 struct vfs_handle_struct *handle,
196 const SMB_STRUCT_STAT *sbuf)
198 struct vfs_glusterfs_fuse_handle_data *data;
199 struct file_id id;
200 uint64_t mapped_device;
201 int ret;
203 ZERO_STRUCT(id);
205 id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, sbuf);
207 SMB_VFS_HANDLE_GET_DATA(handle, data,
208 struct vfs_glusterfs_fuse_handle_data,
209 return id);
211 ret = vfs_glusterfs_fuse_map_device(data, sbuf->st_ex_dev,
212 &mapped_device);
213 if (ret == 0) {
214 id.devid = mapped_device;
215 } else {
216 DBG_WARNING("Failed to map device [%jx], falling back to "
217 "standard file_id [%jx]",
218 (uintmax_t)sbuf->st_ex_dev,
219 (uintmax_t)id.devid);
222 DBG_DEBUG("Returning dev [%jx] inode [%jx]\n",
223 (uintmax_t)id.devid, (uintmax_t)id.inode);
225 return id;
228 static int vfs_glusterfs_fuse_connect(struct vfs_handle_struct *handle,
229 const char *service, const char *user)
231 struct vfs_glusterfs_fuse_handle_data *data;
232 int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
234 if (ret < 0) {
235 return ret;
238 data = talloc_zero(handle->conn, struct vfs_glusterfs_fuse_handle_data);
239 if (data == NULL) {
240 DBG_ERR("talloc_zero() failed.\n");
241 SMB_VFS_NEXT_DISCONNECT(handle);
242 return -1;
246 * Fill the cache in the tree connect, so that the first file/dir access
247 * has chances of being fast...
249 vfs_glusterfs_fuse_load_devices(data);
251 SMB_VFS_HANDLE_SET_DATA(handle, data, NULL,
252 struct vfs_glusterfs_fuse_handle_data,
253 return -1);
255 DBG_DEBUG("vfs_glusterfs_fuse_connect(): connected to service[%s]\n",
256 service);
258 return 0;
261 struct vfs_fn_pointers glusterfs_fuse_fns = {
263 .connect_fn = vfs_glusterfs_fuse_connect,
264 .get_real_filename_at_fn = vfs_gluster_fuse_get_real_filename_at,
265 .file_id_create_fn = vfs_glusterfs_fuse_file_id_create,
268 static_decl_vfs;
269 NTSTATUS vfs_glusterfs_fuse_init(TALLOC_CTX *ctx)
271 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
272 "glusterfs_fuse", &glusterfs_fuse_fns);