/*
Unix SMB/CIFS implementation.
- Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Ronnie Sahlberg 2007
+ Copyright (C) Andrew Tridgell 2007
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
#include "system/filesys.h"
#include "lib/tdb/include/tdb.h"
#include "messaging/messaging.h"
-#include "db_wrap.h"
+#include "tdb_wrap.h"
#include "lib/messaging/irpc.h"
#include "librpc/gen_ndr/ndr_opendb.h"
#include "ntvfs/ntvfs.h"
#include "ntvfs/common/ntvfs_common.h"
#include "cluster/cluster.h"
#include "include/ctdb.h"
+#include "param/param.h"
struct odb_context {
struct ctdb_context *ctdb;
struct ctdb_db_context *ctdb_db;
struct ntvfs_context *ntvfs_ctx;
- BOOL oplocks;
+ bool oplocks;
};
/*
}
odb->ctdb = ctdb;
- odb->ctdb_db = ctdb_db_handle(ctdb, "opendb");
+ odb->ctdb_db = ctdb_attach(ctdb, "opendb");
if (!odb->ctdb_db) {
DEBUG(0,("Failed to get attached ctdb db handle for opendb\n"));
talloc_free(odb);
odb->ntvfs_ctx = ntvfs_ctx;
/* leave oplocks disabled by default until the code is working */
- odb->oplocks = lp_parm_bool(-1, "opendb", "oplocks", False);
+ odb->oplocks = share_bool_option(ntvfs_ctx->config, SHARE_OPLOCKS, SHARE_OPLOCKS_DEFAULT);
return odb;
}
return lck;
}
+static DATA_BLOB odb_ctdb_get_key(TALLOC_CTX *mem_ctx, struct odb_lock *lck)
+{
+ /*
+ * as this file will went away and isn't used yet,
+ * copy the implementation from the tdb backend
+ * --metze
+ */
+ return data_blob_const(NULL, 0);
+}
+
/*
determine if two odb_entry structures conflict
{
TDB_DATA dbuf;
DATA_BLOB blob;
- NTSTATUS status;
-
+ enum ndr_err_code ndr_err;
+
dbuf = lck->data;
+ if (dbuf.dsize == 0) {
+ /* empty record in ctdb means the record isn't there */
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
blob.data = dbuf.dptr;
blob.length = dbuf.dsize;
- status = ndr_pull_struct_blob(&blob, lck, file, (ndr_pull_flags_fn_t)ndr_pull_opendb_file);
+ ndr_err = ndr_pull_struct_blob(&blob, lck, lp_iconv_convenience(lck->odb->ntvfs_ctx->lp_ctx), file, (ndr_pull_flags_fn_t)ndr_pull_opendb_file);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
- return status;
+ return NT_STATUS_OK;
}
/*
{
TDB_DATA dbuf;
DATA_BLOB blob;
- NTSTATUS status;
+ enum ndr_err_code ndr_err;
int ret;
if (!file->num_entries) {
dbuf.dptr = NULL;
dbuf.dsize = 0;
ctdb_record_store(lck->rec, dbuf);
+ talloc_free(lck->rec);
+ return NT_STATUS_OK;
}
- status = ndr_push_struct_blob(&blob, lck, file, (ndr_push_flags_fn_t)ndr_push_opendb_file);
- NT_STATUS_NOT_OK_RETURN(status);
+ ndr_err = ndr_push_struct_blob(&blob, lck,
+ lp_iconv_convenience(lck->odb->ntvfs_ctx->lp_ctx),
+ file, (ndr_push_flags_fn_t)ndr_push_opendb_file);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ return ndr_map_error2ntstatus(ndr_err);
+ }
dbuf.dptr = blob.data;
dbuf.dsize = blob.length;
ret = ctdb_record_store(lck->rec, dbuf);
+ talloc_free(lck->rec);
data_blob_free(&blob);
if (ret != 0) {
return NT_STATUS_INTERNAL_DB_CORRUPTION;
return NT_STATUS_OK;
}
+#if 0
/*
send an oplock break to a client
*/
return messaging_send_ptr(odb->ntvfs_ctx->msg_ctx, e->server,
MSG_NTVFS_OPLOCK_BREAK, e->file_handle);
}
+#endif
/*
register an open file in the open files database. This implements the share_access
Note that the path is only used by the delete on close logic, not
for comparing with other filenames
*/
-static NTSTATUS odb_ctdb_open_file(struct odb_lock *lck, void *file_handle,
- uint32_t stream_id, uint32_t share_access,
- uint32_t access_mask, BOOL delete_on_close,
- const char *path,
- uint32_t oplock_level, uint32_t *oplock_granted)
-{
- struct odb_context *odb = lck->odb;
- struct opendb_entry e;
- int i;
- struct opendb_file file;
- NTSTATUS status;
-
- if (odb->oplocks == False) {
- oplock_level = OPLOCK_NONE;
- }
-
- status = odb_pull_record(lck, &file);
- if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
- /* initialise a blank structure */
- ZERO_STRUCT(file);
- file.path = path;
- } else {
- NT_STATUS_NOT_OK_RETURN(status);
- }
-
- /* see if it conflicts */
- e.server = odb->ntvfs_ctx->server_id;
- e.file_handle = file_handle;
- e.stream_id = stream_id;
- e.share_access = share_access;
- e.access_mask = access_mask;
- e.delete_on_close = delete_on_close;
- e.oplock_level = OPLOCK_NONE;
-
- /* see if anyone has an oplock, which we need to break */
- for (i=0;i<file.num_entries;i++) {
- if (file.entries[i].oplock_level == OPLOCK_BATCH) {
- /* a batch oplock caches close calls, which
- means the client application might have
- already closed the file. We have to allow
- this close to propogate by sending a oplock
- break request and suspending this call
- until the break is acknowledged or the file
- is closed */
- odb_oplock_break_send(odb, &file.entries[i]);
- return NT_STATUS_OPLOCK_NOT_GRANTED;
- }
- }
-
- if (file.delete_on_close ||
- (file.num_entries != 0 && delete_on_close)) {
- /* while delete on close is set, no new opens are allowed */
- return NT_STATUS_DELETE_PENDING;
- }
-
- /* check for sharing violations */
- for (i=0;i<file.num_entries;i++) {
- status = share_conflict(&file.entries[i], &e);
- NT_STATUS_NOT_OK_RETURN(status);
- }
-
- /* we now know the open could succeed, but we need to check
- for any exclusive oplocks. We can't grant a second open
- till these are broken. Note that we check for batch oplocks
- before checking for sharing violations, and check for
- exclusive oplocks afterwards. */
- for (i=0;i<file.num_entries;i++) {
- if (file.entries[i].oplock_level == OPLOCK_EXCLUSIVE) {
- odb_oplock_break_send(odb, &file.entries[i]);
- return NT_STATUS_OPLOCK_NOT_GRANTED;
- }
- }
+static NTSTATUS odb_ctdb_open_file(struct odb_lock *lck,
+ void *file_handle, const char *path,
+ int *fd, bool allow_level_II_oplock,
+ uint32_t oplock_level, uint32_t *oplock_granted)
+{
/*
- possibly grant an exclusive or batch oplock if this is the only client
- with the file open. We don't yet grant levelII oplocks.
- */
- if (oplock_granted != NULL) {
- if ((oplock_level == OPLOCK_BATCH ||
- oplock_level == OPLOCK_EXCLUSIVE) &&
- file.num_entries == 0) {
- (*oplock_granted) = oplock_level;
- } else {
- (*oplock_granted) = OPLOCK_NONE;
- }
- e.oplock_level = (*oplock_granted);
- }
-
- /* it doesn't conflict, so add it to the end */
- file.entries = talloc_realloc(lck, file.entries, struct opendb_entry,
- file.num_entries+1);
- NT_STATUS_HAVE_NO_MEMORY(file.entries);
-
- file.entries[file.num_entries] = e;
- file.num_entries++;
-
- return odb_push_record(lck, &file);
+ * as this file will went away and isn't used yet,
+ * copy the implementation from the tdb backend
+ * --metze
+ */
+ return NT_STATUS_FOOBAR;
}
/*
remove a opendb entry
*/
-static NTSTATUS odb_ctdb_close_file(struct odb_lock *lck, void *file_handle)
+static NTSTATUS odb_ctdb_close_file(struct odb_lock *lck, void *file_handle,
+ const char **_delete_path)
{
struct odb_context *odb = lck->odb;
struct opendb_file file;
+ const char *delete_path = NULL;
int i;
NTSTATUS status;
if (file_handle == file.entries[i].file_handle &&
cluster_id_equal(&odb->ntvfs_ctx->server_id, &file.entries[i].server)) {
if (file.entries[i].delete_on_close) {
- file.delete_on_close = True;
+ file.delete_on_close = true;
}
if (i < file.num_entries-1) {
memmove(file.entries+i, file.entries+i+1,
file.num_pending = 0;
file.num_entries--;
+
+ if (file.num_entries == 0 && file.delete_on_close) {
+ delete_path = talloc_strdup(lck, file.path);
+ NT_STATUS_HAVE_NO_MEMORY(delete_path);
+ }
+
+ if (_delete_path) {
+ *_delete_path = delete_path;
+ }
return odb_push_record(lck, &file);
}
+/*
+ update the oplock level of the client
+*/
+static NTSTATUS odb_ctdb_update_oplock(struct odb_lock *lck, void *file_handle,
+ uint32_t oplock_level)
+{
+ /*
+ * as this file will went away and isn't used yet,
+ * copy the implementation from the tdb backend
+ * --metze
+ */
+ return NT_STATUS_FOOBAR;
+}
+
+static NTSTATUS odb_ctdb_break_oplocks(struct odb_lock *lck)
+{
+ /*
+ * as this file will went away and isn't used yet,
+ * copy the implementation from the tdb backend
+ * --metze
+ */
+ return NT_STATUS_FOOBAR;
+}
/*
remove a pending opendb entry
return odb_push_record(lck, &file);
}
+/*
+ get the path of an open file
+*/
+static NTSTATUS odb_ctdb_get_path(struct odb_lock *lck, const char **path)
+{
+ struct opendb_file file;
+ NTSTATUS status;
+
+ *path = NULL;
+
+ status = odb_pull_record(lck, &file);
+ /* we don't ignore NT_STATUS_OBJECT_NAME_NOT_FOUND here */
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ *path = file.path;
+
+ return NT_STATUS_OK;
+}
+
/*
update delete on close flag on an open file
*/
-static NTSTATUS odb_ctdb_set_delete_on_close(struct odb_lock *lck, BOOL del_on_close)
+static NTSTATUS odb_ctdb_set_delete_on_close(struct odb_lock *lck, bool del_on_close)
{
NTSTATUS status;
struct opendb_file file;
people still have the file open
*/
static NTSTATUS odb_ctdb_get_delete_on_close(struct odb_context *odb,
- DATA_BLOB *key, BOOL *del_on_close,
- int *open_count, char **path)
+ DATA_BLOB *key, bool *del_on_close)
{
NTSTATUS status;
struct opendb_file file;
struct odb_lock *lck;
+ (*del_on_close) = false;
+
lck = odb_lock(odb, odb, key);
NT_STATUS_HAVE_NO_MEMORY(lck);
status = odb_pull_record(lck, &file);
if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
talloc_free(lck);
- (*del_on_close) = False;
return NT_STATUS_OK;
}
if (!NT_STATUS_IS_OK(status)) {
}
(*del_on_close) = file.delete_on_close;
- if (open_count != NULL) {
- (*open_count) = file.num_entries;
- }
- if (path != NULL) {
- *path = talloc_strdup(odb, file.path);
- NT_STATUS_HAVE_NO_MEMORY(*path);
- if (file.num_entries == 1 && file.entries[0].delete_on_close) {
- (*del_on_close) = True;
- }
- }
talloc_free(lck);
create_options and access_mask
*/
static NTSTATUS odb_ctdb_can_open(struct odb_lock *lck,
- uint32_t share_access, uint32_t create_options,
- uint32_t access_mask)
+ uint32_t stream_id, uint32_t share_access,
+ uint32_t access_mask, bool delete_on_close,
+ uint32_t open_disposition, bool break_to_none)
{
struct odb_context *odb = lck->odb;
NTSTATUS status;
}
NT_STATUS_NOT_OK_RETURN(status);
- if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
+ if (delete_on_close &&
file.num_entries != 0) {
return NT_STATUS_SHARING_VIOLATION;
}
static const struct opendb_ops opendb_ctdb_ops = {
.odb_init = odb_ctdb_init,
.odb_lock = odb_ctdb_lock,
+ .odb_get_key = odb_ctdb_get_key,
.odb_open_file = odb_ctdb_open_file,
.odb_open_file_pending = odb_ctdb_open_file_pending,
.odb_close_file = odb_ctdb_close_file,
.odb_remove_pending = odb_ctdb_remove_pending,
.odb_rename = odb_ctdb_rename,
+ .odb_get_path = odb_ctdb_get_path,
.odb_set_delete_on_close = odb_ctdb_set_delete_on_close,
.odb_get_delete_on_close = odb_ctdb_get_delete_on_close,
- .odb_can_open = odb_ctdb_can_open
+ .odb_can_open = odb_ctdb_can_open,
+ .odb_update_oplock = odb_ctdb_update_oplock,
+ .odb_break_oplocks = odb_ctdb_break_oplocks
};