mirror of
https://github.com/samba-team/samba.git
synced 2025-01-22 22:04:08 +03:00
s3:locking: Change the data model for leases_db to cope with dynamic path renames.
interface leases_db { typedef [public] struct { GUID client_guid; smb2_lease_key lease_key; } leases_db_key; typedef [public] struct { file_id id; [string,charset(UTF8)] char *servicepath; [string,charset(UTF8)] char *base_name; [string,charset(UTF8)] char *stream_name; } leases_db_file; typedef [public] struct { uint32 num_files; [size_is(num_files)] leases_db_file files[]; } leases_db_value; } As designed by metze. Signed-off-by: Jeremy Allison <jra@samba.org> Reviewed-by: Stefan Metzmacher <metze@samba.org> Autobuild-User(master): Jeremy Allison <jra@samba.org> Autobuild-Date(master): Tue Dec 9 03:44:04 CET 2014 on sn-devel-104
This commit is contained in:
parent
708f87b79d
commit
5ebb190385
@ -22,9 +22,7 @@ interface leases_db
|
||||
} leases_db_file;
|
||||
|
||||
typedef [public] struct {
|
||||
uint32 num_file_ids;
|
||||
[size_is(num_file_ids)] file_id ids[];
|
||||
[string,charset(UTF8)] char *filename;
|
||||
[string,charset(UTF8)] char *stream_name;
|
||||
uint32 num_files;
|
||||
[size_is(num_files)] leases_db_file files[];
|
||||
} leases_db_value;
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ NTSTATUS leases_db_add(const struct GUID *client_guid,
|
||||
const struct smb2_lease_key *lease_key,
|
||||
const struct file_id *id,
|
||||
const char *servicepath,
|
||||
const char *filename,
|
||||
const char *base_name,
|
||||
const char *stream_name)
|
||||
{
|
||||
TDB_DATA db_key, db_value;
|
||||
@ -95,6 +95,7 @@ NTSTATUS leases_db_add(const struct GUID *client_guid,
|
||||
NTSTATUS status;
|
||||
bool ok;
|
||||
struct leases_db_value new_value;
|
||||
struct leases_db_file new_file;
|
||||
struct leases_db_value *value = NULL;
|
||||
enum ndr_err_code ndr_err;
|
||||
|
||||
@ -140,31 +141,40 @@ NTSTATUS leases_db_add(const struct GUID *client_guid,
|
||||
}
|
||||
|
||||
/* id must be unique. */
|
||||
for (i = 0; i < value->num_file_ids; i++) {
|
||||
if (file_id_equal(id, &value->ids[i])) {
|
||||
for (i = 0; i < value->num_files; i++) {
|
||||
if (file_id_equal(id, &value->files[i].id)) {
|
||||
status = NT_STATUS_OBJECT_NAME_COLLISION;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
value->ids = talloc_realloc(value, value->ids, struct file_id,
|
||||
value->num_file_ids + 1);
|
||||
if (value->ids == NULL) {
|
||||
value->files = talloc_realloc(value, value->files,
|
||||
struct leases_db_file,
|
||||
value->num_files + 1);
|
||||
if (value->files == NULL) {
|
||||
status = NT_STATUS_NO_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
value->ids[value->num_file_ids] = *id;
|
||||
value->num_file_ids += 1;
|
||||
value->files[value->num_files].id = *id;
|
||||
value->files[value->num_files].servicepath = servicepath;
|
||||
value->files[value->num_files].base_name = base_name;
|
||||
value->files[value->num_files].stream_name = stream_name;
|
||||
value->num_files += 1;
|
||||
|
||||
} else {
|
||||
DEBUG(10, ("%s: new record\n", __func__));
|
||||
|
||||
new_value = (struct leases_db_value) {
|
||||
.num_file_ids = 1,
|
||||
.ids = discard_const_p(struct file_id, id),
|
||||
.filename = filename,
|
||||
new_file = (struct leases_db_file) {
|
||||
.id = *id,
|
||||
.servicepath = servicepath,
|
||||
.base_name = base_name,
|
||||
.stream_name = stream_name,
|
||||
};
|
||||
|
||||
new_value = (struct leases_db_value) {
|
||||
.num_files = 1,
|
||||
.files = &new_file,
|
||||
};
|
||||
value = &new_value;
|
||||
}
|
||||
|
||||
@ -253,21 +263,21 @@ NTSTATUS leases_db_del(const struct GUID *client_guid,
|
||||
}
|
||||
|
||||
/* id must exist. */
|
||||
for (i = 0; i < value->num_file_ids; i++) {
|
||||
if (file_id_equal(id, &value->ids[i])) {
|
||||
for (i = 0; i < value->num_files; i++) {
|
||||
if (file_id_equal(id, &value->files[i].id)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == value->num_file_ids) {
|
||||
if (i == value->num_files) {
|
||||
status = NT_STATUS_NOT_FOUND;
|
||||
goto out;
|
||||
}
|
||||
|
||||
value->ids[i] = value->ids[value->num_file_ids-1];
|
||||
value->num_file_ids -= 1;
|
||||
value->files[i] = value->files[value->num_files-1];
|
||||
value->num_files -= 1;
|
||||
|
||||
if (value->num_file_ids == 0) {
|
||||
if (value->num_files == 0) {
|
||||
DEBUG(10, ("%s: deleting record\n", __func__));
|
||||
status = dbwrap_record_delete(rec);
|
||||
} else {
|
||||
@ -304,9 +314,9 @@ NTSTATUS leases_db_del(const struct GUID *client_guid,
|
||||
}
|
||||
|
||||
struct leases_db_fetch_state {
|
||||
void (*parser)(uint32_t num_file_ids,
|
||||
struct file_id *ids, const char *filename,
|
||||
const char *stream_name, void *private_data);
|
||||
void (*parser)(uint32_t num_files,
|
||||
const struct leases_db_file *files,
|
||||
void *private_data);
|
||||
void *private_data;
|
||||
NTSTATUS status;
|
||||
};
|
||||
@ -341,8 +351,8 @@ static void leases_db_parser(TDB_DATA key, TDB_DATA data, void *private_data)
|
||||
NDR_PRINT_DEBUG(leases_db_value, value);
|
||||
}
|
||||
|
||||
state->parser(value->num_file_ids,
|
||||
value->ids, value->filename, value->stream_name,
|
||||
state->parser(value->num_files,
|
||||
value->files,
|
||||
state->private_data);
|
||||
|
||||
TALLOC_FREE(value);
|
||||
@ -351,10 +361,8 @@ static void leases_db_parser(TDB_DATA key, TDB_DATA data, void *private_data)
|
||||
|
||||
NTSTATUS leases_db_parse(const struct GUID *client_guid,
|
||||
const struct smb2_lease_key *lease_key,
|
||||
void (*parser)(uint32_t num_file_ids,
|
||||
struct file_id *ids,
|
||||
const char *filename,
|
||||
const char *stream_name,
|
||||
void (*parser)(uint32_t num_files,
|
||||
const struct leases_db_file *files,
|
||||
void *private_data),
|
||||
void *private_data)
|
||||
{
|
||||
|
@ -38,10 +38,8 @@ NTSTATUS leases_db_del(const struct GUID *client_guid,
|
||||
const struct file_id *id);
|
||||
NTSTATUS leases_db_parse(const struct GUID *client_guid,
|
||||
const struct smb2_lease_key *lease_key,
|
||||
void (*parser)(uint32_t num_file_ids,
|
||||
struct file_id *ids,
|
||||
const char *filename,
|
||||
const char *stream_name,
|
||||
void (*parser)(uint32_t num_files,
|
||||
const struct leases_db_file *files,
|
||||
void *private_data),
|
||||
void *private_data);
|
||||
NTSTATUS leases_db_rename(const struct GUID *client_guid,
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "messages.h"
|
||||
#include "source3/lib/dbwrap/dbwrap_watch.h"
|
||||
#include "locking/leases_db.h"
|
||||
#include "librpc/gen_ndr/ndr_leases_db.h"
|
||||
|
||||
extern const struct generic_mapping file_generic_mapping;
|
||||
|
||||
@ -4127,8 +4128,10 @@ static NTSTATUS inherit_new_acl(files_struct *fsp)
|
||||
* used for a different file name.
|
||||
*/
|
||||
|
||||
struct lease_fname_match_state {
|
||||
struct lease_match_state {
|
||||
/* Input parameters. */
|
||||
TALLOC_CTX *mem_ctx;
|
||||
const char *servicepath;
|
||||
const struct smb_filename *fname;
|
||||
bool file_existed;
|
||||
struct file_id id;
|
||||
@ -4138,57 +4141,139 @@ struct lease_fname_match_state {
|
||||
NTSTATUS match_status;
|
||||
};
|
||||
|
||||
static void lease_fname_match_parser(
|
||||
uint32_t num_file_ids,
|
||||
struct file_id *ids, const char *filename, const char *stream_name,
|
||||
void *private_data)
|
||||
{
|
||||
struct lease_fname_match_state *state =
|
||||
(struct lease_fname_match_state *)private_data;
|
||||
/*************************************************************
|
||||
File doesn't exist but this lease key+guid is already in use.
|
||||
|
||||
if (!strequal(filename, state->fname->base_name) ||
|
||||
!strequal(stream_name, state->fname->stream_name))
|
||||
{
|
||||
/* Names don't match lease key. */
|
||||
state->match_status = NT_STATUS_INVALID_PARAMETER;
|
||||
This is only allowable in the dynamic share case where the
|
||||
service path must be different.
|
||||
|
||||
There is a small race condition here in the multi-connection
|
||||
case where a client sends two create calls on different connections,
|
||||
where the file doesn't exist and one smbd creates the leases_db
|
||||
entry first, but this will get fixed by the multichannel cleanup
|
||||
when all identical client_guids get handled by a single smbd.
|
||||
**************************************************************/
|
||||
|
||||
static void lease_match_parser_new_file(
|
||||
uint32_t num_files,
|
||||
const struct leases_db_file *files,
|
||||
struct lease_match_state *state)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < num_files; i++) {
|
||||
const struct leases_db_file *f = &files[i];
|
||||
if (strequal(state->servicepath, f->servicepath)) {
|
||||
state->match_status = NT_STATUS_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dynamic share case. Break leases on all other files. */
|
||||
state->match_status = leases_db_copy_file_ids(state->mem_ctx,
|
||||
num_files,
|
||||
files,
|
||||
&state->ids);
|
||||
if (!NT_STATUS_IS_OK(state->match_status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->file_existed &&
|
||||
num_file_ids == 1 &&
|
||||
file_id_equal(&ids[0],&state->id))
|
||||
{
|
||||
/* Common case - non-dynamic share. We're ok.. */
|
||||
state->match_status = NT_STATUS_OK;
|
||||
state->num_file_ids = num_files;
|
||||
state->match_status = NT_STATUS_OPLOCK_NOT_GRANTED;
|
||||
return;
|
||||
}
|
||||
|
||||
static void lease_match_parser(
|
||||
uint32_t num_files,
|
||||
const struct leases_db_file *files,
|
||||
void *private_data)
|
||||
{
|
||||
struct lease_match_state *state =
|
||||
(struct lease_match_state *)private_data;
|
||||
uint32_t i;
|
||||
|
||||
if (!state->file_existed) {
|
||||
/*
|
||||
* Deal with name mismatch or
|
||||
* possible dynamic share case separately
|
||||
* to make code clearer.
|
||||
*/
|
||||
lease_match_parser_new_file(num_files,
|
||||
files,
|
||||
state);
|
||||
return;
|
||||
}
|
||||
|
||||
/* File existed. */
|
||||
state->match_status = NT_STATUS_OK;
|
||||
|
||||
for (i = 0; i < num_files; i++) {
|
||||
const struct leases_db_file *f = &files[i];
|
||||
|
||||
/* Everything should be the same. */
|
||||
if (!file_id_equal(&state->id, &f->id)) {
|
||||
/* This should catch all dynamic share cases. */
|
||||
state->match_status = NT_STATUS_OPLOCK_NOT_GRANTED;
|
||||
break;
|
||||
}
|
||||
if (!strequal(f->servicepath, state->servicepath)) {
|
||||
state->match_status = NT_STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
if (!strequal(f->base_name, state->fname->base_name)) {
|
||||
state->match_status = NT_STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
if (!strequal(f->stream_name, state->fname->stream_name)) {
|
||||
state->match_status = NT_STATUS_INVALID_PARAMETER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NT_STATUS_IS_OK(state->match_status)) {
|
||||
/*
|
||||
* Common case - just opening another handle on a
|
||||
* file on a non-dynamic share.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
if (NT_STATUS_EQUAL(state->match_status, NT_STATUS_INVALID_PARAMETER)) {
|
||||
/* Mismatched path. Error back to client. */
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* More than one file id, or not equal, or new file
|
||||
* being created and there's already an existing lease
|
||||
* on this (client_guid, lease id) pair.
|
||||
* File id mismatch. Dynamic share case NT_STATUS_OPLOCK_NOT_GRANTED.
|
||||
* Don't allow leases.
|
||||
*/
|
||||
|
||||
state->match_status = NT_STATUS_OPLOCK_NOT_GRANTED;
|
||||
state->num_file_ids = num_file_ids;
|
||||
state->ids = talloc_memdup(talloc_tos(),
|
||||
ids,
|
||||
num_file_ids * sizeof(struct file_id));
|
||||
if (state->ids == NULL) {
|
||||
state->match_status = NT_STATUS_NO_MEMORY;
|
||||
state->match_status = leases_db_copy_file_ids(state->mem_ctx,
|
||||
num_files,
|
||||
files,
|
||||
&state->ids);
|
||||
if (!NT_STATUS_IS_OK(state->match_status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
state->num_file_ids = num_files;
|
||||
state->match_status = NT_STATUS_OPLOCK_NOT_GRANTED;
|
||||
return;
|
||||
}
|
||||
|
||||
static NTSTATUS lease_match(connection_struct *conn,
|
||||
struct smb_request *req,
|
||||
struct smb2_lease_key *lease_key,
|
||||
const char *servicepath,
|
||||
const struct smb_filename *fname,
|
||||
uint16_t *p_version,
|
||||
uint16_t *p_epoch)
|
||||
{
|
||||
struct smbd_server_connection *sconn = req->sconn;
|
||||
struct lease_fname_match_state state = {
|
||||
TALLOC_CTX *tos = talloc_tos();
|
||||
struct lease_match_state state = {
|
||||
.mem_ctx = tos,
|
||||
.servicepath = servicepath,
|
||||
.fname = fname,
|
||||
.match_status = NT_STATUS_OK
|
||||
};
|
||||
@ -4203,7 +4288,7 @@ static NTSTATUS lease_match(connection_struct *conn,
|
||||
}
|
||||
|
||||
status = leases_db_parse(&sconn->client->connections->smb2.client.guid,
|
||||
lease_key, lease_fname_match_parser, &state);
|
||||
lease_key, lease_match_parser, &state);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
/*
|
||||
* Not found or error means okay: We can make the lease pass
|
||||
@ -4356,6 +4441,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn,
|
||||
status = lease_match(conn,
|
||||
req,
|
||||
&lease->lease_key,
|
||||
conn->connectpath,
|
||||
smb_fname,
|
||||
&version,
|
||||
&epoch);
|
||||
|
@ -340,21 +340,19 @@ struct lease_lookup_state {
|
||||
};
|
||||
|
||||
static void lease_parser(
|
||||
uint32_t num_file_ids,
|
||||
struct file_id *ids, const char *filename, const char *stream_name,
|
||||
uint32_t num_files,
|
||||
const struct leases_db_file *files,
|
||||
void *private_data)
|
||||
{
|
||||
struct lease_lookup_state *lls =
|
||||
(struct lease_lookup_state *)private_data;
|
||||
|
||||
lls->status = NT_STATUS_OK;
|
||||
lls->num_file_ids = num_file_ids;
|
||||
lls->ids = talloc_memdup(lls->mem_ctx,
|
||||
ids,
|
||||
num_file_ids * sizeof(struct file_id));
|
||||
if (lls->ids == NULL) {
|
||||
lls->status = NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
lls->num_file_ids = num_files;
|
||||
lls->status = leases_db_copy_file_ids(lls->mem_ctx,
|
||||
num_files,
|
||||
files,
|
||||
&lls->ids);
|
||||
}
|
||||
|
||||
static struct tevent_req *smbd_smb2_lease_break_send(
|
||||
|
Loading…
x
Reference in New Issue
Block a user