vfs_io_uring: move error handling out of vfs_io_uring_pread_recv()
[Samba.git] / source3 / modules / vfs_glusterfs_fuse.c
blobc621f9abf8e460878d4d0b935605b5c9951218e3
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 int vfs_gluster_fuse_get_real_filename(struct vfs_handle_struct *handle,
27 const char *path,
28 const char *name,
29 TALLOC_CTX *mem_ctx,
30 char **_found_name)
32 int ret;
33 char key_buf[GLUSTER_NAME_MAX + 64];
34 char val_buf[GLUSTER_NAME_MAX + 1];
35 char *found_name = NULL;
37 if (strlen(name) >= GLUSTER_NAME_MAX) {
38 errno = ENAMETOOLONG;
39 return -1;
42 snprintf(key_buf, GLUSTER_NAME_MAX + 64,
43 "glusterfs.get_real_filename:%s", name);
45 ret = getxattr(path, key_buf, val_buf, GLUSTER_NAME_MAX + 1);
46 if (ret == -1) {
47 if (errno == ENOATTR) {
48 errno = ENOENT;
50 return -1;
53 found_name = talloc_strdup(mem_ctx, val_buf);
54 if (found_name == NULL) {
55 errno = ENOMEM;
56 return -1;
58 *_found_name = found_name;
59 return 0;
62 struct device_mapping_entry {
63 SMB_DEV_T device; /* the local device, for reference */
64 uint64_t mapped_device; /* the mapped device */
67 struct vfs_glusterfs_fuse_handle_data {
68 unsigned num_mapped_devices;
69 struct device_mapping_entry *mapped_devices;
72 /* a 64 bit hash, based on the one in tdb, copied from vfs_fileied */
73 static uint64_t vfs_glusterfs_fuse_uint64_hash(const uint8_t *s, size_t len)
75 uint64_t value; /* Used to compute the hash value. */
76 uint32_t i; /* Used to cycle through random values. */
78 /* Set the initial value from the key size. */
79 for (value = 0x238F13AFLL * len, i=0; i < len; i++)
80 value = (value + (((uint64_t)s[i]) << (i*5 % 24)));
82 return (1103515243LL * value + 12345LL);
85 static void vfs_glusterfs_fuse_load_devices(
86 struct vfs_glusterfs_fuse_handle_data *data)
88 FILE *f;
89 struct mntent *m;
91 data->num_mapped_devices = 0;
92 TALLOC_FREE(data->mapped_devices);
94 f = setmntent("/etc/mtab", "r");
95 if (!f) {
96 return;
99 while ((m = getmntent(f))) {
100 struct stat st;
101 char *p;
102 uint64_t mapped_device;
104 if (stat(m->mnt_dir, &st) != 0) {
105 /* TODO: log? */
106 continue;
109 /* strip the host part off of the fsname */
110 p = strrchr(m->mnt_fsname, ':');
111 if (p == NULL) {
112 p = m->mnt_fsname;
113 } else {
114 /* TODO: consider the case of '' ? */
115 p++;
118 mapped_device = vfs_glusterfs_fuse_uint64_hash(
119 (const uint8_t *)p,
120 strlen(p));
122 data->mapped_devices = talloc_realloc(data,
123 data->mapped_devices,
124 struct device_mapping_entry,
125 data->num_mapped_devices + 1);
126 if (data->mapped_devices == NULL) {
127 goto nomem;
130 data->mapped_devices[data->num_mapped_devices].device =
131 st.st_dev;
132 data->mapped_devices[data->num_mapped_devices].mapped_device =
133 mapped_device;
135 data->num_mapped_devices++;
138 endmntent(f);
139 return;
141 nomem:
142 data->num_mapped_devices = 0;
143 TALLOC_FREE(data->mapped_devices);
145 endmntent(f);
146 return;
149 static int vfs_glusterfs_fuse_map_device_cached(
150 struct vfs_glusterfs_fuse_handle_data *data,
151 SMB_DEV_T device,
152 uint64_t *mapped_device)
154 unsigned i;
156 for (i = 0; i < data->num_mapped_devices; i++) {
157 if (data->mapped_devices[i].device == device) {
158 *mapped_device = data->mapped_devices[i].mapped_device;
159 return 0;
163 return -1;
166 static int vfs_glusterfs_fuse_map_device(
167 struct vfs_glusterfs_fuse_handle_data *data,
168 SMB_DEV_T device,
169 uint64_t *mapped_device)
171 int ret;
173 ret = vfs_glusterfs_fuse_map_device_cached(data, device, mapped_device);
174 if (ret == 0) {
175 return 0;
178 vfs_glusterfs_fuse_load_devices(data);
180 ret = vfs_glusterfs_fuse_map_device_cached(data, device, mapped_device);
182 return ret;
185 static struct file_id vfs_glusterfs_fuse_file_id_create(
186 struct vfs_handle_struct *handle,
187 const SMB_STRUCT_STAT *sbuf)
189 struct vfs_glusterfs_fuse_handle_data *data;
190 struct file_id id;
191 uint64_t mapped_device;
192 int ret;
194 ZERO_STRUCT(id);
196 id = SMB_VFS_NEXT_FILE_ID_CREATE(handle, sbuf);
198 SMB_VFS_HANDLE_GET_DATA(handle, data,
199 struct vfs_glusterfs_fuse_handle_data,
200 return id);
202 ret = vfs_glusterfs_fuse_map_device(data, sbuf->st_ex_dev,
203 &mapped_device);
204 if (ret == 0) {
205 id.devid = mapped_device;
206 } else {
207 DBG_WARNING("Failed to map device [%jx], falling back to "
208 "standard file_id [%jx]",
209 (uintmax_t)sbuf->st_ex_dev,
210 (uintmax_t)id.devid);
213 DBG_DEBUG("Returning dev [%jx] inode [%jx]\n",
214 (uintmax_t)id.devid, (uintmax_t)id.inode);
216 return id;
219 static int vfs_glusterfs_fuse_connect(struct vfs_handle_struct *handle,
220 const char *service, const char *user)
222 struct vfs_glusterfs_fuse_handle_data *data;
223 int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
225 if (ret < 0) {
226 return ret;
229 data = talloc_zero(handle->conn, struct vfs_glusterfs_fuse_handle_data);
230 if (data == NULL) {
231 DBG_ERR("talloc_zero() failed.\n");
232 SMB_VFS_NEXT_DISCONNECT(handle);
233 return -1;
237 * Fill the cache in the tree connect, so that the first file/dir access
238 * has chances of being fast...
240 vfs_glusterfs_fuse_load_devices(data);
242 SMB_VFS_HANDLE_SET_DATA(handle, data, NULL,
243 struct vfs_glusterfs_fuse_handle_data,
244 return -1);
246 DBG_DEBUG("vfs_glusterfs_fuse_connect(): connected to service[%s]\n",
247 service);
249 return 0;
252 struct vfs_fn_pointers glusterfs_fuse_fns = {
254 .connect_fn = vfs_glusterfs_fuse_connect,
255 .get_real_filename_fn = vfs_gluster_fuse_get_real_filename,
256 .file_id_create_fn = vfs_glusterfs_fuse_file_id_create,
259 static_decl_vfs;
260 NTSTATUS vfs_glusterfs_fuse_init(TALLOC_CTX *ctx)
262 return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
263 "glusterfs_fuse", &glusterfs_fuse_fns);