diff options
Diffstat (limited to 'source3/locking')
-rw-r--r-- | source3/locking/locking.c | 415 | ||||
-rw-r--r-- | source3/locking/share_mode_lock.c | 463 |
2 files changed, 463 insertions, 415 deletions
diff --git a/source3/locking/locking.c b/source3/locking/locking.c index d98d19b399..9199591d9e 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -52,9 +52,6 @@ #define NO_LOCKING_COUNT (-1) -/* the locking database handle */ -static struct db_context *lock_db; - /**************************************************************************** Debugging aids :-). ****************************************************************************/ @@ -431,64 +428,6 @@ void locking_close_file(struct messaging_context *msg_ctx, } } -/**************************************************************************** - Initialise the locking functions. -****************************************************************************/ - -static bool locking_init_internal(bool read_only) -{ - brl_init(read_only); - - if (lock_db) - return True; - - lock_db = db_open(NULL, lock_path("locking.tdb"), - lp_open_files_db_hash_size(), - TDB_DEFAULT|TDB_VOLATILE|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, - read_only?O_RDONLY:O_RDWR|O_CREAT, 0644); - - if (!lock_db) { - DEBUG(0,("ERROR: Failed to initialise locking database\n")); - return False; - } - - if (!posix_locking_init(read_only)) - return False; - - return True; -} - -bool locking_init(void) -{ - return locking_init_internal(false); -} - -bool locking_init_readonly(void) -{ - return locking_init_internal(true); -} - -/******************************************************************* - Deinitialize the share_mode management. -******************************************************************/ - -bool locking_end(void) -{ - brl_shutdown(); - TALLOC_FREE(lock_db); - return true; -} - -/******************************************************************* - Form a static locking key for a dev/inode pair. -******************************************************************/ - -static TDB_DATA locking_key(const struct file_id *id, struct file_id *tmp) -{ - *tmp = *id; - return make_tdb_data((const uint8_t *)tmp, sizeof(*tmp)); -} - /******************************************************************* Print out a share mode. ********************************************************************/ @@ -509,287 +448,12 @@ char *share_mode_str(TALLOC_CTX *ctx, int num, const struct share_mode_entry *e) (unsigned int)e->name_hash); } -/******************************************************************* - Get all share mode entries for a dev/inode pair. -********************************************************************/ - -static struct share_mode_data *parse_share_modes(TALLOC_CTX *mem_ctx, - const TDB_DATA dbuf) -{ - struct share_mode_data *d; - int i; - struct server_id *pids; - bool *pid_exists; - enum ndr_err_code ndr_err; - DATA_BLOB blob; - - d = talloc_zero(mem_ctx, struct share_mode_data); - if (d == NULL) { - DEBUG(0, ("talloc failed\n")); - goto fail; - } - - blob.data = dbuf.dptr; - blob.length = dbuf.dsize; - - ndr_err = ndr_pull_struct_blob( - &blob, d, d, (ndr_pull_flags_fn_t)ndr_pull_share_mode_data); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(1, ("ndr_pull_share_mode_lock failed\n")); - goto fail; - } - - d->modified = false; - d->fresh = false; - - if (DEBUGLEVEL >= 10) { - DEBUG(10, ("parse_share_modes:\n")); - NDR_PRINT_DEBUG(share_mode_data, d); - } - - /* - * Ensure that each entry has a real process attached. - */ - - pids = talloc_array(talloc_tos(), struct server_id, - d->num_share_modes); - if (pids == NULL) { - DEBUG(0, ("talloc failed\n")); - goto fail; - } - pid_exists = talloc_array(talloc_tos(), bool, d->num_share_modes); - if (pid_exists == NULL) { - DEBUG(0, ("talloc failed\n")); - goto fail; - } - - for (i=0; i<d->num_share_modes; i++) { - pids[i] = d->share_modes[i].pid; - } - if (!serverids_exist(pids, d->num_share_modes, pid_exists)) { - DEBUG(0, ("serverid_exists failed\n")); - goto fail; - } - - i = 0; - while (i < d->num_share_modes) { - struct share_mode_entry *e = &d->share_modes[i]; - if (!pid_exists[i]) { - *e = d->share_modes[d->num_share_modes-1]; - d->num_share_modes -= 1; - d->modified = True; - continue; - } - i += 1; - } - TALLOC_FREE(pid_exists); - TALLOC_FREE(pids); - return d; -fail: - TALLOC_FREE(d); - return NULL; -} - -static TDB_DATA unparse_share_modes(struct share_mode_data *d) -{ - DATA_BLOB blob; - enum ndr_err_code ndr_err; - - if (DEBUGLEVEL >= 10) { - DEBUG(10, ("unparse_share_modes:\n")); - NDR_PRINT_DEBUG(share_mode_data, d); - } - - if (d->num_share_modes == 0) { - DEBUG(10, ("No used share mode found\n")); - return make_tdb_data(NULL, 0); - } - - ndr_err = ndr_push_struct_blob( - &blob, d, d, (ndr_push_flags_fn_t)ndr_push_share_mode_data); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - smb_panic("ndr_push_share_mode_lock failed"); - } - - return make_tdb_data(blob.data, blob.length); -} - -static int share_mode_data_destructor(struct share_mode_data *d) -{ - NTSTATUS status; - TDB_DATA data; - - if (!d->modified) { - return 0; - } - - data = unparse_share_modes(d); - - if (data.dptr == NULL) { - if (!d->fresh) { - /* There has been an entry before, delete it */ - - status = dbwrap_record_delete(d->record); - if (!NT_STATUS_IS_OK(status)) { - char *errmsg; - - DEBUG(0, ("delete_rec returned %s\n", - nt_errstr(status))); - - if (asprintf(&errmsg, "could not delete share " - "entry: %s\n", - nt_errstr(status)) == -1) { - smb_panic("could not delete share" - "entry"); - } - smb_panic(errmsg); - } - } - goto done; - } - - status = dbwrap_record_store(d->record, data, TDB_REPLACE); - if (!NT_STATUS_IS_OK(status)) { - char *errmsg; - - DEBUG(0, ("store returned %s\n", nt_errstr(status))); - - if (asprintf(&errmsg, "could not store share mode entry: %s", - nt_errstr(status)) == -1) { - smb_panic("could not store share mode entry"); - } - smb_panic(errmsg); - } - - done: - - return 0; -} - -static struct share_mode_data *fresh_share_mode_lock( - TALLOC_CTX *mem_ctx, const char *servicepath, - const struct smb_filename *smb_fname, - const struct timespec *old_write_time) -{ - struct share_mode_data *d; - - if ((servicepath == NULL) || (smb_fname == NULL) || - (old_write_time == NULL)) { - return NULL; - } - - d = talloc_zero(mem_ctx, struct share_mode_data); - if (d == NULL) { - goto fail; - } - d->base_name = talloc_strdup(d, smb_fname->base_name); - if (d->base_name == NULL) { - goto fail; - } - if (smb_fname->stream_name != NULL) { - d->stream_name = talloc_strdup(d, smb_fname->stream_name); - if (d->stream_name == NULL) { - goto fail; - } - } - d->servicepath = talloc_strdup(d, servicepath); - if (d->servicepath == NULL) { - goto fail; - } - d->old_write_time = *old_write_time; - d->modified = false; - d->fresh = true; - return d; -fail: - DEBUG(0, ("talloc failed\n")); - TALLOC_FREE(d); - return NULL; -} - -struct share_mode_lock *get_share_mode_lock_fresh(TALLOC_CTX *mem_ctx, - const struct file_id id, - const char *servicepath, - const struct smb_filename *smb_fname, - const struct timespec *old_write_time) -{ - struct share_mode_lock *lck; - struct share_mode_data *d; - struct file_id tmp; - struct db_record *rec; - TDB_DATA key = locking_key(&id, &tmp); - TDB_DATA value; - - rec = dbwrap_fetch_locked(lock_db, mem_ctx, key); - if (rec == NULL) { - DEBUG(3, ("Could not lock share entry\n")); - return NULL; - } - - value = dbwrap_record_get_value(rec); - - if (value.dptr == NULL) { - d = fresh_share_mode_lock(mem_ctx, servicepath, smb_fname, - old_write_time); - } else { - d = parse_share_modes(mem_ctx, value); - } - - if (d == NULL) { - DEBUG(1, ("Could not get share mode lock\n")); - TALLOC_FREE(rec); - return NULL; - } - d->id = id; - d->record = talloc_move(d, &rec); - talloc_set_destructor(d, share_mode_data_destructor); - - lck = talloc(mem_ctx, struct share_mode_lock); - if (lck == NULL) { - DEBUG(1, ("talloc failed\n")); - TALLOC_FREE(d); - return NULL; - } - lck->data = talloc_move(lck, &d); - return lck; -} - struct share_mode_lock *get_share_mode_lock(TALLOC_CTX *mem_ctx, const struct file_id id) { return get_share_mode_lock_fresh(mem_ctx, id, NULL, NULL, NULL); } -struct share_mode_lock *fetch_share_mode_unlocked(TALLOC_CTX *mem_ctx, - const struct file_id id) -{ - struct share_mode_lock *lck; - struct file_id tmp; - TDB_DATA key = locking_key(&id, &tmp); - TDB_DATA data; - NTSTATUS status; - - status = dbwrap_fetch(lock_db, talloc_tos(), key, &data); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(3, ("Could not fetch share entry\n")); - return NULL; - } - if (data.dptr == NULL) { - return NULL; - } - lck = talloc(mem_ctx, struct share_mode_lock); - if (lck == NULL) { - TALLOC_FREE(data.dptr); - return NULL; - } - lck->data = parse_share_modes(mem_ctx, data); - TALLOC_FREE(data.dptr); - if (lck->data == NULL) { - TALLOC_FREE(lck); - return NULL; - } - return lck; -} - /******************************************************************* Sets the service name and filename for rename. At this point we emit "file renamed" messages to all @@ -1373,82 +1037,3 @@ bool set_write_time(struct file_id fileid, struct timespec write_time) TALLOC_FREE(lck); return True; } - - -struct forall_state { - void (*fn)(const struct share_mode_entry *entry, - const char *sharepath, - const char *fname, - void *private_data); - void *private_data; -}; - -static int traverse_fn(struct db_record *rec, void *_state) -{ - struct forall_state *state = (struct forall_state *)_state; - uint32_t i; - TDB_DATA key; - TDB_DATA value; - DATA_BLOB blob; - enum ndr_err_code ndr_err; - struct share_mode_data *d; - - key = dbwrap_record_get_key(rec); - value = dbwrap_record_get_value(rec); - - /* Ensure this is a locking_key record. */ - if (key.dsize != sizeof(struct file_id)) - return 0; - - d = talloc(talloc_tos(), struct share_mode_data); - if (d == NULL) { - return 0; - } - - blob.data = value.dptr; - blob.length = value.dsize; - - ndr_err = ndr_pull_struct_blob( - &blob, d, d, (ndr_pull_flags_fn_t)ndr_pull_share_mode_data); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(1, ("ndr_pull_share_mode_lock failed\n")); - return 0; - } - for (i=0; i<d->num_share_modes; i++) { - state->fn(&d->share_modes[i], - d->servicepath, d->base_name, - state->private_data); - } - TALLOC_FREE(d); - - return 0; -} - -/******************************************************************* - Call the specified function on each entry under management by the - share mode system. -********************************************************************/ - -int share_mode_forall(void (*fn)(const struct share_mode_entry *, const char *, - const char *, void *), - void *private_data) -{ - struct forall_state state; - NTSTATUS status; - int count; - - if (lock_db == NULL) - return 0; - - state.fn = fn; - state.private_data = private_data; - - status = dbwrap_traverse_read(lock_db, traverse_fn, (void *)&state, - &count); - - if (!NT_STATUS_IS_OK(status)) { - return -1; - } else { - return count; - } -} diff --git a/source3/locking/share_mode_lock.c b/source3/locking/share_mode_lock.c new file mode 100644 index 0000000000..1fb96998d7 --- /dev/null +++ b/source3/locking/share_mode_lock.c @@ -0,0 +1,463 @@ +/* + Unix SMB/CIFS implementation. + Locking functions + Copyright (C) Andrew Tridgell 1992-2000 + Copyright (C) Jeremy Allison 1992-2006 + Copyright (C) Volker Lendecke 2005 + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see <http://www.gnu.org/licenses/>. + + Revision History: + + 12 aug 96: Erik.Devriendt@te6.siemens.be + added support for shared memory implementation of share mode locking + + May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode + locking to deal with multiple share modes per open file. + + September 1997. Jeremy Allison (jallison@whistle.com). Added oplock + support. + + rewritten completely to use new tdb code. Tridge, Dec '99 + + Added POSIX locking support. Jeremy Allison (jeremy@valinux.com), Apr. 2000. + Added Unix Extensions POSIX locking support. Jeremy Allison Mar 2006. +*/ + +#include "includes.h" +#include "system/filesys.h" +#include "locking/proto.h" +#include "smbd/globals.h" +#include "dbwrap/dbwrap.h" +#include "dbwrap/dbwrap_open.h" +#include "../libcli/security/security.h" +#include "serverid.h" +#include "messages.h" +#include "util_tdb.h" +#include "../librpc/gen_ndr/ndr_open_files.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_LOCKING + +#define NO_LOCKING_COUNT (-1) + +/* the locking database handle */ +static struct db_context *lock_db; + +static bool locking_init_internal(bool read_only) +{ + brl_init(read_only); + + if (lock_db) + return True; + + lock_db = db_open(NULL, lock_path("locking.tdb"), + lp_open_files_db_hash_size(), + TDB_DEFAULT|TDB_VOLATILE|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, + read_only?O_RDONLY:O_RDWR|O_CREAT, 0644); + + if (!lock_db) { + DEBUG(0,("ERROR: Failed to initialise locking database\n")); + return False; + } + + if (!posix_locking_init(read_only)) + return False; + + return True; +} + +bool locking_init(void) +{ + return locking_init_internal(false); +} + +bool locking_init_readonly(void) +{ + return locking_init_internal(true); +} + +/******************************************************************* + Deinitialize the share_mode management. +******************************************************************/ + +bool locking_end(void) +{ + brl_shutdown(); + TALLOC_FREE(lock_db); + return true; +} + +/******************************************************************* + Form a static locking key for a dev/inode pair. +******************************************************************/ + +static TDB_DATA locking_key(const struct file_id *id, struct file_id *tmp) +{ + *tmp = *id; + return make_tdb_data((const uint8_t *)tmp, sizeof(*tmp)); +} + +/******************************************************************* + Get all share mode entries for a dev/inode pair. +********************************************************************/ + +static struct share_mode_data *parse_share_modes(TALLOC_CTX *mem_ctx, + const TDB_DATA dbuf) +{ + struct share_mode_data *d; + int i; + struct server_id *pids; + bool *pid_exists; + enum ndr_err_code ndr_err; + DATA_BLOB blob; + + d = talloc_zero(mem_ctx, struct share_mode_data); + if (d == NULL) { + DEBUG(0, ("talloc failed\n")); + goto fail; + } + + blob.data = dbuf.dptr; + blob.length = dbuf.dsize; + + ndr_err = ndr_pull_struct_blob( + &blob, d, d, (ndr_pull_flags_fn_t)ndr_pull_share_mode_data); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(1, ("ndr_pull_share_mode_lock failed\n")); + goto fail; + } + + d->modified = false; + d->fresh = false; + + if (DEBUGLEVEL >= 10) { + DEBUG(10, ("parse_share_modes:\n")); + NDR_PRINT_DEBUG(share_mode_data, d); + } + + /* + * Ensure that each entry has a real process attached. + */ + + pids = talloc_array(talloc_tos(), struct server_id, + d->num_share_modes); + if (pids == NULL) { + DEBUG(0, ("talloc failed\n")); + goto fail; + } + pid_exists = talloc_array(talloc_tos(), bool, d->num_share_modes); + if (pid_exists == NULL) { + DEBUG(0, ("talloc failed\n")); + goto fail; + } + + for (i=0; i<d->num_share_modes; i++) { + pids[i] = d->share_modes[i].pid; + } + if (!serverids_exist(pids, d->num_share_modes, pid_exists)) { + DEBUG(0, ("serverid_exists failed\n")); + goto fail; + } + + i = 0; + while (i < d->num_share_modes) { + struct share_mode_entry *e = &d->share_modes[i]; + if (!pid_exists[i]) { + *e = d->share_modes[d->num_share_modes-1]; + d->num_share_modes -= 1; + d->modified = True; + continue; + } + i += 1; + } + TALLOC_FREE(pid_exists); + TALLOC_FREE(pids); + return d; +fail: + TALLOC_FREE(d); + return NULL; +} + +static TDB_DATA unparse_share_modes(struct share_mode_data *d) +{ + DATA_BLOB blob; + enum ndr_err_code ndr_err; + + if (DEBUGLEVEL >= 10) { + DEBUG(10, ("unparse_share_modes:\n")); + NDR_PRINT_DEBUG(share_mode_data, d); + } + + if (d->num_share_modes == 0) { + DEBUG(10, ("No used share mode found\n")); + return make_tdb_data(NULL, 0); + } + + ndr_err = ndr_push_struct_blob( + &blob, d, d, (ndr_push_flags_fn_t)ndr_push_share_mode_data); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + smb_panic("ndr_push_share_mode_lock failed"); + } + + return make_tdb_data(blob.data, blob.length); +} + +static int share_mode_data_destructor(struct share_mode_data *d) +{ + NTSTATUS status; + TDB_DATA data; + + if (!d->modified) { + return 0; + } + + data = unparse_share_modes(d); + + if (data.dptr == NULL) { + if (!d->fresh) { + /* There has been an entry before, delete it */ + + status = dbwrap_record_delete(d->record); + if (!NT_STATUS_IS_OK(status)) { + char *errmsg; + + DEBUG(0, ("delete_rec returned %s\n", + nt_errstr(status))); + + if (asprintf(&errmsg, "could not delete share " + "entry: %s\n", + nt_errstr(status)) == -1) { + smb_panic("could not delete share" + "entry"); + } + smb_panic(errmsg); + } + } + goto done; + } + + status = dbwrap_record_store(d->record, data, TDB_REPLACE); + if (!NT_STATUS_IS_OK(status)) { + char *errmsg; + + DEBUG(0, ("store returned %s\n", nt_errstr(status))); + + if (asprintf(&errmsg, "could not store share mode entry: %s", + nt_errstr(status)) == -1) { + smb_panic("could not store share mode entry"); + } + smb_panic(errmsg); + } + + done: + + return 0; +} + +static struct share_mode_data *fresh_share_mode_lock( + TALLOC_CTX *mem_ctx, const char *servicepath, + const struct smb_filename *smb_fname, + const struct timespec *old_write_time) +{ + struct share_mode_data *d; + + if ((servicepath == NULL) || (smb_fname == NULL) || + (old_write_time == NULL)) { + return NULL; + } + + d = talloc_zero(mem_ctx, struct share_mode_data); + if (d == NULL) { + goto fail; + } + d->base_name = talloc_strdup(d, smb_fname->base_name); + if (d->base_name == NULL) { + goto fail; + } + if (smb_fname->stream_name != NULL) { + d->stream_name = talloc_strdup(d, smb_fname->stream_name); + if (d->stream_name == NULL) { + goto fail; + } + } + d->servicepath = talloc_strdup(d, servicepath); + if (d->servicepath == NULL) { + goto fail; + } + d->old_write_time = *old_write_time; + d->modified = false; + d->fresh = true; + return d; +fail: + DEBUG(0, ("talloc failed\n")); + TALLOC_FREE(d); + return NULL; +} + +struct share_mode_lock *get_share_mode_lock_fresh(TALLOC_CTX *mem_ctx, + const struct file_id id, + const char *servicepath, + const struct smb_filename *smb_fname, + const struct timespec *old_write_time) +{ + struct share_mode_lock *lck; + struct share_mode_data *d; + struct file_id tmp; + struct db_record *rec; + TDB_DATA key = locking_key(&id, &tmp); + TDB_DATA value; + + rec = dbwrap_fetch_locked(lock_db, mem_ctx, key); + if (rec == NULL) { + DEBUG(3, ("Could not lock share entry\n")); + return NULL; + } + + value = dbwrap_record_get_value(rec); + + if (value.dptr == NULL) { + d = fresh_share_mode_lock(mem_ctx, servicepath, smb_fname, + old_write_time); + } else { + d = parse_share_modes(mem_ctx, value); + } + + if (d == NULL) { + DEBUG(1, ("Could not get share mode lock\n")); + TALLOC_FREE(rec); + return NULL; + } + d->id = id; + d->record = talloc_move(d, &rec); + talloc_set_destructor(d, share_mode_data_destructor); + + lck = talloc(mem_ctx, struct share_mode_lock); + if (lck == NULL) { + DEBUG(1, ("talloc failed\n")); + TALLOC_FREE(d); + return NULL; + } + lck->data = talloc_move(lck, &d); + return lck; +} + +struct share_mode_lock *fetch_share_mode_unlocked(TALLOC_CTX *mem_ctx, + const struct file_id id) +{ + struct share_mode_lock *lck; + struct file_id tmp; + TDB_DATA key = locking_key(&id, &tmp); + TDB_DATA data; + NTSTATUS status; + + status = dbwrap_fetch(lock_db, talloc_tos(), key, &data); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3, ("Could not fetch share entry\n")); + return NULL; + } + if (data.dptr == NULL) { + return NULL; + } + lck = talloc(mem_ctx, struct share_mode_lock); + if (lck == NULL) { + TALLOC_FREE(data.dptr); + return NULL; + } + lck->data = parse_share_modes(mem_ctx, data); + TALLOC_FREE(data.dptr); + if (lck->data == NULL) { + TALLOC_FREE(lck); + return NULL; + } + return lck; +} + +struct forall_state { + void (*fn)(const struct share_mode_entry *entry, + const char *sharepath, + const char *fname, + void *private_data); + void *private_data; +}; + +static int traverse_fn(struct db_record *rec, void *_state) +{ + struct forall_state *state = (struct forall_state *)_state; + uint32_t i; + TDB_DATA key; + TDB_DATA value; + DATA_BLOB blob; + enum ndr_err_code ndr_err; + struct share_mode_data *d; + + key = dbwrap_record_get_key(rec); + value = dbwrap_record_get_value(rec); + + /* Ensure this is a locking_key record. */ + if (key.dsize != sizeof(struct file_id)) + return 0; + + d = talloc(talloc_tos(), struct share_mode_data); + if (d == NULL) { + return 0; + } + + blob.data = value.dptr; + blob.length = value.dsize; + + ndr_err = ndr_pull_struct_blob( + &blob, d, d, (ndr_pull_flags_fn_t)ndr_pull_share_mode_data); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(1, ("ndr_pull_share_mode_lock failed\n")); + return 0; + } + for (i=0; i<d->num_share_modes; i++) { + state->fn(&d->share_modes[i], + d->servicepath, d->base_name, + state->private_data); + } + TALLOC_FREE(d); + + return 0; +} + +/******************************************************************* + Call the specified function on each entry under management by the + share mode system. +********************************************************************/ + +int share_mode_forall(void (*fn)(const struct share_mode_entry *, const char *, + const char *, void *), + void *private_data) +{ + struct forall_state state; + NTSTATUS status; + int count; + + if (lock_db == NULL) + return 0; + + state.fn = fn; + state.private_data = private_data; + + status = dbwrap_traverse_read(lock_db, traverse_fn, (void *)&state, + &count); + + if (!NT_STATUS_IS_OK(status)) { + return -1; + } else { + return count; + } +} |