opendb_tdb: keep struct opendb_file arround for the lifetime of struct odb_lock
[Samba/ekacnet.git] / source4 / ntvfs / common / opendb_tdb.c
blob17fcdfbbb452d96a5845599a8b9533f88ae3b161
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2004
5 Copyright (C) Stefan Metzmacher 2008
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 this is the open files database, tdb backend. It implements shared
23 storage of what files are open between server instances, and
24 implements the rules of shared access to files.
26 The caller needs to provide a file_key, which specifies what file
27 they are talking about. This needs to be a unique key across all
28 filesystems, and is usually implemented in terms of a device/inode
29 pair.
31 Before any operations can be performed the caller needs to establish
32 a lock on the record associated with file_key. That is done by
33 calling odb_lock(). The caller releases this lock by calling
34 talloc_free() on the returned handle.
36 All other operations on a record are done by passing the odb_lock()
37 handle back to this module. The handle contains internal
38 information about what file_key is being operated on.
41 #include "includes.h"
42 #include "system/filesys.h"
43 #include "lib/tdb/include/tdb.h"
44 #include "messaging/messaging.h"
45 #include "tdb_wrap.h"
46 #include "lib/messaging/irpc.h"
47 #include "librpc/gen_ndr/ndr_opendb.h"
48 #include "ntvfs/ntvfs.h"
49 #include "ntvfs/common/ntvfs_common.h"
50 #include "cluster/cluster.h"
51 #include "param/param.h"
53 struct odb_context {
54 struct tdb_wrap *w;
55 struct ntvfs_context *ntvfs_ctx;
56 bool oplocks;
60 an odb lock handle. You must obtain one of these using odb_lock() before doing
61 any other operations.
63 struct odb_lock {
64 struct odb_context *odb;
65 TDB_DATA key;
67 struct opendb_file file;
69 struct {
70 struct opendb_entry *e;
71 bool attrs_only;
72 } can_open;
76 Open up the openfiles.tdb database. Close it down using
77 talloc_free(). We need the messaging_ctx to allow for pending open
78 notifications.
80 static struct odb_context *odb_tdb_init(TALLOC_CTX *mem_ctx,
81 struct ntvfs_context *ntvfs_ctx)
83 struct odb_context *odb;
85 odb = talloc(mem_ctx, struct odb_context);
86 if (odb == NULL) {
87 return NULL;
90 odb->w = cluster_tdb_tmp_open(odb, ntvfs_ctx->lp_ctx, "openfiles.tdb", TDB_DEFAULT);
91 if (odb->w == NULL) {
92 talloc_free(odb);
93 return NULL;
96 odb->ntvfs_ctx = ntvfs_ctx;
98 /* leave oplocks disabled by default until the code is working */
99 odb->oplocks = lp_parm_bool(ntvfs_ctx->lp_ctx, NULL, "opendb", "oplocks", false);
101 return odb;
105 destroy a lock on the database
107 static int odb_lock_destructor(struct odb_lock *lck)
109 tdb_chainunlock(lck->odb->w->tdb, lck->key);
110 return 0;
113 static NTSTATUS odb_pull_record(struct odb_lock *lck, struct opendb_file *file);
116 get a lock on a entry in the odb. This call returns a lock handle,
117 which the caller should unlock using talloc_free().
119 static struct odb_lock *odb_tdb_lock(TALLOC_CTX *mem_ctx,
120 struct odb_context *odb, DATA_BLOB *file_key)
122 struct odb_lock *lck;
123 NTSTATUS status;
125 lck = talloc(mem_ctx, struct odb_lock);
126 if (lck == NULL) {
127 return NULL;
130 lck->odb = talloc_reference(lck, odb);
131 lck->key.dptr = talloc_memdup(lck, file_key->data, file_key->length);
132 lck->key.dsize = file_key->length;
133 if (lck->key.dptr == NULL) {
134 talloc_free(lck);
135 return NULL;
138 if (tdb_chainlock(odb->w->tdb, lck->key) != 0) {
139 talloc_free(lck);
140 return NULL;
143 ZERO_STRUCT(lck->can_open);
145 talloc_set_destructor(lck, odb_lock_destructor);
147 status = odb_pull_record(lck, &lck->file);
148 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
149 /* initialise a blank structure */
150 ZERO_STRUCT(lck->file);
151 } else if (!NT_STATUS_IS_OK(status)) {
152 talloc_free(lck);
153 return NULL;
156 return lck;
159 static DATA_BLOB odb_tdb_get_key(TALLOC_CTX *mem_ctx, struct odb_lock *lck)
161 return data_blob_talloc(mem_ctx, lck->key.dptr, lck->key.dsize);
166 determine if two odb_entry structures conflict
168 return NT_STATUS_OK on no conflict
170 static NTSTATUS share_conflict(struct opendb_entry *e1,
171 uint32_t stream_id,
172 uint32_t share_access,
173 uint32_t access_mask)
175 /* if either open involves no read.write or delete access then
176 it can't conflict */
177 if (!(e1->access_mask & (SEC_FILE_WRITE_DATA |
178 SEC_FILE_APPEND_DATA |
179 SEC_FILE_READ_DATA |
180 SEC_FILE_EXECUTE |
181 SEC_STD_DELETE))) {
182 return NT_STATUS_OK;
184 if (!(access_mask & (SEC_FILE_WRITE_DATA |
185 SEC_FILE_APPEND_DATA |
186 SEC_FILE_READ_DATA |
187 SEC_FILE_EXECUTE |
188 SEC_STD_DELETE))) {
189 return NT_STATUS_OK;
192 /* data IO access masks. This is skipped if the two open handles
193 are on different streams (as in that case the masks don't
194 interact) */
195 if (e1->stream_id != stream_id) {
196 return NT_STATUS_OK;
199 #define CHECK_MASK(am, right, sa, share) \
200 if (((am) & (right)) && !((sa) & (share))) return NT_STATUS_SHARING_VIOLATION
202 CHECK_MASK(e1->access_mask, SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA,
203 share_access, NTCREATEX_SHARE_ACCESS_WRITE);
204 CHECK_MASK(access_mask, SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA,
205 e1->share_access, NTCREATEX_SHARE_ACCESS_WRITE);
207 CHECK_MASK(e1->access_mask, SEC_FILE_READ_DATA | SEC_FILE_EXECUTE,
208 share_access, NTCREATEX_SHARE_ACCESS_READ);
209 CHECK_MASK(access_mask, SEC_FILE_READ_DATA | SEC_FILE_EXECUTE,
210 e1->share_access, NTCREATEX_SHARE_ACCESS_READ);
212 CHECK_MASK(e1->access_mask, SEC_STD_DELETE,
213 share_access, NTCREATEX_SHARE_ACCESS_DELETE);
214 CHECK_MASK(access_mask, SEC_STD_DELETE,
215 e1->share_access, NTCREATEX_SHARE_ACCESS_DELETE);
216 #undef CHECK_MASK
217 return NT_STATUS_OK;
221 pull a record, translating from the db format to the opendb_file structure defined
222 in opendb.idl
224 static NTSTATUS odb_pull_record(struct odb_lock *lck, struct opendb_file *file)
226 struct odb_context *odb = lck->odb;
227 TDB_DATA dbuf;
228 DATA_BLOB blob;
229 enum ndr_err_code ndr_err;
231 dbuf = tdb_fetch(odb->w->tdb, lck->key);
232 if (dbuf.dptr == NULL) {
233 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
236 blob.data = dbuf.dptr;
237 blob.length = dbuf.dsize;
239 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);
240 free(dbuf.dptr);
241 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
242 return ndr_map_error2ntstatus(ndr_err);
245 return NT_STATUS_OK;
249 push a record, translating from the opendb_file structure defined in opendb.idl
251 static NTSTATUS odb_push_record(struct odb_lock *lck, struct opendb_file *file)
253 struct odb_context *odb = lck->odb;
254 TDB_DATA dbuf;
255 DATA_BLOB blob;
256 enum ndr_err_code ndr_err;
257 int ret;
259 if (file->num_entries == 0) {
260 ret = tdb_delete(odb->w->tdb, lck->key);
261 if (ret != 0) {
262 return NT_STATUS_INTERNAL_DB_CORRUPTION;
264 return NT_STATUS_OK;
267 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);
268 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
269 return ndr_map_error2ntstatus(ndr_err);
272 dbuf.dptr = blob.data;
273 dbuf.dsize = blob.length;
275 ret = tdb_store(odb->w->tdb, lck->key, dbuf, TDB_REPLACE);
276 data_blob_free(&blob);
277 if (ret != 0) {
278 return NT_STATUS_INTERNAL_DB_CORRUPTION;
281 return NT_STATUS_OK;
285 send an oplock break to a client
287 static NTSTATUS odb_oplock_break_send(struct messaging_context *msg_ctx,
288 struct opendb_entry *e,
289 uint8_t level)
291 NTSTATUS status;
292 struct opendb_oplock_break op_break;
293 DATA_BLOB blob;
295 ZERO_STRUCT(op_break);
297 /* tell the server handling this open file about the need to send the client
298 a break */
299 op_break.file_handle = e->file_handle;
300 op_break.level = level;
302 blob = data_blob_const(&op_break, sizeof(op_break));
304 status = messaging_send(msg_ctx, e->server,
305 MSG_NTVFS_OPLOCK_BREAK, &blob);
306 NT_STATUS_NOT_OK_RETURN(status);
308 return NT_STATUS_OK;
311 static bool access_attributes_only(uint32_t access_mask,
312 uint32_t open_disposition,
313 bool break_to_none)
315 switch (open_disposition) {
316 case NTCREATEX_DISP_SUPERSEDE:
317 case NTCREATEX_DISP_OVERWRITE_IF:
318 case NTCREATEX_DISP_OVERWRITE:
319 return false;
320 default:
321 break;
324 if (break_to_none) {
325 return false;
328 #define CHECK_MASK(m,g) ((m) && (((m) & ~(g))==0) && (((m) & (g)) != 0))
329 return CHECK_MASK(access_mask,
330 SEC_STD_SYNCHRONIZE |
331 SEC_FILE_READ_ATTRIBUTE |
332 SEC_FILE_WRITE_ATTRIBUTE);
333 #undef CHECK_MASK
336 static NTSTATUS odb_tdb_open_can_internal(struct odb_context *odb,
337 const struct opendb_file *file,
338 uint32_t stream_id, uint32_t share_access,
339 uint32_t access_mask, bool delete_on_close,
340 uint32_t open_disposition, bool break_to_none,
341 bool *_attrs_only)
343 NTSTATUS status;
344 uint32_t i;
345 bool attrs_only = false;
347 /* see if anyone has an oplock, which we need to break */
348 for (i=0;i<file->num_entries;i++) {
349 if (file->entries[i].oplock_level == OPLOCK_BATCH) {
350 bool oplock_return = OPLOCK_BREAK_TO_LEVEL_II;
351 /* if this is an attribute only access
352 * it doesn't conflict with a BACTCH oplock
353 * but we'll not grant the oplock below
355 attrs_only = access_attributes_only(access_mask,
356 open_disposition,
357 break_to_none);
358 if (attrs_only) {
359 break;
361 /* a batch oplock caches close calls, which
362 means the client application might have
363 already closed the file. We have to allow
364 this close to propogate by sending a oplock
365 break request and suspending this call
366 until the break is acknowledged or the file
367 is closed */
368 if (break_to_none ||
369 !file->entries[i].allow_level_II_oplock) {
370 oplock_return = OPLOCK_BREAK_TO_NONE;
372 odb_oplock_break_send(odb->ntvfs_ctx->msg_ctx,
373 &file->entries[i],
374 oplock_return);
375 return NT_STATUS_OPLOCK_NOT_GRANTED;
379 if (file->delete_on_close) {
380 /* while delete on close is set, no new opens are allowed */
381 return NT_STATUS_DELETE_PENDING;
384 if (file->num_entries != 0 && delete_on_close) {
385 return NT_STATUS_SHARING_VIOLATION;
388 /* check for sharing violations */
389 for (i=0;i<file->num_entries;i++) {
390 status = share_conflict(&file->entries[i], stream_id,
391 share_access, access_mask);
392 NT_STATUS_NOT_OK_RETURN(status);
395 /* we now know the open could succeed, but we need to check
396 for any exclusive oplocks. We can't grant a second open
397 till these are broken. Note that we check for batch oplocks
398 before checking for sharing violations, and check for
399 exclusive oplocks afterwards. */
400 for (i=0;i<file->num_entries;i++) {
401 if (file->entries[i].oplock_level == OPLOCK_EXCLUSIVE) {
402 bool oplock_return = OPLOCK_BREAK_TO_LEVEL_II;
403 /* if this is an attribute only access
404 * it doesn't conflict with an EXCLUSIVE oplock
405 * but we'll not grant the oplock below
407 attrs_only = access_attributes_only(access_mask,
408 open_disposition,
409 break_to_none);
410 if (attrs_only) {
411 break;
414 * send an oplock break to the holder of the
415 * oplock and tell caller to retry later
417 if (break_to_none ||
418 !file->entries[i].allow_level_II_oplock) {
419 oplock_return = OPLOCK_BREAK_TO_NONE;
421 odb_oplock_break_send(odb->ntvfs_ctx->msg_ctx,
422 &file->entries[i],
423 oplock_return);
424 return NT_STATUS_OPLOCK_NOT_GRANTED;
428 if (_attrs_only) {
429 *_attrs_only = attrs_only;
431 return NT_STATUS_OK;
435 register an open file in the open files database.
436 The share_access rules are implemented by odb_can_open()
437 and it's needed to call odb_can_open() before
438 odb_open_file() otherwise NT_STATUS_INTERNAL_ERROR is returned
440 Note that the path is only used by the delete on close logic, not
441 for comparing with other filenames
443 static NTSTATUS odb_tdb_open_file(struct odb_lock *lck,
444 void *file_handle, const char *path,
445 bool allow_level_II_oplock,
446 uint32_t oplock_level, uint32_t *oplock_granted)
448 struct odb_context *odb = lck->odb;
450 if (!lck->can_open.e) {
451 return NT_STATUS_INTERNAL_ERROR;
454 if (odb->oplocks == false) {
455 oplock_level = OPLOCK_NONE;
458 if (!oplock_granted) {
459 oplock_level = OPLOCK_NONE;
462 if (lck->file.path == NULL) {
463 lck->file.path = talloc_strdup(lck, path);
464 NT_STATUS_HAVE_NO_MEMORY(lck->file.path);
468 possibly grant an exclusive, batch or level2 oplock
470 if (lck->can_open.attrs_only) {
471 oplock_level = OPLOCK_NONE;
472 } else if (oplock_level == OPLOCK_EXCLUSIVE) {
473 if (lck->file.num_entries == 0) {
474 oplock_level = OPLOCK_EXCLUSIVE;
475 } else if (allow_level_II_oplock) {
476 oplock_level = OPLOCK_LEVEL_II;
477 } else {
478 oplock_level = OPLOCK_NONE;
480 } else if (oplock_level == OPLOCK_BATCH) {
481 if (lck->file.num_entries == 0) {
482 oplock_level = OPLOCK_BATCH;
483 } else if (allow_level_II_oplock) {
484 oplock_level = OPLOCK_LEVEL_II;
485 } else {
486 oplock_level = OPLOCK_NONE;
488 } else if (oplock_level == OPLOCK_LEVEL_II) {
489 oplock_level = OPLOCK_LEVEL_II;
490 } else {
491 oplock_level = OPLOCK_NONE;
494 if (oplock_granted) {
495 if (oplock_level == OPLOCK_EXCLUSIVE) {
496 *oplock_granted = EXCLUSIVE_OPLOCK_RETURN;
497 } else if (oplock_level == OPLOCK_BATCH) {
498 *oplock_granted = BATCH_OPLOCK_RETURN;
499 } else if (oplock_level == OPLOCK_LEVEL_II) {
500 *oplock_granted = LEVEL_II_OPLOCK_RETURN;
501 } else {
502 *oplock_granted = NO_OPLOCK_RETURN;
506 lck->can_open.e->file_handle = file_handle;
507 lck->can_open.e->allow_level_II_oplock = allow_level_II_oplock;
508 lck->can_open.e->oplock_level = oplock_level;
510 /* it doesn't conflict, so add it to the end */
511 lck->file.entries = talloc_realloc(lck, lck->file.entries,
512 struct opendb_entry,
513 lck->file.num_entries+1);
514 NT_STATUS_HAVE_NO_MEMORY(lck->file.entries);
516 lck->file.entries[lck->file.num_entries] = *lck->can_open.e;
517 lck->file.num_entries++;
519 talloc_free(lck->can_open.e);
520 lck->can_open.e = NULL;
522 return odb_push_record(lck, &lck->file);
527 register a pending open file in the open files database
529 static NTSTATUS odb_tdb_open_file_pending(struct odb_lock *lck, void *private)
531 struct odb_context *odb = lck->odb;
533 if (lck->file.path == NULL) {
534 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
537 lck->file.pending = talloc_realloc(lck, lck->file.pending,
538 struct opendb_pending,
539 lck->file.num_pending+1);
540 NT_STATUS_HAVE_NO_MEMORY(lck->file.pending);
542 lck->file.pending[lck->file.num_pending].server = odb->ntvfs_ctx->server_id;
543 lck->file.pending[lck->file.num_pending].notify_ptr = private;
545 lck->file.num_pending++;
547 return odb_push_record(lck, &lck->file);
552 remove a opendb entry
554 static NTSTATUS odb_tdb_close_file(struct odb_lock *lck, void *file_handle,
555 const char **_delete_path)
557 struct odb_context *odb = lck->odb;
558 const char *delete_path = NULL;
559 int i;
561 if (lck->file.path == NULL) {
562 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
565 /* find the entry, and delete it */
566 for (i=0;i<lck->file.num_entries;i++) {
567 if (file_handle == lck->file.entries[i].file_handle &&
568 cluster_id_equal(&odb->ntvfs_ctx->server_id, &lck->file.entries[i].server)) {
569 if (lck->file.entries[i].delete_on_close) {
570 lck->file.delete_on_close = true;
572 if (i < lck->file.num_entries-1) {
573 memmove(lck->file.entries+i, lck->file.entries+i+1,
574 (lck->file.num_entries - (i+1)) *
575 sizeof(struct opendb_entry));
577 break;
581 if (i == lck->file.num_entries) {
582 return NT_STATUS_UNSUCCESSFUL;
585 /* send any pending notifications, removing them once sent */
586 for (i=0;i<lck->file.num_pending;i++) {
587 messaging_send_ptr(odb->ntvfs_ctx->msg_ctx,
588 lck->file.pending[i].server,
589 MSG_PVFS_RETRY_OPEN,
590 lck->file.pending[i].notify_ptr);
592 lck->file.num_pending = 0;
594 lck->file.num_entries--;
596 if (lck->file.num_entries == 0 && lck->file.delete_on_close) {
597 delete_path = lck->file.path;
600 if (_delete_path) {
601 *_delete_path = delete_path;
604 return odb_push_record(lck, &lck->file);
608 update the oplock level of the client
610 static NTSTATUS odb_tdb_update_oplock(struct odb_lock *lck, void *file_handle,
611 uint32_t oplock_level)
613 struct odb_context *odb = lck->odb;
614 int i;
616 if (lck->file.path == NULL) {
617 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
620 /* find the entry, and update it */
621 for (i=0;i<lck->file.num_entries;i++) {
622 if (file_handle == lck->file.entries[i].file_handle &&
623 cluster_id_equal(&odb->ntvfs_ctx->server_id, &lck->file.entries[i].server)) {
624 lck->file.entries[i].oplock_level = oplock_level;
625 break;
629 if (i == lck->file.num_entries) {
630 return NT_STATUS_UNSUCCESSFUL;
633 /* send any pending notifications, removing them once sent */
634 for (i=0;i<lck->file.num_pending;i++) {
635 messaging_send_ptr(odb->ntvfs_ctx->msg_ctx,
636 lck->file.pending[i].server,
637 MSG_PVFS_RETRY_OPEN,
638 lck->file.pending[i].notify_ptr);
640 lck->file.num_pending = 0;
642 return odb_push_record(lck, &lck->file);
646 send oplocks breaks to none to all level2 holders
648 static NTSTATUS odb_tdb_break_oplocks(struct odb_lock *lck)
650 struct odb_context *odb = lck->odb;
651 int i;
652 bool modified = false;
654 /* see if anyone has an oplock, which we need to break */
655 for (i=0;i<lck->file.num_entries;i++) {
656 if (lck->file.entries[i].oplock_level == OPLOCK_LEVEL_II) {
658 * there could be multiple level2 oplocks
659 * and we just send a break to none to all of them
660 * without waiting for a release
662 odb_oplock_break_send(odb->ntvfs_ctx->msg_ctx,
663 &lck->file.entries[i],
664 OPLOCK_BREAK_TO_NONE);
665 lck->file.entries[i].oplock_level = OPLOCK_NONE;
666 modified = true;
670 if (modified) {
671 return odb_push_record(lck, &lck->file);
673 return NT_STATUS_OK;
677 remove a pending opendb entry
679 static NTSTATUS odb_tdb_remove_pending(struct odb_lock *lck, void *private)
681 struct odb_context *odb = lck->odb;
682 int i;
684 if (lck->file.path == NULL) {
685 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
688 /* find the entry, and delete it */
689 for (i=0;i<lck->file.num_pending;i++) {
690 if (private == lck->file.pending[i].notify_ptr &&
691 cluster_id_equal(&odb->ntvfs_ctx->server_id, &lck->file.pending[i].server)) {
692 if (i < lck->file.num_pending-1) {
693 memmove(lck->file.pending+i, lck->file.pending+i+1,
694 (lck->file.num_pending - (i+1)) *
695 sizeof(struct opendb_pending));
697 break;
701 if (i == lck->file.num_pending) {
702 return NT_STATUS_UNSUCCESSFUL;
705 lck->file.num_pending--;
707 return odb_push_record(lck, &lck->file);
712 rename the path in a open file
714 static NTSTATUS odb_tdb_rename(struct odb_lock *lck, const char *path)
716 if (lck->file.path == NULL) {
717 /* not having the record at all is OK */
718 return NT_STATUS_OK;
721 lck->file.path = talloc_strdup(lck, path);
722 NT_STATUS_HAVE_NO_MEMORY(lck->file.path);
724 return odb_push_record(lck, &lck->file);
728 get the path of an open file
730 static NTSTATUS odb_tdb_get_path(struct odb_lock *lck, const char **path)
732 *path = NULL;
734 /* we don't ignore NT_STATUS_OBJECT_NAME_NOT_FOUND here */
735 if (lck->file.path == NULL) {
736 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
739 *path = lck->file.path;
741 return NT_STATUS_OK;
745 update delete on close flag on an open file
747 static NTSTATUS odb_tdb_set_delete_on_close(struct odb_lock *lck, bool del_on_close)
749 if (lck->file.path == NULL) {
750 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
753 lck->file.delete_on_close = del_on_close;
755 return odb_push_record(lck, &lck->file);
759 return the current value of the delete_on_close bit, and how many
760 people still have the file open
762 static NTSTATUS odb_tdb_get_delete_on_close(struct odb_context *odb,
763 DATA_BLOB *key, bool *del_on_close)
765 struct odb_lock *lck;
767 (*del_on_close) = false;
769 lck = odb_lock(odb, odb, key);
770 NT_STATUS_HAVE_NO_MEMORY(lck);
772 (*del_on_close) = lck->file.delete_on_close;
774 talloc_free(lck);
776 return NT_STATUS_OK;
781 determine if a file can be opened with the given share_access,
782 create_options and access_mask
784 static NTSTATUS odb_tdb_can_open(struct odb_lock *lck,
785 uint32_t stream_id, uint32_t share_access,
786 uint32_t access_mask, bool delete_on_close,
787 uint32_t open_disposition, bool break_to_none)
789 struct odb_context *odb = lck->odb;
790 NTSTATUS status;
792 status = odb_tdb_open_can_internal(odb, &lck->file, stream_id,
793 share_access, access_mask,
794 delete_on_close, open_disposition,
795 break_to_none, &lck->can_open.attrs_only);
796 NT_STATUS_NOT_OK_RETURN(status);
798 lck->can_open.e = talloc(lck, struct opendb_entry);
799 NT_STATUS_HAVE_NO_MEMORY(lck->can_open.e);
801 lck->can_open.e->server = odb->ntvfs_ctx->server_id;
802 lck->can_open.e->file_handle = NULL;
803 lck->can_open.e->stream_id = stream_id;
804 lck->can_open.e->share_access = share_access;
805 lck->can_open.e->access_mask = access_mask;
806 lck->can_open.e->delete_on_close = delete_on_close;
807 lck->can_open.e->allow_level_II_oplock = false;
808 lck->can_open.e->oplock_level = OPLOCK_NONE;
810 return NT_STATUS_OK;
814 static const struct opendb_ops opendb_tdb_ops = {
815 .odb_init = odb_tdb_init,
816 .odb_lock = odb_tdb_lock,
817 .odb_get_key = odb_tdb_get_key,
818 .odb_open_file = odb_tdb_open_file,
819 .odb_open_file_pending = odb_tdb_open_file_pending,
820 .odb_close_file = odb_tdb_close_file,
821 .odb_remove_pending = odb_tdb_remove_pending,
822 .odb_rename = odb_tdb_rename,
823 .odb_get_path = odb_tdb_get_path,
824 .odb_set_delete_on_close = odb_tdb_set_delete_on_close,
825 .odb_get_delete_on_close = odb_tdb_get_delete_on_close,
826 .odb_can_open = odb_tdb_can_open,
827 .odb_update_oplock = odb_tdb_update_oplock,
828 .odb_break_oplocks = odb_tdb_break_oplocks
832 void odb_tdb_init_ops(void)
834 odb_set_ops(&opendb_tdb_ops);