Exemple #1
0
static int lock_db(const char *dbpath, const char *dbflags)
{
	struct tdb_context *tdb;
	int tdb_flags;

	/* No error checking since CTDB always passes sane values */
	tdb_flags = strtol(dbflags, NULL, 0);

	tdb = tdb_open(dbpath, 0, tdb_flags, O_RDWR, 0600);
	if (tdb == NULL) {
		fprintf(stderr, "%s: Error opening database %s\n", progname, dbpath);
		return 1;
	}

	set_priority();

	if (tdb_lockall(tdb) < 0) {
		fprintf(stderr, "%s: Error getting db lock (%s)\n",
			progname, tdb_errorstr(tdb));
		return 1;
	}

	reset_priority();

	return 0;
}
Exemple #2
0
static int set_new_value(BaseTDBResolver *self, TDB_DATA urn, TDB_DATA attribute, 
			 TDB_DATA value) {
  TDB_DATA key,offset;
  char buff[BUFF_SIZE];
  char buff2[BUFF_SIZE];
  uint32_t new_offset;
  TDB_DATA_LIST i;

  // Update the value in the db and replace with new value
  key.dptr = (unsigned char *)buff;
  key.dsize = calculate_key(self, urn, attribute, buff, BUFF_SIZE, 1);

  // Lock the database
  tdb_lockall(self->data_db);

  // Go to the end and write the new record
  new_offset = lseek(self->data_store_fd, 0, SEEK_END);
  // The offset to the next item in the list
  i.offset = 0;
  i.length = value.dsize;

  write(self->data_store_fd, &i, sizeof(i));
  write(self->data_store_fd, value.dptr, value.dsize);

  offset.dptr = (unsigned char *)buff2;
  offset.dsize = from_int(new_offset, buff2, BUFF_SIZE);

  tdb_store(self->data_db, key, offset, TDB_REPLACE);

  //Done
  tdb_unlockall(self->data_db);

  return 1;
};
Exemple #3
0
static PyObject *obj_lockall(PyTdbObject *self)
{
	int ret;
	PyErr_TDB_RAISE_IF_CLOSED(self);
	ret = tdb_lockall(self->ctx);
	PyErr_TDB_ERROR_IS_ERR_RAISE(ret, self->ctx);
	Py_RETURN_NONE;
}
Exemple #4
0
PyObject *py_tdb_hnd_lock_all(PyObject *self, PyObject *args)
{
	tdb_hnd_object *obj = (tdb_hnd_object *)self;
	int result;

        if (!obj->tdb) {
		PyErr_SetString(py_tdb_error, "tdb object has been closed"); 
		return NULL;
        }	

	result = tdb_lockall(obj->tdb);

	return PyInt_FromLong(result != -1);
}
Exemple #5
0
/* load a msg file into the tdb */
static BOOL load_msg(const char *msg_file)
{
	char **lines;
	int num_lines, i;
	char *msgid, *msgstr;
	TDB_DATA key, data;

	lines = file_lines_load(msg_file, &num_lines);

	if (!lines) {
		return False;
	}

	if (tdb_lockall(tdb) != 0) return False;

	/* wipe the db */
	tdb_traverse(tdb, tdb_traverse_delete_fn, NULL);

	msgid = NULL;
	
	for (i=0;i<num_lines;i++) {
		if (strncmp(lines[i], "msgid \"", 7) == 0) {
			msgid = lines[i] + 7;
		}
		if (msgid && strncmp(lines[i], "msgstr \"", 8) == 0) {
			msgstr = lines[i] + 8;
			trim_char(msgid, '\0', '\"');
			trim_char(msgstr, '\0', '\"');
			if (*msgstr == 0) {
				msgstr = msgid;
			}
			all_string_sub(msgid, "\\n", "\n", 0);
			all_string_sub(msgstr, "\\n", "\n", 0);
			key.dptr = msgid;
			key.dsize = strlen(msgid)+1;
			data.dptr = msgstr;
			data.dsize = strlen(msgstr)+1;
			tdb_store(tdb, key, data, 0);
			msgid = NULL;
		}
	}

	file_lines_free(lines);
	tdb_unlockall(tdb);

	return True;
}
Exemple #6
0
/* load a msg file into the tdb */
static bool load_msg(const char *msg_file)
{
	char **lines;
	int num_lines, i;
	char *msgid, *msgstr;
	TDB_DATA data;

	lines = file_lines_load(msg_file, &num_lines, 0, NULL);

	if (!lines) {
		return False;
	}

	if (tdb_lockall(tdb) != 0) {
		TALLOC_FREE(lines);
		return False;
	}

	/* wipe the db */
	tdb_wipe_all(tdb);

	msgid = NULL;
	
	for (i=0;i<num_lines;i++) {
		if (strncmp(lines[i], "msgid \"", 7) == 0) {
			msgid = lines[i] + 7;
		}
		if (msgid && strncmp(lines[i], "msgstr \"", 8) == 0) {
			msgstr = lines[i] + 8;
			trim_char(msgid, '\0', '\"');
			trim_char(msgstr, '\0', '\"');
			if (*msgstr == 0) {
				msgstr = msgid;
			}
			all_string_sub(msgid, "\\n", "\n", 0);
			all_string_sub(msgstr, "\\n", "\n", 0);
			data = string_term_tdb_data(msgstr);
			tdb_store_bystring(tdb, msgid, data, 0);
			msgid = NULL;
		}
	}

	TALLOC_FREE(lines);
	tdb_unlockall(tdb);

	return True;
}
Exemple #7
0
/** Fetches the id for the given key from the database tdb - if
    create_new is set and there is no id present, we create a new id
    and return id.
*/
static uint32_t get_id(struct tdb_context *tdb, TDB_DATA key, int create_new) {
  char buff[BUFF_SIZE];
  TDB_DATA urn_id;
  uint32_t max_id=0;
  uint32_t result=0;
  
  /* We get given an ID and we retrieve the URN it belongs to */
  tdb_lockall(tdb);
  urn_id = tdb_fetch(tdb, key);

  if(urn_id.dptr) {
    result = to_int(urn_id);
    free(urn_id.dptr);

    tdb_unlockall(tdb);
    return result;
  } else if(create_new) {
    TDB_DATA max_key;

    max_key.dptr = (unsigned char *)MAX_KEY;
    max_key.dsize = strlen(MAX_KEY);

    urn_id = tdb_fetch(tdb, max_key);
    if(urn_id.dptr) {
      max_id = to_int(urn_id);
      free(urn_id.dptr);
    };

    max_id++;
    
    // Update the new MAX_KEY
    urn_id.dptr = (unsigned char *)buff;
    urn_id.dsize = from_int(max_id, buff, BUFF_SIZE);
    tdb_store(tdb, key, urn_id, TDB_REPLACE);
    tdb_store(tdb, max_key, urn_id, TDB_REPLACE);
    tdb_store(tdb, urn_id, key, TDB_REPLACE);

    tdb_unlockall(tdb);
    return max_id;
  };

  tdb_unlockall(tdb);
  // This should never happen
  return 0;
};
Exemple #8
0
static PyObject *add(BaseTDBResolver *self, PyObject *args, PyObject *kwds) {
  char buff[BUFF_SIZE];
  char buff2[BUFF_SIZE];
  static char *kwlist[] = {"urn", "attribute", "value", "unique", NULL};
  TDB_DATA urn;
  TDB_DATA attribute;
  TDB_DATA key;
  PyObject *value_obj, *value_str;
  TDB_DATA value;
  TDB_DATA offset;
  TDB_DATA_LIST i;
  uint32_t previous_offset=0;
  uint32_t new_offset;
  int unique = 0;

  attribute.dsize = 0;
  urn.dsize = 0;
  if(!PyArg_ParseTupleAndKeywords(args, kwds, "s#s#O|L", kwlist, 
				  &urn.dptr, &urn.dsize, 
				  &attribute.dptr, &attribute.dsize,
				  &value_obj, &unique))
    return NULL;

  // Convert the object to a string
  value_str = PyObject_Str(value_obj);
  if(!value_str) return NULL;

  PyString_AsStringAndSize(value_str, (char **)&value.dptr, 
			   &value.dsize);

  /** If the value is already in the list, we just ignore this
      request.
  */
  if(unique && is_value_present(self, urn, attribute, value, 1)) {
    goto exit;
  };

  // Ok if we get here, the value is not already stored there.
  key.dptr = (unsigned char *)buff;
  key.dsize = calculate_key(self, urn, attribute, buff, BUFF_SIZE, 1);

  // Lock the data_db to synchronise access to the store:
  tdb_lockall(self->data_db);

  offset = tdb_fetch(self->data_db, key);
  if(offset.dptr) {
    previous_offset = to_int(offset);
    free(offset.dptr);
  };

  // Go to the end and write the new record
  new_offset = lseek(self->data_store_fd, 0, SEEK_END);
  i.offset = previous_offset;
  i.length = value.dsize;

  write(self->data_store_fd, &i, sizeof(i));
  write(self->data_store_fd, value.dptr, value.dsize);

  // Now store the offset to this in the tdb database
  value.dptr = (unsigned char *)buff2;
  value.dsize = from_int(new_offset, buff2, BUFF_SIZE);

  tdb_store(self->data_db, key, value, TDB_REPLACE);

  // Done
  tdb_unlockall(self->data_db);

  exit:
  Py_DECREF(value_str);
  Py_RETURN_NONE;
};
Exemple #9
0
static int tdbresolver_init(BaseTDBResolver *self, PyObject *args, PyObject *kwds) {
  static char *kwlist[] = {"path", "hashsize", NULL};
  char buff[BUFF_SIZE];
  char *path = ".";
  int flags = O_RDWR | O_CREAT;

  if(!PyArg_ParseTupleAndKeywords(args, kwds, "|sL", kwlist, 
				  &path, &self->hashsize))
    return -1;

  if(snprintf(buff, BUFF_SIZE, "%s/urn.tdb", path) >= BUFF_SIZE)
    goto error;
  
  self->urn_db = tdb_open(buff, self->hashsize,
			  0,
			  O_RDWR | O_CREAT, 0644);
  if(!self->urn_db) 
    goto error;

  if(snprintf(buff, BUFF_SIZE, "%s/attribute.tdb", path) >= BUFF_SIZE)
    goto error1;

  self->attribute_db = tdb_open(buff, self->hashsize,
				0,
				O_RDWR | O_CREAT, 0644);

  if(!self->attribute_db) 
    goto error1;

  if(snprintf(buff, BUFF_SIZE, "%s/data.tdb", path) >= BUFF_SIZE)
    goto error2;

  self->data_db = tdb_open(buff, self->hashsize,
			   0,
			   O_RDWR | O_CREAT, 0644);
  
  if(!self->data_db)
    goto error2;

  if(snprintf(buff, BUFF_SIZE, "%s/data_store.tdb", path) >= BUFF_SIZE)
    goto error3;

  self->data_store_fd = open(buff, O_RDWR | O_CREAT, 0644);
  if(self->data_store_fd < 0)
    goto error3;

  // This ensures that the data store never has an offset of 0 (This
  // indicates an error)
  // Access to the tdb_store is managed via locks on the data.tdb
  tdb_lockall(self->data_db);
  if(lseek(self->data_store_fd, 0, SEEK_END)==0) {
    (void)write(self->data_store_fd, "data",4);
  };
  tdb_unlockall(self->data_db);

  return 0;

 error3:
  tdb_close(self->data_db);
  self->data_db = NULL;
 error2:
  tdb_close(self->attribute_db);
  self->attribute_db = NULL;
 error1:
  tdb_close(self->urn_db);
  self->urn_db = NULL;
 error:
  PyErr_Format(PyExc_IOError, "Unable to open tdb files");

  return -1;
};
Exemple #10
0
static PyObject *pytdb_lock(PyTDB *self, PyObject *args, PyObject *kwds) {
  tdb_lockall(self->context);
  Py_RETURN_NONE;
}
Exemple #11
0
/*
  carefully backup a tdb, validating the contents and
  only doing the backup if its OK
  this function is also used for restore
*/
static int backup_tdb(const char *old_name, const char *new_name,
                      int hash_size, int nolock)
{
    TDB_CONTEXT *tdb;
    TDB_CONTEXT *tdb_new;
    char *tmp_name;
    struct stat st;
    int count1, count2;

    tmp_name = add_suffix(new_name, ".tmp");

    /* stat the old tdb to find its permissions */
    if (stat(old_name, &st) != 0) {
        perror(old_name);
        free(tmp_name);
        return 1;
    }

    /* open the old tdb */
    tdb = tdb_open_ex(old_name, 0,
                      TDB_DEFAULT | (nolock ? TDB_NOLOCK : 0),
                      O_RDWR, 0, &log_ctx, NULL);
    if (!tdb) {
        printf("Failed to open %s\n", old_name);
        free(tmp_name);
        return 1;
    }

    /* create the new tdb */
    unlink(tmp_name);
    tdb_new = tdb_open_ex(tmp_name,
                          hash_size ? hash_size : tdb_hash_size(tdb),
                          TDB_DEFAULT,
                          O_RDWR|O_CREAT|O_EXCL, st.st_mode & 0777,
                          &log_ctx, NULL);
    if (!tdb_new) {
        perror(tmp_name);
        free(tmp_name);
        return 1;
    }

    if (tdb_transaction_start(tdb) != 0) {
        printf("Failed to start transaction on old tdb\n");
        tdb_close(tdb);
        tdb_close(tdb_new);
        unlink(tmp_name);
        free(tmp_name);
        return 1;
    }

    /* lock the backup tdb so that nobody else can change it */
    if (tdb_lockall(tdb_new) != 0) {
        printf("Failed to lock backup tdb\n");
        tdb_close(tdb);
        tdb_close(tdb_new);
        unlink(tmp_name);
        free(tmp_name);
        return 1;
    }

    failed = 0;

    /* traverse and copy */
    count1 = tdb_traverse(tdb, copy_fn, (void *)tdb_new);
    if (count1 < 0 || failed) {
        fprintf(stderr,"failed to copy %s\n", old_name);
        tdb_close(tdb);
        tdb_close(tdb_new);
        unlink(tmp_name);
        free(tmp_name);
        return 1;
    }

    /* close the old tdb */
    tdb_close(tdb);

    /* copy done, unlock the backup tdb */
    tdb_unlockall(tdb_new);

#ifdef HAVE_FDATASYNC
    if (fdatasync(tdb_fd(tdb_new)) != 0) {
#else
    if (fsync(tdb_fd(tdb_new)) != 0) {
#endif
        /* not fatal */
        fprintf(stderr, "failed to fsync backup file\n");
    }

    /* close the new tdb and re-open read-only */
    tdb_close(tdb_new);
    tdb_new = tdb_open_ex(tmp_name,
                          0,
                          TDB_DEFAULT,
                          O_RDONLY, 0,
                          &log_ctx, NULL);
    if (!tdb_new) {
        fprintf(stderr,"failed to reopen %s\n", tmp_name);
        unlink(tmp_name);
        perror(tmp_name);
        free(tmp_name);
        return 1;
    }

    /* traverse the new tdb to confirm */
    count2 = tdb_traverse(tdb_new, test_fn, NULL);
    if (count2 != count1) {
        fprintf(stderr,"failed to copy %s\n", old_name);
        tdb_close(tdb_new);
        unlink(tmp_name);
        free(tmp_name);
        return 1;
    }

    /* close the new tdb and rename it to .bak */
    tdb_close(tdb_new);
    if (rename(tmp_name, new_name) != 0) {
        perror(new_name);
        free(tmp_name);
        return 1;
    }

    free(tmp_name);

    return 0;
}

/*
  verify a tdb and if it is corrupt then restore from *.bak
*/
static int verify_tdb(const char *fname, const char *bak_name)
{
    TDB_CONTEXT *tdb;
    int count = -1;

    /* open the tdb */
    tdb = tdb_open_ex(fname, 0, 0,
                      O_RDONLY, 0, &log_ctx, NULL);

    /* traverse the tdb, then close it */
    if (tdb) {
        count = tdb_traverse(tdb, test_fn, NULL);
        tdb_close(tdb);
    }

    /* count is < 0 means an error */
    if (count < 0) {
        printf("restoring %s\n", fname);
        return backup_tdb(bak_name, fname, 0, 0);
    }

    printf("%s : %d records\n", fname, count);

    return 0;
}
Exemple #12
0
/*
  wipe the entire database, deleting all records. This can be done
  very fast by using a allrecord lock. The entire data portion of the
  file becomes a single entry in the freelist.

  This code carefully steps around the recovery area, leaving it alone
 */
int tdb1_wipe_all(struct tdb_context *tdb)
{
	int i;
	tdb1_off_t offset = 0;
	ssize_t data_len;
	tdb1_off_t recovery_head;
	tdb1_len_t recovery_size = 0;

	if (tdb_lockall(tdb) != TDB_SUCCESS) {
		return -1;
	}


	/* see if the tdb has a recovery area, and remember its size
	   if so. We don't want to lose this as otherwise each
	   tdb1_wipe_all() in a transaction will increase the size of
	   the tdb by the size of the recovery area */
	if (tdb1_ofs_read(tdb, TDB1_RECOVERY_HEAD, &recovery_head) == -1) {
		tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
			   "tdb1_wipe_all: failed to read recovery head");
		goto failed;
	}

	if (recovery_head != 0) {
		struct tdb1_record rec;
		if (tdb->tdb1.io->tdb1_read(tdb, recovery_head, &rec, sizeof(rec), TDB1_DOCONV()) == -1) {
			tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
				   "tdb1_wipe_all: failed to read recovery record");
			return -1;
		}
		recovery_size = rec.rec_len + sizeof(rec);
	}

	/* wipe the hashes */
	for (i=0;i<tdb->tdb1.header.hash_size;i++) {
		if (tdb1_ofs_write(tdb, TDB1_HASH_TOP(i), &offset) == -1) {
			tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
				   "tdb1_wipe_all: failed to write hash %d", i);
			goto failed;
		}
	}

	/* wipe the freelist */
	if (tdb1_ofs_write(tdb, TDB1_FREELIST_TOP, &offset) == -1) {
		tdb_logerr(tdb, tdb->last_error, TDB_LOG_ERROR,
			   "tdb1_wipe_all: failed to write freelist");
		goto failed;
	}

	/* add all the rest of the file to the freelist, possibly leaving a gap
	   for the recovery area */
	if (recovery_size == 0) {
		/* the simple case - the whole file can be used as a freelist */
		data_len = (tdb->file->map_size - TDB1_DATA_START(tdb->tdb1.header.hash_size));
		if (tdb1_free_region(tdb, TDB1_DATA_START(tdb->tdb1.header.hash_size), data_len) != 0) {
			goto failed;
		}
	} else {
		/* we need to add two freelist entries - one on either
		   side of the recovery area

		   Note that we cannot shift the recovery area during
		   this operation. Only the transaction.c code may
		   move the recovery area or we risk subtle data
		   corruption
		*/
		data_len = (recovery_head - TDB1_DATA_START(tdb->tdb1.header.hash_size));
		if (tdb1_free_region(tdb, TDB1_DATA_START(tdb->tdb1.header.hash_size), data_len) != 0) {
			goto failed;
		}
		/* and the 2nd free list entry after the recovery area - if any */
		data_len = tdb->file->map_size - (recovery_head+recovery_size);
		if (tdb1_free_region(tdb, recovery_head+recovery_size, data_len) != 0) {
			goto failed;
		}
	}

	tdb1_increment_seqnum_nonblock(tdb);
	tdb_unlockall(tdb);
	return 0;

failed:
	tdb_unlockall(tdb);
	return -1;
}
Exemple #13
0
/* this backup function is essentially taken from lib/tdb/tools/tdbbackup.tdb
 */
static int tdb_backup(TALLOC_CTX *ctx, const char *src_path,
		      const char *dst_path, int hash_size)
{
	struct tdb_context *src_tdb = NULL;
	struct tdb_context *dst_tdb = NULL;
	char *tmp_path = NULL;
	struct stat st;
	int count1, count2;
	int saved_errno = 0;
	int ret = -1;

	if (stat(src_path, &st) != 0) {
		DEBUG(3, ("Could not stat '%s': %s\n", src_path,
			  strerror(errno)));
		goto done;
	}

	/* open old tdb RDWR - so we can lock it */
	src_tdb = tdb_open_log(src_path, 0, TDB_DEFAULT, O_RDWR, 0);
	if (src_tdb == NULL) {
		DEBUG(3, ("Failed to open tdb '%s'\n", src_path));
		goto done;
	}

	if (tdb_lockall(src_tdb) != 0) {
		DEBUG(3, ("Failed to lock tdb '%s'\n", src_path));
		goto done;
	}

	tmp_path = talloc_asprintf(ctx, "%s%s", dst_path, ".tmp");
	unlink(tmp_path);
	dst_tdb = tdb_open_log(tmp_path,
			       hash_size ? hash_size : tdb_hash_size(src_tdb),
			       TDB_DEFAULT, O_RDWR | O_CREAT | O_EXCL,
			       st.st_mode & 0777);
	if (dst_tdb == NULL) {
		DEBUG(3, ("Error creating tdb '%s': %s\n", tmp_path,
			  strerror(errno)));
		saved_errno = errno;
		unlink(tmp_path);
		goto done;
	}

	count1 = tdb_copy(src_tdb, dst_tdb);
	if (count1 < 0) {
		DEBUG(3, ("Failed to copy tdb '%s': %s\n", src_path,
			  strerror(errno)));
		tdb_close(dst_tdb);
		goto done;
	}

	/* reopen ro and do basic verification */
	tdb_close(dst_tdb);
	dst_tdb = tdb_open_log(tmp_path, 0, TDB_DEFAULT, O_RDONLY, 0);
	if (!dst_tdb) {
		DEBUG(3, ("Failed to reopen tdb '%s': %s\n", tmp_path,
			  strerror(errno)));
		goto done;
	}
	count2 = tdb_verify_basic(dst_tdb);
	if (count2 != count1) {
		DEBUG(3, ("Failed to verify result of copying tdb '%s'.\n",
			  src_path));
		tdb_close(dst_tdb);
		goto done;
	}

	DEBUG(10, ("tdb_backup: successfully copied %d entries\n", count1));

	/* make sure the new tdb has reached stable storage
	 * then rename it to its destination */
	fsync(tdb_fd(dst_tdb));
	tdb_close(dst_tdb);
	unlink(dst_path);
	if (rename(tmp_path, dst_path) != 0) {
		DEBUG(3, ("Failed to rename '%s' to '%s': %s\n",
			  tmp_path, dst_path, strerror(errno)));
		goto done;
	}

	/* success */
	ret = 0;

done:
	if (src_tdb != NULL) {
		tdb_close(src_tdb);
	}
	if (tmp_path != NULL) {
		unlink(tmp_path);
		TALLOC_FREE(tmp_path);
	}
	if (saved_errno != 0) {
		errno = saved_errno;
	}
	return ret;
}
Exemple #14
0
/*
  carefully backup a tdb, validating the contents and
  only doing the backup if its OK
  this function is also used for restore
*/
int backup_tdb(const char *old_name, const char *new_name, int hash_size)
{
	TDB_CONTEXT *tdb;
	TDB_CONTEXT *tdb_new;
	char *tmp_name;
	struct stat st;
	int count1, count2;

	tmp_name = add_suffix(new_name, ".tmp");

	/* stat the old tdb to find its permissions */
	if (stat(old_name, &st) != 0) {
		perror(old_name);
		free(tmp_name);
		return 1;
	}

	/* open the old tdb */
	tdb = tdb_open(old_name, 0, 0, O_RDWR, 0);
	if (!tdb) {
		printf("Failed to open %s\n", old_name);
		free(tmp_name);
		return 1;
	}

	/* create the new tdb */
	unlink(tmp_name);
	tdb_new = tdb_open(tmp_name,
			   hash_size ? hash_size : tdb_hash_size(tdb),
			   TDB_DEFAULT, O_RDWR|O_CREAT|O_EXCL, 
			   st.st_mode & 0777);
	if (!tdb_new) {
		perror(tmp_name);
		free(tmp_name);
		return 1;
	}

	/* lock the old tdb */
	if (tdb_lockall(tdb) != 0) {
		fprintf(stderr,"Failed to lock %s\n", old_name);
		tdb_close(tdb);
		tdb_close(tdb_new);
		unlink(tmp_name);
		free(tmp_name);
		return 1;
	}

	failed = 0;

	/* traverse and copy */
	count1 = tdb_traverse(tdb, copy_fn, (void *)tdb_new);
	if (count1 < 0 || failed) {
		fprintf(stderr,"failed to copy %s\n", old_name);
		tdb_close(tdb);
		tdb_close(tdb_new);
		unlink(tmp_name);
		free(tmp_name);
		return 1;
	}

	/* close the old tdb */
	tdb_close(tdb);

	/* close the new tdb and re-open read-only */
	tdb_close(tdb_new);
	tdb_new = tdb_open(tmp_name, 0, TDB_DEFAULT, O_RDONLY, 0);
	if (!tdb_new) {
		fprintf(stderr,"failed to reopen %s\n", tmp_name);
		unlink(tmp_name);
		perror(tmp_name);
		free(tmp_name);
		return 1;
	}
	
	/* traverse the new tdb to confirm */
	count2 = tdb_traverse(tdb_new, test_fn, 0);
	if (count2 != count1) {
		fprintf(stderr,"failed to copy %s\n", old_name);
		tdb_close(tdb_new);
		unlink(tmp_name);
		free(tmp_name);
		return 1;
	}

	/* make sure the new tdb has reached stable storage */
	fsync(tdb_fd(tdb_new));

	/* close the new tdb and rename it to .bak */
	tdb_close(tdb_new);
	unlink(new_name);
	if (rename(tmp_name, new_name) != 0) {
		perror(new_name);
		free(tmp_name);
		return 1;
	}

	free(tmp_name);

	return 0;
}
Exemple #15
0
int tdb_check(struct tdb_context *tdb,
	      int (*check)(TDB_DATA key, TDB_DATA data, void *private_data),
	      void *private_data)
{
	unsigned int h;
	unsigned char **hashes;
	tdb_off_t off, recovery_start;
	struct tdb_record rec;
	bool found_recovery = false;

	if (tdb_lockall(tdb) == -1)
		return -1;

	/* Make sure we know true size of the underlying file. */
	tdb->methods->tdb_oob(tdb, tdb->map_size + 1, 1);

	/* Header must be OK: also gets us the recovery ptr, if any. */
	if (!tdb_check_header(tdb, &recovery_start))
		goto unlock;

	/* We should have the whole header, too. */
	if (tdb->map_size < TDB_DATA_START(tdb->header.hash_size)) {
		tdb->ecode = TDB_ERR_CORRUPT;
		TDB_LOG((tdb, TDB_DEBUG_ERROR, "File too short for hashes\n"));
		goto unlock;
	}

	/* One big malloc: pointers then bit arrays. */
	hashes = (unsigned char **)calloc(
			1, sizeof(hashes[0]) * (1+tdb->header.hash_size)
			+ BITMAP_BITS / CHAR_BIT * (1+tdb->header.hash_size));
	if (!hashes) {
		tdb->ecode = TDB_ERR_OOM;
		goto unlock;
	}

	/* Initialize pointers */
	hashes[0] = (unsigned char *)(&hashes[1+tdb->header.hash_size]);
	for (h = 1; h < 1+tdb->header.hash_size; h++)
		hashes[h] = hashes[h-1] + BITMAP_BITS / CHAR_BIT;

	/* Freelist and hash headers are all in a row: read them. */
	for (h = 0; h < 1+tdb->header.hash_size; h++) {
		if (tdb_ofs_read(tdb, FREELIST_TOP + h*sizeof(tdb_off_t),
				 &off) == -1)
			goto free;
		if (off)
			record_offset(hashes[h], off);
	}

	/* For each record, read it in and check it's ok. */
	for (off = TDB_DATA_START(tdb->header.hash_size);
	     off < tdb->map_size;
	     off += sizeof(rec) + rec.rec_len) {
		if (tdb->methods->tdb_read(tdb, off, &rec, sizeof(rec),
					   DOCONV()) == -1)
			goto free;
		switch (rec.magic) {
		case TDB_MAGIC:
		case TDB_DEAD_MAGIC:
			if (!tdb_check_used_record(tdb, off, &rec, hashes,
						   check, private_data))
				goto free;
			break;
		case TDB_FREE_MAGIC:
			if (!tdb_check_free_record(tdb, off, &rec, hashes))
				goto free;
			break;
		case TDB_RECOVERY_MAGIC:
		case 0: /* Used for invalid (or in-progress) recovery area. */
			if (recovery_start != off) {
				TDB_LOG((tdb, TDB_DEBUG_ERROR,
					 "Unexpected recovery record at offset %d\n",
					 off));
				goto free;
			}
			found_recovery = true;
			break;
		default:
			tdb->ecode = TDB_ERR_CORRUPT;
			TDB_LOG((tdb, TDB_DEBUG_ERROR,
				 "Bad magic 0x%x at offset %d\n",
				 rec.magic, off));
			goto free;
		}
	}

	/* Now, hashes should all be empty: each record exists and is referred
	 * to by one other. */
	for (h = 0; h < 1+tdb->header.hash_size; h++) {
		unsigned int i;
		for (i = 0; i < BITMAP_BITS / CHAR_BIT; i++) {
			if (hashes[h][i] != 0) {
				tdb->ecode = TDB_ERR_CORRUPT;
				TDB_LOG((tdb, TDB_DEBUG_ERROR,
					 "Hashes do not match records\n"));
				goto free;
			}
		}
	}

	/* We must have found recovery area if there was one. */
	if (recovery_start != 0 && !found_recovery) {
		TDB_LOG((tdb, TDB_DEBUG_ERROR,
			 "Expected %s recovery area, got %s\n",
			 recovery_start ? "a" : "no",
			 found_recovery ? "one" : "none"));
		goto free;
	}

	free(hashes);
	tdb_unlockall(tdb);
	return 0;

free:
	free(hashes);
unlock:
	tdb_unlockall(tdb);
	return -1;
}
int main(int argc, char *argv[])
{
	unsigned int i, extra_msgs;
	struct tdb_context *tdb;
	struct tdb_data key = tdb_mkdata("key", 3);
	struct tdb_data data = tdb_mkdata("data", 4);
	int flags[] = { TDB_DEFAULT, TDB_NOMMAP,
			TDB_CONVERT, TDB_NOMMAP|TDB_CONVERT,
			TDB_VERSION1, TDB_NOMMAP|TDB_VERSION1,
			TDB_CONVERT|TDB_VERSION1,
			TDB_NOMMAP|TDB_CONVERT|TDB_VERSION1 };

	plan_tests(sizeof(flags) / sizeof(flags[0]) * 48);

	for (i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) {
		/* RW -> R0 */
		tdb = tdb_open("run-92-get-set-readonly.tdb", flags[i],
			       O_RDWR|O_CREAT|O_TRUNC, 0600, &tap_log_attr);
		ok1(tdb);
		ok1(!(tdb_get_flags(tdb) & TDB_RDONLY));

		/* TDB1 complains multiple times. */
		if (flags[i] & TDB_VERSION1) {
			extra_msgs = 1;
		} else {
			extra_msgs = 0;
		}

		ok1(tdb_store(tdb, key, data, TDB_INSERT) == TDB_SUCCESS);

		tdb_add_flag(tdb, TDB_RDONLY);
		ok1(tdb_get_flags(tdb) & TDB_RDONLY);

		/* Can't store, append, delete. */
		ok1(tdb_store(tdb, key, data, TDB_MODIFY) == TDB_ERR_RDONLY);
		ok1(tap_log_messages == 1);
		ok1(tdb_append(tdb, key, data) == TDB_ERR_RDONLY);
		tap_log_messages -= extra_msgs;
		ok1(tap_log_messages == 2);
		ok1(tdb_delete(tdb, key) == TDB_ERR_RDONLY);
		tap_log_messages -= extra_msgs;
		ok1(tap_log_messages == 3);

		/* Can't start a transaction, or any write lock. */
		ok1(tdb_transaction_start(tdb) == TDB_ERR_RDONLY);
		ok1(tap_log_messages == 4);
		ok1(tdb_chainlock(tdb, key) == TDB_ERR_RDONLY);
		tap_log_messages -= extra_msgs;
		ok1(tap_log_messages == 5);
		ok1(tdb_lockall(tdb) == TDB_ERR_RDONLY);
		ok1(tap_log_messages == 6);
		ok1(tdb_wipe_all(tdb) == TDB_ERR_RDONLY);
		ok1(tap_log_messages == 7);

		/* Back to RW. */
		tdb_remove_flag(tdb, TDB_RDONLY);
		ok1(!(tdb_get_flags(tdb) & TDB_RDONLY));

		ok1(tdb_store(tdb, key, data, TDB_MODIFY) == TDB_SUCCESS);
		ok1(tdb_append(tdb, key, data) == TDB_SUCCESS);
		ok1(tdb_delete(tdb, key) == TDB_SUCCESS);

		ok1(tdb_transaction_start(tdb) == TDB_SUCCESS);
		ok1(tdb_store(tdb, key, data, TDB_INSERT) == TDB_SUCCESS);
		ok1(tdb_transaction_commit(tdb) == TDB_SUCCESS);

		ok1(tdb_chainlock(tdb, key) == TDB_SUCCESS);
		tdb_chainunlock(tdb, key);
		ok1(tdb_lockall(tdb) == TDB_SUCCESS);
		tdb_unlockall(tdb);
		ok1(tdb_wipe_all(tdb) == TDB_SUCCESS);
		ok1(tap_log_messages == 7);

		tdb_close(tdb);

		/* R0 -> RW */
		tdb = tdb_open("run-92-get-set-readonly.tdb", flags[i],
			       O_RDONLY, 0600, &tap_log_attr);
		ok1(tdb);
		ok1(tdb_get_flags(tdb) & TDB_RDONLY);

		/* Can't store, append, delete. */
		ok1(tdb_store(tdb, key, data, TDB_INSERT) == TDB_ERR_RDONLY);
		ok1(tap_log_messages == 8);
		ok1(tdb_append(tdb, key, data) == TDB_ERR_RDONLY);
		tap_log_messages -= extra_msgs;
		ok1(tap_log_messages == 9);
		ok1(tdb_delete(tdb, key) == TDB_ERR_RDONLY);
		tap_log_messages -= extra_msgs;
		ok1(tap_log_messages == 10);

		/* Can't start a transaction, or any write lock. */
		ok1(tdb_transaction_start(tdb) == TDB_ERR_RDONLY);
		ok1(tap_log_messages == 11);
		ok1(tdb_chainlock(tdb, key) == TDB_ERR_RDONLY);
		tap_log_messages -= extra_msgs;
		ok1(tap_log_messages == 12);
		ok1(tdb_lockall(tdb) == TDB_ERR_RDONLY);
		ok1(tap_log_messages == 13);
		ok1(tdb_wipe_all(tdb) == TDB_ERR_RDONLY);
		ok1(tap_log_messages == 14);

		/* Can't remove TDB_RDONLY since we opened with O_RDONLY */
		tdb_remove_flag(tdb, TDB_RDONLY);
		ok1(tap_log_messages == 15);
		ok1(tdb_get_flags(tdb) & TDB_RDONLY);
		tdb_close(tdb);

		ok1(tap_log_messages == 15);
		tap_log_messages = 0;
	}
	return exit_status();
}