root/source3/lib/dbwrap_file.c

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

DEFINITIONS

This source file includes following definitions.
  1. fsh
  2. db_locked_file_destr
  3. db_file_fetch_locked
  4. db_file_store_root
  5. db_file_store
  6. db_file_delete
  7. db_file_traverse
  8. db_open_file

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    Database interface using a file per record
   4    Copyright (C) Volker Lendecke 2005
   5    
   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.
  10    
  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.
  15    
  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/>.
  18 */
  19 
  20 #include "includes.h"
  21 
  22 struct db_file_ctx {
  23         const char *dirname;
  24 
  25         /* We only support one locked record at a time -- everything else
  26          * would lead to a potential deadlock anyway! */
  27         struct db_record *locked_record;
  28 };
  29 
  30 struct db_locked_file {
  31         int fd;
  32         uint8 hash;
  33         const char *name;
  34         const char *path;
  35         struct db_file_ctx *parent;
  36 };
  37 
  38 /* Copy from statcache.c... */
  39 
  40 static uint32 fsh(const uint8 *p, int len)
     /* [<][>][^][v][top][bottom][index][help] */
  41 {
  42         uint32 n = 0;
  43         int i;
  44         for (i=0; i<len; i++) {
  45                 n = ((n << 5) + n) ^ (uint32)(p[i]);
  46         }
  47         return n;
  48 }
  49 
  50 static int db_locked_file_destr(struct db_locked_file *data)
     /* [<][>][^][v][top][bottom][index][help] */
  51 {
  52         if (data->parent != NULL) {
  53                 data->parent->locked_record = NULL;
  54         }
  55 
  56         if (close(data->fd) != 0) {
  57                 DEBUG(3, ("close failed: %s\n", strerror(errno)));
  58                 return -1;
  59         }
  60 
  61         return 0;
  62 }
  63 
  64 static NTSTATUS db_file_store(struct db_record *rec, TDB_DATA data, int flag);
  65 static NTSTATUS db_file_delete(struct db_record *rec);
  66 
  67 static struct db_record *db_file_fetch_locked(struct db_context *db,
     /* [<][>][^][v][top][bottom][index][help] */
  68                                               TALLOC_CTX *mem_ctx,
  69                                               TDB_DATA key)
  70 {
  71         struct db_file_ctx *ctx = talloc_get_type_abort(db->private_data,
  72                                                         struct db_file_ctx);
  73         struct db_record *result;
  74         struct db_locked_file *file;
  75         struct flock fl;
  76         SMB_STRUCT_STAT statbuf;
  77         ssize_t nread;
  78         int ret;
  79 
  80         SMB_ASSERT(ctx->locked_record == NULL);
  81 
  82  again:
  83         if (!(result = TALLOC_P(mem_ctx, struct db_record))) {
  84                 DEBUG(0, ("talloc failed\n"));
  85                 return NULL;
  86         }
  87 
  88         if (!(file = TALLOC_P(result, struct db_locked_file))) {
  89                 DEBUG(0, ("talloc failed\n"));
  90                 TALLOC_FREE(result);
  91                 return NULL;
  92         }
  93 
  94         result->private_data = file;
  95         result->store = db_file_store;
  96         result->delete_rec = db_file_delete;
  97 
  98         result->key.dsize = key.dsize;
  99         result->key.dptr = (uint8 *)talloc_memdup(result, key.dptr, key.dsize);
 100         if (result->key.dptr == NULL) {
 101                 DEBUG(0, ("talloc failed\n"));
 102                 TALLOC_FREE(result);
 103                 return NULL;
 104         }
 105 
 106         /* Cut to 8 bits */
 107         file->hash = fsh(key.dptr, key.dsize);
 108         file->name = hex_encode_talloc(file, (unsigned char *)key.dptr, key.dsize);
 109         if (file->name == NULL) {
 110                 DEBUG(0, ("hex_encode failed\n"));
 111                 TALLOC_FREE(result);
 112                 return NULL;
 113         }
 114 
 115         file->path = talloc_asprintf(file, "%s/%2.2X/%s", ctx->dirname,
 116                                      file->hash, file->name);
 117         if (file->path == NULL) {
 118                 DEBUG(0, ("talloc_asprintf failed\n"));
 119                 TALLOC_FREE(result);
 120                 return NULL;
 121         }
 122 
 123         become_root();
 124         file->fd = open(file->path, O_RDWR|O_CREAT, 0644);
 125         unbecome_root();
 126 
 127         if (file->fd < 0) {
 128                 DEBUG(3, ("Could not open/create %s: %s\n",
 129                           file->path, strerror(errno)));
 130                 TALLOC_FREE(result);
 131                 return NULL;
 132         }
 133 
 134         talloc_set_destructor(file, db_locked_file_destr);
 135 
 136         fl.l_type = F_WRLCK;
 137         fl.l_whence = SEEK_SET;
 138         fl.l_start = 0;
 139         fl.l_len = 1;
 140         fl.l_pid = 0;
 141 
 142         do {
 143                 ret = fcntl(file->fd, F_SETLKW, &fl);
 144         } while ((ret == -1) && (errno == EINTR));
 145 
 146         if (ret == -1) {
 147                 DEBUG(3, ("Could not get lock on %s: %s\n",
 148                           file->path, strerror(errno)));
 149                 TALLOC_FREE(result);
 150                 return NULL;
 151         }
 152 
 153         if (sys_fstat(file->fd, &statbuf) != 0) {
 154                 DEBUG(3, ("Could not fstat %s: %s\n",
 155                           file->path, strerror(errno)));
 156                 TALLOC_FREE(result);
 157                 return NULL;
 158         }
 159 
 160         if (statbuf.st_nlink == 0) {
 161                 /* Someone has deleted it under the lock, retry */
 162                 TALLOC_FREE(result);
 163                 goto again;
 164         }
 165 
 166         result->value.dsize = 0;
 167         result->value.dptr = NULL;
 168 
 169         if (statbuf.st_size != 0) {
 170                 result->value.dsize = statbuf.st_size;
 171                 result->value.dptr = TALLOC_ARRAY(result, uint8,
 172                                                   statbuf.st_size);
 173                 if (result->value.dptr == NULL) {
 174                         DEBUG(1, ("talloc failed\n"));
 175                         TALLOC_FREE(result);
 176                         return NULL;
 177                 }
 178 
 179                 nread = read_data(file->fd, (char *)result->value.dptr,
 180                                   result->value.dsize);
 181                 if (nread != result->value.dsize) {
 182                         DEBUG(3, ("read_data failed: %s\n", strerror(errno)));
 183                         TALLOC_FREE(result);
 184                         return NULL;
 185                 }
 186         }
 187 
 188         ctx->locked_record = result;
 189         file->parent = (struct db_file_ctx *)talloc_reference(file, ctx);
 190 
 191         return result;
 192 }
 193 
 194 static NTSTATUS db_file_store_root(int fd, TDB_DATA data)
     /* [<][>][^][v][top][bottom][index][help] */
 195 {
 196         if (sys_lseek(fd, 0, SEEK_SET) != 0) {
 197                 DEBUG(0, ("sys_lseek failed: %s\n", strerror(errno)));
 198                 return map_nt_error_from_unix(errno);
 199         }
 200 
 201         if (write_data(fd, (char *)data.dptr, data.dsize) != data.dsize) {
 202                 DEBUG(3, ("write_data failed: %s\n", strerror(errno)));
 203                 return map_nt_error_from_unix(errno);
 204         }
 205 
 206         if (sys_ftruncate(fd, data.dsize) != 0) {
 207                 DEBUG(3, ("sys_ftruncate failed: %s\n", strerror(errno)));
 208                 return map_nt_error_from_unix(errno);
 209         }
 210 
 211         return NT_STATUS_OK;
 212 }
 213 
 214 static NTSTATUS db_file_store(struct db_record *rec, TDB_DATA data, int flag)
     /* [<][>][^][v][top][bottom][index][help] */
 215 {
 216         struct db_locked_file *file =
 217                 talloc_get_type_abort(rec->private_data,
 218                                       struct db_locked_file);
 219         NTSTATUS status;
 220 
 221         become_root();
 222         status = db_file_store_root(file->fd, data);
 223         unbecome_root();
 224 
 225         return status;
 226 }
 227 
 228 static NTSTATUS db_file_delete(struct db_record *rec)
     /* [<][>][^][v][top][bottom][index][help] */
 229 {
 230         struct db_locked_file *file =
 231                 talloc_get_type_abort(rec->private_data,
 232                                       struct db_locked_file);
 233         int res;
 234 
 235         become_root();
 236         res = unlink(file->path);
 237         unbecome_root();
 238 
 239         if (res == -1) {
 240                 DEBUG(3, ("unlink(%s) failed: %s\n", file->path,
 241                           strerror(errno)));
 242                 return map_nt_error_from_unix(errno);
 243         }
 244 
 245         return NT_STATUS_OK;
 246 }
 247 
 248 static int db_file_traverse(struct db_context *db,
     /* [<][>][^][v][top][bottom][index][help] */
 249                             int (*fn)(struct db_record *rec,
 250                                       void *private_data),
 251                             void *private_data)
 252 {
 253         struct db_file_ctx *ctx = talloc_get_type_abort(db->private_data,
 254                                                         struct db_file_ctx);
 255         TALLOC_CTX *mem_ctx = talloc_init("traversal %s\n", ctx->dirname);
 256         
 257         int i;
 258         int count = 0;
 259 
 260         for (i=0; i<256; i++) {
 261                 const char *dirname = talloc_asprintf(mem_ctx, "%s/%2.2X",
 262                                                       ctx->dirname, i);
 263                 DIR *dir;
 264                 struct dirent *dirent;
 265 
 266                 if (dirname == NULL) {
 267                         DEBUG(0, ("talloc failed\n"));
 268                         TALLOC_FREE(mem_ctx);
 269                         return -1;
 270                 }
 271 
 272                 dir = opendir(dirname);
 273                 if (dir == NULL) {
 274                         DEBUG(3, ("Could not open dir %s: %s\n", dirname,
 275                                   strerror(errno)));
 276                         TALLOC_FREE(mem_ctx);
 277                         return -1;
 278                 }
 279 
 280                 while ((dirent = readdir(dir)) != NULL) {
 281                         DATA_BLOB keyblob;
 282                         TDB_DATA key;
 283                         struct db_record *rec;
 284 
 285                         if ((dirent->d_name[0] == '.') &&
 286                             ((dirent->d_name[1] == '\0') ||
 287                              ((dirent->d_name[1] == '.') &&
 288                               (dirent->d_name[2] == '\0')))) {
 289                                 continue;
 290                         }
 291 
 292                         keyblob = strhex_to_data_blob(mem_ctx, dirent->d_name);
 293                         if (keyblob.data == NULL) {
 294                                 DEBUG(5, ("strhex_to_data_blob failed\n"));
 295                                 continue;
 296                         }
 297 
 298                         key.dptr = keyblob.data;
 299                         key.dsize = keyblob.length;
 300 
 301                         if ((ctx->locked_record != NULL) &&
 302                             (key.dsize == ctx->locked_record->key.dsize) &&
 303                             (memcmp(key.dptr, ctx->locked_record->key.dptr,
 304                                     key.dsize) == 0)) {
 305                                 count += 1;
 306                                 if (fn(ctx->locked_record,
 307                                        private_data) != 0) {
 308                                         TALLOC_FREE(mem_ctx);
 309                                         closedir(dir);
 310                                         return count;
 311                                 }
 312                         }
 313 
 314                         rec = db_file_fetch_locked(db, mem_ctx, key);
 315                         if (rec == NULL) {
 316                                 /* Someone might have deleted it */
 317                                 continue;
 318                         }
 319 
 320                         if (rec->value.dptr == NULL) {
 321                                 TALLOC_FREE(rec);
 322                                 continue;
 323                         }
 324 
 325                         count += 1;
 326 
 327                         if (fn(rec, private_data) != 0) {
 328                                 TALLOC_FREE(mem_ctx);
 329                                 closedir(dir);
 330                                 return count;
 331                         }
 332                         TALLOC_FREE(rec);
 333                 }
 334 
 335                 closedir(dir);
 336         }
 337 
 338         TALLOC_FREE(mem_ctx);
 339         return count;
 340 }
 341 
 342 struct db_context *db_open_file(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 343                                 struct messaging_context *msg_ctx,
 344                                 const char *name,
 345                                 int hash_size, int tdb_flags,
 346                                 int open_flags, mode_t mode)
 347 {
 348         struct db_context *result = NULL;
 349         struct db_file_ctx *ctx;
 350 
 351         if (!(result = TALLOC_ZERO_P(mem_ctx, struct db_context))) {
 352                 DEBUG(0, ("talloc failed\n"));
 353                 return NULL;
 354         }
 355 
 356         if (!(ctx = TALLOC_P(result, struct db_file_ctx))) {
 357                 DEBUG(0, ("talloc failed\n"));
 358                 TALLOC_FREE(result);
 359                 return NULL;
 360         }
 361 
 362         result->private_data = ctx;
 363         result->fetch_locked = db_file_fetch_locked;
 364         result->traverse = db_file_traverse;
 365         result->traverse_read = db_file_traverse;
 366         result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
 367 
 368         ctx->locked_record = NULL;
 369         if (!(ctx->dirname = talloc_strdup(ctx, name))) {
 370                 DEBUG(0, ("talloc failed\n"));
 371                 TALLOC_FREE(result);
 372                 return NULL;
 373         }
 374 
 375         if (open_flags & O_CREAT) {
 376                 int ret, i;
 377 
 378                 mode |= (mode & S_IRUSR) ? S_IXUSR : 0;
 379                 mode |= (mode & S_IRGRP) ? S_IXGRP : 0;
 380                 mode |= (mode & S_IROTH) ? S_IXOTH : 0;
 381 
 382                 ret = mkdir(name, mode);
 383                 if ((ret != 0) && (errno != EEXIST)) {
 384                         DEBUG(5, ("mkdir(%s,%o) failed: %s\n", name, mode,
 385                                   strerror(errno)));
 386                         TALLOC_FREE(result);
 387                         return NULL;
 388                 }
 389 
 390                 for (i=0; i<256; i++) {
 391                         char *path;
 392                         path = talloc_asprintf(result, "%s/%2.2X", name, i);
 393                         if (path == NULL) {
 394                                 DEBUG(0, ("asprintf failed\n"));
 395                                 TALLOC_FREE(result);
 396                                 return NULL;
 397                         }
 398                         ret = mkdir(path, mode);
 399                         if ((ret != 0) && (errno != EEXIST)) {
 400                                 DEBUG(5, ("mkdir(%s,%o) failed: %s\n", path,
 401                                           mode, strerror(errno)));
 402                                 TALLOC_FREE(result);
 403                                 return NULL;
 404                         }
 405                         TALLOC_FREE(path);
 406                 }
 407         }
 408 
 409         return result;
 410 }

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