root/source3/modules/vfs_fileid.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fileid_load_mount_entries
  2. fileid_find_mount_entry
  3. fileid_uint64_hash
  4. fileid_device_mapping_fsname
  5. fileid_device_mapping_fsid
  6. fileid_connect
  7. fileid_disconnect
  8. fileid_file_id_create
  9. vfs_fileid_init

   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)
     /* [<][>][^][v][top][bottom][index][help] */
  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,
     /* [<][>][^][v][top][bottom][index][help] */
  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)
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 180                           const char *service, const char *user)
 181 {
 182         struct fileid_handle_data *data;
 183         const char *algorithm;
 184 
 185         data = talloc_zero(handle->conn, struct fileid_handle_data);
 186         if (!data) {
 187                 DEBUG(0, ("talloc_zero() failed\n"));
 188                 return -1;
 189         }
 190 
 191         /*
 192          * "fileid:mapping" is only here as fallback for old setups
 193          * "fileid:algorithm" is the option new setups should use
 194          */
 195         algorithm = lp_parm_const_string(SNUM(handle->conn),
 196                                          "fileid", "mapping",
 197                                          "fsname");
 198         algorithm = lp_parm_const_string(SNUM(handle->conn),
 199                                          "fileid", "algorithm",
 200                                          algorithm);
 201         if (strcmp("fsname", algorithm) == 0) {
 202                 data->device_mapping_fn = fileid_device_mapping_fsname;
 203         } else if (strcmp("fsid", algorithm) == 0) {
 204                 data->device_mapping_fn = fileid_device_mapping_fsid;
 205         } else {
 206                 DEBUG(0,("fileid_connect(): unknown algorithm[%s]\n", algorithm));
 207                 return -1;
 208         }
 209 
 210         SMB_VFS_HANDLE_SET_DATA(handle, data, NULL,
 211                                 struct fileid_handle_data,
 212                                 return -1);
 213 
 214         DEBUG(10, ("fileid_connect(): connect to service[%s] with algorithm[%s]\n",
 215                 service, algorithm));
 216 
 217         return SMB_VFS_NEXT_CONNECT(handle, service, user);
 218 }
 219 
 220 static void fileid_disconnect(struct vfs_handle_struct *handle)
     /* [<][>][^][v][top][bottom][index][help] */
 221 {
 222         DEBUG(10,("fileid_disconnect() connect to service[%s].\n",
 223                 lp_servicename(SNUM(handle->conn))));
 224 
 225         SMB_VFS_NEXT_DISCONNECT(handle);
 226 }
 227 
 228 static struct file_id fileid_file_id_create(struct vfs_handle_struct *handle,
     /* [<][>][^][v][top][bottom][index][help] */
 229                                             const SMB_STRUCT_STAT *sbuf)
 230 {
 231         struct fileid_handle_data *data;
 232         struct file_id id;
 233 
 234         ZERO_STRUCT(id);
 235 
 236         SMB_VFS_HANDLE_GET_DATA(handle, data,
 237                                 struct fileid_handle_data,
 238                                 return id);
 239 
 240         id.devid        = data->device_mapping_fn(data, sbuf->st_dev);
 241         id.inode        = sbuf->st_ino;
 242 
 243         return id;
 244 }
 245 
 246 static vfs_op_tuple fileid_ops[] = {
 247 
 248         /* Disk operations */
 249         {
 250                 SMB_VFS_OP(fileid_connect),
 251                 SMB_VFS_OP_CONNECT,
 252                 SMB_VFS_LAYER_TRANSPARENT
 253         },
 254         {
 255                 SMB_VFS_OP(fileid_disconnect),
 256                 SMB_VFS_OP_DISCONNECT,
 257                 SMB_VFS_LAYER_TRANSPARENT
 258         },
 259 
 260         /* File operations */
 261         {
 262                 SMB_VFS_OP(fileid_file_id_create),
 263                 SMB_VFS_OP_FILE_ID_CREATE,
 264                 SMB_VFS_LAYER_OPAQUE
 265         },
 266 
 267         /* End marker */
 268         {
 269                 SMB_VFS_OP(NULL),
 270                 SMB_VFS_OP_NOOP,
 271                 SMB_VFS_LAYER_NOOP
 272         }
 273 };
 274 
 275 NTSTATUS vfs_fileid_init(void);
 276 NTSTATUS vfs_fileid_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 277 {
 278         NTSTATUS ret;
 279 
 280         ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "fileid", fileid_ops);
 281         if (!NT_STATUS_IS_OK(ret)) {
 282                 return ret;
 283         }
 284 
 285         vfs_fileid_debug_level = debug_add_class("fileid");
 286         if (vfs_fileid_debug_level == -1) {
 287                 vfs_fileid_debug_level = DBGC_VFS;
 288                 DEBUG(0, ("vfs_fileid: Couldn't register custom debugging class!\n"));
 289         } else {
 290                 DEBUG(10, ("vfs_fileid: Debug class number of 'fileid': %d\n", vfs_fileid_debug_level));
 291         }
 292 
 293         return ret;
 294 }

/* [<][>][^][v][top][bottom][index][help] */