smbd: Remove unused [push_pull]_file_id_24
[samba.git] / source3 / modules / vfs_fileid.c
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
24 static int vfs_fileid_debug_level = DBGC_VFS;
25
26 #undef DBGC_CLASS
27 #define DBGC_CLASS vfs_fileid_debug_level
28
29 struct fileid_mount_entry {
30         SMB_DEV_T device;
31         const char *mnt_fsname;
32         fsid_t fsid;
33         uint64_t devid;
34 };
35
36 struct fileid_handle_data {
37         uint64_t (*device_mapping_fn)(struct fileid_handle_data *data,
38                                       SMB_DEV_T dev);
39         unsigned num_mount_entries;
40         struct fileid_mount_entry *mount_entries;
41 };
42
43 /* load all the mount entries from the mtab */
44 static void fileid_load_mount_entries(struct fileid_handle_data *data)
45 {
46         FILE *f;
47         struct mntent *m;
48
49         data->num_mount_entries = 0;
50         TALLOC_FREE(data->mount_entries);
51
52         f = setmntent("/etc/mtab", "r");
53         if (!f) return;
54
55         while ((m = getmntent(f))) {
56                 struct stat st;
57                 struct statfs sfs;
58                 struct fileid_mount_entry *cur;
59
60                 if (stat(m->mnt_dir, &st) != 0) continue;
61                 if (statfs(m->mnt_dir, &sfs) != 0) continue;
62
63                 if (strncmp(m->mnt_fsname, "/dev/", 5) == 0) {
64                         m->mnt_fsname += 5;
65                 }
66
67                 data->mount_entries = TALLOC_REALLOC_ARRAY(data,
68                                                            data->mount_entries,
69                                                            struct fileid_mount_entry,
70                                                            data->num_mount_entries+1);
71                 if (data->mount_entries == NULL) {
72                         goto nomem;
73                 }
74
75                 cur = &data->mount_entries[data->num_mount_entries];
76                 cur->device     = st.st_dev;
77                 cur->mnt_fsname = talloc_strdup(data->mount_entries,
78                                                 m->mnt_fsname);
79                 if (!cur->mnt_fsname) goto nomem;
80                 cur->fsid       = sfs.f_fsid;
81                 cur->devid      = (uint64_t)-1;
82
83                 data->num_mount_entries++;
84         }
85         endmntent(f);
86         return;
87         
88 nomem:
89         if (f) endmntent(f);
90
91         data->num_mount_entries = 0;
92         TALLOC_FREE(data->mount_entries);
93
94         return;
95 }
96
97 /* find a mount entry given a dev_t */
98 static struct fileid_mount_entry *fileid_find_mount_entry(struct fileid_handle_data *data,
99                                                           SMB_DEV_T dev)
100 {
101         int i;
102
103         if (data->num_mount_entries == 0) {
104                 fileid_load_mount_entries(data);
105         }
106         for (i=0;i<data->num_mount_entries;i++) {
107                 if (data->mount_entries[i].device == dev) {
108                         return &data->mount_entries[i];
109                 }
110         }
111         /* 2nd pass after reloading */
112         fileid_load_mount_entries(data);
113         for (i=0;i<data->num_mount_entries;i++) {
114                 if (data->mount_entries[i].device == dev) {
115                         return &data->mount_entries[i];
116                 }
117         }       
118         return NULL;
119 }
120
121
122 /* a 64 bit hash, based on the one in tdb */
123 static uint64_t fileid_uint64_hash(const uint8_t *s, size_t len)
124 {
125         uint64_t value; /* Used to compute the hash value.  */
126         uint32_t i;     /* Used to cycle through random values. */
127
128         /* Set the initial value from the key size. */
129         for (value = 0x238F13AFLL * len, i=0; i < len; i++)
130                 value = (value + (s[i] << (i*5 % 24)));
131
132         return (1103515243LL * value + 12345LL);
133 }
134
135 /* a device mapping using a fsname */
136 static uint64_t fileid_device_mapping_fsname(struct fileid_handle_data *data,
137                                              SMB_DEV_T dev)
138 {
139         struct fileid_mount_entry *m;
140
141         m = fileid_find_mount_entry(data, dev);
142         if (!m) return dev;
143
144         if (m->devid == (uint64_t)-1) {
145                 m->devid = fileid_uint64_hash((uint8_t *)m->mnt_fsname,
146                                               strlen(m->mnt_fsname));
147         }
148
149         return m->devid;
150 }
151
152 /* device mapping functions using a fsid */
153 static uint64_t fileid_device_mapping_fsid(struct fileid_handle_data *data,
154                                            SMB_DEV_T dev)
155 {
156         struct fileid_mount_entry *m;
157
158         m = fileid_find_mount_entry(data, dev);
159         if (!m) return dev;
160
161         if (m->devid == (uint64_t)-1) {
162                 if (sizeof(fsid_t) > sizeof(uint64_t)) {
163                         m->devid = fileid_uint64_hash((uint8_t *)&m->fsid,
164                                                       sizeof(m->fsid));
165                 } else {
166                         union {
167                                 uint64_t ret;
168                                 fsid_t fsid;
169                         } u;
170                         ZERO_STRUCT(u);
171                         u.fsid = m->fsid;
172                         m->devid = u.ret;
173                 }
174         }
175
176         return m->devid;
177 }
178
179 static int fileid_connect(struct vfs_handle_struct *handle,
180                           const char *service, const char *user)
181 {
182         struct fileid_handle_data *data;
183         const char *algorithm;
184         int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
185
186         if (ret < 0) {
187                 return ret;
188         }
189
190         data = talloc_zero(handle->conn, struct fileid_handle_data);
191         if (!data) {
192                 SMB_VFS_NEXT_DISCONNECT(handle);
193                 DEBUG(0, ("talloc_zero() failed\n"));
194                 return -1;
195         }
196
197         /*
198          * "fileid:mapping" is only here as fallback for old setups
199          * "fileid:algorithm" is the option new setups should use
200          */
201         algorithm = lp_parm_const_string(SNUM(handle->conn),
202                                          "fileid", "mapping",
203                                          "fsname");
204         algorithm = lp_parm_const_string(SNUM(handle->conn),
205                                          "fileid", "algorithm",
206                                          algorithm);
207         if (strcmp("fsname", algorithm) == 0) {
208                 data->device_mapping_fn = fileid_device_mapping_fsname;
209         } else if (strcmp("fsid", algorithm) == 0) {
210                 data->device_mapping_fn = fileid_device_mapping_fsid;
211         } else {
212                 SMB_VFS_NEXT_DISCONNECT(handle);
213                 DEBUG(0,("fileid_connect(): unknown algorithm[%s]\n", algorithm));
214                 return -1;
215         }
216
217         SMB_VFS_HANDLE_SET_DATA(handle, data, NULL,
218                                 struct fileid_handle_data,
219                                 return -1);
220
221         DEBUG(10, ("fileid_connect(): connect to service[%s] with algorithm[%s]\n",
222                 service, algorithm));
223
224         return 0;
225 }
226
227 static void fileid_disconnect(struct vfs_handle_struct *handle)
228 {
229         DEBUG(10,("fileid_disconnect() connect to service[%s].\n",
230                 lp_servicename(SNUM(handle->conn))));
231
232         SMB_VFS_NEXT_DISCONNECT(handle);
233 }
234
235 static struct file_id fileid_file_id_create(struct vfs_handle_struct *handle,
236                                             const SMB_STRUCT_STAT *sbuf)
237 {
238         struct fileid_handle_data *data;
239         struct file_id id;
240
241         ZERO_STRUCT(id);
242
243         SMB_VFS_HANDLE_GET_DATA(handle, data,
244                                 struct fileid_handle_data,
245                                 return id);
246
247         id.devid        = data->device_mapping_fn(data, sbuf->st_ex_dev);
248         id.inode        = sbuf->st_ex_ino;
249
250         return id;
251 }
252
253 static struct vfs_fn_pointers vfs_fileid_fns = {
254         .connect_fn = fileid_connect,
255         .disconnect = fileid_disconnect,
256         .file_id_create = fileid_file_id_create
257 };
258
259 NTSTATUS vfs_fileid_init(void);
260 NTSTATUS vfs_fileid_init(void)
261 {
262         NTSTATUS ret;
263
264         ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "fileid",
265                                &vfs_fileid_fns);
266         if (!NT_STATUS_IS_OK(ret)) {
267                 return ret;
268         }
269
270         vfs_fileid_debug_level = debug_add_class("fileid");
271         if (vfs_fileid_debug_level == -1) {
272                 vfs_fileid_debug_level = DBGC_VFS;
273                 DEBUG(0, ("vfs_fileid: Couldn't register custom debugging class!\n"));
274         } else {
275                 DEBUG(10, ("vfs_fileid: Debug class number of 'fileid': %d\n", vfs_fileid_debug_level));
276         }
277
278         return ret;
279 }