*/
#include "includes.h"
+#include "messages.h"
+#include "librpc/gen_ndr/ndr_security.h"
struct odb_context {
struct tdb_wrap *w;
- servid_t server;
- uint16_t tid;
+ uint32_t server;
struct messaging_context *messaging_ctx;
};
following form
*/
struct odb_entry {
- servid_t server;
- uint16_t tid;
- uint16_t fnum;
+ uint32_t server;
+ void *file_handle;
+ uint32_t stream_id;
uint32_t share_access;
uint32_t create_options;
uint32_t access_mask;
+ void *notify_ptr;
+ BOOL pending;
};
talloc_free(). We need the messaging_ctx to allow for pending open
notifications.
*/
-struct odb_context *odb_init(TALLOC_CTX *mem_ctx, servid_t server, uint16_t tid,
+struct odb_context *odb_init(TALLOC_CTX *mem_ctx, uint32_t server,
struct messaging_context *messaging_ctx)
{
char *path;
struct odb_context *odb;
- odb = talloc_p(mem_ctx, struct odb_context);
+ odb = talloc(mem_ctx, struct odb_context);
if (odb == NULL) {
return NULL;
}
- path = lock_path(odb, "openfiles.tdb");
+ path = smbd_tmp_path(odb, "openfiles.tdb");
odb->w = tdb_wrap_open(odb, path, 0,
TDB_DEFAULT,
O_RDWR|O_CREAT, 0600);
}
odb->server = server;
- odb->tid = tid;
odb->messaging_ctx = messaging_ctx;
return odb;
{
struct odb_lock *lck;
- lck = talloc_p(mem_ctx, struct odb_lock);
+ lck = talloc(mem_ctx, struct odb_lock);
if (lck == NULL) {
return NULL;
}
- lck->odb = odb;
+ lck->odb = talloc_reference(lck, odb);
lck->key.dptr = talloc_memdup(lck, file_key->data, file_key->length);
lck->key.dsize = file_key->length;
if (lck->key.dptr == NULL) {
{
#define CHECK_MASK(am, sa, right, share) if (((am) & (right)) && !((sa) & (share))) return True
+ if (e1->pending || e2->pending) return False;
+
/* if either open involves no read.write or delete access then
it can't conflict */
- if (!(e1->access_mask & (SA_RIGHT_FILE_WRITE_DATA | SA_RIGHT_FILE_READ_DATA | STD_RIGHT_DELETE_ACCESS))) {
+ if (!(e1->access_mask & (SEC_FILE_WRITE_DATA |
+ SEC_FILE_APPEND_DATA |
+ SEC_FILE_READ_DATA |
+ SEC_FILE_EXECUTE |
+ SEC_STD_DELETE))) {
return False;
}
- if (!(e2->access_mask & (SA_RIGHT_FILE_WRITE_DATA | SA_RIGHT_FILE_READ_DATA | STD_RIGHT_DELETE_ACCESS))) {
+ if (!(e2->access_mask & (SEC_FILE_WRITE_DATA |
+ SEC_FILE_APPEND_DATA |
+ SEC_FILE_READ_DATA |
+ SEC_FILE_EXECUTE |
+ SEC_STD_DELETE))) {
return False;
}
- /* check the basic share access */
- CHECK_MASK(e1->access_mask, e2->share_access, SA_RIGHT_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE);
- CHECK_MASK(e2->access_mask, e1->share_access, SA_RIGHT_FILE_WRITE_DATA, NTCREATEX_SHARE_ACCESS_WRITE);
-
- CHECK_MASK(e1->access_mask, e2->share_access, SA_RIGHT_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ);
- CHECK_MASK(e2->access_mask, e1->share_access, SA_RIGHT_FILE_READ_DATA, NTCREATEX_SHARE_ACCESS_READ);
+ /* data IO access masks. This is skipped if the two open handles
+ are on different streams (as in that case the masks don't
+ interact) */
+ if (e1->stream_id != e2->stream_id) {
+ return False;
+ }
- CHECK_MASK(e1->access_mask, e2->share_access, STD_RIGHT_DELETE_ACCESS, NTCREATEX_SHARE_ACCESS_DELETE);
- CHECK_MASK(e2->access_mask, e1->share_access, STD_RIGHT_DELETE_ACCESS, NTCREATEX_SHARE_ACCESS_DELETE);
+ CHECK_MASK(e1->access_mask, e2->share_access,
+ SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA,
+ NTCREATEX_SHARE_ACCESS_WRITE);
+ CHECK_MASK(e2->access_mask, e1->share_access,
+ SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA,
+ NTCREATEX_SHARE_ACCESS_WRITE);
+
+ CHECK_MASK(e1->access_mask, e2->share_access,
+ SEC_FILE_READ_DATA | SEC_FILE_EXECUTE,
+ NTCREATEX_SHARE_ACCESS_READ);
+ CHECK_MASK(e2->access_mask, e1->share_access,
+ SEC_FILE_READ_DATA | SEC_FILE_EXECUTE,
+ NTCREATEX_SHARE_ACCESS_READ);
+
+ CHECK_MASK(e1->access_mask, e2->share_access,
+ SEC_STD_DELETE,
+ NTCREATEX_SHARE_ACCESS_DELETE);
+ CHECK_MASK(e2->access_mask, e1->share_access,
+ SEC_STD_DELETE,
+ NTCREATEX_SHARE_ACCESS_DELETE);
/* if a delete is pending then a second open is not allowed */
if ((e1->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) ||
register an open file in the open files database. This implements the share_access
rules
*/
-NTSTATUS odb_open_file(struct odb_lock *lck, uint16_t fnum,
+NTSTATUS odb_open_file(struct odb_lock *lck, void *file_handle,
+ uint32_t stream_id,
uint32_t share_access, uint32_t create_options,
uint32_t access_mask)
{
struct odb_context *odb = lck->odb;
TDB_DATA dbuf;
struct odb_entry e;
- char *tp;
int i, count;
struct odb_entry *elist;
dbuf = tdb_fetch(odb->w->tdb, lck->key);
e.server = odb->server;
- e.tid = odb->tid;
- e.fnum = fnum;
+ e.file_handle = file_handle;
+ e.stream_id = stream_id;
e.share_access = share_access;
e.create_options = create_options;
e.access_mask = access_mask;
+ e.notify_ptr = NULL;
+ e.pending = False;
/* check the existing file opens to see if they
conflict */
}
}
- tp = Realloc(dbuf.dptr, (count+1) * sizeof(struct odb_entry));
- if (tp == NULL) {
+ elist = realloc_p(dbuf.dptr, struct odb_entry, count+1);
+ if (elist == NULL) {
if (dbuf.dptr) free(dbuf.dptr);
return NT_STATUS_NO_MEMORY;
}
- dbuf.dptr = tp;
+ dbuf.dptr = (char *)elist;
+ dbuf.dsize = (count+1) * sizeof(struct odb_entry);
+
+ memcpy(dbuf.dptr + (count*sizeof(struct odb_entry)),
+ &e, sizeof(struct odb_entry));
+
+ if (tdb_store(odb->w->tdb, lck->key, dbuf, TDB_REPLACE) != 0) {
+ free(dbuf.dptr);
+ return NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+
+ free(dbuf.dptr);
+ return NT_STATUS_OK;
+}
+
+
+/*
+ register a pending open file in the open files database
+*/
+NTSTATUS odb_open_file_pending(struct odb_lock *lck, void *private)
+{
+ struct odb_context *odb = lck->odb;
+ TDB_DATA dbuf;
+ struct odb_entry e;
+ struct odb_entry *elist;
+ int count;
+
+ dbuf = tdb_fetch(odb->w->tdb, lck->key);
+
+ e.server = odb->server;
+ e.file_handle = NULL;
+ e.stream_id = 0;
+ e.share_access = 0;
+ e.create_options = 0;
+ e.access_mask = 0;
+ e.notify_ptr = private;
+ e.pending = True;
+
+ /* check the existing file opens to see if they
+ conflict */
+ elist = (struct odb_entry *)dbuf.dptr;
+ count = dbuf.dsize / sizeof(struct odb_entry);
+
+ elist = realloc_p(dbuf.dptr, struct odb_entry, count+1);
+ if (elist == NULL) {
+ if (dbuf.dptr) free(dbuf.dptr);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ dbuf.dptr = (char *)elist;
dbuf.dsize = (count+1) * sizeof(struct odb_entry);
memcpy(dbuf.dptr + (count*sizeof(struct odb_entry)),
/*
remove a opendb entry
*/
-NTSTATUS odb_close_file(struct odb_lock *lck, uint16_t fnum)
+NTSTATUS odb_close_file(struct odb_lock *lck, void *file_handle)
+{
+ struct odb_context *odb = lck->odb;
+ TDB_DATA dbuf;
+ struct odb_entry *elist;
+ int i, count;
+ NTSTATUS status;
+
+ dbuf = tdb_fetch(odb->w->tdb, lck->key);
+
+ if (dbuf.dptr == NULL) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ elist = (struct odb_entry *)dbuf.dptr;
+ count = dbuf.dsize / sizeof(struct odb_entry);
+
+ /* send any pending notifications, removing them once sent */
+ for (i=0;i<count;i++) {
+ if (elist[i].pending) {
+ messaging_send_ptr(odb->messaging_ctx, elist[i].server,
+ MSG_PVFS_RETRY_OPEN, elist[i].notify_ptr);
+ memmove(&elist[i], &elist[i+1], sizeof(struct odb_entry)*(count-(i+1)));
+ i--;
+ count--;
+ }
+ }
+
+ /* find the entry, and delete it */
+ for (i=0;i<count;i++) {
+ if (file_handle == elist[i].file_handle &&
+ odb->server == elist[i].server) {
+ if (i < count-1) {
+ memmove(elist+i, elist+i+1,
+ (count - (i+1)) * sizeof(struct odb_entry));
+ }
+ break;
+ }
+ }
+
+ status = NT_STATUS_OK;
+
+ if (i == count) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ } else if (count == 1) {
+ if (tdb_delete(odb->w->tdb, lck->key) != 0) {
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ } else {
+ dbuf.dsize = (count-1) * sizeof(struct odb_entry);
+ if (tdb_store(odb->w->tdb, lck->key, dbuf, TDB_REPLACE) != 0) {
+ status = NT_STATUS_INTERNAL_DB_CORRUPTION;
+ }
+ }
+
+ free(dbuf.dptr);
+
+ return status;
+}
+
+
+/*
+ remove a pending opendb entry
+*/
+NTSTATUS odb_remove_pending(struct odb_lock *lck, void *private)
{
struct odb_context *odb = lck->odb;
TDB_DATA dbuf;
/* find the entry, and delete it */
for (i=0;i<count;i++) {
- if (fnum == elist[i].fnum &&
- odb->server == elist[i].server &&
- odb->tid == elist[i].tid) {
+ if (private == elist[i].notify_ptr &&
+ odb->server == elist[i].server) {
if (i < count-1) {
memmove(elist+i, elist+i+1,
(count - (i+1)) * sizeof(struct odb_entry));
update create options on an open file
*/
NTSTATUS odb_set_create_options(struct odb_lock *lck,
- uint16_t fnum, uint32_t create_options)
+ void *file_handle, uint32_t create_options)
{
struct odb_context *odb = lck->odb;
TDB_DATA dbuf;
/* find the entry, and modify it */
for (i=0;i<count;i++) {
- if (fnum == elist[i].fnum &&
- odb->server == elist[i].server &&
- odb->tid == elist[i].tid) {
+ if (file_handle == elist[i].file_handle &&
+ odb->server == elist[i].server) {
elist[i].create_options = create_options;
break;
}
int i, count;
struct odb_entry e;
- kbuf.dptr = key->data;
+ kbuf.dptr = (char *)key->data;
kbuf.dsize = key->length;
dbuf = tdb_fetch(odb->w->tdb, kbuf);
}
e.server = odb->server;
- e.tid = odb->tid;
- e.fnum = -1;
+ e.file_handle = NULL;
+ e.stream_id = 0;
e.share_access = share_access;
e.create_options = create_options;
e.access_mask = access_mask;
+ e.notify_ptr = NULL;
+ e.pending = False;
for (i=0;i<count;i++) {
if (share_conflict(elist+i, &e)) {