diff options
author | Jeremy Allison <jra@samba.org> | 2005-09-05 20:36:07 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 11:03:31 -0500 |
commit | 34721ad233227300d9c2e8b5483ba2c6c798a7da (patch) | |
tree | bf21c382d78ebda8dfcd4bd5a046cfce5da4987d /source3 | |
parent | 1171bc9a99358d943f75494fcdaf1a62e594789e (diff) | |
download | samba-34721ad233227300d9c2e8b5483ba2c6c798a7da.tar.gz samba-34721ad233227300d9c2e8b5483ba2c6c798a7da.tar.bz2 samba-34721ad233227300d9c2e8b5483ba2c6c798a7da.zip |
r10042: Add in external LGPL library for accessing the share mode db. Allow
others to examine & test. May not end up here eventually...
Jeremy.
(This used to be commit 7cc70ae63399eacd55bd0bf51ac2c7b004d761bf)
Diffstat (limited to 'source3')
-rw-r--r-- | source3/Makefile.in | 23 | ||||
-rw-r--r-- | source3/configure.in | 52 | ||||
-rw-r--r-- | source3/include/smb_share_modes.h | 103 | ||||
-rw-r--r-- | source3/libsmb/smb_share_modes.c | 452 |
4 files changed, 627 insertions, 3 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index ff0d0ff61d..0c51b3b818 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -97,8 +97,12 @@ LIBSMBCLIENT=bin/libsmbclient.a @LIBSMBCLIENT_SHARED@ LIBSMBCLIENT_MAJOR=0 LIBSMBCLIENT_MINOR=1 +LIBSMBSHAREMODES=bin/libsmbsharemodes.a @LIBSMBSHAREMODES_SHARED@ +LIBSMBSHAREMODES_MAJOR=0 +LIBSMBSHAREMODES_MINOR=1 -FLAGS1 = $(CFLAGS) @FLAGS1@ -Iinclude -I$(srcdir)/include -I$(srcdir)/ubiqx @SMBWRAP_INC@ -I. $(CPPFLAGS) -I$(srcdir) + +FLAGS1 = $(CFLAGS) @FLAGS1@ -Iinclude -I$(srcdir)/include -I$(srcdir)/ubiqx @SMBWRAP_INC@ -I. $(CPPFLAGS) -I$(srcdir) -I$(srcdir)/tdb FLAGS2 = FLAGS3 = FLAGS4 = @@ -137,7 +141,7 @@ BIN_PROGS = $(BIN_PROGS1) $(BIN_PROGS2) $(BIN_PROGS3) @EXTRA_BIN_PROGS@ EVERYTHING_PROGS = bin/debug2html@EXEEXT@ bin/smbfilter@EXEEXT@ bin/talloctort@EXEEXT@ \ bin/log2pcap@EXEEXT@ -SHLIBS = @SHLIB_PROGS@ @LIBSMBCLIENT@ +SHLIBS = @SHLIB_PROGS@ @LIBSMBCLIENT@ @LIBSMBSHAREMODES@ SCRIPTS = $(srcdir)/script/smbtar $(builddir)/script/findsmb @@ -513,6 +517,8 @@ LIBSMBCLIENT_OBJ = libsmb/libsmbclient.o libsmb/libsmb_compat.o \ $(LIBMSRPC_OBJ) $(RPC_PARSE_OBJ) \ $(SECRETS_OBJ) $(PASSDB_OBJ) $(SMBLDAP_OBJ) $(GROUPDB_OBJ) +LIBSMBSHAREMODES_OBJ = libsmb/smb_share_modes.o tdb/tdb.o + CAC_OBJ = $(LIBSMBCLIENT_OBJ) \ libmsrpc/libmsrpc.o libmsrpc/libmsrpc_internal.o \ libmsrpc/cac_lsarpc.o libmsrpc/cac_winreg.o libmsrpc/cac_samr.o \ @@ -641,6 +647,7 @@ WINBIND_WINS_NSS_PICOBJS = $(WINBIND_WINS_NSS_OBJ:.o=.@PICSUFFIX@) PICOBJS = $(SMBWRAPPER_OBJ:.o=.@PICSUFFIX@) LIBSMBCLIENT_PICOBJS = $(LIBSMBCLIENT_OBJ:.o=.@PICSUFFIX@) +LIBSMBSHAREMODES_PICOBJS = $(LIBSMBSHAREMODES_OBJ:.o=.@PICSUFFIX@) CAC_PICOBJS = $(CAC_OBJ:.o=.@PICSUFFIX@) @@ -1016,6 +1023,15 @@ bin/libsmbclient.a: $(LIBSMBCLIENT_PICOBJS) @echo Linking libsmbclient non-shared library $@ @-$(AR) -rc $@ $(LIBSMBCLIENT_PICOBJS) +bin/libsmbsharemodes.@SHLIBEXT@: $(LIBSMBSHAREMODES_PICOBS) + @echo Linking libsmbsharemodes shared library $@ + @$(SHLD) $(LDSHFLAGS) -o $@ $(LIBSMBSHAREMODES_PICOBS) $(LDFLAGS) $(LIBS) \ + $(KRB5LIBS) $(LDAP_LIBS) \ + @SONAMEFLAG@`basename $@`.$(LIBSMBSHAREMODES_MAJOR) + +bin/libsmbsharemodes.a: $(LIBSMBSHAREMODES_PICOBJS) + @echo Linking libsmbsharemodes non-shared library $@ + @-$(AR) -rc $@ $(LIBSMBSHAREMODES_PICOBJS) bin/libmsrpc.@SHLIBEXT@: $(CAC_PICOBJS) @echo Linking libmsrpc shared library $@ @@ -1041,6 +1057,7 @@ bin/libbigballofmud.@SHLIBEXT@: $(LIBBIGBALLOFMUD_PICOBJS) # library. libsmbclient: $(LIBSMBCLIENT) +libsmbsharemodes: $(LIBSMBSHAREMODES) bin/librpc_lsarpc.@SHLIBEXT@: $(RPC_LSA_OBJ) @echo "Linking $@" @@ -1461,7 +1478,7 @@ TOPFILES=dynconfig.o dynconfig.@PICSUFFIX@ clean: delheaders python_clean -rm -f core */*~ *~ */*.o */*.@PICSUFFIX@ */*.@SHLIBEXT@ \ $(TOPFILES) $(BIN_PROGS) $(SBIN_PROGS) $(MODULES) $(TORTURE_PROGS) \ - $(LIBSMBCLIENT) $(EVERYTHING_PROGS) .headers.stamp + $(LIBSMBCLIENT) $(LIBSMBSHAREMODES) $(EVERYTHING_PROGS) .headers.stamp -rm -rf t_dir # Making this target will just make sure that the prototype files diff --git a/source3/configure.in b/source3/configure.in index 95df1ba476..3a77584aec 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -219,6 +219,8 @@ AC_SUBST(INSTALLCLIENTCMD_SH) AC_SUBST(INSTALLCLIENTCMD_A) AC_SUBST(LIBSMBCLIENT_SHARED) AC_SUBST(LIBSMBCLIENT) +AC_SUBST(LIBSMBSHAREMODES_SHARED) +AC_SUBST(LIBSMBSHAREMODES) AC_SUBST(PRINT_LIBS) AC_SUBST(AUTH_LIBS) AC_SUBST(ACL_LIBS) @@ -3872,6 +3874,56 @@ AC_ARG_WITH(libsmbclient, ) +INSTALLCLIENTCMD_SH=: +INSTALLCLIENTCMD_A=: +INSTALLCLIENT= +LIBSMBCLIENT_SHARED= +LIBSMBCLIENT= +AC_MSG_CHECKING(whether to build the libsmbsharemodes shared library) +AC_ARG_WITH(libsmbsharemodes, +[ --with-libsmbsharemodes Build the libsmbsharemodes shared library (default=yes if shared libs supported)], +[ case "$withval" in + no) + AC_MSG_RESULT(no) + ;; + *) + if test $BLDSHARED = true; then + INSTALLCLIENTCMD_SH="\$(INSTALLCMD)" + ## build the static version of libsmbsharemodes as well + INSTALLCLIENTCMD_A="\$(INSTALLCMD)" + LIBSMBSHAREMODES_SHARED=bin/libsmbsharemodes.$SHLIBEXT + LIBSMBSHAREMODES=libsmbclient + AC_MSG_RESULT(yes) + else + enable_static=yes + AC_MSG_RESULT(no shared library support -- will supply static library) + fi + if test $enable_static = yes; then + INSTALLCLIENTCMD_A="\$(INSTALLCMD)" + LIBSMBCLIENT=libsmbsharemodes + fi + INSTALLCLIENT=installclientlib + ;; + esac ], +[ +# if unspecified, default is to built it iff possible. + if test $BLDSHARED = true; then + INSTALLCLIENTCMD_SH="\$(INSTALLCMD)" + LIBSMBSHAREMODES_SHARED=bin/libsmbsharemodes.$SHLIBEXT + LIBSMBSHAREMODES=libsmbsharemodes + AC_MSG_RESULT(yes) + else + enable_static=yes + AC_MSG_RESULT(no shared library support -- will supply static library) + fi + if test $enable_static = yes; then + INSTALLCLIENTCMD_A="\$(INSTALLCMD)" + LIBSMBCLIENT=libsmbsharemodes + fi] + INSTALLCLIENT=installclientlib +) + + ################################################# # these tests are taken from the GNU fileutils package AC_CHECKING(how to get filesystem space usage) diff --git a/source3/include/smb_share_modes.h b/source3/include/smb_share_modes.h new file mode 100644 index 0000000000..5a79e171d5 --- /dev/null +++ b/source3/include/smb_share_modes.h @@ -0,0 +1,103 @@ +/* + Samba share mode database library. + + Copyright (C) Jeremy Allison 2005. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _SMB_SHARE_MODES_H_ +#define _SMB_STATE_MODES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdint.h> +#include "tdb.h" + +/* Database context handle. */ +struct smbdb_ctx { + TDB_CONTEXT *smb_tdb; +}; + +/* Share mode entry. */ +/* + We use 64 bit types for device and inode as + we don't know what size mode Samba has been + compiled in - dev/ino may be 32, may be 64 + bits. This interface copes with either. +*/ + +struct smb_share_mode_entry { + uint64_t dev; + uint64_t ino; + uint32_t share_access; + uint32_t access_mask; + struct timeval open_time; + uint32_t file_id; + pid_t pid; +}; + +/* + * open/close sharemode database. + */ + +struct smbdb_ctx *smb_share_mode_db_open(const char *db_path); +int smb_share_mode_db_close(struct smbdb_ctx *db_ctx); + +/* + * lock/unlock entry in sharemode database. + */ + +int smb_lock_share_mode_entry(struct smbdb_ctx *db_ctx, + uint64_t dev, + uint64_t ino); + +int smb_unlock_share_mode_entry(struct smbdb_ctx *db_ctx, + uint64_t dev, + uint64_t ino); + +/* + * Share mode database accessor functions. + */ + +int smb_get_share_mode_entries(struct smbdb_ctx *db_ctx, + uint64_t dev, + uint64_t ino, + struct smb_share_mode_entry **pp_list, + unsigned char *p_delete_on_close); + +int smb_create_share_mode_entry(struct smbdb_ctx *db_ctx, + uint64_t dev, + uint64_t ino, + const struct smb_share_mode_entry *set_entry, + const char *path); + +int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx, + uint64_t dev, + uint64_t ino, + const struct smb_share_mode_entry *set_entry); + +int smb_change_share_mode_entry(struct smbdb_ctx *db_ctx, + uint64_t dev, + uint64_t ino, + const struct smb_share_mode_entry *set_entry, + const struct smb_share_mode_entry *new_entry); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/source3/libsmb/smb_share_modes.c b/source3/libsmb/smb_share_modes.c new file mode 100644 index 0000000000..0ba68aed06 --- /dev/null +++ b/source3/libsmb/smb_share_modes.c @@ -0,0 +1,452 @@ +/* + Samba share mode database library external interface library. + Used by non-Samba products needing access to the Samba share mode db. + + Copyright (C) Jeremy Allison 2005. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "includes.h" +#include "smb_share_modes.h" + +/* + * open/close sharemode database. + */ + +struct smbdb_ctx *smb_share_mode_db_open(const char *db_path) +{ + struct smbdb_ctx *smb_db = SMB_MALLOC_P(struct smbdb_ctx); + + if (!smb_db) { + return NULL; + } + + memset(smb_db, '\0', sizeof(struct smbdb_ctx)); + + smb_db->smb_tdb = tdb_open_log(lock_path("locking.tdb"), + 0, TDB_DEFAULT|TDB_CLEAR_IF_FIRST, + O_RDWR|O_CREAT, + 0644); + + if (!smb_db->smb_tdb) { + free(smb_db); + return NULL; + } + + /* Should check that this is the correct version.... */ + return smb_db; +} + +int smb_share_mode_db_close(struct smbdb_ctx *db_ctx) +{ + int ret = tdb_close(db_ctx->smb_tdb); + free(db_ctx); + return ret; +} + +/* Create locking key. */ + +struct samba_locking_key { + SMB_DEV_T dev; + SMB_INO_T ino; +}; + +static TDB_DATA get_locking_key(uint64_t dev, uint64_t ino) +{ + static struct samba_locking_key lk; + TDB_DATA ld; + + memset(&lk, '\0', sizeof(struct samba_locking_key)); + lk.dev = (SMB_DEV_T)dev; + lk.ino = (SMB_INO_T)ino; + ld.dptr = (char *)&lk; + ld.dsize = sizeof(lk); + return ld; +} + +/* + * lock/unlock entry in sharemode database. + */ + +int smb_lock_share_mode_entry(struct smbdb_ctx *db_ctx, + uint64_t dev, + uint64_t ino) +{ + return tdb_chainlock(db_ctx->smb_tdb, get_locking_key(dev, ino)); +} + +int smb_unlock_share_mode_entry(struct smbdb_ctx *db_ctx, + dev_t dev, + ino_t ino) +{ + return tdb_chainunlock(db_ctx->smb_tdb, get_locking_key(dev, ino)); +} + +/* Internal structure of Samba share mode db. */ +/* FIXME ! This should be moved into a Samba include file. */ + +struct locking_data { + union { + struct { + int num_share_mode_entries; + BOOL delete_on_close; + } s; + share_mode_entry dummy; /* Needed for alignment. */ + } u; + /* the following two entries are implicit + share_mode_entry modes[num_share_mode_entries]; + char file_name[]; + */ +}; + +/* + * Check if an external smb_share_mode_entry and an internal share_mode entry match. + */ + +static int share_mode_entry_equal(const struct smb_share_mode_entry *e_entry, const share_mode_entry *entry) +{ + return (e_entry->pid == entry->pid && + e_entry->file_id == (uint32_t)entry->share_file_id && + e_entry->open_time.tv_sec == entry->time.tv_sec && + e_entry->open_time.tv_usec == entry->time.tv_usec && + e_entry->share_access == (uint32_t)entry->share_access && + e_entry->access_mask == (uint32_t)entry->access_mask && + e_entry->dev == (uint64_t)entry->dev && + e_entry->ino == (uint64_t)entry->inode); +} + +/* + * Create an internal Samba share_mode entry from an external smb_share_mode_entry. + */ + +static void create_share_mode_entry(share_mode_entry *out, const struct smb_share_mode_entry *in) +{ + memset(out, '\0', sizeof(share_mode_entry)); + + out->pid = in->pid; + out->share_file_id = (unsigned long)in->file_id; + out->time.tv_sec = in->open_time.tv_sec; + out->time.tv_usec = in->open_time.tv_usec; + out->share_access = in->share_access; + out->access_mask = in->access_mask; + out->dev = (SMB_DEV_T)in->dev; + out->inode = (SMB_INO_T)in->ino; +} + +/* + * Return the current share mode list for an open file. + * This uses similar (but simplified) logic to locking/locking.c + */ + +int smb_get_share_mode_entries(struct smbdb_ctx *db_ctx, + uint64_t dev, + uint64_t ino, + struct smb_share_mode_entry **pp_list, + unsigned char *p_delete_on_close) +{ + TDB_DATA db_data; + struct smb_share_mode_entry *list = NULL; + int num_share_modes = 0; + struct locking_data *ld = NULL; /* internal samba db state. */ + share_mode_entry *shares = NULL; + size_t i; + + *pp_list = NULL; + *p_delete_on_close = 0; + + db_data = tdb_fetch(db_ctx->smb_tdb, get_locking_key(dev, ino)); + if (!db_data.dptr) { + return 0; + } + + ld = (struct locking_data *)db_data.dptr; + num_share_modes = ld->u.s.num_share_mode_entries; + + if (!num_share_modes) { + free(db_data.dptr); + return 0; + } + + list = SMB_MALLOC_ARRAY(struct smb_share_mode_entry, num_share_modes); + if (!list) { + free(db_data.dptr); + return -1; + } + + memset(list, '\0', num_share_modes * sizeof(struct smb_share_mode_entry)); + + shares = (share_mode_entry *)(db_data.dptr + sizeof(struct locking_data)); + + for (i = 0; i < num_share_modes; i++) { + share_mode_entry *share = &shares[i]; + struct smb_share_mode_entry *sme = &list[i]; + pid_t pid = share->pid; + + /* Check this process really exists. */ + if (kill(pid, 0) == -1 && (errno == ESRCH)) { + continue; /* No longer exists. */ + } + + /* Copy into the external list. */ + sme->dev = (uint64_t)share->dev; + sme->ino = (uint64_t)share->inode; + sme->share_access = (uint32_t)share->share_access; + sme->access_mask = (uint32_t)share->access_mask; + sme->open_time.tv_sec = share->time.tv_sec; + sme->open_time.tv_usec = share->time.tv_usec; + sme->file_id = (uint32_t)share->share_file_id; + sme->pid = share->pid; + } + + if (i == 0) { + free(db_data.dptr); + free(list); + return 0; + } + + *p_delete_on_close = ld->u.s.delete_on_close; + *pp_list = list; + return i; +} + +/* + * Create an entry in the Samba share mode db. + */ + +int smb_create_share_mode_entry(struct smbdb_ctx *db_ctx, + uint64_t dev, + uint64_t ino, + const struct smb_share_mode_entry *new_entry, + const char *filename) /* Must be abolute utf8 path. */ +{ + TDB_DATA db_data; + TDB_DATA locking_key = get_locking_key(dev, ino); + int orig_num_share_modes = 0; + struct locking_data *ld = NULL; /* internal samba db state. */ + share_mode_entry *shares = NULL; + char *new_data_p = NULL; + size_t new_data_size = 0; + + db_data = tdb_fetch(db_ctx->smb_tdb, locking_key); + if (!db_data.dptr) { + /* We must create the entry. */ + db_data.dptr = SMB_MALLOC(sizeof(struct locking_data) + sizeof(share_mode_entry) + strlen(filename) + 1); + if (!db_data.dptr) { + return -1; + } + ld = (struct locking_data *)db_data.dptr; + ld->u.s.num_share_mode_entries = 1; + ld->u.s.delete_on_close = 0; + shares = (share_mode_entry *)db_data.dptr + sizeof(struct locking_data); + create_share_mode_entry(shares, new_entry); + memcpy(db_data.dptr + sizeof(struct locking_data) + sizeof(share_mode_entry), + filename, + strlen(filename) + 1); + + db_data.dsize = sizeof(struct locking_data) + sizeof(share_mode_entry) + strlen(filename) + 1; + if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_INSERT) == -1) { + free(db_data.dptr); + return -1; + } + free(db_data.dptr); + return 0; + } + + /* Entry exists, we must add a new entry. */ + new_data_p = SMB_MALLOC(db_data.dsize + sizeof(share_mode_entry)); + if (!new_data_p) { + free(db_data.dptr); + return -1; + } + + ld = (struct locking_data *)db_data.dptr; + orig_num_share_modes = ld->u.s.num_share_mode_entries; + + /* Copy the original data. */ + memcpy(new_data_p, db_data.dptr, sizeof(struct locking_data) + (orig_num_share_modes*sizeof(share_mode_entry))); + + /* Add in the new share mode */ + shares = (share_mode_entry *)(db_data.dptr + sizeof(struct locking_data) + (orig_num_share_modes*sizeof(share_mode_entry))); + create_share_mode_entry(shares, new_entry); + + ld = (struct locking_data *)new_data_p; + ld->u.s.num_share_mode_entries++; + + /* Append the original filename */ + memcpy(new_data_p + sizeof(struct locking_data) + (ld->u.s.num_share_mode_entries * sizeof(share_mode_entry)), + db_data.dptr + sizeof(struct locking_data) + (orig_num_share_modes * sizeof(share_mode_entry)), + db_data.dsize - (sizeof(struct locking_data) + (orig_num_share_modes * sizeof(share_mode_entry)))); + + new_data_size = db_data.dsize + sizeof(share_mode_entry); + + free(db_data.dptr); + + db_data.dptr = new_data_p; + db_data.dsize = new_data_size; + + if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_REPLACE) == -1) { + free(db_data.dptr); + return -1; + } + free(db_data.dptr); + return 0; +} + +int smb_delete_share_mode_entry(struct smbdb_ctx *db_ctx, + uint64_t dev, + uint64_t ino, + const struct smb_share_mode_entry *del_entry) +{ + TDB_DATA db_data; + TDB_DATA locking_key = get_locking_key(dev, ino); + int orig_num_share_modes = 0; + struct locking_data *ld = NULL; /* internal samba db state. */ + share_mode_entry *shares = NULL; + char *new_data_p = NULL; + size_t filename_size = 0; + size_t i; + + db_data = tdb_fetch(db_ctx->smb_tdb, locking_key); + if (!db_data.dptr) { + return -1; /* Error - missing entry ! */ + } + + ld = (struct locking_data *)db_data.dptr; + orig_num_share_modes = ld->u.s.num_share_mode_entries; + shares = (share_mode_entry *)(db_data.dptr + sizeof(struct locking_data)); + + if (orig_num_share_modes == 1) { + /* Only one entry - better be ours... */ + if (!share_mode_entry_equal(del_entry, shares)) { + /* Error ! We can't delete someone else's entry ! */ + free(db_data.dptr); + return -1; + } + /* It's ours - just remove the entire record. */ + free(db_data.dptr); + return tdb_delete(db_ctx->smb_tdb, locking_key); + } + + /* More than one - allocate a new record minus the one we'll delete. */ + new_data_p = SMB_MALLOC(db_data.dsize - sizeof(share_mode_entry)); + if (!new_data_p) { + free(db_data.dptr); + return -1; + } + + /* Copy the header. */ + memcpy(new_data_p, db_data.dptr, sizeof(struct locking_data)); + + for (i = 0; i < orig_num_share_modes; i++) { + share_mode_entry *share = &shares[i]; + pid_t pid = share->pid; + + /* Check this process really exists. */ + if (kill(pid, 0) == -1 && (errno == ESRCH)) { + continue; /* No longer exists. */ + } + + if (share_mode_entry_equal(del_entry, share)) { + continue; /* This is our delete taget. */ + } + + memcpy(new_data_p + sizeof(struct locking_data) + (i*sizeof(share_mode_entry)), + share, sizeof(share_mode_entry) ); + } + + if (i == 0) { + /* None left after pruning. Delete record. */ + free(db_data.dptr); + free(new_data_p); + return tdb_delete(db_ctx->smb_tdb, locking_key); + } + + /* Copy the terminating filename. */ + filename_size = db_data.dsize - ( sizeof(struct locking_data) + (orig_num_share_modes * sizeof(share_mode_entry))); + + memcpy(new_data_p + sizeof(struct locking_data) + (i*sizeof(share_mode_entry)), + db_data.dptr + sizeof(struct locking_data) + (orig_num_share_modes * sizeof(share_mode_entry)), + filename_size); + + free(db_data.dptr); + + db_data.dptr = new_data_p; + + /* Re-save smaller record. */ + ld = (struct locking_data *)db_data.dptr; + ld->u.s.num_share_mode_entries = i; + + db_data.dsize = sizeof(struct locking_data) + (i*sizeof(share_mode_entry)) + filename_size; + + if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_REPLACE) == -1) { + free(db_data.dptr); + return -1; + } + free(db_data.dptr); + return 0; +} + +int smb_change_share_mode_entry(struct smbdb_ctx *db_ctx, + uint64_t dev, + uint64_t ino, + const struct smb_share_mode_entry *set_entry, + const struct smb_share_mode_entry *new_entry) +{ + TDB_DATA db_data; + TDB_DATA locking_key = get_locking_key(dev, ino); + int num_share_modes = 0; + struct locking_data *ld = NULL; /* internal samba db state. */ + share_mode_entry *shares = NULL; + size_t i; + int found_entry = 0; + + db_data = tdb_fetch(db_ctx->smb_tdb, locking_key); + if (!db_data.dptr) { + return -1; /* Error - missing entry ! */ + } + + ld = (struct locking_data *)db_data.dptr; + num_share_modes = ld->u.s.num_share_mode_entries; + shares = (share_mode_entry *)(db_data.dptr + sizeof(struct locking_data)); + + for (i = 0; i < num_share_modes; i++) { + share_mode_entry *share = &shares[i]; + pid_t pid = share->pid; + + /* Check this process really exists. */ + if (kill(pid, 0) == -1 && (errno == ESRCH)) { + continue; /* No longer exists. */ + } + + if (share_mode_entry_equal(set_entry, share)) { + create_share_mode_entry(share, new_entry); + break; + } + } + + if (!found_entry) { + free(db_data.dptr); + return -1; + } + + /* Save modified data. */ + if (tdb_store(db_ctx->smb_tdb, locking_key, db_data, TDB_REPLACE) == -1) { + free(db_data.dptr); + return -1; + } + free(db_data.dptr); + return 0; +} |