Line data Source code
1 : /*
2 : * VFS module to alter the algorithm to calculate
3 : * the struct file_id used as key for the share mode
4 : * and byte range locking db's.
5 : *
6 : * Copyright (C) 2007, Stefan Metzmacher
7 : *
8 : * This program is free software; you can redistribute it and/or modify
9 : * it under the terms of the GNU General Public License as published by
10 : * the Free Software Foundation; either version 3 of the License, or
11 : * (at your option) any later version.
12 : *
13 : * This program is distributed in the hope that it will be useful,
14 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : * GNU General Public License for more details.
17 : *
18 : * You should have received a copy of the GNU General Public License
19 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "smbd/smbd.h"
24 : #include "system/filesys.h"
25 :
26 : static int vfs_fileid_debug_level = DBGC_VFS;
27 :
28 : #undef DBGC_CLASS
29 : #define DBGC_CLASS vfs_fileid_debug_level
30 :
31 : struct fileid_mount_entry {
32 : SMB_DEV_T device;
33 : const char *mnt_fsname;
34 : fsid_t fsid;
35 : uint64_t devid;
36 : };
37 :
38 : struct fileid_nolock_inode {
39 : dev_t dev;
40 : ino_t ino;
41 : };
42 :
43 : struct fileid_handle_data {
44 : struct vfs_handle_struct *handle;
45 : struct file_id (*mapping_fn)(struct fileid_handle_data *data,
46 : const SMB_STRUCT_STAT *sbuf);
47 : char **fstype_deny_list;
48 : char **fstype_allow_list;
49 : char **mntdir_deny_list;
50 : char **mntdir_allow_list;
51 : unsigned num_mount_entries;
52 : struct fileid_mount_entry *mount_entries;
53 : struct {
54 : bool force_all_inodes;
55 : bool force_all_dirs;
56 : uint64_t extid;
57 : size_t num_inodes;
58 : struct fileid_nolock_inode *inodes;
59 : } nolock;
60 : };
61 :
62 : /* check if a mount entry is allowed based on fstype and mount directory */
63 0 : static bool fileid_mount_entry_allowed(struct fileid_handle_data *data,
64 : struct mntent *m)
65 : {
66 : int i;
67 0 : char **fstype_deny = data->fstype_deny_list;
68 0 : char **fstype_allow = data->fstype_allow_list;
69 0 : char **mntdir_deny = data->mntdir_deny_list;
70 0 : char **mntdir_allow = data->mntdir_allow_list;
71 :
72 0 : if (fstype_deny != NULL) {
73 0 : for (i = 0; fstype_deny[i] != NULL; i++) {
74 0 : if (strcmp(m->mnt_type, fstype_deny[i]) == 0) {
75 0 : return false;
76 : }
77 : }
78 : }
79 0 : if (fstype_allow != NULL) {
80 0 : for (i = 0; fstype_allow[i] != NULL; i++) {
81 0 : if (strcmp(m->mnt_type, fstype_allow[i]) == 0) {
82 0 : break;
83 : }
84 : }
85 0 : if (fstype_allow[i] == NULL) {
86 0 : return false;
87 : }
88 : }
89 0 : if (mntdir_deny != NULL) {
90 0 : for (i=0; mntdir_deny[i] != NULL; i++) {
91 0 : if (strcmp(m->mnt_dir, mntdir_deny[i]) == 0) {
92 0 : return false;
93 : }
94 : }
95 : }
96 0 : if (mntdir_allow != NULL) {
97 0 : for (i=0; mntdir_allow[i] != NULL; i++) {
98 0 : if (strcmp(m->mnt_dir, mntdir_allow[i]) == 0) {
99 0 : break;
100 : }
101 : }
102 0 : if (mntdir_allow[i] == NULL) {
103 0 : return false;
104 : }
105 : }
106 0 : return true;
107 : }
108 :
109 :
110 : /* load all the mount entries from the mtab */
111 0 : static void fileid_load_mount_entries(struct fileid_handle_data *data)
112 : {
113 : FILE *f;
114 : struct mntent *m;
115 :
116 0 : data->num_mount_entries = 0;
117 0 : TALLOC_FREE(data->mount_entries);
118 :
119 0 : f = setmntent("/etc/mtab", "r");
120 0 : if (!f) return;
121 :
122 0 : while ((m = getmntent(f))) {
123 : struct stat st;
124 : struct statfs sfs;
125 : struct fileid_mount_entry *cur;
126 : bool allowed;
127 :
128 0 : allowed = fileid_mount_entry_allowed(data, m);
129 0 : if (!allowed) {
130 0 : DBG_DEBUG("skipping mount entry %s\n", m->mnt_dir);
131 0 : continue;
132 : }
133 0 : if (stat(m->mnt_dir, &st) != 0) continue;
134 0 : if (statfs(m->mnt_dir, &sfs) != 0) continue;
135 :
136 0 : if (strncmp(m->mnt_fsname, "/dev/", 5) == 0) {
137 0 : m->mnt_fsname += 5;
138 : }
139 :
140 0 : data->mount_entries = talloc_realloc(data,
141 : data->mount_entries,
142 : struct fileid_mount_entry,
143 : data->num_mount_entries+1);
144 0 : if (data->mount_entries == NULL) {
145 0 : goto nomem;
146 : }
147 :
148 0 : cur = &data->mount_entries[data->num_mount_entries];
149 0 : cur->device = st.st_dev;
150 0 : cur->mnt_fsname = talloc_strdup(data->mount_entries,
151 0 : m->mnt_fsname);
152 0 : if (!cur->mnt_fsname) goto nomem;
153 0 : cur->fsid = sfs.f_fsid;
154 0 : cur->devid = (uint64_t)-1;
155 :
156 0 : data->num_mount_entries++;
157 : }
158 0 : endmntent(f);
159 0 : return;
160 :
161 0 : nomem:
162 0 : if (f) endmntent(f);
163 :
164 0 : data->num_mount_entries = 0;
165 0 : TALLOC_FREE(data->mount_entries);
166 :
167 0 : return;
168 : }
169 :
170 : /* find a mount entry given a dev_t */
171 0 : static struct fileid_mount_entry *fileid_find_mount_entry(struct fileid_handle_data *data,
172 : SMB_DEV_T dev)
173 : {
174 : unsigned i;
175 :
176 0 : if (data->num_mount_entries == 0) {
177 0 : fileid_load_mount_entries(data);
178 : }
179 0 : for (i=0;i<data->num_mount_entries;i++) {
180 0 : if (data->mount_entries[i].device == dev) {
181 0 : return &data->mount_entries[i];
182 : }
183 : }
184 : /* 2nd pass after reloading */
185 0 : fileid_load_mount_entries(data);
186 0 : for (i=0;i<data->num_mount_entries;i++) {
187 0 : if (data->mount_entries[i].device == dev) {
188 0 : return &data->mount_entries[i];
189 : }
190 : }
191 0 : return NULL;
192 : }
193 :
194 :
195 : /* a 64 bit hash, based on the one in tdb */
196 0 : static uint64_t fileid_uint64_hash(const uint8_t *s, size_t len)
197 : {
198 : uint64_t value; /* Used to compute the hash value. */
199 : uint32_t i; /* Used to cycle through random values. */
200 :
201 : /* Set the initial value from the key size. */
202 0 : for (value = 0x238F13AFLL * len, i=0; i < len; i++)
203 0 : value = (value + (((uint64_t)s[i]) << (i*5 % 24)));
204 :
205 0 : return (1103515243LL * value + 12345LL);
206 : }
207 :
208 : /* a device mapping using a fsname */
209 0 : static uint64_t fileid_device_mapping_fsname(struct fileid_handle_data *data,
210 : const SMB_STRUCT_STAT *sbuf)
211 : {
212 : struct fileid_mount_entry *m;
213 :
214 0 : m = fileid_find_mount_entry(data, sbuf->st_ex_dev);
215 0 : if (!m) return sbuf->st_ex_dev;
216 :
217 0 : if (m->devid == (uint64_t)-1) {
218 0 : m->devid = fileid_uint64_hash((const uint8_t *)m->mnt_fsname,
219 : strlen(m->mnt_fsname));
220 : }
221 :
222 0 : return m->devid;
223 : }
224 :
225 0 : static struct file_id fileid_mapping_fsname(struct fileid_handle_data *data,
226 : const SMB_STRUCT_STAT *sbuf)
227 : {
228 0 : struct file_id id = { .inode = sbuf->st_ex_ino, };
229 :
230 0 : id.devid = fileid_device_mapping_fsname(data, sbuf);
231 :
232 0 : return id;
233 : }
234 :
235 : /* a device mapping using a hostname */
236 0 : static uint64_t fileid_device_mapping_hostname(struct fileid_handle_data *data,
237 : const SMB_STRUCT_STAT *sbuf)
238 : {
239 : char hostname[HOST_NAME_MAX+1];
240 0 : char *devname = NULL;
241 : uint64_t id;
242 : size_t devname_len;
243 : int rc;
244 :
245 0 : rc = gethostname(hostname, HOST_NAME_MAX+1);
246 0 : if (rc != 0) {
247 0 : DBG_ERR("gethostname failed\n");
248 0 : return UINT64_MAX;
249 : }
250 :
251 0 : devname = talloc_asprintf(talloc_tos(), "%s%ju",
252 0 : hostname, (uintmax_t)sbuf->st_ex_dev);
253 0 : if (devname == NULL) {
254 0 : DBG_ERR("talloc_asprintf failed\n");
255 0 : return UINT64_MAX;
256 : }
257 0 : devname_len = talloc_array_length(devname) - 1;
258 :
259 0 : id = fileid_uint64_hash((uint8_t *)devname, devname_len);
260 :
261 0 : TALLOC_FREE(devname);
262 :
263 0 : return id;
264 : }
265 :
266 0 : static struct file_id fileid_mapping_hostname(struct fileid_handle_data *data,
267 : const SMB_STRUCT_STAT *sbuf)
268 : {
269 0 : struct file_id id = { .inode = sbuf->st_ex_ino, };
270 :
271 0 : id.devid = fileid_device_mapping_hostname(data, sbuf);
272 :
273 0 : return id;
274 : }
275 :
276 0 : static bool fileid_is_nolock_inode(struct fileid_handle_data *data,
277 : const SMB_STRUCT_STAT *sbuf)
278 : {
279 : size_t i;
280 :
281 0 : if (data->nolock.force_all_inodes) {
282 0 : return true;
283 : }
284 :
285 0 : if (S_ISDIR(sbuf->st_ex_mode) && data->nolock.force_all_dirs) {
286 0 : return true;
287 : }
288 :
289 : /*
290 : * We could make this a binary search over an sorted array,
291 : * but for now we keep things simple.
292 : */
293 :
294 0 : for (i=0; i < data->nolock.num_inodes; i++) {
295 0 : if (data->nolock.inodes[i].ino != sbuf->st_ex_ino) {
296 0 : continue;
297 : }
298 :
299 0 : if (data->nolock.inodes[i].dev == 0) {
300 : /*
301 : * legacy "fileid:nolockinode"
302 : * handling ignoring dev
303 : */
304 0 : return true;
305 : }
306 :
307 0 : if (data->nolock.inodes[i].dev != sbuf->st_ex_dev) {
308 0 : continue;
309 : }
310 :
311 0 : return true;
312 : }
313 :
314 0 : return false;
315 : }
316 :
317 0 : static int fileid_add_nolock_inode(struct fileid_handle_data *data,
318 : const SMB_STRUCT_STAT *sbuf)
319 : {
320 0 : bool exists = fileid_is_nolock_inode(data, sbuf);
321 0 : struct fileid_nolock_inode *inodes = NULL;
322 :
323 0 : if (exists) {
324 0 : return 0;
325 : }
326 :
327 0 : inodes = talloc_realloc(data, data->nolock.inodes,
328 : struct fileid_nolock_inode,
329 : data->nolock.num_inodes + 1);
330 0 : if (inodes == NULL) {
331 0 : return -1;
332 : }
333 :
334 0 : inodes[data->nolock.num_inodes] = (struct fileid_nolock_inode) {
335 0 : .dev = sbuf->st_ex_dev,
336 0 : .ino = sbuf->st_ex_ino,
337 : };
338 0 : data->nolock.inodes = inodes;
339 0 : data->nolock.num_inodes += 1;
340 :
341 0 : return 0;
342 : }
343 :
344 0 : static uint64_t fileid_mapping_nolock_extid(uint64_t max_slots)
345 : {
346 0 : char buf[8+4+HOST_NAME_MAX+1] = { 0, };
347 0 : uint64_t slot = 0;
348 : uint64_t id;
349 : int rc;
350 :
351 0 : if (max_slots > 1) {
352 0 : slot = getpid() % max_slots;
353 : }
354 :
355 0 : PUSH_LE_U64(buf, 0, slot);
356 0 : PUSH_LE_U32(buf, 8, get_my_vnn());
357 :
358 0 : rc = gethostname(&buf[12], HOST_NAME_MAX+1);
359 0 : if (rc != 0) {
360 0 : DBG_ERR("gethostname failed\n");
361 0 : return UINT64_MAX;
362 : }
363 :
364 0 : id = fileid_uint64_hash((uint8_t *)buf, ARRAY_SIZE(buf));
365 :
366 0 : return id;
367 : }
368 :
369 : /* device mapping functions using a fsid */
370 0 : static uint64_t fileid_device_mapping_fsid(struct fileid_handle_data *data,
371 : const SMB_STRUCT_STAT *sbuf)
372 : {
373 : struct fileid_mount_entry *m;
374 :
375 0 : m = fileid_find_mount_entry(data, sbuf->st_ex_dev);
376 0 : if (!m) return sbuf->st_ex_dev;
377 :
378 0 : if (m->devid == (uint64_t)-1) {
379 : if (sizeof(fsid_t) > sizeof(uint64_t)) {
380 : m->devid = fileid_uint64_hash((uint8_t *)&m->fsid,
381 : sizeof(m->fsid));
382 : } else {
383 : union {
384 : uint64_t ret;
385 : fsid_t fsid;
386 : } u;
387 0 : ZERO_STRUCT(u);
388 0 : u.fsid = m->fsid;
389 0 : m->devid = u.ret;
390 : }
391 : }
392 :
393 0 : return m->devid;
394 : }
395 :
396 0 : static struct file_id fileid_mapping_fsid(struct fileid_handle_data *data,
397 : const SMB_STRUCT_STAT *sbuf)
398 : {
399 0 : struct file_id id = { .inode = sbuf->st_ex_ino, };
400 :
401 0 : id.devid = fileid_device_mapping_fsid(data, sbuf);
402 :
403 0 : return id;
404 : }
405 :
406 0 : static struct file_id fileid_mapping_next_module(struct fileid_handle_data *data,
407 : const SMB_STRUCT_STAT *sbuf)
408 : {
409 0 : return SMB_VFS_NEXT_FILE_ID_CREATE(data->handle, sbuf);
410 : }
411 :
412 0 : static int get_connectpath_ino(struct vfs_handle_struct *handle,
413 : const char *path,
414 : SMB_STRUCT_STAT *psbuf)
415 : {
416 0 : TALLOC_CTX *frame = talloc_stackframe();
417 0 : struct smb_filename *fname = NULL;
418 0 : const char *fullpath = NULL;
419 : int ret;
420 :
421 0 : if (path[0] == '/') {
422 0 : fullpath = path;
423 : } else {
424 0 : fullpath = talloc_asprintf(frame,
425 : "%s/%s",
426 0 : handle->conn->connectpath,
427 : path);
428 0 : if (fullpath == NULL) {
429 0 : DBG_ERR("talloc_asprintf() failed\n");
430 0 : TALLOC_FREE(frame);
431 0 : return -1;
432 : }
433 : }
434 :
435 0 : fname = synthetic_smb_fname(frame,
436 : fullpath,
437 : NULL,
438 : NULL,
439 : 0,
440 : 0);
441 0 : if (fname == NULL) {
442 0 : DBG_ERR("synthetic_smb_fname(%s) failed - %s\n",
443 : fullpath, strerror(errno));
444 0 : TALLOC_FREE(frame);
445 0 : return -1;
446 : }
447 :
448 0 : ret = SMB_VFS_NEXT_STAT(handle, fname);
449 0 : if (ret != 0) {
450 0 : DBG_ERR("stat failed for %s with %s\n",
451 : fullpath, strerror(errno));
452 0 : TALLOC_FREE(frame);
453 0 : return -1;
454 : }
455 0 : *psbuf = fname->st;
456 :
457 0 : TALLOC_FREE(frame);
458 :
459 0 : return 0;
460 : }
461 :
462 0 : static int fileid_connect(struct vfs_handle_struct *handle,
463 : const char *service, const char *user)
464 : {
465 : struct fileid_handle_data *data;
466 : const char *algorithm;
467 0 : const char **fstype_deny_list = NULL;
468 0 : const char **fstype_allow_list = NULL;
469 0 : const char **mntdir_deny_list = NULL;
470 0 : const char **mntdir_allow_list = NULL;
471 : ino_t nolockinode;
472 0 : uint64_t max_slots = 0;
473 0 : bool rootdir_nolock = false;
474 0 : const char **nolock_paths = NULL;
475 : size_t i;
476 : int saved_errno;
477 0 : int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
478 :
479 0 : if (ret < 0) {
480 0 : return ret;
481 : }
482 :
483 0 : data = talloc_zero(handle, struct fileid_handle_data);
484 0 : if (!data) {
485 0 : saved_errno = errno;
486 0 : SMB_VFS_NEXT_DISCONNECT(handle);
487 0 : DEBUG(0, ("talloc_zero() failed\n"));
488 0 : errno = saved_errno;
489 0 : return -1;
490 : }
491 0 : data->handle = handle;
492 :
493 : /*
494 : * "fileid:mapping" is only here as fallback for old setups
495 : * "fileid:algorithm" is the option new setups should use
496 : */
497 0 : algorithm = lp_parm_const_string(SNUM(handle->conn),
498 : "fileid", "mapping",
499 : "fsname");
500 0 : algorithm = lp_parm_const_string(SNUM(handle->conn),
501 : "fileid", "algorithm",
502 : algorithm);
503 0 : if (strcmp("fsname", algorithm) == 0) {
504 0 : data->mapping_fn = fileid_mapping_fsname;
505 0 : } else if (strcmp("fsname_nodirs", algorithm) == 0) {
506 0 : data->mapping_fn = fileid_mapping_fsname;
507 0 : data->nolock.force_all_dirs = true;
508 0 : } else if (strcmp("fsid", algorithm) == 0) {
509 0 : data->mapping_fn = fileid_mapping_fsid;
510 0 : } else if (strcmp("hostname", algorithm) == 0) {
511 0 : data->mapping_fn = fileid_mapping_hostname;
512 0 : data->nolock.force_all_inodes = true;
513 0 : } else if (strcmp("fsname_norootdir", algorithm) == 0) {
514 0 : data->mapping_fn = fileid_mapping_fsname;
515 0 : rootdir_nolock = true;
516 0 : } else if (strcmp("fsname_norootdir_ext", algorithm) == 0) {
517 0 : data->mapping_fn = fileid_mapping_fsname;
518 0 : rootdir_nolock = true;
519 0 : max_slots = UINT64_MAX;
520 0 : } else if (strcmp("next_module", algorithm) == 0) {
521 0 : data->mapping_fn = fileid_mapping_next_module;
522 : } else {
523 0 : SMB_VFS_NEXT_DISCONNECT(handle);
524 0 : DEBUG(0,("fileid_connect(): unknown algorithm[%s]\n", algorithm));
525 0 : return -1;
526 : }
527 :
528 0 : fstype_deny_list = lp_parm_string_list(SNUM(handle->conn), "fileid",
529 : "fstype deny", NULL);
530 0 : if (fstype_deny_list != NULL) {
531 0 : data->fstype_deny_list = str_list_copy(data, fstype_deny_list);
532 0 : if (data->fstype_deny_list == NULL) {
533 0 : saved_errno = errno;
534 0 : DBG_ERR("str_list_copy failed\n");
535 0 : SMB_VFS_NEXT_DISCONNECT(handle);
536 0 : errno = saved_errno;
537 0 : return -1;
538 : }
539 : }
540 :
541 0 : fstype_allow_list = lp_parm_string_list(SNUM(handle->conn), "fileid",
542 : "fstype allow", NULL);
543 0 : if (fstype_allow_list != NULL) {
544 0 : data->fstype_allow_list = str_list_copy(data, fstype_allow_list);
545 0 : if (data->fstype_allow_list == NULL) {
546 0 : saved_errno = errno;
547 0 : DBG_ERR("str_list_copy failed\n");
548 0 : SMB_VFS_NEXT_DISCONNECT(handle);
549 0 : errno = saved_errno;
550 0 : return -1;
551 : }
552 : }
553 :
554 0 : mntdir_deny_list = lp_parm_string_list(SNUM(handle->conn), "fileid",
555 : "mntdir deny", NULL);
556 0 : if (mntdir_deny_list != NULL) {
557 0 : data->mntdir_deny_list = str_list_copy(data, mntdir_deny_list);
558 0 : if (data->mntdir_deny_list == NULL) {
559 0 : saved_errno = errno;
560 0 : DBG_ERR("str_list_copy failed\n");
561 0 : SMB_VFS_NEXT_DISCONNECT(handle);
562 0 : errno = saved_errno;
563 0 : return -1;
564 : }
565 : }
566 :
567 0 : mntdir_allow_list = lp_parm_string_list(SNUM(handle->conn), "fileid",
568 : "mntdir allow", NULL);
569 0 : if (mntdir_allow_list != NULL) {
570 0 : data->mntdir_allow_list = str_list_copy(data, mntdir_allow_list);
571 0 : if (data->mntdir_allow_list == NULL) {
572 0 : saved_errno = errno;
573 0 : DBG_ERR("str_list_copy failed\n");
574 0 : SMB_VFS_NEXT_DISCONNECT(handle);
575 0 : errno = saved_errno;
576 0 : return -1;
577 : }
578 : }
579 :
580 0 : data->nolock.force_all_inodes = lp_parm_bool(SNUM(handle->conn),
581 : "fileid", "nolock_all_inodes",
582 0 : data->nolock.force_all_inodes);
583 0 : data->nolock.force_all_dirs = lp_parm_bool(SNUM(handle->conn),
584 : "fileid", "nolock_all_dirs",
585 0 : data->nolock.force_all_dirs);
586 :
587 0 : max_slots = lp_parm_ulonglong(SNUM(handle->conn),
588 : "fileid", "nolock_max_slots",
589 : max_slots);
590 0 : max_slots = MAX(max_slots, 1);
591 :
592 0 : data->nolock.extid = fileid_mapping_nolock_extid(max_slots);
593 :
594 0 : nolockinode = lp_parm_ulong(SNUM(handle->conn), "fileid", "nolockinode", 0);
595 0 : if (nolockinode != 0) {
596 0 : SMB_STRUCT_STAT tmpsbuf = { .st_ex_ino = nolockinode, };
597 :
598 0 : ret = fileid_add_nolock_inode(data, &tmpsbuf);
599 0 : if (ret != 0) {
600 0 : saved_errno = errno;
601 0 : SMB_VFS_NEXT_DISCONNECT(handle);
602 0 : errno = saved_errno;
603 0 : return -1;
604 : }
605 : }
606 :
607 0 : if (rootdir_nolock) {
608 : SMB_STRUCT_STAT rootdirsbuf;
609 :
610 0 : ret = get_connectpath_ino(handle, ".", &rootdirsbuf);
611 0 : if (ret != 0) {
612 0 : saved_errno = errno;
613 0 : SMB_VFS_NEXT_DISCONNECT(handle);
614 0 : errno = saved_errno;
615 0 : return -1;
616 : }
617 :
618 0 : ret = fileid_add_nolock_inode(data, &rootdirsbuf);
619 0 : if (ret != 0) {
620 0 : saved_errno = errno;
621 0 : SMB_VFS_NEXT_DISCONNECT(handle);
622 0 : errno = saved_errno;
623 0 : return -1;
624 : }
625 : }
626 :
627 0 : nolock_paths = lp_parm_string_list(SNUM(handle->conn), "fileid", "nolock_paths", NULL);
628 0 : for (i = 0; nolock_paths != NULL && nolock_paths[i] != NULL; i++) {
629 : SMB_STRUCT_STAT tmpsbuf;
630 :
631 0 : ret = get_connectpath_ino(handle, nolock_paths[i], &tmpsbuf);
632 0 : if (ret == -1 && errno == ENOENT) {
633 0 : DBG_ERR("ignoring non existing nolock_paths[%zu]='%s'\n",
634 : i, nolock_paths[i]);
635 0 : continue;
636 : }
637 0 : if (ret != 0) {
638 0 : saved_errno = errno;
639 0 : SMB_VFS_NEXT_DISCONNECT(handle);
640 0 : errno = saved_errno;
641 0 : return -1;
642 : }
643 :
644 0 : ret = fileid_add_nolock_inode(data, &tmpsbuf);
645 0 : if (ret != 0) {
646 0 : saved_errno = errno;
647 0 : SMB_VFS_NEXT_DISCONNECT(handle);
648 0 : errno = saved_errno;
649 0 : return -1;
650 : }
651 0 : DBG_DEBUG("Adding nolock_paths[%zu]='%s'\n",
652 : i, nolock_paths[i]);
653 : }
654 :
655 0 : SMB_VFS_HANDLE_SET_DATA(handle, data, NULL,
656 : struct fileid_handle_data,
657 : return -1);
658 :
659 0 : DBG_DEBUG("connect to service[%s] with algorithm[%s] nolock.inodes %zu\n",
660 : service, algorithm, data->nolock.num_inodes);
661 :
662 0 : return 0;
663 : }
664 :
665 0 : static void fileid_disconnect(struct vfs_handle_struct *handle)
666 : {
667 : const struct loadparm_substitution *lp_sub =
668 0 : loadparm_s3_global_substitution();
669 :
670 0 : DEBUG(10,("fileid_disconnect() connect to service[%s].\n",
671 : lp_servicename(talloc_tos(), lp_sub, SNUM(handle->conn))));
672 :
673 0 : SMB_VFS_NEXT_DISCONNECT(handle);
674 0 : }
675 :
676 0 : static struct file_id fileid_file_id_create(struct vfs_handle_struct *handle,
677 : const SMB_STRUCT_STAT *sbuf)
678 : {
679 : struct fileid_handle_data *data;
680 0 : struct file_id id = { .inode = 0, };
681 :
682 0 : SMB_VFS_HANDLE_GET_DATA(handle, data,
683 : struct fileid_handle_data,
684 : return id);
685 :
686 0 : id = data->mapping_fn(data, sbuf);
687 0 : if (id.extid == 0 && fileid_is_nolock_inode(data, sbuf)) {
688 0 : id.extid = data->nolock.extid;
689 : }
690 :
691 0 : DBG_DEBUG("Returning dev [%jx] inode [%jx] extid [%jx]\n",
692 : (uintmax_t)id.devid, (uintmax_t)id.inode, (uintmax_t)id.extid);
693 :
694 0 : return id;
695 : }
696 :
697 : static struct vfs_fn_pointers vfs_fileid_fns = {
698 : .connect_fn = fileid_connect,
699 : .disconnect_fn = fileid_disconnect,
700 : .file_id_create_fn = fileid_file_id_create
701 : };
702 :
703 : static_decl_vfs;
704 27 : NTSTATUS vfs_fileid_init(TALLOC_CTX *ctx)
705 : {
706 : NTSTATUS ret;
707 :
708 27 : ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "fileid",
709 : &vfs_fileid_fns);
710 27 : if (!NT_STATUS_IS_OK(ret)) {
711 0 : return ret;
712 : }
713 :
714 27 : vfs_fileid_debug_level = debug_add_class("fileid");
715 27 : if (vfs_fileid_debug_level == -1) {
716 0 : vfs_fileid_debug_level = DBGC_VFS;
717 0 : DEBUG(0, ("vfs_fileid: Couldn't register custom debugging class!\n"));
718 : } else {
719 27 : DEBUG(10, ("vfs_fileid: Debug class number of 'fileid': %d\n", vfs_fileid_debug_level));
720 : }
721 :
722 27 : return ret;
723 : }
|