1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-15 23:24:37 +03:00

Merge branch 'ctdb-merge' into v3-2-test

(This used to be commit 175662b5bbb5c8ecd81a60539f5846a938c26a3a)
This commit is contained in:
Alexander Bokovoy 2008-01-16 18:53:16 +03:00
commit 02680bd75d
33 changed files with 3033 additions and 276 deletions

View File

@ -308,7 +308,7 @@ LIB_WITH_PROTO_OBJ = $(VERSION_OBJ) lib/charcnv.o lib/debug.o lib/fault.o \
lib/util_str.o lib/clobber.o lib/util_sid.o lib/util_uuid.o \
lib/util_unistr.o lib/util_file.o lib/data_blob.o \
lib/util.o lib/util_sock.o lib/sock_exec.o lib/util_sec.o \
lib/substitute.o lib/fsusage.o \
lib/substitute.o lib/fsusage.o lib/dbwrap_util.o \
lib/ms_fnmatch.o lib/select.o lib/errmap_unix.o \
lib/tallocmsg.o lib/dmallocmsg.o libsmb/smb_signing.o \
lib/md5.o lib/hmacmd5.o lib/arc4.o lib/iconv.o \
@ -503,6 +503,7 @@ VFS_READONLY_OBJ = modules/vfs_readonly.o modules/getdate.o
VFS_CAP_OBJ = modules/vfs_cap.o
VFS_EXPAND_MSDFS_OBJ = modules/vfs_expand_msdfs.o
VFS_SHADOW_COPY_OBJ = modules/vfs_shadow_copy.o
VFS_SHADOW_COPY2_OBJ = modules/vfs_shadow_copy2.o
VFS_AFSACL_OBJ = modules/vfs_afsacl.o
VFS_XATTR_TDB_OBJ = modules/vfs_xattr_tdb.o librpc/gen_ndr/ndr_xattr.o
VFS_POSIXACL_OBJ = modules/vfs_posixacl.o
@ -520,6 +521,7 @@ VFS_COMMIT_OBJ = modules/vfs_commit.o
VFS_GPFS_OBJ = modules/vfs_gpfs.o modules/gpfs.o modules/nfs4_acls.o
VFS_NOTIFY_FAM_OBJ = modules/vfs_notify_fam.o
VFS_READAHEAD_OBJ = modules/vfs_readahead.o
VFS_TSMSM_OBJ = modules/vfs_tsmsm.o
VFS_FILEID_OBJ = modules/vfs_fileid.o
VFS_SYNCOPS_OBJ = modules/vfs_syncops.o
@ -1611,6 +1613,10 @@ bin/ad.@SHLIBEXT@: $(BINARY_PREREQS) winbindd/idmap_ad.o
@echo "Building plugin $@"
@$(SHLD_MODULE) winbindd/idmap_ad.o
bin/tdb2.@SHLIBEXT@: $(BINARY_PREREQS) winbindd/idmap_tdb2.o
@echo "Building plugin $@"
@$(SHLD_MODULE) winbindd/idmap_tdb2.o
bin/ldap.@SHLIBEXT@: $(BINARY_PREREQS) winbindd/idmap_ldap.o
@echo "Building plugin $@"
@$(SHLD_MODULE) winbindd/idmap_ldap.o
@ -1670,6 +1676,10 @@ bin/shadow_copy.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_SHADOW_COPY_OBJ)
@echo "Building plugin $@"
@$(SHLD_MODULE) $(VFS_SHADOW_COPY_OBJ)
bin/shadow_copy2.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_SHADOW_COPY2_OBJ)
@echo "Building plugin $@"
@$(SHLD_MODULE) $(VFS_SHADOW_COPY2_OBJ)
bin/syncops.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_SYNCOPS_OBJ)
@echo "Building plugin $@"
@$(SHLD_MODULE) $(VFS_SYNCOPS_OBJ)
@ -1750,6 +1760,10 @@ bin/readahead.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_READAHEAD_OBJ)
@echo "Building plugin $@"
@$(SHLD_MODULE) $(VFS_READAHEAD_OBJ)
bin/tsmsm.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_TSMSM_OBJ)
@echo "Building plugin $@"
@$(SHLD_MODULE) $(VFS_TSMSM_OBJ)
bin/fileid.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_FILEID_OBJ)
@echo "Building plugin $@"
@$(SHLD_MODULE) $(VFS_FILEID_OBJ)

View File

@ -707,7 +707,7 @@ dnl These have to be built static:
default_static_modules="pdb_smbpasswd pdb_tdbsam rpc_lsa rpc_samr rpc_winreg rpc_initshutdown rpc_lsa_ds rpc_wkssvc rpc_svcctl2 rpc_ntsvcs rpc_net rpc_netdfs rpc_srvsvc2 rpc_spoolss rpc_eventlog2 auth_sam auth_unix auth_winbind auth_server auth_domain auth_builtin vfs_default nss_info_template"
dnl These are preferably build shared, and static if dlopen() is not available
default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy charset_CP850 charset_CP437 auth_script vfs_readahead vfs_syncops vfs_xattr_tdb"
default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy vfs_shadow_copy2 charset_CP850 charset_CP437 auth_script vfs_readahead vfs_syncops vfs_xattr_tdb"
if test "x$developer" = xyes; then
default_static_modules="$default_static_modules rpc_rpcecho"
@ -2751,6 +2751,12 @@ AC_SUBST(SMB_FAM_LIBS)
SMB_CHECK_DMAPI([], AC_MSG_NOTICE(DMAPI support not present) )
# Add TSM SM VFS module only if there are both GPFS and DMAPI support
# Theoretically it should work with AIX JFS2 too but this needs testing
if test x"$samba_cv_HAVE_GPFS" = x"yes" && test x"$samba_dmapi_libs" != x"" ; then
default_shared_modules="$default_shared_modules vfs_tsmsm"
fi
AC_CACHE_CHECK([for kernel share modes],samba_cv_HAVE_KERNEL_SHARE_MODES,[
AC_TRY_RUN([
#include <sys/types.h>
@ -6452,6 +6458,7 @@ SMB_SUBSYSTEM(RPC,smbd/server.o)
SMB_MODULE(idmap_ldap, winbindd/idmap_ldap.o, "bin/ldap.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_tdb, winbindd/idmap_tdb.o, "bin/tdb.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_tdb2, winbindd/idmap_tdb2.o, "bin/tdb2.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_passdb, winbindd/idmap_passdb.o, "bin/passdb.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_nss, winbindd/idmap_nss.o, "bin/nss.$SHLIBEXT", IDMAP)
SMB_MODULE(idmap_rid, winbindd/idmap_rid.o, "bin/rid.$SHLIBEXT", IDMAP)
@ -6488,6 +6495,7 @@ SMB_MODULE(vfs_readonly, \$(VFS_READONLY_OBJ), "bin/readonly.$SHLIBEXT", VFS)
SMB_MODULE(vfs_cap, \$(VFS_CAP_OBJ), "bin/cap.$SHLIBEXT", VFS)
SMB_MODULE(vfs_expand_msdfs, \$(VFS_EXPAND_MSDFS_OBJ), "bin/expand_msdfs.$SHLIBEXT", VFS)
SMB_MODULE(vfs_shadow_copy, \$(VFS_SHADOW_COPY_OBJ), "bin/shadow_copy.$SHLIBEXT", VFS)
SMB_MODULE(vfs_shadow_copy2, \$(VFS_SHADOW_COPY2_OBJ), "bin/shadow_copy2.$SHLIBEXT", VFS)
SMB_MODULE(vfs_afsacl, \$(VFS_AFSACL_OBJ), "bin/afsacl.$SHLIBEXT", VFS)
SMB_MODULE(vfs_xattr_tdb, \$(VFS_XATTR_TDB_OBJ), "bin/xattr_tdb.$SHLIBEXT", VFS)
SMB_MODULE(vfs_posixacl, \$(VFS_POSIXACL_OBJ), "bin/posixacl.$SHLIBEXT", VFS)
@ -6503,6 +6511,7 @@ SMB_MODULE(vfs_prealloc, \$(VFS_PREALLOC_OBJ), "bin/prealloc.$SHLIBEXT", VFS)
SMB_MODULE(vfs_commit, \$(VFS_COMMIT_OBJ), "bin/commit.$SHLIBEXT", VFS)
SMB_MODULE(vfs_gpfs, \$(VFS_GPFS_OBJ), "bin/gpfs.$SHLIBEXT", VFS)
SMB_MODULE(vfs_readahead, \$(VFS_READAHEAD_OBJ), "bin/readahead.$SHLIBEXT", VFS)
SMB_MODULE(vfs_tsmsm, \$(VFS_TSMSM_OBJ), "bin/tsmsm.$SHLIBEXT", VFS)
SMB_MODULE(vfs_fileid, \$(VFS_FILEID_OBJ), "bin/fileid.$SHLIBEXT", VFS)
SMB_MODULE(vfs_syncops, \$(VFS_SYNCOPS_OBJ), "bin/syncops.$SHLIBEXT", VFS)
SMB_MODULE(vfs_zfsacl, \$(VFS_ZFSACL_OBJ), "bin/zfsacl.$SHLIBEXT", VFS)

View File

@ -17,6 +17,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CTDBD_CONN_H
#define _CTDBD_CONN_H
struct ctdbd_connection;
NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx,
@ -62,3 +65,6 @@ NTSTATUS ctdbd_register_ips(struct ctdbd_connection *conn,
NTSTATUS ctdbd_register_reconfigure(struct ctdbd_connection *conn);
NTSTATUS ctdbd_persistent_store(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key, TDB_DATA data);
#endif /* _CTDBD_CONN_H */

View File

@ -43,6 +43,7 @@ struct db_context {
void *private_data);
int (*get_seqnum)(struct db_context *db);
void *private_data;
bool persistent;
};
struct db_context *db_open(TALLOC_CTX *mem_ctx,

View File

@ -70,6 +70,7 @@
* timestamp resolition. JRA. */
/* Changed to version21 to add chflags operation -- jpeach */
/* Changed to version22 to add lchown operation -- jra */
/* Additional change: add operations for offline files and remote storage volume abstraction -- ab*/
/* Leave at 22 - not yet released. But change set_nt_acl to return an NTSTATUS. jra. */
/* Leave at 22 - not yet released. Add file_id_create operation. --metze */
/* Leave at 22 - not yet released. Change all BOOL parameters (int) to bool. jra. */
@ -257,6 +258,12 @@ typedef enum _vfs_op_type {
SMB_VFS_OP_AIO_ERROR,
SMB_VFS_OP_AIO_FSYNC,
SMB_VFS_OP_AIO_SUSPEND,
SMB_VFS_OP_AIO_FORCE,
/* offline operations */
SMB_VFS_OP_IS_OFFLINE,
SMB_VFS_OP_SET_OFFLINE,
SMB_VFS_OP_IS_REMOTESTORAGE,
/* This should always be last enum value */
@ -405,6 +412,12 @@ struct vfs_ops {
int (*aio_error_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_STRUCT_AIOCB *aiocb);
int (*aio_fsync)(struct vfs_handle_struct *handle, struct files_struct *fsp, int op, SMB_STRUCT_AIOCB *aiocb);
int (*aio_suspend)(struct vfs_handle_struct *handle, struct files_struct *fsp, const SMB_STRUCT_AIOCB * const aiocb[], int n, const struct timespec *timeout);
bool (*aio_force)(struct vfs_handle_struct *handle, struct files_struct *fsp);
/* offline operations */
int (*is_offline)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, bool *offline);
int (*set_offline)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path);
bool (*is_remotestorage)(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path);
} ops;
@ -526,6 +539,12 @@ struct vfs_ops {
struct vfs_handle_struct *aio_error;
struct vfs_handle_struct *aio_fsync;
struct vfs_handle_struct *aio_suspend;
struct vfs_handle_struct *aio_force;
/* offline operations */
struct vfs_handle_struct *is_offline;
struct vfs_handle_struct *set_offline;
struct vfs_handle_struct *is_remotestorage;
} handles;
};

View File

@ -138,6 +138,12 @@
#define SMB_VFS_AIO_ERROR(fsp,aiocb) ((fsp)->conn->vfs.ops.aio_error_fn((fsp)->conn->vfs.handles.aio_error,(fsp),(aiocb)))
#define SMB_VFS_AIO_FSYNC(fsp,op,aiocb) ((fsp)->conn->vfs.ops.aio_fsync((fsp)->conn->vfs.handles.aio_fsync,(fsp),(op),(aiocb)))
#define SMB_VFS_AIO_SUSPEND(fsp,aiocb,n,ts) ((fsp)->conn->vfs.ops.aio_suspend((fsp)->conn->vfs.handles.aio_suspend,(fsp),(aiocb),(n),(ts)))
#define SMB_VFS_AIO_FORCE(fsp) ((fsp)->conn->vfs.ops.aio_force((fsp)->conn->vfs.handles.aio_force,(fsp)))
/* Offline operations */
#define SMB_VFS_IS_OFFLINE(conn,path,sbuf,offline) ((conn)->vfs.ops.is_offline((conn)->vfs.handles.is_offline,(conn),(path),(sbuf),(offline)))
#define SMB_VFS_SET_OFFLINE(conn,path) ((conn)->vfs.ops.set_offline((conn)->vfs.handles.set_offline,(conn),(path)))
#define SMB_VFS_IS_REMOTESTORAGE(conn,path) ((conn)->vfs.ops.is_remotestorage((conn)->vfs.handles.is_remotestorage,(conn),(path)))
/*******************************************************************
Don't access conn->vfs_opaque.ops directly!!!
@ -257,6 +263,12 @@
#define SMB_VFS_OPAQUE_AIO_ERROR(fsp,aiocb) ((fsp)->conn->vfs_opaque.ops.aio_error_fn((fsp)->conn->vfs_opaque.handles.aio_error,(fsp),(aiocb)))
#define SMB_VFS_OPAQUE_AIO_FSYNC(fsp,op,aiocb) ((fsp)->conn->vfs_opaque.ops.aio_fsync((fsp)->conn->vfs_opaque.handles.aio_fsync,(fsp),(op),(aiocb)))
#define SMB_VFS_OPAQUE_AIO_SUSPEND(fsp,aiocb,n,ts) ((fsp)->conn->vfs_opaque.ops.aio_suspend((fsp)->conn->vfs_opaque.handles.aio_suspend,(fsp),(aiocb),(n),(ts)))
#define SMB_VFS_OPAQUE_AIO_FORCE(fsp) ((fsp)->conn->vfs_opaque.ops.aio_force((fsp)->conn->vfs_opaque.handles.aio_force,(fsp)))
/* Offline operations */
#define SMB_VFS_OPAQUE_IS_OFFLINE(conn,path,sbuf,offline) ((conn)->vfs_opaque.ops.is_offline((conn)->vfs_opaque.handles.is_offline,(conn),(path),(sbuf),(offline)))
#define SMB_VFS_OPAQUE_SET_OFFLINE(conn,path) ((conn)->vfs_opaque.ops.set_offline((conn)->vfs_opaque.handles.set_offline,(conn),(path)))
#define SMB_VFS_OPAQUE_IS_REMOTESTORAGE(conn,path) ((conn)->vfs_opaque.ops.is_remotestorage((conn)->vfs_opaque.handles.is_remotestorage,(conn),(path)))
/*******************************************************************
Don't access handle->vfs_next.ops.* directly!!!
@ -377,5 +389,11 @@
#define SMB_VFS_NEXT_AIO_ERROR(handle,fsp,aiocb) ((handle)->vfs_next.ops.aio_error_fn((handle)->vfs_next.handles.aio_error,(fsp),(aiocb)))
#define SMB_VFS_NEXT_AIO_FSYNC(handle,fsp,op,aiocb) ((handle)->vfs_next.ops.aio_fsync((handle)->vfs_next.handles.aio_fsync,(fsp),(op),(aiocb)))
#define SMB_VFS_NEXT_AIO_SUSPEND(handle,fsp,aiocb,n,ts) ((handle)->vfs_next.ops.aio_suspend((handle)->vfs_next.handles.aio_suspend,(fsp),(aiocb),(n),(ts)))
#define SMB_VFS_NEXT_AIO_FORCE(handle,fsp) ((handle)->vfs_next.ops.aio_force((handle)->vfs_next.handles.aio_force,(fsp)))
/* Offline operations */
#define SMB_VFS_NEXT_IS_OFFLINE(conn,path,sbuf,offline) ((conn)->vfs_next.ops.is_offline((conn)->vfs_next.handles.is_offline,(conn),(path),(sbuf),(offline)))
#define SMB_VFS_NEXT_SET_OFFLINE(conn,path) ((conn)->vfs_next.ops.set_offline((conn)->vfs_next.handles.set_offline,(conn),(path)))
#define SMB_VFS_NEXT_IS_REMOTESTORAGE(conn,path) ((conn)->vfs_next.ops.is_remotestorage((conn)->vfs_next.handles.is_remotestorage,(conn),(path)))
#endif /* _VFS_MACROS_H */

View File

@ -34,7 +34,7 @@ static struct db_context *connections_db_ctx(bool rw)
}
else {
db_ctx = db_open(NULL, lock_path("connections.tdb"), 0,
TDB_DEFAULT, O_RDONLY, 0);
TDB_CLEAR_IF_FIRST|TDB_DEFAULT, O_RDONLY, 0);
}
return db_ctx;

View File

@ -1203,6 +1203,42 @@ NTSTATUS ctdbd_register_reconfigure(struct ctdbd_connection *conn)
return register_with_ctdbd(conn, CTDB_SRVID_RECONFIGURE);
}
/*
persstent store. Used when we update a record in a persistent database
*/
NTSTATUS ctdbd_persistent_store(struct ctdbd_connection *conn, uint32_t db_id, TDB_DATA key, TDB_DATA data)
{
int cstatus=0;
struct ctdb_rec_data *rec;
TDB_DATA recdata;
size_t length;
NTSTATUS status;
length = offsetof(struct ctdb_rec_data, data) + key.dsize + data.dsize;
rec = (struct ctdb_rec_data *)talloc_size(conn, length);
NT_STATUS_HAVE_NO_MEMORY(rec);
rec->length = length;
rec->reqid = db_id;
rec->keylen = key.dsize;
rec->datalen= data.dsize;
memcpy(&rec->data[0], key.dptr, key.dsize);
memcpy(&rec->data[key.dsize], data.dptr, data.dsize);
recdata.dptr = (uint8_t *)rec;
recdata.dsize = length;
status = ctdbd_control(conn, CTDB_CURRENT_NODE,
CTDB_CONTROL_PERSISTENT_STORE,
0, recdata, NULL, NULL, &cstatus);
if (cstatus != 0) {
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
return status;
}
#else
NTSTATUS ctdbd_init_connection(TALLOC_CTX *mem_ctx,

View File

@ -20,7 +20,9 @@
*/
#include "includes.h"
#ifdef CLUSTER_SUPPORT
#include "ctdb_private.h"
#endif
/*
* Fall back using fetch_locked if no genuine fetch operation is provided
*/
@ -46,10 +48,16 @@ struct db_context *db_open(TALLOC_CTX *mem_ctx,
int open_flags, mode_t mode)
{
struct db_context *result = NULL;
#ifdef CLUSTER_SUPPORT
const char *sockname = lp_ctdbd_socket();
#endif
#ifdef CLUSTER_SUPPORT
if(!sockname || !*sockname) {
sockname = CTDB_PATH;
}
if (lp_clustering()) {
if (lp_clustering() && socket_exist(sockname)) {
const char *partname;
/* ctdb only wants the file part of the name */
partname = strrchr(name, '/');

View File

@ -18,16 +18,14 @@
*/
#include "includes.h"
#ifdef CLUSTER_SUPPORT
#include "ctdb.h"
#include "ctdb_private.h"
#include "ctdbd_conn.h"
struct db_ctdb_ctx {
struct tdb_wrap *wtdb;
uint32 db_id;
struct ctdbd_connection *conn;
};
struct db_ctdb_rec {
@ -35,8 +33,6 @@ struct db_ctdb_rec {
struct ctdb_ltdb_header header;
};
static struct ctdbd_connection *db_ctdbd_conn(struct db_ctdb_ctx *ctx);
static NTSTATUS db_ctdb_store(struct db_record *rec, TDB_DATA data, int flag)
{
struct db_ctdb_rec *crec = talloc_get_type_abort(
@ -60,6 +56,42 @@ static NTSTATUS db_ctdb_store(struct db_record *rec, TDB_DATA data, int flag)
return (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
}
/* for persistent databases the store is a bit different. We have to
ask the ctdb daemon to push the record to all nodes after the
store */
static NTSTATUS db_ctdb_store_persistent(struct db_record *rec, TDB_DATA data, int flag)
{
struct db_ctdb_rec *crec = talloc_get_type_abort(
rec->private_data, struct db_ctdb_rec);
TDB_DATA cdata;
int ret;
NTSTATUS status;
cdata.dsize = sizeof(crec->header) + data.dsize;
if (!(cdata.dptr = SMB_MALLOC_ARRAY(uint8, cdata.dsize))) {
return NT_STATUS_NO_MEMORY;
}
crec->header.rsn++;
memcpy(cdata.dptr, &crec->header, sizeof(crec->header));
memcpy(cdata.dptr + sizeof(crec->header), data.dptr, data.dsize);
ret = tdb_store(crec->ctdb_ctx->wtdb->tdb, rec->key, cdata, TDB_REPLACE);
status = (ret == 0) ? NT_STATUS_OK : NT_STATUS_INTERNAL_DB_CORRUPTION;
/* now tell ctdbd to update this record on all other nodes */
if (NT_STATUS_IS_OK(status)) {
status = ctdbd_persistent_store(messaging_ctdbd_connection(), crec->ctdb_ctx->db_id, rec->key, cdata);
}
SAFE_FREE(cdata.dptr);
return status;
}
static NTSTATUS db_ctdb_delete(struct db_record *rec)
{
struct db_ctdb_rec *crec = talloc_get_type_abort(
@ -110,6 +142,7 @@ static struct db_record *db_ctdb_fetch_locked(struct db_context *db,
struct db_ctdb_rec *crec;
NTSTATUS status;
TDB_DATA ctdb_data;
int migrate_attempts = 0;
if (!(result = talloc(mem_ctx, struct db_record))) {
DEBUG(0, ("talloc failed\n"));
@ -153,7 +186,11 @@ again:
return NULL;
}
result->store = db_ctdb_store;
if (db->persistent) {
result->store = db_ctdb_store_persistent;
} else {
result->store = db_ctdb_store;
}
result->delete_rec = db_ctdb_delete;
talloc_set_destructor(result, db_ctdb_record_destr);
@ -175,12 +212,14 @@ again:
tdb_chainunlock(ctx->wtdb->tdb, key);
talloc_set_destructor(result, NULL);
migrate_attempts += 1;
DEBUG(10, ("ctdb_data.dptr = %p, dmaster = %u (%u)\n",
ctdb_data.dptr, ctdb_data.dptr ?
((struct ctdb_ltdb_header *)ctdb_data.dptr)->dmaster : -1,
get_my_vnn()));
status = ctdbd_migrate(db_ctdbd_conn(ctx), ctx->db_id, key);
status = ctdbd_migrate(messaging_ctdbd_connection(),ctx->db_id, key);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(5, ("ctdb_migrate failed: %s\n",
nt_errstr(status)));
@ -191,6 +230,11 @@ again:
goto again;
}
if (migrate_attempts > 10) {
DEBUG(0, ("db_ctdb_fetch_locked needed %d attempts\n",
migrate_attempts));
}
memcpy(&crec->header, ctdb_data.dptr, sizeof(crec->header));
result->value.dsize = ctdb_data.dsize - sizeof(crec->header);
@ -226,10 +270,12 @@ static int db_ctdb_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
/*
* See if we have a valid record and we are the dmaster. If so, we can
* take the shortcut and just return it.
* we bypass the dmaster check for persistent databases
*/
if ((ctdb_data.dptr != NULL) &&
(ctdb_data.dsize >= sizeof(struct ctdb_ltdb_header)) &&
((struct ctdb_ltdb_header *)ctdb_data.dptr)->dmaster == get_my_vnn()) {
(db->persistent ||
((struct ctdb_ltdb_header *)ctdb_data.dptr)->dmaster == get_my_vnn())) {
/* we are the dmaster - avoid the ctdb protocol op */
data->dsize = ctdb_data.dsize - sizeof(struct ctdb_ltdb_header);
@ -254,8 +300,7 @@ static int db_ctdb_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
SAFE_FREE(ctdb_data.dptr);
/* we weren't able to get it locally - ask ctdb to fetch it for us */
status = ctdbd_fetch(db_ctdbd_conn(ctx), ctx->db_id, key, mem_ctx,
data);
status = ctdbd_fetch(messaging_ctdbd_connection(),ctx->db_id, key, mem_ctx, data);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(5, ("ctdbd_fetch failed: %s\n", nt_errstr(status)));
return -1;
@ -283,6 +328,22 @@ static void traverse_callback(TDB_DATA key, TDB_DATA data, void *private_data)
talloc_free(tmp_ctx);
}
static int traverse_persistent_callback(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
void *private_data)
{
struct traverse_state *state = (struct traverse_state *)private_data;
struct db_record *rec;
TALLOC_CTX *tmp_ctx = talloc_new(state->db);
int ret = 0;
/* we have to give them a locked record to prevent races */
rec = db_ctdb_fetch_locked(state->db, tmp_ctx, kbuf);
if (rec && rec->value.dsize > 0) {
ret = state->fn(rec, state->private_data);
}
talloc_free(tmp_ctx);
return ret;
}
static int db_ctdb_traverse(struct db_context *db,
int (*fn)(struct db_record *rec,
void *private_data),
@ -296,6 +357,13 @@ static int db_ctdb_traverse(struct db_context *db,
state.fn = fn;
state.private_data = private_data;
if (db->persistent) {
/* for persistent databases we don't need to do a ctdb traverse,
we can do a faster local traverse */
return tdb_traverse(ctx->wtdb->tdb, traverse_persistent_callback, &state);
}
ctdbd_traverse(ctx->db_id, traverse_callback, &state);
return 0;
}
@ -322,6 +390,27 @@ static void traverse_read_callback(TDB_DATA key, TDB_DATA data, void *private_da
state->fn(&rec, state->private_data);
}
static int traverse_persistent_callback_read(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
void *private_data)
{
struct traverse_state *state = (struct traverse_state *)private_data;
struct db_record rec;
rec.key = kbuf;
rec.value = dbuf;
rec.store = db_ctdb_store_deny;
rec.delete_rec = db_ctdb_delete_deny;
rec.private_data = state->db;
if (rec.value.dsize <= sizeof(struct ctdb_ltdb_header)) {
/* a deleted record */
return 0;
}
rec.value.dsize -= sizeof(struct ctdb_ltdb_header);
rec.value.dptr += sizeof(struct ctdb_ltdb_header);
return state->fn(&rec, state->private_data);
}
static int db_ctdb_traverse_read(struct db_context *db,
int (*fn)(struct db_record *rec,
void *private_data),
@ -335,6 +424,12 @@ static int db_ctdb_traverse_read(struct db_context *db,
state.fn = fn;
state.private_data = private_data;
if (db->persistent) {
/* for persistent databases we don't need to do a ctdb traverse,
we can do a faster local traverse */
return tdb_traverse_read(ctx->wtdb->tdb, traverse_persistent_callback_read, &state);
}
ctdbd_traverse(ctx->db_id, traverse_read_callback, &state);
return 0;
}
@ -346,41 +441,6 @@ static int db_ctdb_get_seqnum(struct db_context *db)
return tdb_get_seqnum(ctx->wtdb->tdb);
}
/*
* Get the ctdbd connection for a database. If possible, re-use the messaging
* ctdbd connection
*/
static struct ctdbd_connection *db_ctdbd_conn(struct db_ctdb_ctx *ctx)
{
struct ctdbd_connection *result;
result = messaging_ctdbd_connection();
if (result != NULL) {
if (ctx->conn == NULL) {
/*
* Someone has initialized messaging since we
* initialized our own connection, we don't need it
* anymore.
*/
TALLOC_FREE(ctx->conn);
}
return result;
}
if (ctx->conn == NULL) {
NTSTATUS status;
status = ctdbd_init_connection(ctx, &ctx->conn);
if (!NT_STATUS_IS_OK(status)) {
return NULL;
}
set_my_vnn(ctdbd_vnn(ctx->conn));
}
return ctx->conn;
}
struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
const char *name,
@ -390,7 +450,6 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
struct db_context *result;
struct db_ctdb_ctx *db_ctdb;
char *db_path;
NTSTATUS status;
if (!lp_clustering()) {
DEBUG(10, ("Clustering disabled -- no ctdb\n"));
@ -409,20 +468,15 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
return NULL;
}
db_ctdb->conn = NULL;
status = ctdbd_db_attach(db_ctdbd_conn(db_ctdb), name,
&db_ctdb->db_id, tdb_flags);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("ctdbd_db_attach failed for %s: %s\n", name,
nt_errstr(status)));
if (!NT_STATUS_IS_OK(ctdbd_db_attach(messaging_ctdbd_connection(),name, &db_ctdb->db_id, tdb_flags))) {
DEBUG(0, ("ctdbd_db_attach failed for %s\n", name));
TALLOC_FREE(result);
return NULL;
}
db_path = ctdbd_dbpath(db_ctdbd_conn(db_ctdb), db_ctdb,
db_ctdb->db_id);
db_path = ctdbd_dbpath(messaging_ctdbd_connection(), db_ctdb, db_ctdb->db_id);
result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
/* only pass through specific flags */
tdb_flags &= TDB_SEQNUM;
@ -447,16 +501,4 @@ struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
return result;
}
#else
struct db_context *db_open_ctdb(TALLOC_CTX *mem_ctx,
const char *name,
int hash_size, int tdb_flags,
int open_flags, mode_t mode)
{
DEBUG(0, ("no clustering compiled in\n"));
return NULL;
}
#endif

View File

@ -17,10 +17,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Be aware that this is just sample code that has not seen too much testing
*/
#include "includes.h"
struct db_file_ctx {
@ -367,6 +363,7 @@ struct db_context *db_open_file(TALLOC_CTX *mem_ctx,
result->fetch_locked = db_file_fetch_locked;
result->traverse = db_file_traverse;
result->traverse_read = db_file_traverse;
result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
ctx->locked_record = NULL;
if (!(ctx->dirname = talloc_strdup(ctx, name))) {

View File

@ -31,6 +31,11 @@ static int db_tdb_record_destr(struct db_record* data)
struct db_tdb_ctx *ctx =
talloc_get_type_abort(data->private_data, struct db_tdb_ctx);
/* This hex_encode() call allocates memory on data context. By way how current
__talloc_free() code works, it is OK to allocate in the destructor as
the children of data will be freed after call to the destructor and this
new 'child' will be caught and freed correctly.
*/
DEBUG(10, (DEBUGLEVEL > 10
? "Unlocking key %s\n" : "Unlocking key %.20s\n",
hex_encode(data, (unsigned char *)data->key.dptr,
@ -88,8 +93,9 @@ static struct db_record *db_tdb_fetch_locked(struct db_context *db,
struct tdb_fetch_locked_state state;
int res;
if (DEBUGLEVEL >= 10) {
char *keystr = hex_encode(NULL, key.dptr, key.dsize);
/* Do not accidently allocate/deallocate w/o need when debug level is lower than needed */
if(DEBUGLEVEL >= 10) {
char *keystr = hex_encode(NULL, (unsigned char*)key.dptr, key.dsize);
DEBUG(10, (DEBUGLEVEL > 10
? "Locking key %s\n" : "Locking key %.20s\n",
keystr));
@ -191,15 +197,9 @@ static NTSTATUS db_tdb_delete(struct db_record *rec)
{
struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
struct db_tdb_ctx);
int res;
res = tdb_delete(ctx->wtdb->tdb, rec->key);
if (res == 0) {
return NT_STATUS_OK;
}
return map_nt_error_from_tdb(tdb_error(ctx->wtdb->tdb));
return (tdb_delete(ctx->wtdb->tdb, rec->key) == 0) ?
NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
}
struct db_tdb_traverse_ctx {
@ -318,6 +318,7 @@ struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
result->traverse = db_tdb_traverse;
result->traverse_read = db_tdb_traverse_read;
result->get_seqnum = db_tdb_get_seqnum;
result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
return result;
fail:

90
source3/lib/dbwrap_util.c Normal file
View File

@ -0,0 +1,90 @@
/*
Unix SMB/CIFS implementation.
Utility functions for the dbwrap API
Copyright (C) Volker Lendecke 2007
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
int32_t dbwrap_fetch_int32(struct db_context *db, const char *keystr)
{
TDB_DATA dbuf;
int32 ret;
if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
return -1;
}
if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(int32_t))) {
TALLOC_FREE(dbuf.dptr);
return -1;
}
ret = IVAL(dbuf.dptr, 0);
TALLOC_FREE(dbuf.dptr);
return ret;
}
int dbwrap_store_int32(struct db_context *db, const char *keystr, int32_t v)
{
struct db_record *rec;
int32 v_store;
NTSTATUS status;
rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
if (rec == NULL) {
return -1;
}
SIVAL(&v_store, 0, v);
status = rec->store(rec, make_tdb_data((const uint8 *)&v_store,
sizeof(v_store)),
TDB_REPLACE);
TALLOC_FREE(rec);
return NT_STATUS_IS_OK(status) ? 0 : -1;
}
uint32_t dbwrap_change_uint32_atomic(struct db_context *db, const char *keystr,
uint32_t *oldval, uint32_t change_val)
{
struct db_record *rec;
uint32 val = -1;
TDB_DATA data;
if (!(rec = db->fetch_locked(db, NULL,
string_term_tdb_data(keystr)))) {
return -1;
}
if ((rec->value.dptr != NULL)
&& (rec->value.dsize == sizeof(val))) {
val = IVAL(rec->value.dptr, 0);
}
val += change_val;
data.dsize = sizeof(val);
data.dptr = (uint8 *)&val;
rec->store(rec, data, TDB_REPLACE);
TALLOC_FREE(rec);
return 0;
}

View File

@ -22,6 +22,10 @@
#ifdef CLUSTER_SUPPORT
#include "librpc/gen_ndr/messaging.h"
#include "ctdb.h"
#include "ctdb_private.h"
#include "ctdbd_conn.h"
struct messaging_ctdbd_context {
struct ctdbd_connection *conn;

View File

@ -505,6 +505,19 @@ bool file_exist(const char *fname,SMB_STRUCT_STAT *sbuf)
return((S_ISREG(sbuf->st_mode)) || (S_ISFIFO(sbuf->st_mode)));
}
/*******************************************************************
Check if a unix domain socket exists - call vfs_file_exist for samba files.
********************************************************************/
bool socket_exist(const char *fname)
{
SMB_STRUCT_STAT st;
if (sys_stat(fname,&st) != 0)
return(False);
return S_ISSOCK(st.st_mode);
}
/*******************************************************************
Check a files mod time.
********************************************************************/

View File

@ -41,11 +41,11 @@ static struct db_context *brlock_db;
static void print_lock_struct(unsigned int i, struct lock_struct *pls)
{
DEBUG(10,("[%u]: smbpid = %u, tid = %u, pid = %s, ",
DEBUG(10,("[%u]: smbpid = %u, tid = %u, pid = %u, ",
i,
(unsigned int)pls->context.smbpid,
(unsigned int)pls->context.tid,
procid_str_static(&pls->context.pid) ));
(unsigned int)procid_to_pid(&pls->context.pid) ));
DEBUG(10,("start = %.0f, size = %.0f, fnum = %d, %s %s\n",
(double)pls->start,
@ -263,10 +263,9 @@ void brl_init(bool read_only)
if (brlock_db) {
return;
}
brlock_db = db_open(NULL, lock_path("brlock.tdb"), 0,
TDB_DEFAULT
|TDB_VOLATILE
|(read_only?0x0:TDB_CLEAR_IF_FIRST),
brlock_db = db_open(NULL, lock_path("brlock.tdb"),
lp_open_files_db_hash_size(),
TDB_DEFAULT | TDB_CLEAR_IF_FIRST,
read_only?O_RDONLY:(O_RDWR|O_CREAT), 0644 );
if (!brlock_db) {
DEBUG(0,("Failed to open byte range locking database %s\n",
@ -1495,14 +1494,16 @@ static int traverse_fn(struct db_record *rec, void *state)
}
}
for ( i=0; i<num_locks; i++) {
cb->fn(*key,
locks[i].context.pid,
locks[i].lock_type,
locks[i].lock_flav,
locks[i].start,
locks[i].size,
cb->private_data);
if (cb->fn) {
for ( i=0; i<num_locks; i++) {
cb->fn(*key,
locks[i].context.pid,
locks[i].lock_type,
locks[i].lock_flav,
locks[i].start,
locks[i].size,
cb->private_data);
}
}
SAFE_FREE(locks);

View File

@ -22,9 +22,11 @@
#ifdef HAVE_GPFS
#include "gpfs_gpl.h"
#include "vfs_gpfs.h"
static void *libgpfs_handle = NULL;
static bool gpfs_share_modes;
static bool gpfs_leases;
static int (*gpfs_set_share_fn)(int fd, unsigned int allow, unsigned int deny);
static int (*gpfs_set_lease_fn)(int fd, unsigned int leaseType);
@ -42,7 +44,7 @@ bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask,
if (!gpfs_share_modes) {
return True;
}
if (gpfs_set_share_fn == NULL) {
return False;
}
@ -88,7 +90,7 @@ int set_gpfs_lease(int fd, int leasetype)
{
int gpfs_type = GPFS_LEASE_NONE;
if (!gpfs_share_modes) {
if (!gpfs_leases) {
return True;
}
@ -103,6 +105,13 @@ int set_gpfs_lease(int fd, int leasetype)
if (leasetype == F_WRLCK) {
gpfs_type = GPFS_LEASE_WRITE;
}
/* we unconditionally set CAP_LEASE, rather than looking for
-1/EACCES as there is a bug in some versions of
libgpfs_gpl.so which results in a leaked fd on /dev/ss0
each time we try this with the wrong capabilities set
*/
linux_set_lease_capability();
return gpfs_set_lease_fn(fd, gpfs_type);
}
@ -172,11 +181,8 @@ void init_gpfs(void)
goto failed;
}
if (lp_parm_bool(-1, "gpfs", "sharemodes", True)) {
gpfs_share_modes = True;
} else {
gpfs_share_modes = False;
}
gpfs_share_modes = lp_parm_bool(-1, "gpfs", "sharemodes", True);
gpfs_leases = lp_parm_bool(-1, "gpfs", "leases", True);
return;

View File

@ -20,6 +20,9 @@
#include "includes.h"
#include "nfs4_acls.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_ACLS
#define SMBACL4_PARAM_TYPE_NAME "nfs4"
#define SMB_ACE4_INT_MAGIC 0x76F8A967
@ -352,6 +355,7 @@ typedef struct _smbacl4_vfs_params {
enum smbacl4_mode_enum mode;
bool do_chown;
enum smbacl4_acedup_enum acedup;
struct db_context *sid_mapping_table;
} smbacl4_vfs_params;
/*
@ -451,8 +455,65 @@ static SMB_ACE4PROP_T *smbacl4_find_equal_special(
return NULL;
}
static int smbacl4_fill_ace4(
static bool nfs4_map_sid(smbacl4_vfs_params *params, const DOM_SID *src,
DOM_SID *dst)
{
static struct db_context *mapping_db = NULL;
TDB_DATA data;
if (mapping_db == NULL) {
const char *dbname = lp_parm_const_string(
-1, SMBACL4_PARAM_TYPE_NAME, "sidmap", NULL);
if (dbname == NULL) {
DEBUG(10, ("%s:sidmap not defined\n",
SMBACL4_PARAM_TYPE_NAME));
return False;
}
become_root();
mapping_db = db_open(NULL, dbname, 0, TDB_DEFAULT,
O_RDONLY, 0600);
unbecome_root();
if (mapping_db == NULL) {
DEBUG(1, ("could not open sidmap: %s\n",
strerror(errno)));
return False;
}
}
if (mapping_db->fetch(mapping_db, NULL,
string_term_tdb_data(sid_string_tos(src)),
&data) == -1) {
DEBUG(10, ("could not find mapping for SID %s\n",
sid_string_dbg(src)));
return False;
}
if ((data.dptr == NULL) || (data.dsize <= 0)
|| (data.dptr[data.dsize-1] != '\0')) {
DEBUG(5, ("invalid mapping for SID %s\n",
sid_string_dbg(src)));
TALLOC_FREE(data.dptr);
return False;
}
if (!string_to_sid(dst, (char *)data.dptr)) {
DEBUG(1, ("invalid mapping %s for SID %s\n",
(char *)data.dptr, sid_string_dbg(src)));
TALLOC_FREE(data.dptr);
return False;
}
TALLOC_FREE(data.dptr);
return True;
}
static bool smbacl4_fill_ace4(
TALLOC_CTX *mem_ctx,
const char *filename,
smbacl4_vfs_params *params,
uid_t ownerUID,
gid_t ownerGID,
@ -460,11 +521,6 @@ static int smbacl4_fill_ace4(
SMB_ACE4PROP_T *ace_v4 /* output */
)
{
const char *dom, *name;
enum lsa_SidType type;
uid_t uid;
gid_t gid;
DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
@ -485,18 +541,46 @@ static int smbacl4_fill_ace4(
ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
} else {
if (!lookup_sid(mem_ctx, &ace_nt->trustee, &dom, &name, &type)) {
DEBUG(8, ("Could not find %s' type\n",
sid_string_dbg(&ace_nt->trustee)));
errno = EINVAL;
return -1;
const char *dom, *name;
enum lsa_SidType type;
uid_t uid;
gid_t gid;
DOM_SID sid;
sid_copy(&sid, &ace_nt->trustee);
if (!lookup_sid(mem_ctx, &sid, &dom, &name, &type)) {
DOM_SID mapped;
if (!nfs4_map_sid(params, &sid, &mapped)) {
DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
"unknown\n", filename, sid_string_dbg(&sid)));
errno = EINVAL;
return False;
}
DEBUG(2, ("nfs4_acls.c: file [%s]: mapped SID %s "
"to %s\n", filename, sid_string_dbg(&sid), sid_string_dbg(&mapped)));
if (!lookup_sid(mem_ctx, &mapped, &dom,
&name, &type)) {
DEBUG(1, ("nfs4_acls.c: file [%s]: SID %s "
"mapped from %s is unknown\n",
filename, sid_string_dbg(&mapped), sid_string_dbg(&sid)));
errno = EINVAL;
return False;
}
sid_copy(&sid, &mapped);
}
if (type == SID_NAME_USER) {
if (!sid_to_uid(&ace_nt->trustee, &uid)) {
DEBUG(2, ("Could not convert %s to uid\n",
sid_string_dbg(&ace_nt->trustee)));
return -1;
if (!sid_to_uid(&sid, &uid)) {
DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
"convert %s to uid\n", filename,
sid_string_dbg(&sid)));
return False;
}
if (params->mode==e_special && uid==ownerUID) {
@ -506,11 +590,13 @@ static int smbacl4_fill_ace4(
ace_v4->who.uid = uid;
}
} else { /* else group? - TODO check it... */
if (!sid_to_gid(&ace_nt->trustee, &gid)) {
DEBUG(2, ("Could not convert %s to gid\n",
sid_string_dbg(&ace_nt->trustee)));
return -1;
if (!sid_to_gid(&sid, &gid)) {
DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
"convert %s to gid\n", filename,
sid_string_dbg(&sid)));
return False;
}
ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
if (params->mode==e_special && gid==ownerGID) {
@ -522,7 +608,7 @@ static int smbacl4_fill_ace4(
}
}
return 0; /* OK */
return True; /* OK */
}
static int smbacl4_MergeIgnoreReject(
@ -560,6 +646,7 @@ static int smbacl4_MergeIgnoreReject(
}
static SMB4ACL_T *smbacl4_win2nfs4(
const char *filename,
SEC_ACL *dacl,
smbacl4_vfs_params *pparams,
uid_t ownerUID,
@ -580,9 +667,14 @@ static SMB4ACL_T *smbacl4_win2nfs4(
SMB_ACE4PROP_T ace_v4;
bool addNewACE = True;
if (smbacl4_fill_ace4(mem_ctx, pparams, ownerUID, ownerGID,
dacl->aces + i, &ace_v4))
return NULL;
if (!smbacl4_fill_ace4(mem_ctx, filename, pparams,
ownerUID, ownerGID,
dacl->aces + i, &ace_v4)) {
DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
filename,
sid_string_dbg(&((dacl->aces+i)->trustee))));
continue;
}
if (pparams->acedup!=e_dontcare) {
if (smbacl4_MergeIgnoreReject(pparams->acedup, acl,
@ -607,6 +699,7 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
bool result;
SMB_STRUCT_STAT sbuf;
bool need_chown = False;
uid_t newUID = (uid_t)-1;
gid_t newGID = (gid_t)-1;
@ -635,25 +728,33 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
return status;
}
if (((newUID != (uid_t)-1) && (sbuf.st_uid != newUID)) ||
((newGID != (gid_t)-1) && (sbuf.st_gid != newGID))) {
if(try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) {
DEBUG(3,("chown %s, %u, %u failed. Error = %s.\n",
fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID, strerror(errno) ));
if (errno == EPERM) {
return NT_STATUS_INVALID_OWNER;
((newGID != (gid_t)-1) && (sbuf.st_gid != newGID))) {
need_chown = True;
}
if (need_chown) {
if ((newUID == (uid_t)-1 || newUID == current_user.ut.uid)) {
if(try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) {
DEBUG(3,("chown %s, %u, %u failed. Error = %s.\n",
fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID,
strerror(errno)));
return map_nt_error_from_unix(errno);
}
return map_nt_error_from_unix(errno);
DEBUG(10,("chown %s, %u, %u succeeded.\n",
fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
if (smbacl4_GetFileOwner(fsp->conn, fsp->fsp_name, &sbuf))
return map_nt_error_from_unix(errno);
need_chown = False;
} else { /* chown is needed, but _after_ changing acl */
sbuf.st_uid = newUID; /* OWNER@ in case of e_special */
sbuf.st_gid = newGID; /* GROUP@ in case of e_special */
}
DEBUG(10,("chown %s, %u, %u succeeded.\n",
fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
if (smbacl4_fGetFileOwner(fsp, &sbuf))
return map_nt_error_from_unix(errno);
}
}
if ((security_info_sent & DACL_SECURITY_INFORMATION)!=0 && psd->dacl!=NULL)
{
acl = smbacl4_win2nfs4(psd->dacl, &params, sbuf.st_uid, sbuf.st_gid);
acl = smbacl4_win2nfs4(fsp->fsp_name, psd->dacl, &params, sbuf.st_uid, sbuf.st_gid);
if (!acl)
return map_nt_error_from_unix(errno);
@ -668,6 +769,20 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
} else
DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n", security_info_sent));
/* Any chown pending? */
if (need_chown) {
DEBUG(3,("chown#2 %s. uid = %u, gid = %u.\n",
fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
if (try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) {
DEBUG(2,("chown#2 %s, %u, %u failed. Error = %s.\n",
fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID,
strerror(errno)));
return map_nt_error_from_unix(errno);
}
DEBUG(10,("chown#2 %s, %u, %u succeeded.\n",
fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
}
DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
return NT_STATUS_OK;
}

View File

@ -1225,6 +1225,38 @@ static int vfswrap_aio_suspend(struct vfs_handle_struct *handle, struct files_st
return sys_aio_suspend(aiocb, n, timeout);
}
static int vfswrap_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
{
return False;
}
static int vfswrap_is_offline(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, bool *offline)
{
if (ISDOT(path) || ISDOTDOT(path)) {
return 1;
}
if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
return -1;
}
*offline = (dmapi_file_flags(path) & FILE_ATTRIBUTE_OFFLINE) != 0;
return 0;
}
static int vfswrap_set_offline(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path)
{
/* We don't know how to set offline bit by default, needs to be overriden in the vfs modules */
return -1;
}
static bool vfswrap_is_remotestorage(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path)
{
/* We don't know how to detect that volume is remote storage. VFS modules should redefine it. */
return False;
}
static vfs_op_tuple vfs_default_ops[] = {
/* Disk operations */
@ -1442,6 +1474,16 @@ static vfs_op_tuple vfs_default_ops[] = {
{SMB_VFS_OP(vfswrap_aio_suspend),SMB_VFS_OP_AIO_SUSPEND,
SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(vfswrap_aio_force), SMB_VFS_OP_AIO_FORCE,
SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(vfswrap_is_offline),SMB_VFS_OP_IS_OFFLINE,
SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(vfswrap_set_offline),SMB_VFS_OP_SET_OFFLINE,
SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(vfswrap_is_remotestorage),SMB_VFS_OP_IS_REMOTESTORAGE,
SMB_VFS_LAYER_OPAQUE},
/* Finish VFS operations definition */
{SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP,

View File

@ -30,7 +30,7 @@
#include <gpfs_gpl.h>
#include "nfs4_acls.h"
#include "vfs_gpfs.h"
static int vfs_gpfs_kernel_flock(vfs_handle_struct *handle, files_struct *fsp,
uint32 share_mode)
@ -153,7 +153,7 @@ static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl)
DEBUG(10, ("gpfs_get_nfs4_acl invoked for %s\n", fname));
/* First get the real acl length */
gacl = gpfs_getacl_alloc(fname, GPFS_ACL_TYPE_NFS4);
gacl = gpfs_getacl_alloc(fname, 0);
if (gacl == NULL) {
DEBUG(9, ("gpfs_getacl failed for %s with %s\n",
fname, strerror(errno)));
@ -208,10 +208,10 @@ static int gpfs_get_nfs4_acl(const char *fname, SMB4ACL_T **ppacl)
if (i > 0 && gace->aceType == SMB_ACE4_ACCESS_DENIED_ACE_TYPE) {
struct gpfs_ace_v4 *prev = &gacl->ace_v4[i-1];
if (prev->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE &&
prev->aceFlags == gace->aceFlags &&
prev->aceIFlags == gace->aceIFlags &&
(gace->aceMask & prev->aceMask) == 0 &&
gace->aceWho == prev->aceWho) {
prev->aceFlags == gace->aceFlags &&
prev->aceIFlags == gace->aceIFlags &&
(gace->aceMask & prev->aceMask) == 0 &&
gace->aceWho == prev->aceWho) {
/* its redundent - skip it */
continue;
}
@ -256,7 +256,7 @@ static NTSTATUS gpfsacl_get_nt_acl(vfs_handle_struct *handle,
int result;
*ppdesc = NULL;
result = gpfs_get_nfs4_acl(fsp->fsp_name, &pacl);
result = gpfs_get_nfs4_acl(name, &pacl);
if (result == 0)
return smb_get_nt_acl_nfs4(handle->conn, name, security_info, ppdesc, pacl);
@ -301,8 +301,31 @@ static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl)
gace->aceType = aceprop->aceType;
gace->aceFlags = aceprop->aceFlags;
gace->aceMask = aceprop->aceMask;
/*
* GPFS can't distinguish between WRITE and APPEND on
* files, so one being set without the other is an
* error. Sorry for the many ()'s :-)
*/
if (!fsp->is_directory
&&
((((gace->aceMask & ACE4_MASK_WRITE) == 0)
&& ((gace->aceMask & ACE4_MASK_APPEND) != 0))
||
(((gace->aceMask & ACE4_MASK_WRITE) != 0)
&& ((gace->aceMask & ACE4_MASK_APPEND) == 0)))
&&
lp_parm_bool(fsp->conn->params->service, "gpfs",
"merge_writeappend", True)) {
DEBUG(2, ("vfs_gpfs.c: file [%s]: ACE contains "
"WRITE^APPEND, setting WRITE|APPEND\n",
fsp->fsp_name));
gace->aceMask |= ACE4_MASK_WRITE|ACE4_MASK_APPEND;
}
gace->aceIFlags = (aceprop->flags&SMB_ACE4_ID_SPECIAL) ? ACE4_IFLAG_SPECIAL_ID : 0;
if (aceprop->flags&SMB_ACE4_ID_SPECIAL)
{
switch(aceprop->who.special_id)
@ -347,7 +370,7 @@ static NTSTATUS gpfsacl_set_nt_acl_internal(files_struct *fsp, uint32 security_i
struct gpfs_acl *acl;
NTSTATUS result = NT_STATUS_ACCESS_DENIED;
acl = gpfs_getacl_alloc(fsp->fsp_name, GPFS_ACL_TYPE_ACCESS);
acl = gpfs_getacl_alloc(fsp->fsp_name, 0);
if (acl == NULL)
return result;
@ -628,75 +651,225 @@ int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle,
return -1;
}
/*
* Assumed: mode bits are shiftable and standard
* Output: the new aceMask field for an smb nfs4 ace
*/
static uint32 gpfsacl_mask_filter(uint32 aceType, uint32 aceMask, uint32 rwx)
{
const uint32 posix_nfs4map[3] = {
SMB_ACE4_EXECUTE, /* execute */
SMB_ACE4_WRITE_DATA | SMB_ACE4_APPEND_DATA, /* write; GPFS specific */
SMB_ACE4_READ_DATA /* read */
};
int i;
uint32_t posix_mask = 0x01;
uint32_t posix_bit;
uint32_t nfs4_bits;
for(i=0; i<3; i++) {
nfs4_bits = posix_nfs4map[i];
posix_bit = rwx & posix_mask;
if (aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
if (posix_bit)
aceMask |= nfs4_bits;
else
aceMask &= ~nfs4_bits;
} else {
/* add deny bits when suitable */
if (!posix_bit)
aceMask |= nfs4_bits;
else
aceMask &= ~nfs4_bits;
} /* other ace types are unexpected */
posix_mask <<= 1;
}
return aceMask;
}
static int gpfsacl_emu_chmod(const char *path, mode_t mode)
{
SMB4ACL_T *pacl = NULL;
int result;
bool haveAllowEntry[SMB_ACE4_WHO_EVERYONE + 1] = {False, False, False, False};
int i;
files_struct fake_fsp; /* TODO: rationalize parametrization */
SMB4ACE_T *smbace;
DEBUG(10, ("gpfsacl_emu_chmod invoked for %s mode %o\n", path, mode));
result = gpfs_get_nfs4_acl(path, &pacl);
if (result)
return result;
if (mode & ~(S_IRWXU | S_IRWXG | S_IRWXO)) {
DEBUG(2, ("WARNING: cutting extra mode bits %o on %s\n", mode, path));
}
for (smbace=smb_first_ace4(pacl); smbace!=NULL; smbace = smb_next_ace4(smbace)) {
SMB_ACE4PROP_T *ace = smb_get_ace4(smbace);
uint32_t specid = ace->who.special_id;
if (ace->flags&SMB_ACE4_ID_SPECIAL &&
ace->aceType<=SMB_ACE4_ACCESS_DENIED_ACE_TYPE &&
specid <= SMB_ACE4_WHO_EVERYONE) {
uint32_t newMask;
if (ace->aceType==SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE)
haveAllowEntry[specid] = True;
/* mode >> 6 for @owner, mode >> 3 for @group,
* mode >> 0 for @everyone */
newMask = gpfsacl_mask_filter(ace->aceType, ace->aceMask,
mode >> ((SMB_ACE4_WHO_EVERYONE - specid) * 3));
if (ace->aceMask!=newMask) {
DEBUG(10, ("ace changed for %s (%o -> %o) id=%d\n",
path, ace->aceMask, newMask, specid));
}
ace->aceMask = newMask;
}
}
/* make sure we have at least ALLOW entries
* for all the 3 special ids (@EVERYONE, @OWNER, @GROUP)
* - if necessary
*/
for(i = SMB_ACE4_WHO_OWNER; i<=SMB_ACE4_WHO_EVERYONE; i++) {
SMB_ACE4PROP_T ace;
if (haveAllowEntry[i]==True)
continue;
memset(&ace, 0, sizeof(SMB_ACE4PROP_T));
ace.aceType = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE;
ace.flags |= SMB_ACE4_ID_SPECIAL;
ace.who.special_id = i;
if (i==SMB_ACE4_WHO_GROUP) /* not sure it's necessary... */
ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
ace.aceMask = gpfsacl_mask_filter(ace.aceType, ace.aceMask,
mode >> ((SMB_ACE4_WHO_EVERYONE - i) * 3));
/* don't add unnecessary aces */
if (!ace.aceMask)
continue;
/* we add it to the END - as windows expects allow aces */
smb_add_ace4(pacl, &ace);
DEBUG(10, ("Added ALLOW ace for %s, mode=%o, id=%d, aceMask=%x\n",
path, mode, i, ace.aceMask));
}
/* don't add complementary DENY ACEs here */
memset(&fake_fsp, 0, sizeof(struct files_struct));
fake_fsp.fsp_name = (char *)path; /* no file_new is needed here */
/* put the acl */
if (gpfsacl_process_smbacl(&fake_fsp, pacl) == False)
return -1;
return 0; /* ok for [f]chmod */
}
static int vfs_gpfs_chmod(vfs_handle_struct *handle, const char *path, mode_t mode)
{
SMB_STRUCT_STAT st;
int rc;
if (SMB_VFS_NEXT_STAT(handle, path, &st) != 0) {
return -1;
return -1;
}
/* avoid chmod() if possible, to preserve acls */
if ((st.st_mode & ~S_IFMT) == mode) {
return 0;
return 0;
}
return SMB_VFS_NEXT_CHMOD(handle, path, mode);
rc = gpfsacl_emu_chmod(path, mode);
if (rc == 1)
return SMB_VFS_NEXT_CHMOD(handle, path, mode);
return rc;
}
static int vfs_gpfs_fchmod(vfs_handle_struct *handle, files_struct *fsp, mode_t mode)
{
SMB_STRUCT_STAT st;
int rc;
if (SMB_VFS_NEXT_FSTAT(handle, fsp, &st) != 0) {
return -1;
return -1;
}
/* avoid chmod() if possible, to preserve acls */
if ((st.st_mode & ~S_IFMT) == mode) {
return 0;
return 0;
}
return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
rc = gpfsacl_emu_chmod(fsp->fsp_name, mode);
if (rc == 1)
return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
return rc;
}
/* VFS operations structure */
static vfs_op_tuple gpfs_op_tuples[] = {
{ SMB_VFS_OP(vfs_gpfs_kernel_flock), SMB_VFS_OP_KERNEL_FLOCK,
SMB_VFS_LAYER_OPAQUE },
{ SMB_VFS_OP(vfs_gpfs_setlease), SMB_VFS_OP_LINUX_SETLEASE,
SMB_VFS_LAYER_OPAQUE },
{ SMB_VFS_OP(gpfsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(gpfsacl_get_nt_acl), SMB_VFS_OP_GET_NT_ACL,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(gpfsacl_fset_nt_acl), SMB_VFS_OP_FSET_NT_ACL,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(gpfsacl_set_nt_acl), SMB_VFS_OP_SET_NT_ACL,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(gpfsacl_sys_acl_get_file), SMB_VFS_OP_SYS_ACL_GET_FILE,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(gpfsacl_sys_acl_get_fd), SMB_VFS_OP_SYS_ACL_GET_FD,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(gpfsacl_sys_acl_set_file), SMB_VFS_OP_SYS_ACL_SET_FILE,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(gpfsacl_sys_acl_set_fd), SMB_VFS_OP_SYS_ACL_SET_FD,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(vfs_gpfs_kernel_flock),
SMB_VFS_OP_KERNEL_FLOCK,
SMB_VFS_LAYER_OPAQUE },
{ SMB_VFS_OP(vfs_gpfs_setlease),
SMB_VFS_OP_LINUX_SETLEASE,
SMB_VFS_LAYER_OPAQUE },
{ SMB_VFS_OP(gpfsacl_fget_nt_acl),
SMB_VFS_OP_FGET_NT_ACL,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(gpfsacl_get_nt_acl),
SMB_VFS_OP_GET_NT_ACL,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(gpfsacl_fset_nt_acl),
SMB_VFS_OP_FSET_NT_ACL,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(gpfsacl_set_nt_acl),
SMB_VFS_OP_SET_NT_ACL,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(gpfsacl_sys_acl_get_file),
SMB_VFS_OP_SYS_ACL_GET_FILE,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(gpfsacl_sys_acl_get_fd),
SMB_VFS_OP_SYS_ACL_GET_FD,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(gpfsacl_sys_acl_set_file),
SMB_VFS_OP_SYS_ACL_SET_FILE,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(gpfsacl_sys_acl_set_fd),
SMB_VFS_OP_SYS_ACL_SET_FD,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(gpfsacl_sys_acl_delete_def_file),
SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(vfs_gpfs_chmod), SMB_VFS_OP_CHMOD,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(vfs_gpfs_fchmod), SMB_VFS_OP_FCHMOD,
SMB_VFS_LAYER_TRANSPARENT },
SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(vfs_gpfs_chmod),
SMB_VFS_OP_CHMOD,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(vfs_gpfs_fchmod),
SMB_VFS_OP_FCHMOD,
SMB_VFS_LAYER_TRANSPARENT },
{ SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP }

View File

@ -0,0 +1,32 @@
/*
Unix SMB/CIFS implementation.
Wrap gpfs calls in vfs functions.
Copyright (C) Christian Ambach <cambach1@de.ibm.com> 2006
Major code contributions by Chetan Shringarpure <chetan.sh@in.ibm.com>
and Gomati Mohanan <gomati.mohanan@in.ibm.com>
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 2 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, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask,
uint32 share_access);
int set_gpfs_lease(int fd, int leasetype);
int smbd_gpfs_getacl(char *pathname, int flags, void *acl);
int smbd_gpfs_putacl(char *pathname, int flags, void *acl);
void init_gpfs(void);

View File

@ -47,11 +47,16 @@
#define lock_type struct flock64
#endif
#ifdef HAVE_GPFS
#include "gpfs_gpl.h"
#endif
#define MODULE "prealloc"
static int module_debug;
static int preallocate_space(int fd, SMB_OFF_T size)
{
#ifndef HAVE_GPFS
lock_type fl = {0};
int err;
@ -78,6 +83,9 @@ static int preallocate_space(int fd, SMB_OFF_T size)
err = -1;
errno = ENOSYS;
#endif
#else /* GPFS uses completely different interface */
err = gpfs_prealloc(fd, (gpfs_off64_t)0, (gpfs_off64_t)size);
#endif
if (err) {
DEBUG(module_debug,

View File

@ -0,0 +1,637 @@
/*
* implementation of an Shadow Copy module - version 2
*
* Copyright (C) Andrew Tridgell 2007
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "includes.h"
/*
This is a 2nd implemetation of a shadow copy module for exposing
snapshots to windows clients as shadow copies. This version has the
following features:
1) you don't need to populate your shares with symlinks to the
snapshots. This can be very important when you have thousands of
shares, or use [homes]
2) the inode number of the files is altered so it is different
from the original. This allows the 'restore' button to work
without a sharing violation
Module options:
shadow:snapdir = <directory where snapshots are kept>
This is the directory containing the @GMT-* snapshot directories. If it is an absolute
path it is used as-is. If it is a relative path, then it is taken relative to the mount
point of the filesystem that the root of this share is on
shadow:basedir = <base directory that snapshots are from>
This is an optional parameter that specifies the directory that
the snapshots are relative to. It defaults to the filesystem
mount point
shadow:fixinodes = yes/no
If you enable shadow:fixinodes then this module will modify the
apparent inode number of files in the snapshot directories using
a hash of the files path. This is needed for snapshot systems
where the snapshots have the same device:inode number as the
original files (such as happens with GPFS snapshots). If you
don't set this option then the 'restore' button in the shadow
copy UI will fail with a sharing violation.
Note that the directory names in the snapshot directory must take the form
@GMT-YYYY.MM.DD-HH.MM.SS
The following command would generate a correctly formatted directory name:
date -u +@GMT-%Y.%m.%d-%H.%M.%S
*/
static int vfs_shadow_copy2_debug_level = DBGC_VFS;
#undef DBGC_CLASS
#define DBGC_CLASS vfs_shadow_copy2_debug_level
#define GMT_NAME_LEN 24 /* length of a @GMT- name */
/*
make very sure it is one of our special names
*/
static inline bool shadow_copy2_match_name(const char *name)
{
unsigned year, month, day, hr, min, sec;
if (name[0] != '@') return False;
if (strncmp(name, "@GMT-", 5) != 0) return False;
if (sscanf(name, "@GMT-%04u.%02u.%02u-%02u.%02u.%02u", &year, &month,
&day, &hr, &min, &sec) != 6) {
return False;
}
if (name[24] != 0 && name[24] != '/') {
return False;
}
return True;
}
/*
convert a name to the shadow directory
*/
#define _SHADOW2_NEXT(op, args, rtype, eret, extra) do { \
const char *name = fname; \
if (shadow_copy2_match_name(fname)) { \
char *name2; \
rtype ret; \
name2 = convert_shadow2_name(handle, fname); \
if (name2 == NULL) { \
errno = EINVAL; \
return eret; \
} \
name = name2; \
ret = SMB_VFS_NEXT_ ## op args; \
talloc_free(name2); \
if (ret != eret) extra; \
return ret; \
} else { \
return SMB_VFS_NEXT_ ## op args; \
} \
} while (0)
/*
convert a name to the shadow directory: NTSTATUS-specific handling
*/
#define _SHADOW2_NTSTATUS_NEXT(op, args, eret, extra) do { \
const char *name = fname; \
if (shadow_copy2_match_name(fname)) { \
char *name2; \
NTSTATUS ret; \
name2 = convert_shadow2_name(handle, fname); \
if (name2 == NULL) { \
errno = EINVAL; \
return eret; \
} \
name = name2; \
ret = SMB_VFS_NEXT_ ## op args; \
talloc_free(name2); \
if (!NT_STATUS_EQUAL(ret, eret)) extra; \
return ret; \
} else { \
return SMB_VFS_NEXT_ ## op args; \
} \
} while (0)
#define SHADOW2_NTSTATUS_NEXT(op, args, eret) _SHADOW2_NTSTATUS_NEXT(op, args, eret, )
#define SHADOW2_NEXT(op, args, rtype, eret) _SHADOW2_NEXT(op, args, rtype, eret, )
#define SHADOW2_NEXT2(op, args) do { \
if (shadow_copy2_match_name(oldname) || shadow_copy2_match_name(newname)) { \
errno = EROFS; \
return -1; \
} else { \
return SMB_VFS_NEXT_ ## op args; \
} \
} while (0)
/*
find the mount point of a filesystem
*/
static char *find_mount_point(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
{
char *path = talloc_strdup(mem_ctx, handle->conn->connectpath);
dev_t dev;
struct stat st;
char *p;
if (stat(path, &st) != 0) {
talloc_free(path);
return NULL;
}
dev = st.st_dev;
while ((p = strrchr(path, '/')) && p > path) {
*p = 0;
if (stat(path, &st) != 0) {
talloc_free(path);
return NULL;
}
if (st.st_dev != dev) {
*p = '/';
break;
}
}
return path;
}
/*
work out the location of the snapshot for this share
*/
static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
{
const char *snapdir;
char *mount_point;
const char *ret;
snapdir = lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir", NULL);
if (snapdir == NULL) {
return NULL;
}
/* if its an absolute path, we're done */
if (*snapdir == '/') {
return snapdir;
}
/* other its relative to the filesystem mount point */
mount_point = find_mount_point(mem_ctx, handle);
if (mount_point == NULL) {
return NULL;
}
ret = talloc_asprintf(mem_ctx, "%s/%s", mount_point, snapdir);
talloc_free(mount_point);
return ret;
}
/*
work out the location of the base directory for snapshots of this share
*/
static const char *shadow_copy2_find_basedir(TALLOC_CTX *mem_ctx, vfs_handle_struct *handle)
{
const char *basedir = lp_parm_const_string(SNUM(handle->conn), "shadow", "basedir", NULL);
/* other its the filesystem mount point */
if (basedir == NULL) {
basedir = find_mount_point(mem_ctx, handle);
}
return basedir;
}
/*
convert a filename from a share relative path, to a path in the
snapshot directory
*/
static char *convert_shadow2_name(vfs_handle_struct *handle, const char *fname)
{
TALLOC_CTX *tmp_ctx = talloc_new(handle->data);
const char *snapdir, *relpath, *baseoffset, *basedir;
size_t baselen;
char *ret;
snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
if (snapdir == NULL) {
DEBUG(2,("no snapdir found for share at %s\n", handle->conn->connectpath));
talloc_free(tmp_ctx);
return NULL;
}
basedir = shadow_copy2_find_basedir(tmp_ctx, handle);
if (basedir == NULL) {
DEBUG(2,("no basedir found for share at %s\n", handle->conn->connectpath));
talloc_free(tmp_ctx);
return NULL;
}
relpath = fname + GMT_NAME_LEN;
baselen = strlen(basedir);
baseoffset = handle->conn->connectpath + baselen;
/* some sanity checks */
if (strncmp(basedir, handle->conn->connectpath, baselen) != 0 ||
(handle->conn->connectpath[baselen] != 0 && handle->conn->connectpath[baselen] != '/')) {
DEBUG(0,("convert_shadow2_name: basedir %s is not a parent of %s\n",
basedir, handle->conn->connectpath));
talloc_free(tmp_ctx);
return NULL;
}
if (*relpath == '/') relpath++;
if (*baseoffset == '/') baseoffset++;
ret = talloc_asprintf(handle->data, "%s/%.*s/%s/%s",
snapdir,
GMT_NAME_LEN, fname,
baseoffset,
relpath);
DEBUG(6,("convert_shadow2_name: '%s' -> '%s'\n", fname, ret));
talloc_free(tmp_ctx);
return ret;
}
/*
simple string hash
*/
static uint32 string_hash(const char *s)
{
uint32 n = 0;
while (*s) {
n = ((n << 5) + n) ^ (uint32)(*s++);
}
return n;
}
/*
modify a sbuf return to ensure that inodes in the shadow directory
are different from those in the main directory
*/
static void convert_sbuf(vfs_handle_struct *handle, const char *fname, SMB_STRUCT_STAT *sbuf)
{
if (lp_parm_bool(SNUM(handle->conn), "shadow", "fixinodes", False)) {
/* some snapshot systems, like GPFS, return the name
device:inode for the snapshot files as the current
files. That breaks the 'restore' button in the shadow copy
GUI, as the client gets a sharing violation.
This is a crude way of allowing both files to be
open at once. It has a slight chance of inode
number collision, but I can't see a better approach
without significant VFS changes
*/
uint32_t shash = string_hash(fname) & 0xFF000000;
if (shash == 0) {
shash = 1;
}
sbuf->st_ino ^= shash;
}
}
static int shadow_copy2_rename(vfs_handle_struct *handle,
const char *oldname, const char *newname)
{
SHADOW2_NEXT2(RENAME, (handle, oldname, newname));
}
static int shadow_copy2_symlink(vfs_handle_struct *handle,
const char *oldname, const char *newname)
{
SHADOW2_NEXT2(SYMLINK, (handle, oldname, newname));
}
static int shadow_copy2_link(vfs_handle_struct *handle,
const char *oldname, const char *newname)
{
SHADOW2_NEXT2(LINK, (handle, oldname, newname));
}
static int shadow_copy2_open(vfs_handle_struct *handle,
const char *fname, files_struct *fsp, int flags, mode_t mode)
{
SHADOW2_NEXT(OPEN, (handle, name, fsp, flags, mode), int, -1);
}
static SMB_STRUCT_DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
const char *fname, const char *mask, uint32 attr)
{
SHADOW2_NEXT(OPENDIR, (handle, name, mask, attr), void*, NULL);
}
static int shadow_copy2_stat(vfs_handle_struct *handle,
const char *fname, SMB_STRUCT_STAT *sbuf)
{
_SHADOW2_NEXT(STAT, (handle, name, sbuf), int, -1, convert_sbuf(handle, fname, sbuf));
}
static int shadow_copy2_lstat(vfs_handle_struct *handle,
const char *fname, SMB_STRUCT_STAT *sbuf)
{
_SHADOW2_NEXT(LSTAT, (handle, name, sbuf), int, -1, convert_sbuf(handle, fname, sbuf));
}
static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
{
int ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
if (ret == 0 && shadow_copy2_match_name(fsp->fsp_name)) {
convert_sbuf(handle, fsp->fsp_name, sbuf);
}
return ret;
}
static int shadow_copy2_unlink(vfs_handle_struct *handle, const char *fname)
{
SHADOW2_NEXT(UNLINK, (handle, name), int, -1);
}
static int shadow_copy2_chmod(vfs_handle_struct *handle,
const char *fname, mode_t mode)
{
SHADOW2_NEXT(CHMOD, (handle, name, mode), int, -1);
}
static int shadow_copy2_chown(vfs_handle_struct *handle,
const char *fname, uid_t uid, gid_t gid)
{
SHADOW2_NEXT(CHOWN, (handle, name, uid, gid), int, -1);
}
static int shadow_copy2_chdir(vfs_handle_struct *handle,
const char *fname)
{
SHADOW2_NEXT(CHDIR, (handle, name), int, -1);
}
static int shadow_copy2_ntimes(vfs_handle_struct *handle,
const char *fname, const struct timespec ts[2])
{
SHADOW2_NEXT(NTIMES, (handle, name, ts), int, -1);
}
static int shadow_copy2_readlink(vfs_handle_struct *handle,
const char *fname, char *buf, size_t bufsiz)
{
SHADOW2_NEXT(READLINK, (handle, name, buf, bufsiz), int, -1);
}
static int shadow_copy2_mknod(vfs_handle_struct *handle,
const char *fname, mode_t mode, SMB_DEV_T dev)
{
SHADOW2_NEXT(MKNOD, (handle, name, mode, dev), int, -1);
}
static char *shadow_copy2_realpath(vfs_handle_struct *handle,
const char *fname, char *resolved_path)
{
SHADOW2_NEXT(REALPATH, (handle, name, resolved_path), void*, NULL);
}
static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
const char *fname, uint32 security_info,
struct security_descriptor **ppdesc)
{
SHADOW2_NTSTATUS_NEXT(GET_NT_ACL, (handle, name, security_info, ppdesc), NT_STATUS_ACCESS_DENIED);
}
static NTSTATUS shadow_copy2_set_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
const char *fname, uint32 security_info_sent,
struct security_descriptor *psd)
{
SHADOW2_NTSTATUS_NEXT(SET_NT_ACL, (handle, fsp, name, security_info_sent, psd), NT_STATUS_ACCESS_DENIED);
}
static int shadow_copy2_mkdir(vfs_handle_struct *handle, const char *fname, mode_t mode)
{
SHADOW2_NEXT(MKDIR, (handle, name, mode), int, -1);
}
static int shadow_copy2_rmdir(vfs_handle_struct *handle, const char *fname)
{
SHADOW2_NEXT(RMDIR, (handle, name), int, -1);
}
static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname, int flags)
{
SHADOW2_NEXT(CHFLAGS, (handle, name, flags), int, -1);
}
static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
const char *fname, const char *aname, void *value, size_t size)
{
SHADOW2_NEXT(GETXATTR, (handle, name, aname, value, size), ssize_t, -1);
}
static ssize_t shadow_copy2_lgetxattr(vfs_handle_struct *handle,
const char *fname, const char *aname, void *value, size_t size)
{
SHADOW2_NEXT(LGETXATTR, (handle, name, aname, value, size), ssize_t, -1);
}
static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle, const char *fname,
char *list, size_t size)
{
SHADOW2_NEXT(LISTXATTR, (handle, name, list, size), ssize_t, -1);
}
static int shadow_copy2_removexattr(struct vfs_handle_struct *handle, const char *fname,
const char *aname)
{
SHADOW2_NEXT(REMOVEXATTR, (handle, name, aname), int, -1);
}
static int shadow_copy2_lremovexattr(struct vfs_handle_struct *handle, const char *fname,
const char *aname)
{
SHADOW2_NEXT(LREMOVEXATTR, (handle, name, aname), int, -1);
}
static int shadow_copy2_setxattr(struct vfs_handle_struct *handle, const char *fname,
const char *aname, const void *value, size_t size, int flags)
{
SHADOW2_NEXT(SETXATTR, (handle, name, aname, value, size, flags), int, -1);
}
static int shadow_copy2_lsetxattr(struct vfs_handle_struct *handle, const char *fname,
const char *aname, const void *value, size_t size, int flags)
{
SHADOW2_NEXT(LSETXATTR, (handle, name, aname, value, size, flags), int, -1);
}
static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
const char *fname, mode_t mode)
{
/* If the underlying VFS doesn't have ACL support... */
if (!handle->vfs_next.ops.chmod_acl) {
errno = ENOSYS;
return -1;
}
SHADOW2_NEXT(CHMOD_ACL, (handle, name, mode), int, -1);
}
static int shadow_copy2_get_shadow_copy2_data(vfs_handle_struct *handle,
files_struct *fsp,
SHADOW_COPY_DATA *shadow_copy2_data,
bool labels)
{
SMB_STRUCT_DIR *p;
const char *snapdir;
SMB_STRUCT_DIRENT *d;
TALLOC_CTX *tmp_ctx = talloc_new(handle->data);
snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle);
if (snapdir == NULL) {
DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
handle->conn->connectpath));
errno = EINVAL;
talloc_free(tmp_ctx);
return -1;
}
p = SMB_VFS_NEXT_OPENDIR(handle, snapdir, NULL, 0);
if (!p) {
DEBUG(0,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s' - %s\n",
snapdir, strerror(errno)));
talloc_free(tmp_ctx);
return -1;
}
talloc_free(tmp_ctx);
shadow_copy2_data->num_volumes = 0;
shadow_copy2_data->labels = NULL;
while ((d = SMB_VFS_NEXT_READDIR(handle, p))) {
SHADOW_COPY_LABEL *tlabels;
/* ignore names not of the right form in the snapshot directory */
if (!shadow_copy2_match_name(d->d_name)) {
continue;
}
if (!labels) {
/* the caller doesn't want the labels */
shadow_copy2_data->num_volumes++;
continue;
}
tlabels = talloc_realloc(shadow_copy2_data->mem_ctx,
shadow_copy2_data->labels,
SHADOW_COPY_LABEL, shadow_copy2_data->num_volumes+1);
if (tlabels == NULL) {
DEBUG(0,("shadow_copy2: out of memory\n"));
SMB_VFS_NEXT_CLOSEDIR(handle, p);
return -1;
}
strlcpy(tlabels[shadow_copy2_data->num_volumes], d->d_name, sizeof(*tlabels));
shadow_copy2_data->num_volumes++;
shadow_copy2_data->labels = tlabels;
}
SMB_VFS_NEXT_CLOSEDIR(handle,p);
return 0;
}
/* VFS operations structure */
static vfs_op_tuple shadow_copy2_ops[] = {
{SMB_VFS_OP(shadow_copy2_opendir), SMB_VFS_OP_OPENDIR, SMB_VFS_LAYER_TRANSPARENT},
/* directory operations */
{SMB_VFS_OP(shadow_copy2_mkdir), SMB_VFS_OP_MKDIR, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_rmdir), SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_TRANSPARENT},
/* xattr and flags operations */
{SMB_VFS_OP(shadow_copy2_chflags), SMB_VFS_OP_CHFLAGS, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_getxattr), SMB_VFS_OP_GETXATTR, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_lgetxattr), SMB_VFS_OP_LGETXATTR, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_listxattr), SMB_VFS_OP_LISTXATTR, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_removexattr), SMB_VFS_OP_REMOVEXATTR, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_lremovexattr),SMB_VFS_OP_LREMOVEXATTR,SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_setxattr), SMB_VFS_OP_SETXATTR, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_lsetxattr), SMB_VFS_OP_LSETXATTR, SMB_VFS_LAYER_TRANSPARENT},
/* File operations */
{SMB_VFS_OP(shadow_copy2_open), SMB_VFS_OP_OPEN, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_rename), SMB_VFS_OP_RENAME, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_stat), SMB_VFS_OP_STAT, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_lstat), SMB_VFS_OP_LSTAT, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_fstat), SMB_VFS_OP_FSTAT, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_unlink), SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_chmod), SMB_VFS_OP_CHMOD, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_chown), SMB_VFS_OP_CHOWN, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_chdir), SMB_VFS_OP_CHDIR, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_ntimes), SMB_VFS_OP_NTIMES, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_symlink), SMB_VFS_OP_SYMLINK, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_readlink), SMB_VFS_OP_READLINK, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_link), SMB_VFS_OP_LINK, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_mknod), SMB_VFS_OP_MKNOD, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_realpath), SMB_VFS_OP_REALPATH, SMB_VFS_LAYER_TRANSPARENT},
/* NT File ACL operations */
{SMB_VFS_OP(shadow_copy2_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(shadow_copy2_set_nt_acl), SMB_VFS_OP_SET_NT_ACL, SMB_VFS_LAYER_TRANSPARENT},
/* POSIX ACL operations */
{SMB_VFS_OP(shadow_copy2_chmod_acl), SMB_VFS_OP_CHMOD_ACL, SMB_VFS_LAYER_TRANSPARENT},
/* special shadown copy op */
{SMB_VFS_OP(shadow_copy2_get_shadow_copy2_data),
SMB_VFS_OP_GET_SHADOW_COPY_DATA,SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
};
NTSTATUS vfs_shadow_copy2_init(void);
NTSTATUS vfs_shadow_copy2_init(void)
{
NTSTATUS ret;
ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "shadow_copy2", shadow_copy2_ops);
if (!NT_STATUS_IS_OK(ret))
return ret;
vfs_shadow_copy2_debug_level = debug_add_class("shadow_copy2");
if (vfs_shadow_copy2_debug_level == -1) {
vfs_shadow_copy2_debug_level = DBGC_VFS;
DEBUG(0, ("%s: Couldn't register custom debugging class!\n",
"vfs_shadow_copy2_init"));
} else {
DEBUG(10, ("%s: Debug class number of '%s': %d\n",
"vfs_shadow_copy2_init","shadow_copy2",vfs_shadow_copy2_debug_level));
}
return ret;
}

338
source3/modules/vfs_tsmsm.c Normal file
View File

@ -0,0 +1,338 @@
/*
Unix SMB/CIFS implementation.
Samba VFS module for handling offline files
with Tivoli Storage Manager Space Management
(c) Alexander Bokovoy, 2007
(c) Andrew Tridgell, 2007
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/>.
*/
/*
This VFS module accepts following options:
tsmsm: hsm script = <path to hsm script> (/bin/true by default, i.e. does nothing)
hsm script should point to a shell script which accepts two arguments:
<operation> <filepath>
where <operation> is currently 'offline' to set offline status of the <filepath>
tsmsm: online ratio = ratio to check reported size against actual file size (0.5 by default)
The TSMSM VFS module tries to avoid calling expensive DMAPI calls with some heuristics
based on the fact that number of blocks reported of a file multiplied by 512 will be
bigger than 'online ratio' of actual size for online (non-migrated) files.
If checks fail, we call DMAPI and ask for specific IBM attribute which present for
offline (migrated) files. If this attribute presents, we consider file offline.
*/
#include "includes.h"
#ifndef USE_DMAPI
#error "This module requires DMAPI support!"
#endif
#ifdef HAVE_XFS_DMAPI_H
#include <xfs/dmapi.h>
#elif defined(HAVE_SYS_DMI_H)
#include <sys/dmi.h>
#elif defined(HAVE_SYS_JFSDMAPI_H)
#include <sys/jfsdmapi.h>
#elif defined(HAVE_SYS_DMAPI_H)
#include <sys/dmapi.h>
#elif defined(HAVE_DMAPI_H)
#include <dmapi.h>
#endif
#ifndef _ISOC99_SOURCE
#define _ISOC99_SOURCE
#endif
#include <math.h>
/* optimisation tunables - used to avoid the DMAPI slow path */
#define FILE_IS_ONLINE_RATIO 0.5
#define DM_ATTRIB_OBJECT "IBMObj"
#define DM_ATTRIB_MIGRATED "IBMMig"
struct tsmsm_struct {
dm_sessid_t sid;
float online_ratio;
char *hsmscript;
};
#define TSM_STRINGIFY(a) #a
#define TSM_TOSTRING(a) TSM_STRINGIFY(a)
static void tsmsm_free_data(void **pptr) {
struct tsmsm_struct **tsmd = (struct tsmsm_struct **)pptr;
if(!tsmd) return;
TALLOC_FREE(*tsmd);
}
static int tsmsm_connect(struct vfs_handle_struct *handle,
const char *service,
const char *user) {
struct tsmsm_struct *tsmd = TALLOC_ZERO_P(handle, struct tsmsm_struct);
const char *hsmscript, *tsmname;
const char *fres;
if (!tsmd) {
DEBUG(0,("tsmsm_connect: out of memory!\n"));
return -1;
}
tsmd->sid = *(dm_sessid_t*) dmapi_get_current_session();
if (tsmd->sid == DM_NO_SESSION) {
DEBUG(0,("tsmsm_connect: no DMAPI session for Samba is available!\n"));
TALLOC_FREE(tsmd);
return -1;
}
tsmname = (handle->param ? handle->param : "tsmsm");
hsmscript = lp_parm_const_string(SNUM(handle->conn), tsmname,
"hsm script", NULL);
if (hsmscript) {
tsmd->hsmscript = talloc_strdup(tsmd, hsmscript);
if(!tsmd->hsmscript) {
DEBUG(1, ("tsmsm_connect: can't allocate memory for hsm script path"));
TALLOC_FREE(tsmd);
return -1;
}
} else {
DEBUG(1, ("tsmsm_connect: can't call hsm script because it "
"is not set to anything in the smb.conf\n"
"Use %s: 'hsm script = path' to set it\n",
tsmname));
TALLOC_FREE(tsmd);
return -1;
}
fres = lp_parm_const_string(SNUM(handle->conn), tsmname,
"online ratio", TSM_TOSTRING(FILE_IS_ONLINE_RATIO));
tsmd->online_ratio = strtof(fres, NULL);
if((tsmd->online_ratio == (float)0) || ((errno == ERANGE) &&
((tsmd->online_ratio == HUGE_VALF) ||
(tsmd->online_ratio == HUGE_VALL)))) {
DEBUG(1, ("tsmsm_connect: error while getting online ratio from smb.conf."
"Default to %s.\n", TSM_TOSTRING(FILE_IS_ONLINE_RATIO)));
tsmd->online_ratio = FILE_IS_ONLINE_RATIO;
}
/* Store the private data. */
SMB_VFS_HANDLE_SET_DATA(handle, tsmd, tsmsm_free_data,
struct tsmsm_struct, return -1);
return SMB_VFS_NEXT_CONNECT(handle, service, user);
}
static int tsmsm_is_offline(struct vfs_handle_struct *handle,
struct connection_struct *conn,
const char *path,
SMB_STRUCT_STAT *stbuf,
bool *offline) {
struct tsmsm_struct *tsmd = (struct tsmsm_struct *) handle->data;
void *dmhandle = NULL;
size_t dmhandle_len = 0;
size_t rlen;
dm_attrname_t dmname;
int ret;
/* if the file has more than FILE_IS_ONLINE_RATIO of blocks available,
then assume it is not offline (it may not be 100%, as it could be sparse) */
if (512 * (off_t)stbuf->st_blocks >= stbuf->st_size * tsmd->online_ratio) {
*offline = false;
DEBUG(10,("%s not offline: st_blocks=%ld st_size=%ld online_ratio=%.2f\n",
path, stbuf->st_blocks, stbuf->st_size, tsmd->online_ratio));
return 0;
}
/* using POSIX capabilities does not work here. It's a slow path, so
* become_root() is just as good anyway (tridge)
*/
/* Also, AIX has DMAPI but no POSIX capablities support. In this case,
* we need to be root to do DMAPI manipulations.
*/
become_root();
/* go the slow DMAPI route */
if (dm_path_to_handle((char*)path, &dmhandle, &dmhandle_len) != 0) {
ret = -1;
DEBUG(2,("dm_path_to_handle failed - assuming offline (%s) - %s\n",
path, strerror(errno)));
*offline = True;
goto done;
}
memset(&dmname, 0, sizeof(dmname));
strlcpy((char *)&dmname.an_chars[0], DM_ATTRIB_OBJECT, sizeof(dmname.an_chars));
ret = dm_get_dmattr(tsmd->sid, dmhandle, dmhandle_len,
DM_NO_TOKEN, &dmname, 0, NULL, &rlen);
/* its offline if the IBMObj attribute exists */
*offline = (ret == 0 || (ret == -1 && errno == E2BIG));
DEBUG(10,("dm_get_dmattr %s ret=%d (%s)\n", path, ret, strerror(errno)));
ret = 0;
dm_handle_free(dmhandle, dmhandle_len);
done:
unbecome_root();
return ret;
}
static bool tsmsm_aio_force(struct vfs_handle_struct *handle, struct files_struct *fsp)
{
SMB_STRUCT_STAT sbuf;
struct tsmsm_struct *tsmd = (struct tsmsm_struct *) handle->data;
/* see if the file might be offline. This is called before each IO
to ensure we use AIO if the file is offline. We don't do the full dmapi
call as that would be too slow, instead we err on the side of using AIO
if the file might be offline
*/
if(SMB_VFS_FSTAT(fsp, &sbuf) == 0) {
DEBUG(10,("tsmsm_aio_force st_blocks=%ld st_size=%ld online_ratio=%.2f\n",
sbuf.st_blocks, sbuf.st_size, tsmd->online_ratio));
return !(512 * (off_t)sbuf.st_blocks >= sbuf.st_size * tsmd->online_ratio);
}
return False;
}
static ssize_t tsmsm_aio_return(struct vfs_handle_struct *handle, struct files_struct *fsp,
SMB_STRUCT_AIOCB *aiocb)
{
ssize_t result;
result = SMB_VFS_NEXT_AIO_RETURN(handle, fsp, aiocb);
if(result >= 0) {
notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
FILE_NOTIFY_CHANGE_ATTRIBUTES,
fsp->fsp_name);
}
return result;
}
static ssize_t tsmsm_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fsp, const DATA_BLOB *hdr,
SMB_OFF_T offset, size_t n)
{
bool file_online = tsmsm_aio_force(handle, fsp);
if(!file_online)
return ENOSYS;
return SMB_VFS_NEXT_SENDFILE(handle, tofd, fsp, hdr, offset, n);
}
/* We do overload pread to allow notification when file becomes online after offline status */
/* We don't intercept SMB_VFS_READ here because all file I/O now goes through SMB_VFS_PREAD instead */
static ssize_t tsmsm_pread(struct vfs_handle_struct *handle, struct files_struct *fsp,
void *data, size_t n, SMB_OFF_T offset) {
ssize_t result;
bool notify_online = tsmsm_aio_force(handle, fsp);
result = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
if((result != -1) && notify_online) {
/* We can't actually force AIO at this point (came here not from reply_read_and_X)
what we can do is to send notification that file became online
*/
notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
FILE_NOTIFY_CHANGE_ATTRIBUTES,
fsp->fsp_name);
}
return result;
}
static ssize_t tsmsm_pwrite(struct vfs_handle_struct *handle, struct files_struct *fsp,
void *data, size_t n, SMB_OFF_T offset) {
ssize_t result;
bool notify_online = tsmsm_aio_force(handle, fsp);
result = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
if((result != -1) && notify_online) {
/* We can't actually force AIO at this point (came here not from reply_read_and_X)
what we can do is to send notification that file became online
*/
notify_fname(handle->conn, NOTIFY_ACTION_MODIFIED,
FILE_NOTIFY_CHANGE_ATTRIBUTES,
fsp->fsp_name);
}
return result;
}
static int tsmsm_set_offline(struct vfs_handle_struct *handle, struct connection_struct *conn,
const char *path) {
struct tsmsm_struct *tsmd = (struct tsmsm_struct *) handle->data;
int result = 0;
char *command;
/* Now, call the script */
command = talloc_asprintf(tsmd, "%s offline \"%s\"", tsmd->hsmscript, path);
if(!command) {
DEBUG(1, ("tsmsm_set_offline: can't allocate memory to run hsm script"));
return -1;
}
DEBUG(10, ("tsmsm_set_offline: Running [%s]\n", command));
if((result = smbrun(command, NULL)) != 0) {
DEBUG(1,("tsmsm_set_offline: Running [%s] returned %d\n", command, result));
}
TALLOC_FREE(command);
return result;
}
static bool tsmsm_is_remotestorage(struct vfs_handle_struct *handle, struct connection_struct *conn, const char *path) {
return True;
}
static vfs_op_tuple vfs_tsmsm_ops[] = {
/* Disk operations */
{SMB_VFS_OP(tsmsm_connect), SMB_VFS_OP_CONNECT,
SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(tsmsm_aio_force), SMB_VFS_OP_AIO_FORCE,
SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(tsmsm_aio_return), SMB_VFS_OP_AIO_RETURN,
SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(tsmsm_pread), SMB_VFS_OP_PREAD,
SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(tsmsm_pwrite), SMB_VFS_OP_PWRITE,
SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(tsmsm_sendfile), SMB_VFS_OP_SENDFILE,
SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(tsmsm_is_offline),SMB_VFS_OP_IS_OFFLINE,
SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(tsmsm_set_offline),SMB_VFS_OP_SET_OFFLINE,
SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(tsmsm_is_remotestorage),SMB_VFS_OP_IS_REMOTESTORAGE,
SMB_VFS_LAYER_OPAQUE},
/* Finish VFS operations definition */
{SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP,
SMB_VFS_LAYER_NOOP}
};
NTSTATUS vfs_tsmsm_init(void);
NTSTATUS vfs_tsmsm_init(void)
{
return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
"tsmsm", vfs_tsmsm_ops);
}

View File

@ -117,6 +117,15 @@ int count_current_connections( const char *sharename, bool clear )
return cs.curr_connections;
}
/****************************************************************************
Count the number of connections open across all shares.
****************************************************************************/
int count_all_current_connections(void)
{
return count_current_connections(NULL, True /* clear stale entries */);
}
/****************************************************************************
Claim an entry in the connections database.
****************************************************************************/

View File

@ -46,7 +46,7 @@ bool dmapi_have_session(void) { return False; }
#define DMAPI_SESSION_NAME "samba"
#define DMAPI_TRACE 10
static dm_sessid_t dmapi_session = DM_NO_SESSION;
static dm_sessid_t samba_dmapi_session = DM_NO_SESSION;
/* Initialise the DMAPI interface. Make sure that we only end up initialising
* once per process to avoid resource leaks across different DMAPI
@ -75,7 +75,7 @@ static int init_dmapi_service(void)
bool dmapi_have_session(void)
{
return dmapi_session != DM_NO_SESSION;
return samba_dmapi_session != DM_NO_SESSION;
}
static dm_sessid_t *realloc_session_list(dm_sessid_t * sessions, int count)
@ -110,7 +110,7 @@ int dmapi_init_session(void)
*/
SMB_WARN(getuid() == 0, "dmapi_init_session must be called as root");
dmapi_session = DM_NO_SESSION;
samba_dmapi_session = DM_NO_SESSION;
if (init_dmapi_service() < 0) {
return -1;
}
@ -139,7 +139,7 @@ retry:
err = dm_query_session(sessions[i], sizeof(buf), buf, &buflen);
buf[sizeof(buf) - 1] = '\0';
if (err == 0 && strcmp(DMAPI_SESSION_NAME, buf) == 0) {
dmapi_session = sessions[i];
samba_dmapi_session = sessions[i];
DEBUGADD(DMAPI_TRACE,
("attached to existing DMAPI session "
"named '%s'\n", buf));
@ -150,16 +150,15 @@ retry:
TALLOC_FREE(sessions);
/* No session already defined. */
if (dmapi_session == DM_NO_SESSION) {
err = dm_create_session(DM_NO_SESSION,
CONST_DISCARD(char *,
DMAPI_SESSION_NAME),
&dmapi_session);
if (samba_dmapi_session == DM_NO_SESSION) {
err = dm_create_session(DM_NO_SESSION,
CONST_DISCARD(char *, DMAPI_SESSION_NAME),
&samba_dmapi_session);
if (err < 0) {
DEBUGADD(DMAPI_TRACE,
("failed to create new DMAPI session: %s\n",
strerror(errno)));
dmapi_session = DM_NO_SESSION;
samba_dmapi_session = DM_NO_SESSION;
return -1;
}
@ -185,22 +184,22 @@ static int reattach_dmapi_session(void)
char buf[DM_SESSION_INFO_LEN];
size_t buflen;
if (dmapi_session != DM_NO_SESSION ) {
if (samba_dmapi_session != DM_NO_SESSION ) {
become_root();
/* NOTE: On Linux, this call opens /dev/dmapi, costing us a
* file descriptor. Ideally, we would close this when we fork.
*/
if (init_dmapi_service() < 0) {
dmapi_session = DM_NO_SESSION;
samba_dmapi_session = DM_NO_SESSION;
unbecome_root();
return -1;
}
if (dm_query_session(dmapi_session, sizeof(buf),
if (dm_query_session(samba_dmapi_session, sizeof(buf),
buf, &buflen) < 0) {
/* Session is stale. Disable DMAPI. */
dmapi_session = DM_NO_SESSION;
samba_dmapi_session = DM_NO_SESSION;
unbecome_root();
return -1;
}
@ -214,33 +213,42 @@ static int reattach_dmapi_session(void)
return 0;
}
uint32 dmapi_file_flags(const char * const path)
/* If a DMAPI session has been initialised, then we need to make sure
* we are attached to it and have the correct privileges. This is
* necessary to be able to do DMAPI operations across a fork(2). If
* it fails, there is no likelihood of that failure being transient.
*
* Note that this use of the static attached flag relies on the fact
* that dmapi_file_flags() is never called prior to forking the
* per-client server process.
*/
const void * dmapi_get_current_session(void)
{
static int attached = 0;
if (dmapi_have_session() && !attached) {
attached++;
if (reattach_dmapi_session() < 0) {
return DM_NO_SESSION;
}
}
return &samba_dmapi_session;
}
uint32 dmapi_file_flags(const char * const path)
{
dm_sessid_t dmapi_session;
int err;
dm_eventset_t events = {0};
uint nevents;
void *dm_handle;
size_t dm_handle_len;
void *dm_handle = NULL;
size_t dm_handle_len = 0;
uint32 flags = 0;
/* If a DMAPI session has been initialised, then we need to make sure
* we are attached to it and have the correct privileges. This is
* necessary to be able to do DMAPI operations across a fork(2). If
* it fails, there is no liklihood of that failure being transient.
*
* Note that this use of the static attached flag relies on the fact
* that dmapi_file_flags() is never called prior to forking the
* per-client server process.
*/
if (dmapi_have_session() && !attached) {
attached++;
if (reattach_dmapi_session() < 0) {
return 0;
}
dmapi_session = *(dm_sessid_t*) dmapi_get_current_session();
if (dmapi_session == DM_NO_SESSION) {
return 0;
}
/* AIX has DMAPI but no POSIX capablities support. In this case,
@ -313,4 +321,5 @@ done:
return flags;
}
#endif /* USE_DMAPI */

View File

@ -30,23 +30,6 @@ static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
return 0;
}
/****************************************************************************
Work out whether this file is offline
****************************************************************************/
static uint32 set_offline_flag(connection_struct *conn, const char *const path)
{
if (ISDOT(path) || ISDOTDOT(path)) {
return 0;
}
if (!lp_dmapi_support(SNUM(conn)) || !dmapi_have_session()) {
return 0;
}
return dmapi_file_flags(path);
}
/****************************************************************************
Change a dos mode to a unix mode.
Base permission for files:
@ -366,6 +349,8 @@ uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT
uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
{
uint32 result = 0;
bool offline;
int ret;
DEBUG(8,("dos_mode: %s\n", path));
@ -395,8 +380,10 @@ uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
result |= dos_mode_from_sbuf(conn, path, sbuf);
}
if (S_ISREG(sbuf->st_mode)) {
result |= set_offline_flag(conn, path);
ret = SMB_VFS_IS_OFFLINE(conn, path, sbuf, &offline);
if (S_ISREG(sbuf->st_mode) && (ret == 0) && offline) {
result |= FILE_ATTRIBUTE_OFFLINE;
}
/* Optimization : Only call is_hidden_path if it's not already
@ -432,7 +419,7 @@ int file_set_dosmode(connection_struct *conn, const char *fname,
int mask=0;
mode_t tmp;
mode_t unixmode;
int ret = -1;
int ret = -1, lret = -1;
/* We only allow READONLY|HIDDEN|SYSTEM|DIRECTORY|ARCHIVE here. */
dosmode &= SAMBA_ATTRIBUTES_MASK;
@ -505,10 +492,21 @@ int file_set_dosmode(connection_struct *conn, const char *fname,
unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH));
}
if ((ret = SMB_VFS_CHMOD(conn,fname,unixmode)) == 0) {
if (!newfile) {
if (dosmode & FILE_ATTRIBUTE_OFFLINE) {
lret = SMB_VFS_SET_OFFLINE(conn, fname);
if (lret == -1) {
DEBUG(0, ("set_dos_mode: client has asked to set "
"FILE_ATTRIBUTE_OFFLINE to %s/%s but there was "
"an error while setting it or it is not supported.\n",
parent_dir, fname));
}
}
ret = SMB_VFS_CHMOD(conn, fname, unixmode);
if (ret == 0) {
if(!newfile || (lret != -1)) {
notify_fname(conn, NOTIFY_ACTION_MODIFIED,
FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
FILE_NOTIFY_CHANGE_ATTRIBUTES, fname);
}
st->st_mode = unixmode;
return 0;

View File

@ -93,17 +93,27 @@ static void set_capability(unsigned capability)
return;
}
data.effective |= (1<<capability);
if (0 == (data.effective & (1<<capability))) {
data.effective |= (1<<capability);
if (capset(&header, &data) == -1) {
DEBUG(3,("Unable to set %d capability (%s)\n",
capability, strerror(errno)));
if (capset(&header, &data) == -1) {
DEBUG(3,("Unable to set %d capability (%s)\n",
capability, strerror(errno)));
}
}
}
/*
Call to set the kernel lease signal handler
*/
* public function to get linux lease capability. Needed by some VFS modules (eg. gpfs.c)
*/
void linux_set_lease_capability(void)
{
set_capability(CAP_LEASE);
}
/*
* Call to set the kernel lease signal handler
*/
int linux_set_lease_sighandler(int fd)
{
if (fcntl(fd, F_SETSIG, RT_SIGNAL_LEASE) == -1) {

View File

@ -3413,6 +3413,9 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
bool acl_perms = False;
mode_t orig_mode = (mode_t)0;
NTSTATUS status;
uid_t orig_uid;
gid_t orig_gid;
bool need_chown = False;
DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
@ -3435,6 +3438,8 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
/* Save the original elements we check against. */
orig_mode = sbuf.st_mode;
orig_uid = sbuf.st_uid;
orig_gid = sbuf.st_gid;
/*
* Unpack the user/group/world id's.
@ -3449,7 +3454,11 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
* Do we need to chown ?
*/
if (((user != (uid_t)-1) && (sbuf.st_uid != user)) || (( grp != (gid_t)-1) && (sbuf.st_gid != grp))) {
if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp))) {
need_chown = True;
}
if (need_chown && (user == (uid_t)-1 || user == current_user.ut.uid)) {
DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
@ -3487,6 +3496,11 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
/* Save the original elements we check against. */
orig_mode = sbuf.st_mode;
orig_uid = sbuf.st_uid;
orig_gid = sbuf.st_gid;
/* We did chown already, drop the flag */
need_chown = False;
}
create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
@ -3630,6 +3644,21 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
free_canon_ace_list(dir_ace_list);
}
/* Any chown pending? */
if (need_chown) {
DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
if (errno == EPERM) {
return NT_STATUS_INVALID_OWNER;
}
return map_nt_error_from_unix(errno);
}
}
return NT_STATUS_OK;
}

View File

@ -3329,8 +3329,12 @@ void reply_read_and_X(struct smb_request *req)
return;
}
if (!big_readX
&& schedule_aio_read_and_X(conn, req, fsp, startpos, smb_maxcnt)) {
/* It is possible for VFS modules to selectively decide whether Async I/O should be used
for the file or not.
*/
if ((SMB_VFS_AIO_FORCE(fsp)) &&
!big_readX &&
schedule_aio_read_and_X(conn, req, fsp, startpos, smb_maxcnt)) {
END_PROFILE(SMBreadX);
return;
}
@ -4001,13 +4005,16 @@ void reply_write_and_X(struct smb_request *req)
nwritten = 0;
} else {
if (req->unread_bytes == 0 &&
schedule_aio_write_and_X(conn, req, fsp, data,
startpos, numtowrite)) {
/* It is possible for VFS modules to selectively decide whether Async I/O
should be used for the file or not.
*/
if ((SMB_VFS_AIO_FORCE(fsp)) && (req->unread_bytes == 0) &&
schedule_aio_write_and_X(conn, req, fsp, data, startpos,
numtowrite)) {
END_PROFILE(SMBwriteX);
return;
}
nwritten = write_file(req,fsp,data,startpos,numtowrite);
}

View File

@ -268,10 +268,20 @@ static void add_child_pid(pid_t pid)
num_children += 1;
}
static void remove_child_pid(pid_t pid)
static void remove_child_pid(pid_t pid, bool unclean_shutdown)
{
struct child_pid *child;
if (unclean_shutdown) {
/* a child terminated uncleanly so tickle all processes to see
if they can grab any of the pending locks
*/
messaging_send_buf(smbd_messaging_context(), procid_self(),
MSG_SMB_BRL_VALIDATE, NULL, 0);
message_send_all(smbd_messaging_context(),
MSG_SMB_UNLOCK, NULL, 0, NULL);
}
if (lp_max_smbd_processes() == 0) {
/* Don't bother with the child list if we don't care anyway */
return;
@ -560,10 +570,27 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
if (got_sig_cld) {
pid_t pid;
int status;
got_sig_cld = False;
while ((pid = sys_waitpid(-1, NULL, WNOHANG)) > 0) {
remove_child_pid(pid);
while ((pid = sys_waitpid(-1, &status, WNOHANG)) > 0) {
bool unclean_shutdown = False;
/* If the child terminated normally, assume
it was an unclean shutdown unless the
status is 0
*/
if (WIFEXITED(status)) {
unclean_shutdown = WEXITSTATUS(status);
}
/* If the child terminated due to a signal
we always assume it was unclean.
*/
if (WIFSIGNALED(status)) {
unclean_shutdown = True;
}
remove_child_pid(pid, unclean_shutdown);
}
}
@ -603,6 +630,15 @@ static bool open_sockets_smbd(bool is_daemon, bool interactive, const char *smb_
continue;
}
/* If the idle timeout fired and we don't have any connected
* users, exit gracefully. We should be running under a process
* controller that will restart us if necessry.
*/
if (num == 0 && count_all_current_connections() == 0) {
exit_server_cleanly("idle timeout");
}
/* process pending nDNS responses */
if (dns_register_smbd_reply(dns_reg, &r_fds, &idle_timeout)) {
@ -906,6 +942,29 @@ void exit_server_fault(void)
exit_server("critical server fault");
}
/****************************************************************************
received when we should release a specific IP
****************************************************************************/
static void msg_release_ip(struct messaging_context *msg_ctx, void *private_data,
uint32_t msg_type, struct server_id server_id, DATA_BLOB *data)
{
const char *ip = (const char *)data->data;
char addr[INET6_ADDRSTRLEN];
if (strcmp(client_socket_addr(get_client_fd(),addr,sizeof(addr)), ip) == 0) {
/* we can't afford to do a clean exit - that involves
database writes, which would potentially mean we
are still running after the failover has finished -
we have to get rid of this process ID straight
away */
DEBUG(0,("Got release IP message for our IP %s - exiting immediately\n",
ip));
_exit(0);
}
}
/****************************************************************************
Initialise connect, service and file structs.
****************************************************************************/
@ -1305,6 +1364,8 @@ extern void build_options(bool screen);
/* register our message handlers */
messaging_register(smbd_messaging_context(), NULL,
MSG_SMB_FORCE_TDIS, msg_force_tdis);
messaging_register(smbd_messaging_context(), NULL,
MSG_SMB_RELEASE_IP, msg_release_ip);
if ((lp_keepalive() != 0)
&& !(event_add_idle(smbd_event_context(), NULL,

View File

@ -2373,8 +2373,8 @@ static void call_trans2qfsinfo(connection_struct *conn,
const char *vname = volume_label(SNUM(conn));
int snum = SNUM(conn);
char *fstype = lp_fstype(SNUM(conn));
int quota_flag = 0;
uint32 additional_flags = 0;
if (total_params < 2) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
return;
@ -2487,16 +2487,23 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_dev, (unsi
case SMB_QUERY_FS_ATTRIBUTE_INFO:
case SMB_FS_ATTRIBUTE_INFORMATION:
additional_flags = 0;
#if defined(HAVE_SYS_QUOTAS)
quota_flag = FILE_VOLUME_QUOTAS;
additional_flags |= FILE_VOLUME_QUOTAS;
#endif
if(lp_nt_acl_support(SNUM(conn))) {
additional_flags |= FILE_PERSISTENT_ACLS;
}
if(SMB_VFS_IS_REMOTESTORAGE(conn, lp_pathname(SNUM(conn)))) {
additional_flags |= FILE_SUPPORTS_REMOTE_STORAGE;
additional_flags |= FILE_SUPPORTS_REPARSE_POINTS;
}
SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
(lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)|
FILE_SUPPORTS_OBJECT_IDS|
FILE_UNICODE_ON_DISK|
quota_flag); /* FS ATTRIBUTES */
FILE_SUPPORTS_OBJECT_IDS|FILE_UNICODE_ON_DISK|
additional_flags); /* FS ATTRIBUTES */
SIVAL(pdata,4,255); /* Max filename component length */
/* NOTE! the fstype must *not* be null terminated or win98 won't recognise it

File diff suppressed because it is too large Load Diff