mirror of
https://github.com/samba-team/samba.git
synced 2025-12-16 00:23:52 +03:00
converted all our existing shared memory code to use a tdb database
instead of either sysv or mmap shared memory or lock files. this means we can now completely remove locking_shm.c locking_slow.c shmem.c shmem_sysv.c and lots of other things also got simpler locking.c got a bit larger, but is much better compartmentalised now
This commit is contained in:
@@ -135,8 +135,7 @@ RPC_CLIENT_OBJ = \
|
|||||||
rpc_client/cli_samr.o
|
rpc_client/cli_samr.o
|
||||||
|
|
||||||
|
|
||||||
LOCKING_OBJ = locking/locking.o locking/locking_shm.o locking/locking_slow.o \
|
LOCKING_OBJ = locking/locking.o
|
||||||
locking/shmem.o locking/shmem_sysv.o
|
|
||||||
|
|
||||||
PASSDB_OBJ = passdb/passdb.o passdb/smbpassfile.o passdb/smbpass.o \
|
PASSDB_OBJ = passdb/passdb.o passdb/smbpassfile.o passdb/smbpass.o \
|
||||||
passdb/pass_check.o passdb/ldap.o passdb/nispass.o passdb/smbpasschange.o
|
passdb/pass_check.o passdb/ldap.o passdb/nispass.o passdb/smbpasschange.o
|
||||||
|
|||||||
@@ -299,6 +299,7 @@ BOOL reg_split_key(char *full_keyname, uint32 *reg_type, char *key_name);
|
|||||||
char *smbd_mktemp(char *template);
|
char *smbd_mktemp(char *template);
|
||||||
void *memdup(void *p, size_t size);
|
void *memdup(void *p, size_t size);
|
||||||
char *myhostname(void);
|
char *myhostname(void);
|
||||||
|
char *lock_path(char *name);
|
||||||
|
|
||||||
/*The following definitions come from lib/util_file.c */
|
/*The following definitions come from lib/util_file.c */
|
||||||
|
|
||||||
@@ -618,17 +619,18 @@ BOOL do_unlock(files_struct *fsp,connection_struct *conn,
|
|||||||
BOOL locking_init(int read_only);
|
BOOL locking_init(int read_only);
|
||||||
BOOL locking_end(void);
|
BOOL locking_end(void);
|
||||||
BOOL lock_share_entry(connection_struct *conn,
|
BOOL lock_share_entry(connection_struct *conn,
|
||||||
SMB_DEV_T dev, SMB_INO_T inode, int *ptok);
|
SMB_DEV_T dev, SMB_INO_T inode);
|
||||||
BOOL unlock_share_entry(connection_struct *conn,
|
BOOL unlock_share_entry(connection_struct *conn,
|
||||||
SMB_DEV_T dev, SMB_INO_T inode, int token);
|
SMB_DEV_T dev, SMB_INO_T inode);
|
||||||
int get_share_modes(connection_struct *conn,
|
int get_share_modes(connection_struct *conn,
|
||||||
int token, SMB_DEV_T dev, SMB_INO_T inode,
|
SMB_DEV_T dev, SMB_INO_T inode,
|
||||||
share_mode_entry **shares);
|
share_mode_entry **shares);
|
||||||
void del_share_mode(int token, files_struct *fsp);
|
void del_share_mode(files_struct *fsp);
|
||||||
BOOL set_share_mode(int token, files_struct *fsp, uint16 port, uint16 op_type);
|
BOOL set_share_mode(files_struct *fsp, uint16 port, uint16 op_type);
|
||||||
BOOL remove_share_oplock(int token, files_struct *fsp);
|
BOOL remove_share_oplock(files_struct *fsp);
|
||||||
BOOL downgrade_share_oplock(int token, files_struct *fsp);
|
BOOL downgrade_share_oplock(files_struct *fsp);
|
||||||
BOOL modify_share_mode(int token, files_struct *fsp, int new_mode, uint16 new_oplock);
|
BOOL modify_share_mode(files_struct *fsp, int new_mode, uint16 new_oplock);
|
||||||
|
int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf);
|
||||||
int share_mode_forall(void (*fn)(share_mode_entry *, char *));
|
int share_mode_forall(void (*fn)(share_mode_entry *, char *));
|
||||||
void share_status(FILE *f);
|
void share_status(FILE *f);
|
||||||
|
|
||||||
@@ -2375,7 +2377,6 @@ void conn_free(connection_struct *conn);
|
|||||||
|
|
||||||
/*The following definitions come from smbd/connection.c */
|
/*The following definitions come from smbd/connection.c */
|
||||||
|
|
||||||
TDB_CONTEXT *open_db(char *name);
|
|
||||||
BOOL yield_connection(connection_struct *conn,char *name,int max_connections);
|
BOOL yield_connection(connection_struct *conn,char *name,int max_connections);
|
||||||
int delete_dead(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf);
|
int delete_dead(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf);
|
||||||
BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOOL Clear);
|
BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOOL Clear);
|
||||||
@@ -2809,6 +2810,8 @@ TDB_CONTEXT *tdb_open(char *name, int hash_size, int flags, mode_t mode);
|
|||||||
int tdb_close(TDB_CONTEXT *tdb);
|
int tdb_close(TDB_CONTEXT *tdb);
|
||||||
int tdb_writelock(TDB_CONTEXT *tdb);
|
int tdb_writelock(TDB_CONTEXT *tdb);
|
||||||
int tdb_writeunlock(TDB_CONTEXT *tdb);
|
int tdb_writeunlock(TDB_CONTEXT *tdb);
|
||||||
|
int tdb_lockchain(TDB_CONTEXT *tdb, TDB_DATA key);
|
||||||
|
int tdb_unlockchain(TDB_CONTEXT *tdb, TDB_DATA key);
|
||||||
|
|
||||||
/*The following definitions come from utils/nbio.c */
|
/*The following definitions come from utils/nbio.c */
|
||||||
|
|
||||||
|
|||||||
@@ -858,6 +858,22 @@ struct connections_data {
|
|||||||
time_t start;
|
time_t start;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* key and data records in the tdb locking database */
|
||||||
|
struct locking_key {
|
||||||
|
SMB_DEV_T dev;
|
||||||
|
SMB_INO_T inode;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct locking_data {
|
||||||
|
int num_share_mode_entries;
|
||||||
|
/* the following two entries are implicit
|
||||||
|
share_mode_entry modes[num_share_mode_entries];
|
||||||
|
char file_name[];
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* the following are used by loadparm for option lists */
|
/* the following are used by loadparm for option lists */
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3213,3 +3213,24 @@ char *myhostname(void)
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************
|
||||||
|
a useful function for returning a path in the Samba lock directory
|
||||||
|
*****************************************************************/
|
||||||
|
char *lock_path(char *name)
|
||||||
|
{
|
||||||
|
static pstring fname;
|
||||||
|
|
||||||
|
pstrcpy(fname,lp_lockdir());
|
||||||
|
trim_string(fname,"","/");
|
||||||
|
|
||||||
|
if (!directory_exist(fname,NULL)) {
|
||||||
|
mkdir(fname,0755);
|
||||||
|
}
|
||||||
|
|
||||||
|
pstrcat(fname,"/");
|
||||||
|
pstrcat(fname,name);
|
||||||
|
|
||||||
|
return fname;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
Unix SMB/Netbios implementation.
|
Unix SMB/Netbios implementation.
|
||||||
Version 1.9.
|
Version 3.0
|
||||||
Locking functions
|
Locking functions
|
||||||
Copyright (C) Andrew Tridgell 1992-1998
|
Copyright (C) Andrew Tridgell 1992-1999
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@@ -29,42 +29,43 @@
|
|||||||
September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
|
September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
|
||||||
support.
|
support.
|
||||||
|
|
||||||
|
rewrtten completely to use new tdb code. Tridge, Dec '99
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
extern int DEBUGLEVEL;
|
extern int DEBUGLEVEL;
|
||||||
|
|
||||||
static struct share_ops *share_ops;
|
/* the locking database handle */
|
||||||
|
static TDB_CONTEXT *tdb;
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
Utility function to map a lock type correctly depending on the real open
|
Utility function to map a lock type correctly depending on the real open
|
||||||
mode of a file.
|
mode of a file.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
static int map_lock_type(files_struct *fsp, int lock_type)
|
||||||
static int map_lock_type( files_struct *fsp, int lock_type)
|
|
||||||
{
|
{
|
||||||
if((lock_type == F_WRLCK) && (fsp->fd_ptr->real_open_flags == O_RDONLY)) {
|
if((lock_type == F_WRLCK) && (fsp->fd_ptr->real_open_flags == O_RDONLY)) {
|
||||||
/*
|
/*
|
||||||
* Many UNIX's cannot get a write lock on a file opened read-only.
|
* Many UNIX's cannot get a write lock on a file opened read-only.
|
||||||
* Win32 locking semantics allow this.
|
* Win32 locking semantics allow this.
|
||||||
* Do the best we can and attempt a read-only lock.
|
* Do the best we can and attempt a read-only lock.
|
||||||
*/
|
*/
|
||||||
DEBUG(10,("map_lock_type: Downgrading write lock to read due to read-only file.\n"));
|
DEBUG(10,("map_lock_type: Downgrading write lock to read due to read-only file.\n"));
|
||||||
return F_RDLCK;
|
return F_RDLCK;
|
||||||
} else if( (lock_type == F_RDLCK) && (fsp->fd_ptr->real_open_flags == O_WRONLY)) {
|
} else if( (lock_type == F_RDLCK) && (fsp->fd_ptr->real_open_flags == O_WRONLY)) {
|
||||||
/*
|
/*
|
||||||
* Ditto for read locks on write only files.
|
* Ditto for read locks on write only files.
|
||||||
*/
|
*/
|
||||||
DEBUG(10,("map_lock_type: Changing read lock to write due to write-only file.\n"));
|
DEBUG(10,("map_lock_type: Changing read lock to write due to write-only file.\n"));
|
||||||
return F_WRLCK;
|
return F_WRLCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This return should be the most normal, as we attempt
|
* This return should be the most normal, as we attempt
|
||||||
* to always open files read/write.
|
* to always open files read/write.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return lock_type;
|
return lock_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -74,7 +75,7 @@ BOOL is_locked(files_struct *fsp,connection_struct *conn,
|
|||||||
SMB_OFF_T count,SMB_OFF_T offset, int lock_type)
|
SMB_OFF_T count,SMB_OFF_T offset, int lock_type)
|
||||||
{
|
{
|
||||||
int snum = SNUM(conn);
|
int snum = SNUM(conn);
|
||||||
|
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
return(False);
|
return(False);
|
||||||
|
|
||||||
@@ -98,30 +99,30 @@ BOOL do_lock(files_struct *fsp,connection_struct *conn,
|
|||||||
SMB_OFF_T count,SMB_OFF_T offset,int lock_type,
|
SMB_OFF_T count,SMB_OFF_T offset,int lock_type,
|
||||||
int *eclass,uint32 *ecode)
|
int *eclass,uint32 *ecode)
|
||||||
{
|
{
|
||||||
BOOL ok = False;
|
BOOL ok = False;
|
||||||
|
|
||||||
if (!lp_locking(SNUM(conn)))
|
if (!lp_locking(SNUM(conn)))
|
||||||
return(True);
|
return(True);
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
*eclass = ERRDOS;
|
*eclass = ERRDOS;
|
||||||
*ecode = ERRnoaccess;
|
*ecode = ERRnoaccess;
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEBUG(10,("do_lock: lock type %d start=%.0f len=%.0f requested for file %s\n",
|
||||||
|
lock_type, (double)offset, (double)count, fsp->fsp_name ));
|
||||||
|
|
||||||
DEBUG(10,("do_lock: lock type %d start=%.0f len=%.0f requested for file %s\n",
|
if (OPEN_FSP(fsp) && fsp->can_lock && (fsp->conn == conn))
|
||||||
lock_type, (double)offset, (double)count, fsp->fsp_name ));
|
ok = fcntl_lock(fsp->fd_ptr->fd,SMB_F_SETLK,offset,count,
|
||||||
|
map_lock_type(fsp,lock_type));
|
||||||
|
|
||||||
if (OPEN_FSP(fsp) && fsp->can_lock && (fsp->conn == conn))
|
if (!ok) {
|
||||||
ok = fcntl_lock(fsp->fd_ptr->fd,SMB_F_SETLK,offset,count,
|
*eclass = ERRDOS;
|
||||||
map_lock_type(fsp,lock_type));
|
*ecode = ERRlock;
|
||||||
|
return False;
|
||||||
if (!ok) {
|
}
|
||||||
*eclass = ERRDOS;
|
return True; /* Got lock */
|
||||||
*ecode = ERRlock;
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
return True; /* Got lock */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -131,46 +132,38 @@ BOOL do_lock(files_struct *fsp,connection_struct *conn,
|
|||||||
BOOL do_unlock(files_struct *fsp,connection_struct *conn,
|
BOOL do_unlock(files_struct *fsp,connection_struct *conn,
|
||||||
SMB_OFF_T count,SMB_OFF_T offset,int *eclass,uint32 *ecode)
|
SMB_OFF_T count,SMB_OFF_T offset,int *eclass,uint32 *ecode)
|
||||||
{
|
{
|
||||||
BOOL ok = False;
|
BOOL ok = False;
|
||||||
|
|
||||||
if (!lp_locking(SNUM(conn)))
|
if (!lp_locking(SNUM(conn)))
|
||||||
return(True);
|
return(True);
|
||||||
|
|
||||||
DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for file %s\n",
|
DEBUG(10,("do_unlock: unlock start=%.0f len=%.0f requested for file %s\n",
|
||||||
(double)offset, (double)count, fsp->fsp_name ));
|
(double)offset, (double)count, fsp->fsp_name ));
|
||||||
|
|
||||||
if (OPEN_FSP(fsp) && fsp->can_lock && (fsp->conn == conn))
|
if (OPEN_FSP(fsp) && fsp->can_lock && (fsp->conn == conn))
|
||||||
ok = fcntl_lock(fsp->fd_ptr->fd,SMB_F_SETLK,offset,count,F_UNLCK);
|
ok = fcntl_lock(fsp->fd_ptr->fd,SMB_F_SETLK,offset,count,F_UNLCK);
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
*eclass = ERRDOS;
|
*eclass = ERRDOS;
|
||||||
*ecode = ERRlock;
|
*ecode = ERRlock;
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
return True; /* Did unlock */
|
return True; /* Did unlock */
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
Initialise the locking functions.
|
Initialise the locking functions.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
BOOL locking_init(int read_only)
|
BOOL locking_init(int read_only)
|
||||||
{
|
{
|
||||||
if (share_ops)
|
if (tdb) return True;
|
||||||
return True;
|
|
||||||
|
|
||||||
#ifdef FAST_SHARE_MODES
|
tdb = tdb_open(lock_path("locking.tdb"),
|
||||||
share_ops = locking_shm_init(read_only);
|
0,
|
||||||
if (!share_ops && read_only && (getuid() == 0)) {
|
read_only?O_RDONLY:O_RDWR|O_CREAT,
|
||||||
/* this may be the first time the share modes code has
|
0644);
|
||||||
been run. Initialise it now by running it read-write */
|
|
||||||
share_ops = locking_shm_init(0);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
share_ops = locking_slow_init(read_only);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!share_ops) {
|
if (!tdb) {
|
||||||
DEBUG(0,("ERROR: Failed to initialise share modes\n"));
|
DEBUG(0,("ERROR: Failed to initialise share modes\n"));
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
@@ -181,110 +174,271 @@ BOOL locking_init(int read_only)
|
|||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
Deinitialize the share_mode management.
|
Deinitialize the share_mode management.
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
|
|
||||||
BOOL locking_end(void)
|
BOOL locking_end(void)
|
||||||
{
|
{
|
||||||
if (share_ops)
|
if (tdb && tdb_close(tdb) != 0) return False;
|
||||||
return share_ops->stop_mgmt();
|
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
form a static locking key for a dev/inode pair
|
||||||
|
******************************************************************/
|
||||||
|
static TDB_DATA locking_key(SMB_DEV_T dev, SMB_INO_T inode)
|
||||||
|
{
|
||||||
|
static struct locking_key key;
|
||||||
|
TDB_DATA kbuf;
|
||||||
|
key.dev = dev;
|
||||||
|
key.inode = inode;
|
||||||
|
kbuf.dptr = (char *)&key;
|
||||||
|
kbuf.dsize = sizeof(key);
|
||||||
|
return kbuf;
|
||||||
|
}
|
||||||
|
static TDB_DATA locking_key_fsp(files_struct *fsp)
|
||||||
|
{
|
||||||
|
return locking_key(fsp->fd_ptr->dev, fsp->fd_ptr->inode);
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
Lock a hash bucket entry.
|
Lock a hash bucket entry.
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
BOOL lock_share_entry(connection_struct *conn,
|
BOOL lock_share_entry(connection_struct *conn,
|
||||||
SMB_DEV_T dev, SMB_INO_T inode, int *ptok)
|
SMB_DEV_T dev, SMB_INO_T inode)
|
||||||
{
|
{
|
||||||
return share_ops->lock_entry(conn, dev, inode, ptok);
|
return tdb_lockchain(tdb, locking_key(dev, inode)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
Unlock a hash bucket entry.
|
Unlock a hash bucket entry.
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
BOOL unlock_share_entry(connection_struct *conn,
|
BOOL unlock_share_entry(connection_struct *conn,
|
||||||
SMB_DEV_T dev, SMB_INO_T inode, int token)
|
SMB_DEV_T dev, SMB_INO_T inode)
|
||||||
{
|
{
|
||||||
return share_ops->unlock_entry(conn, dev, inode, token);
|
return tdb_unlockchain(tdb, locking_key(dev, inode)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
Get all share mode entries for a dev/inode pair.
|
Get all share mode entries for a dev/inode pair.
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
int get_share_modes(connection_struct *conn,
|
int get_share_modes(connection_struct *conn,
|
||||||
int token, SMB_DEV_T dev, SMB_INO_T inode,
|
SMB_DEV_T dev, SMB_INO_T inode,
|
||||||
share_mode_entry **shares)
|
share_mode_entry **shares)
|
||||||
{
|
{
|
||||||
return share_ops->get_entries(conn, token, dev, inode, shares);
|
TDB_DATA dbuf;
|
||||||
|
struct locking_data *data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dbuf = tdb_fetch(tdb, locking_key(dev, inode));
|
||||||
|
if (!dbuf.dptr) return 0;
|
||||||
|
|
||||||
|
data = (struct locking_data *)dbuf.dptr;
|
||||||
|
ret = data->num_share_mode_entries;
|
||||||
|
*shares = (share_mode_entry *)memdup(dbuf.dptr + sizeof(*data), ret * sizeof(**shares));
|
||||||
|
free(dbuf.dptr);
|
||||||
|
|
||||||
|
if (! *shares) return 0;
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
Del the share mode of a file.
|
Del the share mode of a file for this process
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
void del_share_mode(int token, files_struct *fsp)
|
void del_share_mode(files_struct *fsp)
|
||||||
{
|
{
|
||||||
share_ops->del_entry(token, fsp);
|
TDB_DATA dbuf;
|
||||||
|
struct locking_data *data;
|
||||||
|
int i, del_count=0;
|
||||||
|
share_mode_entry *shares;
|
||||||
|
pid_t pid = getpid();
|
||||||
|
|
||||||
|
/* read in the existing share modes */
|
||||||
|
dbuf = tdb_fetch(tdb, locking_key_fsp(fsp));
|
||||||
|
if (!dbuf.dptr) return;
|
||||||
|
|
||||||
|
data = (struct locking_data *)dbuf.dptr;
|
||||||
|
shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
|
||||||
|
|
||||||
|
/* find any with our pid and delete it by overwriting with the rest of the data
|
||||||
|
from the record */
|
||||||
|
for (i=0;i<data->num_share_mode_entries;) {
|
||||||
|
if (shares[i].pid == pid &&
|
||||||
|
memcmp(&shares[i].time,
|
||||||
|
&fsp->open_time,sizeof(struct timeval)) == 0) {
|
||||||
|
data->num_share_mode_entries--;
|
||||||
|
memmove(&shares[i], &shares[i+1],
|
||||||
|
dbuf.dsize - (sizeof(*data) + (i+1)*sizeof(*shares)));
|
||||||
|
del_count++;
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the record has shrunk a bit */
|
||||||
|
dbuf.dsize -= del_count * sizeof(*shares);
|
||||||
|
|
||||||
|
/* store it back in the database */
|
||||||
|
tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE);
|
||||||
|
|
||||||
|
free(dbuf.dptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
fill a share mode entry
|
||||||
|
********************************************************************/
|
||||||
|
static void fill_share_mode(char *p, files_struct *fsp, uint16 port, uint16 op_type)
|
||||||
|
{
|
||||||
|
share_mode_entry *e = (share_mode_entry *)p;
|
||||||
|
e->pid = getpid();
|
||||||
|
e->share_mode = fsp->share_mode;
|
||||||
|
e->op_port = port;
|
||||||
|
e->op_type = op_type;
|
||||||
|
memcpy((char *)&e->time, (char *)&fsp->open_time, sizeof(struct timeval));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
Set the share mode of a file. Return False on fail, True on success.
|
Set the share mode of a file. Return False on fail, True on success.
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
BOOL set_share_mode(int token, files_struct *fsp, uint16 port, uint16 op_type)
|
BOOL set_share_mode(files_struct *fsp, uint16 port, uint16 op_type)
|
||||||
{
|
{
|
||||||
return share_ops->set_entry(token, fsp, port, op_type);
|
TDB_DATA dbuf;
|
||||||
|
struct locking_data *data;
|
||||||
|
share_mode_entry *shares;
|
||||||
|
char *p=NULL;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
/* read in the existing share modes if any */
|
||||||
|
dbuf = tdb_fetch(tdb, locking_key_fsp(fsp));
|
||||||
|
if (!dbuf.dptr) {
|
||||||
|
/* we'll need to create a new record */
|
||||||
|
pstring fname;
|
||||||
|
|
||||||
|
pstrcpy(fname, fsp->conn->connectpath);
|
||||||
|
pstrcat(fname, "/");
|
||||||
|
pstrcat(fname, fsp->fsp_name);
|
||||||
|
|
||||||
|
size = sizeof(*data) + sizeof(*shares) + strlen(fname) + 1;
|
||||||
|
p = (char *)malloc(size);
|
||||||
|
data = (struct locking_data *)p;
|
||||||
|
shares = (share_mode_entry *)(p + sizeof(*data));
|
||||||
|
data->num_share_mode_entries = 1;
|
||||||
|
pstrcpy(p + sizeof(*data) + sizeof(*shares), fname);
|
||||||
|
fill_share_mode(p + sizeof(*data), fsp, port, op_type);
|
||||||
|
dbuf.dptr = p;
|
||||||
|
dbuf.dsize = size;
|
||||||
|
tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE);
|
||||||
|
free(p);
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we're adding to an existing entry - this is a bit fiddly */
|
||||||
|
data = (struct locking_data *)dbuf.dptr;
|
||||||
|
shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
|
||||||
|
|
||||||
|
data->num_share_mode_entries++;
|
||||||
|
size = dbuf.dsize + sizeof(*shares);
|
||||||
|
p = malloc(size);
|
||||||
|
memcpy(p, dbuf.dptr, sizeof(*data));
|
||||||
|
fill_share_mode(p + sizeof(*data), fsp, port, op_type);
|
||||||
|
memcpy(p + sizeof(*data) + sizeof(*shares), dbuf.dptr + sizeof(*data),
|
||||||
|
dbuf.dsize - sizeof(*data));
|
||||||
|
free(dbuf.dptr);
|
||||||
|
dbuf.dptr = p;
|
||||||
|
dbuf.dsize = size;
|
||||||
|
tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE);
|
||||||
|
free(p);
|
||||||
|
return True;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
a generic in-place modification call for share mode entries
|
||||||
|
********************************************************************/
|
||||||
|
static BOOL mod_share_mode(files_struct *fsp,
|
||||||
|
void (*mod_fn)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *),
|
||||||
|
void *param)
|
||||||
|
{
|
||||||
|
TDB_DATA dbuf;
|
||||||
|
struct locking_data *data;
|
||||||
|
int i;
|
||||||
|
share_mode_entry *shares;
|
||||||
|
pid_t pid = getpid();
|
||||||
|
int need_store=0;
|
||||||
|
|
||||||
|
/* read in the existing share modes */
|
||||||
|
dbuf = tdb_fetch(tdb, locking_key_fsp(fsp));
|
||||||
|
if (!dbuf.dptr) return False;
|
||||||
|
|
||||||
|
data = (struct locking_data *)dbuf.dptr;
|
||||||
|
shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
|
||||||
|
|
||||||
|
/* find any with our pid and call the supplied function */
|
||||||
|
for (i=0;i<data->num_share_mode_entries;i++) {
|
||||||
|
if (pid == shares[i].pid &&
|
||||||
|
shares[i].share_mode == fsp->share_mode &&
|
||||||
|
memcmp(&shares[i].time,
|
||||||
|
&fsp->open_time,sizeof(struct timeval)) == 0) {
|
||||||
|
mod_fn(&shares[i], fsp->fd_ptr->dev, fsp->fd_ptr->inode, param);
|
||||||
|
need_store=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if the mod fn was called then store it back */
|
||||||
|
if (need_store) {
|
||||||
|
tdb_store(tdb, locking_key_fsp(fsp), dbuf, TDB_REPLACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(dbuf.dptr);
|
||||||
|
return need_store;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
Static function that actually does the work for the generic function
|
Static function that actually does the work for the generic function
|
||||||
below.
|
below.
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
|
|
||||||
static void remove_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode,
|
static void remove_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode,
|
||||||
void *param)
|
void *param)
|
||||||
{
|
{
|
||||||
DEBUG(10,("remove_share_oplock_fn: removing oplock info for entry dev=%x ino=%.0f\n",
|
DEBUG(10,("remove_share_oplock_fn: removing oplock info for entry dev=%x ino=%.0f\n",
|
||||||
(unsigned int)dev, (double)inode ));
|
(unsigned int)dev, (double)inode ));
|
||||||
/* Delete the oplock info. */
|
/* Delete the oplock info. */
|
||||||
entry->op_port = 0;
|
entry->op_port = 0;
|
||||||
entry->op_type = NO_OPLOCK;
|
entry->op_type = NO_OPLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
Remove an oplock port and mode entry from a share mode.
|
Remove an oplock port and mode entry from a share mode.
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
|
BOOL remove_share_oplock(files_struct *fsp)
|
||||||
BOOL remove_share_oplock(int token, files_struct *fsp)
|
|
||||||
{
|
{
|
||||||
return share_ops->mod_entry(token, fsp, remove_share_oplock_fn, NULL);
|
return mod_share_mode(fsp, remove_share_oplock_fn, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
Static function that actually does the work for the generic function
|
Static function that actually does the work for the generic function
|
||||||
below.
|
below.
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
|
|
||||||
static void downgrade_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode,
|
static void downgrade_share_oplock_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO_T inode,
|
||||||
void *param)
|
void *param)
|
||||||
{
|
{
|
||||||
DEBUG(10,("downgrade_share_oplock_fn: downgrading oplock info for entry dev=%x ino=%.0f\n",
|
DEBUG(10,("downgrade_share_oplock_fn: downgrading oplock info for entry dev=%x ino=%.0f\n",
|
||||||
(unsigned int)dev, (double)inode ));
|
(unsigned int)dev, (double)inode ));
|
||||||
entry->op_type = LEVEL_II_OPLOCK;
|
entry->op_type = LEVEL_II_OPLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
Downgrade a oplock type from exclusive to level II.
|
Downgrade a oplock type from exclusive to level II.
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
|
BOOL downgrade_share_oplock(files_struct *fsp)
|
||||||
BOOL downgrade_share_oplock(int token, files_struct *fsp)
|
|
||||||
{
|
{
|
||||||
return share_ops->mod_entry(token, fsp, downgrade_share_oplock_fn, NULL);
|
return mod_share_mode(fsp, downgrade_share_oplock_fn, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
Static function that actually does the work for the generic function
|
Static function that actually does the work for the generic function
|
||||||
below.
|
below.
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
|
|
||||||
struct mod_val {
|
struct mod_val {
|
||||||
int new_share_mode;
|
int new_share_mode;
|
||||||
uint16 new_oplock;
|
uint16 new_oplock;
|
||||||
@@ -308,33 +462,46 @@ static void modify_share_mode_fn(share_mode_entry *entry, SMB_DEV_T dev, SMB_INO
|
|||||||
Modify a share mode on a file. Used by the delete open file code.
|
Modify a share mode on a file. Used by the delete open file code.
|
||||||
Return False on fail, True on success.
|
Return False on fail, True on success.
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
|
BOOL modify_share_mode(files_struct *fsp, int new_mode, uint16 new_oplock)
|
||||||
BOOL modify_share_mode(int token, files_struct *fsp, int new_mode, uint16 new_oplock)
|
|
||||||
{
|
{
|
||||||
struct mod_val mv;
|
struct mod_val mv;
|
||||||
|
|
||||||
mv.new_share_mode = new_mode;
|
mv.new_share_mode = new_mode;
|
||||||
mv.new_oplock = new_oplock;
|
mv.new_oplock = new_oplock;
|
||||||
|
|
||||||
return share_ops->mod_entry(token, fsp, modify_share_mode_fn, (void *)&mv);
|
return mod_share_mode(fsp, modify_share_mode_fn, (void *)&mv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void (*traverse_callback)(share_mode_entry *, char *);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
traverse the whole database with this function, calling traverse_callback
|
||||||
|
on each share mode
|
||||||
|
****************************************************************************/
|
||||||
|
int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf)
|
||||||
|
{
|
||||||
|
struct locking_data *data;
|
||||||
|
share_mode_entry *shares;
|
||||||
|
char *name;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
data = (struct locking_data *)dbuf.dptr;
|
||||||
|
shares = (share_mode_entry *)(dbuf.dptr + sizeof(*data));
|
||||||
|
name = dbuf.dptr + sizeof(*data) + data->num_share_mode_entries*sizeof(*shares);
|
||||||
|
|
||||||
|
for (i=0;i<data->num_share_mode_entries;i++) {
|
||||||
|
traverse_callback(&shares[i], name);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************
|
/*******************************************************************
|
||||||
Call the specified function on each entry under management by the
|
Call the specified function on each entry under management by the
|
||||||
share mode system.
|
share mode system.
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
|
|
||||||
int share_mode_forall(void (*fn)(share_mode_entry *, char *))
|
int share_mode_forall(void (*fn)(share_mode_entry *, char *))
|
||||||
{
|
{
|
||||||
if (!share_ops) return 0;
|
if (!tdb) return 0;
|
||||||
return share_ops->forall(fn);
|
traverse_callback = fn;
|
||||||
}
|
return tdb_traverse(tdb, traverse_fn);
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
Dump the state of the system.
|
|
||||||
********************************************************************/
|
|
||||||
|
|
||||||
void share_status(FILE *f)
|
|
||||||
{
|
|
||||||
share_ops->status(f);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,711 +0,0 @@
|
|||||||
/*
|
|
||||||
Unix SMB/Netbios implementation.
|
|
||||||
Version 1.9.
|
|
||||||
shared memory locking implementation
|
|
||||||
Copyright (C) Andrew Tridgell 1992-1998
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
12 aug 96: Erik.Devriendt@te6.siemens.be
|
|
||||||
added support for shared memory implementation of share mode locking
|
|
||||||
|
|
||||||
May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode
|
|
||||||
locking to deal with multiple share modes per open file.
|
|
||||||
|
|
||||||
September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
|
|
||||||
support.
|
|
||||||
|
|
||||||
October 1997 - split into separate file (tridge)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "includes.h"
|
|
||||||
|
|
||||||
#ifdef FAST_SHARE_MODES
|
|
||||||
|
|
||||||
extern int DEBUGLEVEL;
|
|
||||||
|
|
||||||
static struct shmem_ops *shmops;
|
|
||||||
|
|
||||||
/* share mode record pointed to in shared memory hash bucket */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int next_offset; /* offset of next record in chain from hash bucket */
|
|
||||||
int locking_version;
|
|
||||||
SMB_DEV_T st_dev;
|
|
||||||
SMB_INO_T st_ino;
|
|
||||||
int num_share_mode_entries;
|
|
||||||
int share_mode_entries; /* Chain of share mode entries for this file */
|
|
||||||
char file_name[1];
|
|
||||||
} share_mode_record;
|
|
||||||
|
|
||||||
/* share mode entry pointed to by share_mode_record struct */
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int next_share_mode_entry;
|
|
||||||
share_mode_entry e;
|
|
||||||
} shm_share_mode_entry;
|
|
||||||
|
|
||||||
static int read_only;
|
|
||||||
|
|
||||||
|
|
||||||
/* Conversion to hash entry index from device and inode numbers. */
|
|
||||||
#define HASH_ENTRY(dev,ino) ((unsigned int)(((dev) ^ (ino)) % shmops->hash_size()))
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
deinitialize the shared memory for share_mode management
|
|
||||||
******************************************************************/
|
|
||||||
static BOOL shm_stop_share_mode_mgmt(void)
|
|
||||||
{
|
|
||||||
return shmops->shm_close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
lock a hash bucket entry in shared memory for share_mode management
|
|
||||||
******************************************************************/
|
|
||||||
static BOOL shm_lock_share_entry(connection_struct *conn,
|
|
||||||
SMB_DEV_T dev, SMB_INO_T inode, int *ptok)
|
|
||||||
{
|
|
||||||
*ptok = 0; /* For purify... */
|
|
||||||
return shmops->lock_hash_entry(HASH_ENTRY(dev, inode));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
unlock a hash bucket entry in shared memory for share_mode management
|
|
||||||
******************************************************************/
|
|
||||||
static BOOL shm_unlock_share_entry(connection_struct *conn,
|
|
||||||
SMB_DEV_T dev, SMB_INO_T inode, int token)
|
|
||||||
{
|
|
||||||
return shmops->unlock_hash_entry(HASH_ENTRY(dev, inode));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
get all share mode entries in shared memory for a dev/inode pair.
|
|
||||||
********************************************************************/
|
|
||||||
static int shm_get_share_modes(connection_struct *conn,
|
|
||||||
int token, SMB_DEV_T dev, SMB_INO_T inode,
|
|
||||||
share_mode_entry **old_shares)
|
|
||||||
{
|
|
||||||
int *mode_array;
|
|
||||||
unsigned int hash_entry = HASH_ENTRY(dev, inode);
|
|
||||||
share_mode_record *file_scanner_p;
|
|
||||||
share_mode_record *file_prev_p;
|
|
||||||
shm_share_mode_entry *entry_scanner_p;
|
|
||||||
shm_share_mode_entry *entry_prev_p;
|
|
||||||
int num_entries;
|
|
||||||
int num_entries_copied;
|
|
||||||
BOOL found = False;
|
|
||||||
share_mode_entry *share_array = (share_mode_entry *)0;
|
|
||||||
|
|
||||||
*old_shares = 0;
|
|
||||||
|
|
||||||
mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
|
|
||||||
|
|
||||||
if(mode_array[hash_entry] == 0)
|
|
||||||
{
|
|
||||||
DEBUG(5,("get_share_modes hash bucket %d empty\n", hash_entry));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
|
|
||||||
file_prev_p = file_scanner_p;
|
|
||||||
while(file_scanner_p)
|
|
||||||
{
|
|
||||||
if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
|
|
||||||
{
|
|
||||||
found = True;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
file_prev_p = file_scanner_p ;
|
|
||||||
file_scanner_p = (share_mode_record *)shmops->offset2addr(
|
|
||||||
file_scanner_p->next_offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!found)
|
|
||||||
{
|
|
||||||
DEBUG(5,("get_share_modes no entry for file dev = %x ino = %.0f\n",
|
|
||||||
(unsigned int)dev, (double)inode));
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(file_scanner_p->locking_version != LOCKING_VERSION)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR: get_share_modes Deleting old share mode v1 %d dev=%x ino=%.0f\n",
|
|
||||||
file_scanner_p->locking_version, (unsigned int)dev, (double)inode));
|
|
||||||
|
|
||||||
if(file_prev_p == file_scanner_p)
|
|
||||||
mode_array[hash_entry] = file_scanner_p->next_offset;
|
|
||||||
else
|
|
||||||
file_prev_p->next_offset = file_scanner_p->next_offset;
|
|
||||||
shmops->shm_free(shmops->addr2offset(file_scanner_p));
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate the old_shares array */
|
|
||||||
num_entries = file_scanner_p->num_share_mode_entries;
|
|
||||||
if(num_entries)
|
|
||||||
{
|
|
||||||
*old_shares = share_array = (share_mode_entry *)
|
|
||||||
malloc(num_entries * sizeof(share_mode_entry));
|
|
||||||
if(*old_shares == 0)
|
|
||||||
{
|
|
||||||
DEBUG(0,("get_share_modes: malloc fail for size 0x%x!\n", (unsigned int)(num_entries * sizeof(share_mode_entry))));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
num_entries_copied = 0;
|
|
||||||
|
|
||||||
entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
|
|
||||||
file_scanner_p->share_mode_entries);
|
|
||||||
entry_prev_p = entry_scanner_p;
|
|
||||||
while(entry_scanner_p)
|
|
||||||
{
|
|
||||||
pid_t pid = entry_scanner_p->e.pid;
|
|
||||||
|
|
||||||
if (pid && !process_exists(pid))
|
|
||||||
{
|
|
||||||
/* Delete this share mode entry */
|
|
||||||
shm_share_mode_entry *delete_entry_p = entry_scanner_p;
|
|
||||||
|
|
||||||
if(entry_prev_p == entry_scanner_p)
|
|
||||||
{
|
|
||||||
/* We are at start of list */
|
|
||||||
file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
|
|
||||||
entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
|
|
||||||
file_scanner_p->share_mode_entries);
|
|
||||||
entry_prev_p = entry_scanner_p;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
|
|
||||||
entry_scanner_p = (shm_share_mode_entry*)
|
|
||||||
shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
|
|
||||||
}
|
|
||||||
/* Decrement the number of share mode entries on this share mode record */
|
|
||||||
file_scanner_p->num_share_mode_entries -= 1;
|
|
||||||
|
|
||||||
/* PARANOIA TEST */
|
|
||||||
if(file_scanner_p->num_share_mode_entries < 0)
|
|
||||||
{
|
|
||||||
DEBUG(0,("PANIC ERROR: get_share_mode: entries=%d dev=%x ino=%.0f\n",
|
|
||||||
file_scanner_p->num_share_mode_entries, (unsigned int)dev, (double)inode));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(0,("get_share_modes: process %d no longer exists\n", (int)pid));
|
|
||||||
|
|
||||||
shmops->shm_free(shmops->addr2offset(delete_entry_p));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* This is a valid share mode entry and the process that
|
|
||||||
created it still exists. Copy it into the output array.
|
|
||||||
*/
|
|
||||||
share_array[num_entries_copied].pid = entry_scanner_p->e.pid;
|
|
||||||
share_array[num_entries_copied].share_mode = entry_scanner_p->e.share_mode;
|
|
||||||
share_array[num_entries_copied].op_port = entry_scanner_p->e.op_port;
|
|
||||||
share_array[num_entries_copied].op_type = entry_scanner_p->e.op_type;
|
|
||||||
memcpy(&share_array[num_entries_copied].time, &entry_scanner_p->e.time,
|
|
||||||
sizeof(struct timeval));
|
|
||||||
num_entries_copied++;
|
|
||||||
DEBUG(5,("get_share_modes Read share mode 0x%X pid=%d\n",
|
|
||||||
entry_scanner_p->e.share_mode, (int)entry_scanner_p->e.pid));
|
|
||||||
entry_prev_p = entry_scanner_p;
|
|
||||||
entry_scanner_p = (shm_share_mode_entry *)
|
|
||||||
shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If no valid share mode entries were found then this record shouldn't exist ! */
|
|
||||||
if(num_entries_copied == 0)
|
|
||||||
{
|
|
||||||
DEBUG(0,("get_share_modes: file with dev %x inode %.0f empty\n",
|
|
||||||
(unsigned int)dev, (double)inode));
|
|
||||||
|
|
||||||
if(*old_shares)
|
|
||||||
free((char *)*old_shares);
|
|
||||||
*old_shares = 0;
|
|
||||||
|
|
||||||
if(file_prev_p == file_scanner_p)
|
|
||||||
mode_array[hash_entry] = file_scanner_p->next_offset;
|
|
||||||
else
|
|
||||||
file_prev_p->next_offset = file_scanner_p->next_offset;
|
|
||||||
shmops->shm_free(shmops->addr2offset(file_scanner_p));
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(5,("get_share_modes: file with dev %x inode %.0f -> %d entries\n",
|
|
||||||
(unsigned int)dev, (double)inode, num_entries_copied));
|
|
||||||
|
|
||||||
return(num_entries_copied);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
del the share mode of a file.
|
|
||||||
********************************************************************/
|
|
||||||
static void shm_del_share_mode(int token, files_struct *fsp)
|
|
||||||
{
|
|
||||||
SMB_DEV_T dev;
|
|
||||||
SMB_INO_T inode;
|
|
||||||
int *mode_array;
|
|
||||||
unsigned int hash_entry;
|
|
||||||
share_mode_record *file_scanner_p;
|
|
||||||
share_mode_record *file_prev_p;
|
|
||||||
shm_share_mode_entry *entry_scanner_p;
|
|
||||||
shm_share_mode_entry *entry_prev_p;
|
|
||||||
BOOL found = False;
|
|
||||||
pid_t pid = getpid();
|
|
||||||
|
|
||||||
dev = fsp->fd_ptr->dev;
|
|
||||||
inode = fsp->fd_ptr->inode;
|
|
||||||
|
|
||||||
hash_entry = HASH_ENTRY(dev, inode);
|
|
||||||
|
|
||||||
mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
|
|
||||||
|
|
||||||
if(mode_array[hash_entry] == 0)
|
|
||||||
{
|
|
||||||
DEBUG(0,("PANIC ERROR:del_share_mode hash bucket %d empty\n",
|
|
||||||
hash_entry));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
|
|
||||||
file_prev_p = file_scanner_p;
|
|
||||||
|
|
||||||
while(file_scanner_p)
|
|
||||||
{
|
|
||||||
if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
|
|
||||||
{
|
|
||||||
found = True;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
file_prev_p = file_scanner_p ;
|
|
||||||
file_scanner_p = (share_mode_record *)
|
|
||||||
shmops->offset2addr(file_scanner_p->next_offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!found)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR: del_share_mode no entry for dev %x inode %.0f\n",
|
|
||||||
(unsigned int)dev, (double)inode));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(file_scanner_p->locking_version != LOCKING_VERSION)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR: del_share_modes Deleting old share mode v1 %d dev=%x ino=%.0f\n",
|
|
||||||
file_scanner_p->locking_version, (unsigned int)dev, (double)inode));
|
|
||||||
|
|
||||||
if(file_prev_p == file_scanner_p)
|
|
||||||
mode_array[hash_entry] = file_scanner_p->next_offset;
|
|
||||||
else
|
|
||||||
file_prev_p->next_offset = file_scanner_p->next_offset;
|
|
||||||
shmops->shm_free(shmops->addr2offset(file_scanner_p));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
found = False;
|
|
||||||
entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
|
|
||||||
file_scanner_p->share_mode_entries);
|
|
||||||
entry_prev_p = entry_scanner_p;
|
|
||||||
while(entry_scanner_p)
|
|
||||||
{
|
|
||||||
if( (pid == entry_scanner_p->e.pid) &&
|
|
||||||
(memcmp(&entry_scanner_p->e.time,
|
|
||||||
&fsp->open_time,sizeof(struct timeval)) == 0) )
|
|
||||||
{
|
|
||||||
found = True;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry_prev_p = entry_scanner_p;
|
|
||||||
entry_scanner_p = (shm_share_mode_entry *)
|
|
||||||
shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found)
|
|
||||||
{
|
|
||||||
/* Decrement the number of entries in the record. */
|
|
||||||
file_scanner_p->num_share_mode_entries -= 1;
|
|
||||||
|
|
||||||
DEBUG(2,("del_share_modes Deleting share mode entry dev=%x ino=%.0f\n",
|
|
||||||
(unsigned int)dev, (double)inode));
|
|
||||||
|
|
||||||
if(entry_prev_p == entry_scanner_p)
|
|
||||||
/* We are at start of list */
|
|
||||||
file_scanner_p->share_mode_entries = entry_scanner_p->next_share_mode_entry;
|
|
||||||
else
|
|
||||||
entry_prev_p->next_share_mode_entry = entry_scanner_p->next_share_mode_entry;
|
|
||||||
shmops->shm_free(shmops->addr2offset(entry_scanner_p));
|
|
||||||
|
|
||||||
/* PARANOIA TEST */
|
|
||||||
if(file_scanner_p->num_share_mode_entries < 0)
|
|
||||||
{
|
|
||||||
DEBUG(0,("PANIC ERROR:del_share_mode num_share_mode_entries=%d\n",
|
|
||||||
file_scanner_p->num_share_mode_entries));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we deleted the last share mode entry then remove the share mode record. */
|
|
||||||
if(file_scanner_p->num_share_mode_entries == 0)
|
|
||||||
{
|
|
||||||
DEBUG(2,("del_share_modes num entries = 0, deleting share_mode dev=%x ino=%.0f\n",
|
|
||||||
(unsigned int)dev, (double)inode));
|
|
||||||
|
|
||||||
if(file_prev_p == file_scanner_p)
|
|
||||||
mode_array[hash_entry] = file_scanner_p->next_offset;
|
|
||||||
else
|
|
||||||
file_prev_p->next_offset = file_scanner_p->next_offset;
|
|
||||||
shmops->shm_free(shmops->addr2offset(file_scanner_p));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR: del_share_modes No share mode dev=%x ino=%.0f\n",
|
|
||||||
(unsigned int)dev, (double)inode));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
set the share mode of a file. Return False on fail, True on success.
|
|
||||||
********************************************************************/
|
|
||||||
static BOOL shm_set_share_mode(int token, files_struct *fsp, uint16 port, uint16 op_type)
|
|
||||||
{
|
|
||||||
SMB_DEV_T dev;
|
|
||||||
SMB_INO_T inode;
|
|
||||||
int *mode_array;
|
|
||||||
unsigned int hash_entry;
|
|
||||||
share_mode_record *file_scanner_p;
|
|
||||||
shm_share_mode_entry *new_entry_p;
|
|
||||||
int new_entry_offset;
|
|
||||||
BOOL found = False;
|
|
||||||
|
|
||||||
dev = fsp->fd_ptr->dev;
|
|
||||||
inode = fsp->fd_ptr->inode;
|
|
||||||
|
|
||||||
hash_entry = HASH_ENTRY(dev, inode);
|
|
||||||
|
|
||||||
mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
|
|
||||||
|
|
||||||
file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
|
|
||||||
|
|
||||||
while(file_scanner_p)
|
|
||||||
{
|
|
||||||
if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
|
|
||||||
{
|
|
||||||
found = True;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
file_scanner_p = (share_mode_record *)
|
|
||||||
shmops->offset2addr(file_scanner_p->next_offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!found)
|
|
||||||
{
|
|
||||||
/* We must create a share_mode_record */
|
|
||||||
share_mode_record *new_mode_p = NULL;
|
|
||||||
int new_offset = shmops->shm_alloc(sizeof(share_mode_record) +
|
|
||||||
strlen(fsp->fsp_name) + strlen(fsp->conn->connectpath) + 2);
|
|
||||||
if(new_offset == 0) {
|
|
||||||
DEBUG(0,("ERROR:set_share_mode shmops->shm_alloc fail!\n"));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
new_mode_p = shmops->offset2addr(new_offset);
|
|
||||||
new_mode_p->locking_version = LOCKING_VERSION;
|
|
||||||
new_mode_p->st_dev = dev;
|
|
||||||
new_mode_p->st_ino = inode;
|
|
||||||
new_mode_p->num_share_mode_entries = 0;
|
|
||||||
new_mode_p->share_mode_entries = 0;
|
|
||||||
pstrcpy(new_mode_p->file_name, fsp->conn->connectpath);
|
|
||||||
pstrcat(new_mode_p->file_name, "/");
|
|
||||||
pstrcat(new_mode_p->file_name, fsp->fsp_name);
|
|
||||||
|
|
||||||
/* Chain onto the start of the hash chain (in the hope we will be used first). */
|
|
||||||
new_mode_p->next_offset = mode_array[hash_entry];
|
|
||||||
mode_array[hash_entry] = new_offset;
|
|
||||||
|
|
||||||
file_scanner_p = new_mode_p;
|
|
||||||
|
|
||||||
DEBUG(3,("set_share_mode: Created share record for %s (dev %x inode %.0f)\n",
|
|
||||||
fsp->fsp_name, (unsigned int)dev, (double)inode));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now create the share mode entry */
|
|
||||||
new_entry_offset = shmops->shm_alloc(sizeof(shm_share_mode_entry));
|
|
||||||
if(new_entry_offset == 0) {
|
|
||||||
int delete_offset = mode_array[hash_entry];
|
|
||||||
DEBUG(0,("ERROR:set_share_mode: shmops->shm_alloc fail 1!\n"));
|
|
||||||
/* Unlink the damaged record */
|
|
||||||
mode_array[hash_entry] = file_scanner_p->next_offset;
|
|
||||||
/* And delete it */
|
|
||||||
shmops->shm_free( delete_offset );
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_entry_p = shmops->offset2addr(new_entry_offset);
|
|
||||||
|
|
||||||
new_entry_p->e.pid = getpid();
|
|
||||||
new_entry_p->e.share_mode = fsp->share_mode;
|
|
||||||
new_entry_p->e.op_port = port;
|
|
||||||
new_entry_p->e.op_type = op_type;
|
|
||||||
memcpy( (char *)&new_entry_p->e.time, (char *)&fsp->open_time, sizeof(struct timeval));
|
|
||||||
|
|
||||||
/* Chain onto the share_mode_record */
|
|
||||||
new_entry_p->next_share_mode_entry = file_scanner_p->share_mode_entries;
|
|
||||||
file_scanner_p->share_mode_entries = new_entry_offset;
|
|
||||||
|
|
||||||
/* PARANOIA TEST */
|
|
||||||
if(file_scanner_p->num_share_mode_entries < 0)
|
|
||||||
{
|
|
||||||
DEBUG(0,("PANIC ERROR:set_share_mode num_share_mode_entries=%d\n",
|
|
||||||
file_scanner_p->num_share_mode_entries));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Increment the share_mode_entries counter */
|
|
||||||
file_scanner_p->num_share_mode_entries += 1;
|
|
||||||
|
|
||||||
DEBUG(3,("set_share_mode: Created share entry for %s with mode 0x%X pid=%d\n",
|
|
||||||
fsp->fsp_name, fsp->share_mode, (int)new_entry_p->e.pid));
|
|
||||||
|
|
||||||
return(True);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
Call a generic modify function for a share mode entry.
|
|
||||||
********************************************************************/
|
|
||||||
|
|
||||||
static BOOL shm_mod_share_entry(int token, files_struct *fsp,
|
|
||||||
void (*mod_fn)(share_mode_entry *, SMB_DEV_T, SMB_INO_T, void *),
|
|
||||||
void *param)
|
|
||||||
{
|
|
||||||
SMB_DEV_T dev;
|
|
||||||
SMB_INO_T inode;
|
|
||||||
int *mode_array;
|
|
||||||
unsigned int hash_entry;
|
|
||||||
share_mode_record *file_scanner_p;
|
|
||||||
share_mode_record *file_prev_p;
|
|
||||||
shm_share_mode_entry *entry_scanner_p;
|
|
||||||
BOOL found = False;
|
|
||||||
pid_t pid = getpid();
|
|
||||||
|
|
||||||
dev = fsp->fd_ptr->dev;
|
|
||||||
inode = fsp->fd_ptr->inode;
|
|
||||||
|
|
||||||
hash_entry = HASH_ENTRY(dev, inode);
|
|
||||||
|
|
||||||
mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
|
|
||||||
|
|
||||||
if(mode_array[hash_entry] == 0)
|
|
||||||
{
|
|
||||||
DEBUG(0,("PANIC ERROR:modify_share_entry: hash bucket %d empty\n",
|
|
||||||
hash_entry));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[hash_entry]);
|
|
||||||
file_prev_p = file_scanner_p;
|
|
||||||
|
|
||||||
while(file_scanner_p)
|
|
||||||
{
|
|
||||||
if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
|
|
||||||
{
|
|
||||||
found = True;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
file_prev_p = file_scanner_p ;
|
|
||||||
file_scanner_p = (share_mode_record *)
|
|
||||||
shmops->offset2addr(file_scanner_p->next_offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!found)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR:modify_share_entry: no entry found for dev=%x ino=%.0f\n",
|
|
||||||
(unsigned int)dev, (double)inode));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(file_scanner_p->locking_version != LOCKING_VERSION)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR: modify_share_entry: Deleting old share mode v1=%d dev=%x ino=%.0f\n",
|
|
||||||
file_scanner_p->locking_version, (unsigned int)dev, (double)inode));
|
|
||||||
|
|
||||||
if(file_prev_p == file_scanner_p)
|
|
||||||
mode_array[hash_entry] = file_scanner_p->next_offset;
|
|
||||||
else
|
|
||||||
file_prev_p->next_offset = file_scanner_p->next_offset;
|
|
||||||
shmops->shm_free(shmops->addr2offset(file_scanner_p));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
found = False;
|
|
||||||
entry_scanner_p = (shm_share_mode_entry*)shmops->offset2addr(
|
|
||||||
file_scanner_p->share_mode_entries);
|
|
||||||
while(entry_scanner_p)
|
|
||||||
{
|
|
||||||
if( (pid == entry_scanner_p->e.pid) &&
|
|
||||||
(entry_scanner_p->e.share_mode == fsp->share_mode) &&
|
|
||||||
(memcmp(&entry_scanner_p->e.time,
|
|
||||||
&fsp->open_time,sizeof(struct timeval)) == 0) )
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Call the generic function with the given parameter.
|
|
||||||
*/
|
|
||||||
|
|
||||||
DEBUG(5,("modify_share_entry: Calling generic function to modify entry for dev=%x ino=%.0f\n",
|
|
||||||
(unsigned int)dev, (double)inode));
|
|
||||||
|
|
||||||
(*mod_fn)( &entry_scanner_p->e, dev, inode, param);
|
|
||||||
found = True;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry_scanner_p = (shm_share_mode_entry *)
|
|
||||||
shmops->offset2addr(entry_scanner_p->next_share_mode_entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!found)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR: modify_share_entry: No entry found for dev=%x ino=%.0f\n",
|
|
||||||
(unsigned int)dev, (double)inode));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
call the specified function on each entry under management by the
|
|
||||||
share mode system
|
|
||||||
********************************************************************/
|
|
||||||
static int shm_share_forall(void (*fn)(share_mode_entry *, char *))
|
|
||||||
{
|
|
||||||
int i, count=0;
|
|
||||||
int *mode_array;
|
|
||||||
share_mode_record *file_scanner_p;
|
|
||||||
|
|
||||||
mode_array = (int *)shmops->offset2addr(shmops->get_userdef_off());
|
|
||||||
|
|
||||||
for( i = 0; i < shmops->hash_size(); i++) {
|
|
||||||
shmops->lock_hash_entry(i);
|
|
||||||
if(mode_array[i] == 0) {
|
|
||||||
shmops->unlock_hash_entry(i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
file_scanner_p = (share_mode_record *)shmops->offset2addr(mode_array[i]);
|
|
||||||
while((file_scanner_p != 0) &&
|
|
||||||
(file_scanner_p->num_share_mode_entries != 0)) {
|
|
||||||
shm_share_mode_entry *entry_scanner_p =
|
|
||||||
(shm_share_mode_entry *)
|
|
||||||
shmops->offset2addr(file_scanner_p->share_mode_entries);
|
|
||||||
|
|
||||||
while(entry_scanner_p != 0) {
|
|
||||||
|
|
||||||
if (process_exists(entry_scanner_p->e.pid)) {
|
|
||||||
fn(&entry_scanner_p->e,
|
|
||||||
file_scanner_p->file_name);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry_scanner_p =
|
|
||||||
(shm_share_mode_entry *)
|
|
||||||
shmops->offset2addr(
|
|
||||||
entry_scanner_p->next_share_mode_entry);
|
|
||||||
} /* end while entry_scanner_p */
|
|
||||||
file_scanner_p = (share_mode_record *)
|
|
||||||
shmops->offset2addr(file_scanner_p->next_offset);
|
|
||||||
} /* end while file_scanner_p */
|
|
||||||
shmops->unlock_hash_entry(i);
|
|
||||||
} /* end for */
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
dump the state of the system
|
|
||||||
********************************************************************/
|
|
||||||
static void shm_share_status(FILE *f)
|
|
||||||
{
|
|
||||||
int bytes_free, bytes_used, bytes_overhead, bytes_total;
|
|
||||||
|
|
||||||
shmops->get_usage(&bytes_free, &bytes_used, &bytes_overhead);
|
|
||||||
bytes_total = bytes_free + bytes_used + bytes_overhead;
|
|
||||||
|
|
||||||
fprintf(f, "Share mode memory usage (bytes):\n");
|
|
||||||
fprintf(f, " %d(%d%%) free + %d(%d%%) used + %d(%d%%) overhead = %d(100%%) total\n",
|
|
||||||
bytes_free, (bytes_free * 100)/bytes_total,
|
|
||||||
bytes_used, (bytes_used * 100)/bytes_total,
|
|
||||||
bytes_overhead, (bytes_overhead * 100)/bytes_total,
|
|
||||||
bytes_total);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct share_ops share_ops = {
|
|
||||||
shm_stop_share_mode_mgmt,
|
|
||||||
shm_lock_share_entry,
|
|
||||||
shm_unlock_share_entry,
|
|
||||||
shm_get_share_modes,
|
|
||||||
shm_del_share_mode,
|
|
||||||
shm_set_share_mode,
|
|
||||||
shm_mod_share_entry,
|
|
||||||
shm_share_forall,
|
|
||||||
shm_share_status,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
initialize the shared memory for share_mode management
|
|
||||||
******************************************************************/
|
|
||||||
struct share_ops *locking_shm_init(int ronly)
|
|
||||||
{
|
|
||||||
read_only = ronly;
|
|
||||||
|
|
||||||
#ifdef USE_SYSV_IPC
|
|
||||||
shmops = sysv_shm_open(read_only);
|
|
||||||
if (shmops) return &share_ops;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_SHARED_MMAP
|
|
||||||
shmops = smb_shm_open(read_only);
|
|
||||||
if (shmops) return &share_ops;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
int locking_shm_dummy_procedure(void)
|
|
||||||
{return 0;}
|
|
||||||
#endif /* FAST_SHARE_MODES */
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,963 +0,0 @@
|
|||||||
/*
|
|
||||||
Unix SMB/Netbios implementation.
|
|
||||||
Version 1.9.
|
|
||||||
Shared memory functions
|
|
||||||
Copyright (C) Erik Devriendt 1996-1998
|
|
||||||
|
|
||||||
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"
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_SHARED_MMAP
|
|
||||||
|
|
||||||
|
|
||||||
extern int DEBUGLEVEL;
|
|
||||||
|
|
||||||
|
|
||||||
#define SMB_SHM_MAGIC 0x53484100
|
|
||||||
/* = "SHM" in hex */
|
|
||||||
|
|
||||||
#define SMB_SHM_VERSION 2
|
|
||||||
|
|
||||||
/* we need world read for smbstatus to function correctly */
|
|
||||||
#ifdef SECURE_SHARE_MODES
|
|
||||||
#define SHM_FILE_MODE 0600
|
|
||||||
#else
|
|
||||||
#define SHM_FILE_MODE 0644
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SHMEM_HASH_SIZE 13
|
|
||||||
|
|
||||||
|
|
||||||
/* WARNING : offsets are used because mmap() does not guarantee that all processes have the
|
|
||||||
shared memory mapped to the same address */
|
|
||||||
|
|
||||||
struct SmbShmHeader
|
|
||||||
{
|
|
||||||
int smb_shm_magic;
|
|
||||||
int smb_shm_version;
|
|
||||||
int total_size; /* in bytes */
|
|
||||||
BOOL consistent;
|
|
||||||
int first_free_off;
|
|
||||||
int userdef_off; /* a userdefined offset. can be used to store root of tree or list */
|
|
||||||
struct { /* a cell is a range of bytes of sizeof(struct SmbShmBlockDesc) size */
|
|
||||||
int cells_free;
|
|
||||||
int cells_used;
|
|
||||||
int cells_system; /* number of cells used as allocated block descriptors */
|
|
||||||
} statistics;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define SMB_SHM_NOT_FREE_OFF (-1)
|
|
||||||
struct SmbShmBlockDesc
|
|
||||||
{
|
|
||||||
int next; /* offset of next block in the free list or SMB_SHM_NOT_FREE_OFF when block in use */
|
|
||||||
int size; /* user size in BlockDescSize units */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define EOList_Addr (struct SmbShmBlockDesc *)( 0 )
|
|
||||||
#define EOList_Off 0
|
|
||||||
|
|
||||||
#define CellSize sizeof(struct SmbShmBlockDesc)
|
|
||||||
|
|
||||||
/* HeaderSize aligned on 8 byte boundary */
|
|
||||||
#define AlignedHeaderSize ((sizeof(struct SmbShmHeader)+7) & ~7)
|
|
||||||
|
|
||||||
static int smb_shm_fd = -1;
|
|
||||||
static pstring smb_shm_processreg_name = "";
|
|
||||||
|
|
||||||
static struct SmbShmHeader *smb_shm_header_p = (struct SmbShmHeader *)0;
|
|
||||||
static int smb_shm_times_locked = 0;
|
|
||||||
|
|
||||||
static BOOL smb_shm_initialize_called = False;
|
|
||||||
|
|
||||||
static int read_only;
|
|
||||||
|
|
||||||
static BOOL smb_shm_global_lock(void)
|
|
||||||
{
|
|
||||||
if (smb_shm_fd < 0)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_global_lock : bad smb_shm_fd (%d)\n",smb_shm_fd));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
smb_shm_times_locked++;
|
|
||||||
|
|
||||||
if(smb_shm_times_locked > 1)
|
|
||||||
{
|
|
||||||
DEBUG(5,("smb_shm_global_lock : locked %d times\n",smb_shm_times_locked));
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (read_only)
|
|
||||||
return True;
|
|
||||||
|
|
||||||
/* Do an exclusive wait lock on the first byte of the file */
|
|
||||||
if (fcntl_lock(smb_shm_fd, SMB_F_SETLKW, 0, 1, F_WRLCK) == False)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_global_lock : fcntl_lock failed with code %s\n",strerror(errno)));
|
|
||||||
smb_shm_times_locked--;
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
return True;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL smb_shm_global_unlock(void)
|
|
||||||
{
|
|
||||||
if (smb_shm_fd < 0)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_global_unlock : bad smb_shm_fd (%d)\n",smb_shm_fd));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(smb_shm_times_locked == 0)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_global_unlock : shmem not locked\n"));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
smb_shm_times_locked--;
|
|
||||||
|
|
||||||
if(smb_shm_times_locked > 0)
|
|
||||||
{
|
|
||||||
DEBUG(5,("smb_shm_global_unlock : still locked %d times\n",smb_shm_times_locked));
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (read_only)
|
|
||||||
return True;
|
|
||||||
|
|
||||||
/* Do a wait unlock on the first byte of the file */
|
|
||||||
if (fcntl_lock(smb_shm_fd, SMB_F_SETLKW, 0, 1, F_UNLCK) == False)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_global_unlock : fcntl_lock failed with code %s\n",strerror(errno)));
|
|
||||||
smb_shm_times_locked++;
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
return True;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void *smb_shm_offset2addr(int offset)
|
|
||||||
{
|
|
||||||
if (offset == 0 )
|
|
||||||
return (void *)(0);
|
|
||||||
|
|
||||||
if (!smb_shm_header_p)
|
|
||||||
return (void *)(0);
|
|
||||||
|
|
||||||
return (void *)((char *)smb_shm_header_p + offset );
|
|
||||||
}
|
|
||||||
|
|
||||||
static int smb_shm_addr2offset(void *addr)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!smb_shm_header_p)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return (int)((char *)addr - (char *)smb_shm_header_p);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int smb_shm_alloc(int size)
|
|
||||||
{
|
|
||||||
unsigned num_cells ;
|
|
||||||
struct SmbShmBlockDesc *scanner_p;
|
|
||||||
struct SmbShmBlockDesc *prev_p;
|
|
||||||
struct SmbShmBlockDesc *new_p;
|
|
||||||
int result_offset;
|
|
||||||
|
|
||||||
|
|
||||||
if( !smb_shm_header_p )
|
|
||||||
{
|
|
||||||
/* not mapped yet */
|
|
||||||
DEBUG(0,("ERROR smb_shm_alloc : shmem not mapped\n"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
smb_shm_global_lock();
|
|
||||||
|
|
||||||
if( !smb_shm_header_p->consistent)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_alloc : shmem not consistent\n"));
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* calculate the number of cells */
|
|
||||||
num_cells = (size + CellSize -1) / CellSize;
|
|
||||||
|
|
||||||
/* set start of scan */
|
|
||||||
prev_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(smb_shm_header_p->first_free_off);
|
|
||||||
scanner_p = prev_p ;
|
|
||||||
|
|
||||||
/* scan the free list to find a matching free space */
|
|
||||||
while ( ( scanner_p != EOList_Addr ) && ( scanner_p->size < num_cells ) )
|
|
||||||
{
|
|
||||||
prev_p = scanner_p;
|
|
||||||
scanner_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(scanner_p->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* at this point scanner point to a block header or to the end of the list */
|
|
||||||
if ( scanner_p == EOList_Addr )
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_alloc : alloc of %d bytes failed, no free space found\n",size));
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* going to modify shared mem */
|
|
||||||
smb_shm_header_p->consistent = False;
|
|
||||||
|
|
||||||
/* if we found a good one : scanner == the good one */
|
|
||||||
if ( scanner_p->size <= num_cells + 2 )
|
|
||||||
{
|
|
||||||
/* there is no use in making a new one, it will be too small anyway
|
|
||||||
* we will link out scanner
|
|
||||||
*/
|
|
||||||
if ( prev_p == scanner_p )
|
|
||||||
{
|
|
||||||
smb_shm_header_p->first_free_off = scanner_p->next ;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
prev_p->next = scanner_p->next ;
|
|
||||||
}
|
|
||||||
smb_shm_header_p->statistics.cells_free -= scanner_p->size;
|
|
||||||
smb_shm_header_p->statistics.cells_used += scanner_p->size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Make a new one */
|
|
||||||
new_p = scanner_p + 1 + num_cells;
|
|
||||||
new_p->size = scanner_p->size - num_cells - 1;
|
|
||||||
new_p->next = scanner_p->next;
|
|
||||||
scanner_p->size = num_cells;
|
|
||||||
scanner_p->next = smb_shm_addr2offset(new_p);
|
|
||||||
|
|
||||||
if ( prev_p != scanner_p )
|
|
||||||
{
|
|
||||||
prev_p->next = smb_shm_addr2offset(new_p) ;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
smb_shm_header_p->first_free_off = smb_shm_addr2offset(new_p) ;
|
|
||||||
}
|
|
||||||
smb_shm_header_p->statistics.cells_free -= num_cells+1;
|
|
||||||
smb_shm_header_p->statistics.cells_used += num_cells;
|
|
||||||
smb_shm_header_p->statistics.cells_system += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
result_offset = smb_shm_addr2offset( &(scanner_p[1]) );
|
|
||||||
scanner_p->next = SMB_SHM_NOT_FREE_OFF ;
|
|
||||||
|
|
||||||
/* end modification of shared mem */
|
|
||||||
smb_shm_header_p->consistent = True;
|
|
||||||
|
|
||||||
DEBUG(6,("smb_shm_alloc : request for %d bytes, allocated %d bytes at offset %d\n",size,scanner_p->size*CellSize,result_offset ));
|
|
||||||
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
return ( result_offset );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function to create the hash table for the share mode entries. Called
|
|
||||||
* when smb shared memory is global locked.
|
|
||||||
*/
|
|
||||||
static BOOL smb_shm_create_hash_table( unsigned int size )
|
|
||||||
{
|
|
||||||
size *= sizeof(int);
|
|
||||||
|
|
||||||
smb_shm_global_lock();
|
|
||||||
smb_shm_header_p->userdef_off = smb_shm_alloc( size );
|
|
||||||
|
|
||||||
if(smb_shm_header_p->userdef_off == 0)
|
|
||||||
{
|
|
||||||
DEBUG(0,("smb_shm_create_hash_table: Failed to create hash table of size %d\n",size));
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear hash buckets. */
|
|
||||||
memset( smb_shm_offset2addr(smb_shm_header_p->userdef_off), '\0', size);
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL smb_shm_register_process(char *processreg_file, pid_t pid, BOOL *other_processes)
|
|
||||||
{
|
|
||||||
int smb_shm_processes_fd = -1;
|
|
||||||
int nb_read;
|
|
||||||
pid_t other_pid;
|
|
||||||
SMB_OFF_T seek_back = -((SMB_OFF_T)sizeof(other_pid));
|
|
||||||
SMB_OFF_T free_slot = -1;
|
|
||||||
SMB_OFF_T erased_slot;
|
|
||||||
|
|
||||||
smb_shm_processes_fd = sys_open(processreg_file,
|
|
||||||
read_only?O_RDONLY:(O_RDWR|O_CREAT),
|
|
||||||
SHM_FILE_MODE);
|
|
||||||
|
|
||||||
if ( smb_shm_processes_fd < 0 )
|
|
||||||
{
|
|
||||||
DEBUG(0, ("ERROR smb_shm_register_process : processreg_file \
|
|
||||||
open failed with code %s\n",strerror(errno)));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
*other_processes = False;
|
|
||||||
|
|
||||||
while ((nb_read = read(smb_shm_processes_fd, &other_pid, sizeof(other_pid))) > 0)
|
|
||||||
{
|
|
||||||
if(other_pid)
|
|
||||||
{
|
|
||||||
if(process_exists(other_pid))
|
|
||||||
*other_processes = True;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* erase old pid */
|
|
||||||
DEBUG(5,("smb_shm_register_process : erasing stale record \
|
|
||||||
for pid %d (seek_back = %.0f)\n", (int)other_pid, (double)seek_back));
|
|
||||||
other_pid = (pid_t)0;
|
|
||||||
if((erased_slot = sys_lseek(smb_shm_processes_fd,
|
|
||||||
seek_back, SEEK_CUR)) == -1)
|
|
||||||
{
|
|
||||||
DEBUG(0, ("ERROR smb_shm_register_process : sys_lseek failed \
|
|
||||||
with error %s\n", strerror(errno)));
|
|
||||||
close(smb_shm_processes_fd);
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(write(smb_shm_processes_fd, &other_pid, sizeof(other_pid)) == -1)
|
|
||||||
{
|
|
||||||
DEBUG(0, ("ERROR smb_shm_register_process : write failed \
|
|
||||||
with error %s\n", strerror(errno)));
|
|
||||||
close(smb_shm_processes_fd);
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(free_slot < 0)
|
|
||||||
free_slot = erased_slot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(free_slot < 0)
|
|
||||||
{
|
|
||||||
if((free_slot = sys_lseek(smb_shm_processes_fd,
|
|
||||||
seek_back, SEEK_CUR))==-1)
|
|
||||||
{
|
|
||||||
DEBUG(0, ("ERROR smb_shm_register_process : sys_lseek \
|
|
||||||
failed with error %s\n", strerror(errno)));
|
|
||||||
close(smb_shm_processes_fd);
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
} /* end if free_slot */
|
|
||||||
} /* end else */
|
|
||||||
} /* end if other_pid */
|
|
||||||
|
|
||||||
if (nb_read < 0)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_register_process : processreg_file read \
|
|
||||||
failed with code %s\n",strerror(errno)));
|
|
||||||
close(smb_shm_processes_fd);
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(free_slot < 0)
|
|
||||||
{
|
|
||||||
if((free_slot = sys_lseek(smb_shm_processes_fd, 0, SEEK_END)) == -1)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_register_process : sys_lseek failed with code %s\n",strerror(errno)));
|
|
||||||
close(smb_shm_processes_fd);
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(5,("smb_shm_register_process : writing record for pid %d at offset %.0f\n",
|
|
||||||
(int)pid, (double)free_slot));
|
|
||||||
|
|
||||||
if(sys_lseek(smb_shm_processes_fd, free_slot, SEEK_SET) == -1)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_register_process : sys_lseek failed with code %s\n",strerror(errno)));
|
|
||||||
close(smb_shm_processes_fd);
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(write(smb_shm_processes_fd, &pid, sizeof(pid)) == -1)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_register_process : processreg_file write failed with code %s\n",strerror(errno)));
|
|
||||||
close(smb_shm_processes_fd);
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
close(smb_shm_processes_fd);
|
|
||||||
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL smb_shm_unregister_process(char *processreg_file, pid_t pid)
|
|
||||||
{
|
|
||||||
int smb_shm_processes_fd = -1;
|
|
||||||
int nb_read;
|
|
||||||
pid_t other_pid;
|
|
||||||
SMB_OFF_T seek_back = -((SMB_OFF_T)sizeof(other_pid));
|
|
||||||
BOOL found = False;
|
|
||||||
|
|
||||||
|
|
||||||
smb_shm_processes_fd = sys_open(processreg_file, O_RDWR, 0);
|
|
||||||
if ( smb_shm_processes_fd < 0 )
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file open failed with code %s\n",strerror(errno)));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((nb_read = read(smb_shm_processes_fd, &other_pid, sizeof(other_pid))) > 0)
|
|
||||||
{
|
|
||||||
DEBUG(5,("smb_shm_unregister_process : read record for pid %d\n",(int)other_pid));
|
|
||||||
if(other_pid == pid)
|
|
||||||
{
|
|
||||||
/* erase pid */
|
|
||||||
DEBUG(5,("smb_shm_unregister_process : erasing record for pid %d (seek_val = %.0f)\n",
|
|
||||||
(int)other_pid, (double)seek_back));
|
|
||||||
other_pid = (pid_t)0;
|
|
||||||
if(sys_lseek(smb_shm_processes_fd, seek_back, SEEK_CUR) == -1)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file sys_lseek failed with code %s\n",strerror(errno)));
|
|
||||||
close(smb_shm_processes_fd);
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
if(write(smb_shm_processes_fd, &other_pid, sizeof(other_pid)) < 0)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file write failed with code %s\n",strerror(errno)));
|
|
||||||
close(smb_shm_processes_fd);
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
found = True;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (nb_read < 0)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_unregister_process : processreg_file read failed with code %s\n",strerror(errno)));
|
|
||||||
close(smb_shm_processes_fd);
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!found)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_unregister_process : couldn't find pid %d in file %s\n",
|
|
||||||
(int)pid,processreg_file));
|
|
||||||
close(smb_shm_processes_fd);
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
close(smb_shm_processes_fd);
|
|
||||||
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static BOOL smb_shm_validate_header(int size)
|
|
||||||
{
|
|
||||||
if( !smb_shm_header_p )
|
|
||||||
{
|
|
||||||
/* not mapped yet */
|
|
||||||
DEBUG(0,("ERROR smb_shm_validate_header : shmem not mapped\n"));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(smb_shm_header_p->smb_shm_magic != SMB_SHM_MAGIC)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_validate_header : bad magic\n"));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
if(smb_shm_header_p->smb_shm_version != SMB_SHM_VERSION)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_validate_header : bad version %X\n",smb_shm_header_p->smb_shm_version));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(smb_shm_header_p->total_size != size)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_validate_header : shmem size mismatch (old = %d, new = %d)\n",smb_shm_header_p->total_size,size));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!smb_shm_header_p->consistent)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_validate_header : shmem not consistent\n"));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL smb_shm_initialize(int size)
|
|
||||||
{
|
|
||||||
struct SmbShmBlockDesc * first_free_block_p;
|
|
||||||
|
|
||||||
DEBUG(5,("smb_shm_initialize : initializing shmem file of size %d\n",size));
|
|
||||||
|
|
||||||
if( !smb_shm_header_p )
|
|
||||||
{
|
|
||||||
/* not mapped yet */
|
|
||||||
DEBUG(0,("ERROR smb_shm_initialize : shmem not mapped\n"));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
smb_shm_header_p->smb_shm_magic = SMB_SHM_MAGIC;
|
|
||||||
smb_shm_header_p->smb_shm_version = SMB_SHM_VERSION;
|
|
||||||
smb_shm_header_p->total_size = size;
|
|
||||||
smb_shm_header_p->first_free_off = AlignedHeaderSize;
|
|
||||||
smb_shm_header_p->userdef_off = 0;
|
|
||||||
|
|
||||||
first_free_block_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(smb_shm_header_p->first_free_off);
|
|
||||||
first_free_block_p->next = EOList_Off;
|
|
||||||
first_free_block_p->size = ( size - AlignedHeaderSize - CellSize ) / CellSize ;
|
|
||||||
|
|
||||||
smb_shm_header_p->statistics.cells_free = first_free_block_p->size;
|
|
||||||
smb_shm_header_p->statistics.cells_used = 0;
|
|
||||||
smb_shm_header_p->statistics.cells_system = 1;
|
|
||||||
|
|
||||||
smb_shm_header_p->consistent = True;
|
|
||||||
|
|
||||||
smb_shm_initialize_called = True;
|
|
||||||
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void smb_shm_solve_neighbors(struct SmbShmBlockDesc *head_p )
|
|
||||||
{
|
|
||||||
struct SmbShmBlockDesc *next_p;
|
|
||||||
|
|
||||||
/* Check if head_p and head_p->next are neighbors and if so join them */
|
|
||||||
if ( head_p == EOList_Addr ) return ;
|
|
||||||
if ( head_p->next == EOList_Off ) return ;
|
|
||||||
|
|
||||||
next_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(head_p->next);
|
|
||||||
if ( ( head_p + head_p->size + 1 ) == next_p)
|
|
||||||
{
|
|
||||||
head_p->size += next_p->size +1 ; /* adapt size */
|
|
||||||
head_p->next = next_p->next ; /* link out */
|
|
||||||
|
|
||||||
smb_shm_header_p->statistics.cells_free += 1;
|
|
||||||
smb_shm_header_p->statistics.cells_system -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static BOOL smb_shm_close( void )
|
|
||||||
{
|
|
||||||
|
|
||||||
if(smb_shm_initialize_called == False)
|
|
||||||
return True;
|
|
||||||
|
|
||||||
DEBUG(5,("smb_shm_close\n"));
|
|
||||||
if(smb_shm_times_locked > 0)
|
|
||||||
DEBUG(0,("WARNING smb_shm_close : shmem was still locked %d times\n",smb_shm_times_locked));;
|
|
||||||
if ((smb_shm_header_p != NULL) &&
|
|
||||||
(munmap((caddr_t)smb_shm_header_p, smb_shm_header_p->total_size) < 0))
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_close : munmap failed with code %s\n",strerror(errno)));
|
|
||||||
}
|
|
||||||
|
|
||||||
smb_shm_global_lock();
|
|
||||||
DEBUG(5,("calling smb_shm_unregister_process(%s, %d)\n",
|
|
||||||
smb_shm_processreg_name, (int)getpid()));
|
|
||||||
smb_shm_unregister_process(smb_shm_processreg_name, getpid());
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
|
|
||||||
close(smb_shm_fd);
|
|
||||||
|
|
||||||
smb_shm_fd = -1;
|
|
||||||
smb_shm_processreg_name[0] = '\0';
|
|
||||||
|
|
||||||
smb_shm_header_p = (struct SmbShmHeader *)0;
|
|
||||||
smb_shm_times_locked = 0;
|
|
||||||
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static BOOL smb_shm_free(int offset)
|
|
||||||
{
|
|
||||||
struct SmbShmBlockDesc *header_p ; /* pointer to header of block to free */
|
|
||||||
struct SmbShmBlockDesc *scanner_p ; /* used to scan the list */
|
|
||||||
struct SmbShmBlockDesc *prev_p ; /* holds previous in the list */
|
|
||||||
|
|
||||||
if( !smb_shm_header_p )
|
|
||||||
{
|
|
||||||
/* not mapped yet */
|
|
||||||
DEBUG(0,("ERROR smb_shm_free : shmem not mapped\n"));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
smb_shm_global_lock();
|
|
||||||
|
|
||||||
if( !smb_shm_header_p->consistent)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_free : shmem not consistent\n"));
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
header_p = ( (struct SmbShmBlockDesc *)smb_shm_offset2addr(offset) - 1); /* make pointer to header of block */
|
|
||||||
|
|
||||||
if (header_p->next != SMB_SHM_NOT_FREE_OFF)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_free : bad offset (%d)\n",offset));
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find a place in the free_list to put the header in */
|
|
||||||
|
|
||||||
/* set scanner and previous pointer to start of list */
|
|
||||||
prev_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(smb_shm_header_p->first_free_off);
|
|
||||||
scanner_p = prev_p ;
|
|
||||||
|
|
||||||
while ( ( scanner_p != EOList_Addr) && (scanner_p < header_p) ) /* while we didn't scan past its position */
|
|
||||||
{
|
|
||||||
prev_p = scanner_p ;
|
|
||||||
scanner_p = (struct SmbShmBlockDesc *)smb_shm_offset2addr(scanner_p->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
smb_shm_header_p->consistent = False;
|
|
||||||
|
|
||||||
DEBUG(6,("smb_shm_free : freeing %d bytes at offset %d\n",header_p->size*CellSize,offset));
|
|
||||||
|
|
||||||
/* zero the area being freed - this allows us to find bugs faster */
|
|
||||||
memset(smb_shm_offset2addr(offset), 0, header_p->size*CellSize);
|
|
||||||
|
|
||||||
if ( scanner_p == prev_p )
|
|
||||||
{
|
|
||||||
smb_shm_header_p->statistics.cells_free += header_p->size;
|
|
||||||
smb_shm_header_p->statistics.cells_used -= header_p->size;
|
|
||||||
|
|
||||||
/* we must free it at the beginning of the list */
|
|
||||||
smb_shm_header_p->first_free_off = smb_shm_addr2offset(header_p); /* set the free_list_pointer to this block_header */
|
|
||||||
|
|
||||||
/* scanner is the one that was first in the list */
|
|
||||||
header_p->next = smb_shm_addr2offset(scanner_p);
|
|
||||||
smb_shm_solve_neighbors( header_p ); /* if neighbors then link them */
|
|
||||||
|
|
||||||
smb_shm_header_p->consistent = True;
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
smb_shm_header_p->statistics.cells_free += header_p->size;
|
|
||||||
smb_shm_header_p->statistics.cells_used -= header_p->size;
|
|
||||||
|
|
||||||
prev_p->next = smb_shm_addr2offset(header_p);
|
|
||||||
header_p->next = smb_shm_addr2offset(scanner_p);
|
|
||||||
smb_shm_solve_neighbors(header_p) ;
|
|
||||||
smb_shm_solve_neighbors(prev_p) ;
|
|
||||||
|
|
||||||
smb_shm_header_p->consistent = True;
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int smb_shm_get_userdef_off(void)
|
|
||||||
{
|
|
||||||
if (!smb_shm_header_p)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return smb_shm_header_p->userdef_off;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
Lock a particular hash bucket entry.
|
|
||||||
******************************************************************/
|
|
||||||
static BOOL smb_shm_lock_hash_entry( unsigned int entry)
|
|
||||||
{
|
|
||||||
int start = (smb_shm_header_p->userdef_off + (entry * sizeof(int)));
|
|
||||||
|
|
||||||
if (smb_shm_fd < 0)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_lock_hash_entry : bad smb_shm_fd (%d)\n",smb_shm_fd));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (read_only)
|
|
||||||
return True;
|
|
||||||
|
|
||||||
/* Do an exclusive wait lock on the 4 byte region mapping into this entry */
|
|
||||||
if (fcntl_lock(smb_shm_fd, SMB_F_SETLKW, start, sizeof(int), F_WRLCK) == False)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_lock_hash_entry : fcntl_lock failed with code %s\n",strerror(errno)));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(9,("smb_shm_lock_hash_entry: locked hash bucket %d\n", entry));
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
Unlock a particular hash bucket entry.
|
|
||||||
******************************************************************/
|
|
||||||
static BOOL smb_shm_unlock_hash_entry( unsigned int entry )
|
|
||||||
{
|
|
||||||
int start = (smb_shm_header_p->userdef_off + (entry * sizeof(int)));
|
|
||||||
|
|
||||||
if (smb_shm_fd < 0)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_unlock_hash_entry : bad smb_shm_fd (%d)\n",smb_shm_fd));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (read_only)
|
|
||||||
return True;
|
|
||||||
|
|
||||||
/* Do a wait lock on the 4 byte region mapping into this entry */
|
|
||||||
if (fcntl_lock(smb_shm_fd, SMB_F_SETLKW, start, sizeof(int), F_UNLCK) == False)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_unlock_hash_entry : fcntl_lock failed with code %s\n",strerror(errno)));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(9,("smb_shm_unlock_hash_entry: unlocked hash bucket %d\n", entry));
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
Gather statistics on shared memory usage.
|
|
||||||
******************************************************************/
|
|
||||||
static BOOL smb_shm_get_usage(int *bytes_free,
|
|
||||||
int *bytes_used,
|
|
||||||
int *bytes_overhead)
|
|
||||||
{
|
|
||||||
if( !smb_shm_header_p )
|
|
||||||
{
|
|
||||||
/* not mapped yet */
|
|
||||||
DEBUG(0,("ERROR smb_shm_free : shmem not mapped\n"));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
*bytes_free = smb_shm_header_p->statistics.cells_free * CellSize;
|
|
||||||
*bytes_used = smb_shm_header_p->statistics.cells_used * CellSize;
|
|
||||||
*bytes_overhead = smb_shm_header_p->statistics.cells_system * CellSize + AlignedHeaderSize;
|
|
||||||
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
hash a number into a hash_entry
|
|
||||||
******************************************************************/
|
|
||||||
static unsigned smb_shm_hash_size(void)
|
|
||||||
{
|
|
||||||
return SHMEM_HASH_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct shmem_ops shmops = {
|
|
||||||
smb_shm_close,
|
|
||||||
smb_shm_alloc,
|
|
||||||
smb_shm_free,
|
|
||||||
smb_shm_get_userdef_off,
|
|
||||||
smb_shm_offset2addr,
|
|
||||||
smb_shm_addr2offset,
|
|
||||||
smb_shm_lock_hash_entry,
|
|
||||||
smb_shm_unlock_hash_entry,
|
|
||||||
smb_shm_get_usage,
|
|
||||||
smb_shm_hash_size,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
open the shared memory
|
|
||||||
******************************************************************/
|
|
||||||
struct shmem_ops *smb_shm_open(int ronly)
|
|
||||||
{
|
|
||||||
pstring file_name;
|
|
||||||
SMB_OFF_T filesize;
|
|
||||||
BOOL created_new = False;
|
|
||||||
BOOL other_processes = True;
|
|
||||||
SMB_OFF_T size = (SMB_OFF_T)lp_shmem_size();
|
|
||||||
|
|
||||||
read_only = ronly;
|
|
||||||
|
|
||||||
pstrcpy(file_name,lp_lockdir());
|
|
||||||
if (!directory_exist(file_name,NULL)) {
|
|
||||||
if (read_only)
|
|
||||||
return NULL;
|
|
||||||
mkdir(file_name,0755);
|
|
||||||
}
|
|
||||||
trim_string(file_name,"","/");
|
|
||||||
if (!*file_name)
|
|
||||||
return(False);
|
|
||||||
pstrcat(file_name, "/SHARE_MEM_FILE");
|
|
||||||
|
|
||||||
DEBUG(5,("smb_shm_open : using shmem file %s to be of size %.0f\n",
|
|
||||||
file_name,(double)size));
|
|
||||||
|
|
||||||
smb_shm_fd = sys_open(file_name, read_only?O_RDONLY:(O_RDWR|O_CREAT),
|
|
||||||
SHM_FILE_MODE);
|
|
||||||
|
|
||||||
if ( smb_shm_fd < 0 )
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_open : open failed with code %s\n",strerror(errno)));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!smb_shm_global_lock())
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_open : can't do smb_shm_global_lock\n"));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( (filesize = sys_lseek(smb_shm_fd, 0, SEEK_END)) == -1)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_open : sys_lseek failed with code %s\n",
|
|
||||||
strerror(errno)));
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
close(smb_shm_fd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return the file offset to 0 to save on later seeks.
|
|
||||||
*/
|
|
||||||
if(sys_lseek(smb_shm_fd,0,SEEK_SET) == -1)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_open : sys_lseek failed with code %s\n",
|
|
||||||
strerror(errno)));
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
close(smb_shm_fd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filesize == 0)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* We just created a new one.
|
|
||||||
*/
|
|
||||||
created_new = True;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* To find out if some other process is already mapping the file,
|
|
||||||
* we use a registration file containing the processids of the file
|
|
||||||
* mapping processes.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* construct processreg file name */
|
|
||||||
pstrcpy(smb_shm_processreg_name, file_name);
|
|
||||||
pstrcat(smb_shm_processreg_name, ".processes");
|
|
||||||
|
|
||||||
if (!read_only && !smb_shm_register_process(smb_shm_processreg_name,
|
|
||||||
getpid(), &other_processes))
|
|
||||||
{
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
close(smb_shm_fd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!read_only && (created_new || !other_processes))
|
|
||||||
{
|
|
||||||
/* we just created a new one, or are the first opener, lets set it size */
|
|
||||||
if( sys_ftruncate(smb_shm_fd, size) <0)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_open : ftruncate failed with code %s\n",
|
|
||||||
strerror(errno)));
|
|
||||||
smb_shm_unregister_process(smb_shm_processreg_name, getpid());
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
close(smb_shm_fd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* paranoia */
|
|
||||||
if(sys_lseek(smb_shm_fd,0,SEEK_SET) == -1)
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_open : sys_lseek failed with code %s\n",
|
|
||||||
strerror(errno)));
|
|
||||||
smb_shm_unregister_process(smb_shm_processreg_name, getpid());
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
close(smb_shm_fd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
filesize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size != filesize )
|
|
||||||
{
|
|
||||||
/* the existing file has a different size and we are not the first opener.
|
|
||||||
Since another process is still using it, we will use the file size */
|
|
||||||
DEBUG(0,("WARNING smb_shm_open : filesize (%.0f) != expected \
|
|
||||||
size (%.0f), using filesize\n", (double)filesize, (double)size));
|
|
||||||
|
|
||||||
size = filesize;
|
|
||||||
}
|
|
||||||
|
|
||||||
smb_shm_header_p = (struct SmbShmHeader *)sys_mmap(NULL, size,
|
|
||||||
read_only?PROT_READ: (PROT_READ | PROT_WRITE),
|
|
||||||
MAP_FILE | MAP_SHARED, smb_shm_fd, (SMB_OFF_T)0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* WARNING, smb_shm_header_p can be different for different
|
|
||||||
* processes mapping the same file !
|
|
||||||
*/
|
|
||||||
if (smb_shm_header_p == (struct SmbShmHeader *)(-1))
|
|
||||||
{
|
|
||||||
DEBUG(0,("ERROR smb_shm_open : mmap failed with code %s\n",strerror(errno)));
|
|
||||||
smb_shm_unregister_process(smb_shm_processreg_name, getpid());
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
close(smb_shm_fd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!read_only && (created_new || !other_processes))
|
|
||||||
{
|
|
||||||
smb_shm_initialize(size);
|
|
||||||
/* Create the hash buckets for the share file entries. */
|
|
||||||
smb_shm_create_hash_table(SHMEM_HASH_SIZE);
|
|
||||||
}
|
|
||||||
else if (!smb_shm_validate_header(size) )
|
|
||||||
{
|
|
||||||
/* existing file is corrupt, samba admin should remove it by hand */
|
|
||||||
DEBUG(0,("ERROR smb_shm_open : corrupt shared mem file, remove it manually\n"));
|
|
||||||
munmap((caddr_t)smb_shm_header_p, size);
|
|
||||||
smb_shm_unregister_process(smb_shm_processreg_name, getpid());
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
close(smb_shm_fd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
smb_shm_global_unlock();
|
|
||||||
return &shmops;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#else /* HAVE_SHARED_MMAP */
|
|
||||||
int shmem_dummy_procedure(void)
|
|
||||||
{return 0;}
|
|
||||||
#endif /* HAVE_SHARED_MMAP */
|
|
||||||
@@ -1,724 +0,0 @@
|
|||||||
/*
|
|
||||||
Unix SMB/Netbios implementation.
|
|
||||||
Version 1.9.
|
|
||||||
Shared memory functions - SYSV IPC implementation
|
|
||||||
Copyright (C) Andrew Tridgell 1997-1998
|
|
||||||
|
|
||||||
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"
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_SYSV_IPC
|
|
||||||
|
|
||||||
extern int DEBUGLEVEL;
|
|
||||||
|
|
||||||
#define SHMEM_KEY ((key_t)0x280267)
|
|
||||||
#define SEMAPHORE_KEY (SHMEM_KEY+2)
|
|
||||||
|
|
||||||
#define SHM_MAGIC 0x53484100
|
|
||||||
#define SHM_VERSION 2
|
|
||||||
|
|
||||||
#ifdef SHM_R
|
|
||||||
#define IPC_PERMS ((SHM_R | SHM_W) | (SHM_R>>3) | (SHM_R>>6))
|
|
||||||
#else
|
|
||||||
#define IPC_PERMS 0644
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef SECURE_SEMAPHORES
|
|
||||||
/* secure semaphores are slow because we have to do a become_root()
|
|
||||||
on every call! */
|
|
||||||
#define SEMAPHORE_PERMS IPC_PERMS
|
|
||||||
#else
|
|
||||||
#define SEMAPHORE_PERMS 0666
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SHMEM_HASH_SIZE 13
|
|
||||||
|
|
||||||
#define MIN_SHM_SIZE 0x1000
|
|
||||||
|
|
||||||
static int shm_id;
|
|
||||||
static int sem_id;
|
|
||||||
static int shm_size;
|
|
||||||
static int hash_size;
|
|
||||||
static int global_lock_count;
|
|
||||||
|
|
||||||
struct ShmHeader {
|
|
||||||
int shm_magic;
|
|
||||||
int shm_version;
|
|
||||||
int total_size; /* in bytes */
|
|
||||||
BOOL consistent;
|
|
||||||
int first_free_off;
|
|
||||||
int userdef_off; /* a userdefined offset. can be used to store
|
|
||||||
root of tree or list */
|
|
||||||
struct { /* a cell is a range of bytes of sizeof(struct
|
|
||||||
ShmBlockDesc) size */
|
|
||||||
int cells_free;
|
|
||||||
int cells_used;
|
|
||||||
int cells_system; /* number of cells used as allocated
|
|
||||||
block descriptors */
|
|
||||||
} statistics;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define SHM_NOT_FREE_OFF (-1)
|
|
||||||
struct ShmBlockDesc
|
|
||||||
{
|
|
||||||
int next; /* offset of next block in the free list or
|
|
||||||
SHM_NOT_FREE_OFF when block in use */
|
|
||||||
int size; /* user size in BlockDescSize units */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define EOList_Addr NULL
|
|
||||||
#define EOList_Off (0)
|
|
||||||
|
|
||||||
#define CellSize sizeof(struct ShmBlockDesc)
|
|
||||||
|
|
||||||
/* HeaderSize aligned on a 8 byte boundary */
|
|
||||||
#define AlignedHeaderSize ((sizeof(struct ShmHeader)+7) & ~7)
|
|
||||||
|
|
||||||
static struct ShmHeader *shm_header_p = NULL;
|
|
||||||
|
|
||||||
static int read_only;
|
|
||||||
|
|
||||||
static BOOL sem_change(int i, int op)
|
|
||||||
{
|
|
||||||
#ifdef SECURE_SEMAPHORES
|
|
||||||
extern struct current_user current_user;
|
|
||||||
int became_root=0;
|
|
||||||
#endif
|
|
||||||
struct sembuf sb;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (read_only) return True;
|
|
||||||
|
|
||||||
#ifdef SECURE_SEMAPHORES
|
|
||||||
if (current_user.uid != 0) {
|
|
||||||
become_root(0);
|
|
||||||
became_root = 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
sb.sem_num = i;
|
|
||||||
sb.sem_op = op;
|
|
||||||
sb.sem_flg = 0;
|
|
||||||
|
|
||||||
ret = semop(sem_id, &sb, 1);
|
|
||||||
|
|
||||||
if (ret != 0) {
|
|
||||||
DEBUG(0,("ERROR: sem_change(%d,%d) failed (%s)\n",
|
|
||||||
i, op, strerror(errno)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SECURE_SEMAPHORES
|
|
||||||
if (became_root) {
|
|
||||||
unbecome_root(0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return ret == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL global_lock(void)
|
|
||||||
{
|
|
||||||
global_lock_count++;
|
|
||||||
if (global_lock_count == 1)
|
|
||||||
return sem_change(0, -1);
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL global_unlock(void)
|
|
||||||
{
|
|
||||||
global_lock_count--;
|
|
||||||
if (global_lock_count == 0)
|
|
||||||
return sem_change(0, 1);
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *shm_offset2addr(int offset)
|
|
||||||
{
|
|
||||||
if (offset == 0 )
|
|
||||||
return (void *)(0);
|
|
||||||
|
|
||||||
if (!shm_header_p)
|
|
||||||
return (void *)(0);
|
|
||||||
|
|
||||||
return (void *)((char *)shm_header_p + offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int shm_addr2offset(void *addr)
|
|
||||||
{
|
|
||||||
if (!addr)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!shm_header_p)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return (int)((char *)addr - (char *)shm_header_p);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int shm_alloc(int size)
|
|
||||||
{
|
|
||||||
unsigned num_cells ;
|
|
||||||
struct ShmBlockDesc *scanner_p;
|
|
||||||
struct ShmBlockDesc *prev_p;
|
|
||||||
struct ShmBlockDesc *new_p;
|
|
||||||
int result_offset;
|
|
||||||
|
|
||||||
|
|
||||||
if (!shm_header_p) {
|
|
||||||
/* not mapped yet */
|
|
||||||
DEBUG(0,("ERROR shm_alloc : shmem not mapped\n"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
global_lock();
|
|
||||||
|
|
||||||
if (!shm_header_p->consistent) {
|
|
||||||
DEBUG(0,("ERROR shm_alloc : shmem not consistent\n"));
|
|
||||||
global_unlock();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* calculate the number of cells */
|
|
||||||
num_cells = (size + (CellSize-1)) / CellSize;
|
|
||||||
|
|
||||||
/* set start of scan */
|
|
||||||
prev_p = (struct ShmBlockDesc *)shm_offset2addr(shm_header_p->first_free_off);
|
|
||||||
scanner_p = prev_p ;
|
|
||||||
|
|
||||||
/* scan the free list to find a matching free space */
|
|
||||||
while ((scanner_p != EOList_Addr) && (scanner_p->size < num_cells)) {
|
|
||||||
prev_p = scanner_p;
|
|
||||||
scanner_p = (struct ShmBlockDesc *)shm_offset2addr(scanner_p->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* at this point scanner point to a block header or to the end of
|
|
||||||
the list */
|
|
||||||
if (scanner_p == EOList_Addr) {
|
|
||||||
DEBUG(0,("ERROR shm_alloc : alloc of %d bytes failed\n",size));
|
|
||||||
global_unlock();
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* going to modify shared mem */
|
|
||||||
shm_header_p->consistent = False;
|
|
||||||
|
|
||||||
/* if we found a good one : scanner == the good one */
|
|
||||||
if (scanner_p->size > num_cells + 2) {
|
|
||||||
/* Make a new one */
|
|
||||||
new_p = scanner_p + 1 + num_cells;
|
|
||||||
new_p->size = scanner_p->size - (num_cells + 1);
|
|
||||||
new_p->next = scanner_p->next;
|
|
||||||
scanner_p->size = num_cells;
|
|
||||||
scanner_p->next = shm_addr2offset(new_p);
|
|
||||||
|
|
||||||
shm_header_p->statistics.cells_free -= 1;
|
|
||||||
shm_header_p->statistics.cells_system += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* take it from the free list */
|
|
||||||
if (prev_p == scanner_p) {
|
|
||||||
shm_header_p->first_free_off = scanner_p->next;
|
|
||||||
} else {
|
|
||||||
prev_p->next = scanner_p->next;
|
|
||||||
}
|
|
||||||
shm_header_p->statistics.cells_free -= scanner_p->size;
|
|
||||||
shm_header_p->statistics.cells_used += scanner_p->size;
|
|
||||||
|
|
||||||
result_offset = shm_addr2offset(&(scanner_p[1]));
|
|
||||||
scanner_p->next = SHM_NOT_FREE_OFF;
|
|
||||||
|
|
||||||
/* end modification of shared mem */
|
|
||||||
shm_header_p->consistent = True;
|
|
||||||
|
|
||||||
global_unlock();
|
|
||||||
|
|
||||||
DEBUG(6,("shm_alloc : allocated %d bytes at offset %d\n",
|
|
||||||
size,result_offset));
|
|
||||||
|
|
||||||
return result_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void shm_solve_neighbors(struct ShmBlockDesc *head_p )
|
|
||||||
{
|
|
||||||
struct ShmBlockDesc *next_p;
|
|
||||||
|
|
||||||
/* Check if head_p and head_p->next are neighbors and if so
|
|
||||||
join them */
|
|
||||||
if ( head_p == EOList_Addr ) return ;
|
|
||||||
if ( head_p->next == EOList_Off ) return ;
|
|
||||||
|
|
||||||
next_p = (struct ShmBlockDesc *)shm_offset2addr(head_p->next);
|
|
||||||
if ((head_p + head_p->size + 1) == next_p) {
|
|
||||||
head_p->size += next_p->size + 1; /* adapt size */
|
|
||||||
head_p->next = next_p->next; /* link out */
|
|
||||||
|
|
||||||
shm_header_p->statistics.cells_free += 1;
|
|
||||||
shm_header_p->statistics.cells_system -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static BOOL shm_free(int offset)
|
|
||||||
{
|
|
||||||
struct ShmBlockDesc *header_p; /* pointer to header of
|
|
||||||
block to free */
|
|
||||||
struct ShmBlockDesc *scanner_p; /* used to scan the list */
|
|
||||||
struct ShmBlockDesc *prev_p; /* holds previous in the
|
|
||||||
list */
|
|
||||||
|
|
||||||
if (!shm_header_p) {
|
|
||||||
/* not mapped yet */
|
|
||||||
DEBUG(0,("ERROR shm_free : shmem not mapped\n"));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
global_lock();
|
|
||||||
|
|
||||||
if (!shm_header_p->consistent) {
|
|
||||||
DEBUG(0,("ERROR shm_free : shmem not consistent\n"));
|
|
||||||
global_unlock();
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make pointer to header of block */
|
|
||||||
header_p = ((struct ShmBlockDesc *)shm_offset2addr(offset) - 1);
|
|
||||||
|
|
||||||
if (header_p->next != SHM_NOT_FREE_OFF) {
|
|
||||||
DEBUG(0,("ERROR shm_free : bad offset (%d)\n",offset));
|
|
||||||
global_unlock();
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find a place in the free_list to put the header in */
|
|
||||||
|
|
||||||
/* set scanner and previous pointer to start of list */
|
|
||||||
prev_p = (struct ShmBlockDesc *)
|
|
||||||
shm_offset2addr(shm_header_p->first_free_off);
|
|
||||||
scanner_p = prev_p ;
|
|
||||||
|
|
||||||
while ((scanner_p != EOList_Addr) &&
|
|
||||||
(scanner_p < header_p)) {
|
|
||||||
/* while we didn't scan past its position */
|
|
||||||
prev_p = scanner_p ;
|
|
||||||
scanner_p = (struct ShmBlockDesc *)
|
|
||||||
shm_offset2addr(scanner_p->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
shm_header_p->consistent = False;
|
|
||||||
|
|
||||||
DEBUG(6,("shm_free : freeing %d bytes at offset %d\n",
|
|
||||||
(int)(header_p->size*CellSize),(int)offset));
|
|
||||||
|
|
||||||
/* zero the area being freed - this allows us to find bugs faster */
|
|
||||||
memset(shm_offset2addr(offset), 0, header_p->size*CellSize);
|
|
||||||
|
|
||||||
if (scanner_p == prev_p) {
|
|
||||||
shm_header_p->statistics.cells_free += header_p->size;
|
|
||||||
shm_header_p->statistics.cells_used -= header_p->size;
|
|
||||||
|
|
||||||
/* we must free it at the beginning of the list */
|
|
||||||
shm_header_p->first_free_off = shm_addr2offset(header_p);
|
|
||||||
/* set the free_list_pointer to this block_header */
|
|
||||||
|
|
||||||
/* scanner is the one that was first in the list */
|
|
||||||
header_p->next = shm_addr2offset(scanner_p);
|
|
||||||
shm_solve_neighbors(header_p);
|
|
||||||
|
|
||||||
shm_header_p->consistent = True;
|
|
||||||
} else {
|
|
||||||
shm_header_p->statistics.cells_free += header_p->size;
|
|
||||||
shm_header_p->statistics.cells_used -= header_p->size;
|
|
||||||
|
|
||||||
prev_p->next = shm_addr2offset(header_p);
|
|
||||||
header_p->next = shm_addr2offset(scanner_p);
|
|
||||||
shm_solve_neighbors(header_p) ;
|
|
||||||
shm_solve_neighbors(prev_p) ;
|
|
||||||
|
|
||||||
shm_header_p->consistent = True;
|
|
||||||
}
|
|
||||||
|
|
||||||
global_unlock();
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Function to create the hash table for the share mode entries. Called
|
|
||||||
* when smb shared memory is global locked.
|
|
||||||
*/
|
|
||||||
static BOOL shm_create_hash_table(unsigned int hash_entries)
|
|
||||||
{
|
|
||||||
int size = hash_entries * sizeof(int);
|
|
||||||
|
|
||||||
global_lock();
|
|
||||||
shm_header_p->userdef_off = shm_alloc(size);
|
|
||||||
|
|
||||||
if(shm_header_p->userdef_off == 0) {
|
|
||||||
DEBUG(0,("shm_create_hash_table: Failed to create hash table of size %d\n",
|
|
||||||
size));
|
|
||||||
global_unlock();
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear hash buckets. */
|
|
||||||
memset(shm_offset2addr(shm_header_p->userdef_off), '\0', size);
|
|
||||||
global_unlock();
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static BOOL shm_validate_header(int size)
|
|
||||||
{
|
|
||||||
if(!shm_header_p) {
|
|
||||||
/* not mapped yet */
|
|
||||||
DEBUG(0,("ERROR shm_validate_header : shmem not mapped\n"));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(shm_header_p->shm_magic != SHM_MAGIC) {
|
|
||||||
DEBUG(0,("ERROR shm_validate_header : bad magic\n"));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(shm_header_p->shm_version != SHM_VERSION) {
|
|
||||||
DEBUG(0,("ERROR shm_validate_header : bad version %X\n",
|
|
||||||
shm_header_p->shm_version));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(shm_header_p->total_size != size) {
|
|
||||||
DEBUG(0,("ERROR shmem size mismatch (old = %d, new = %d)\n",
|
|
||||||
shm_header_p->total_size,size));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!shm_header_p->consistent) {
|
|
||||||
DEBUG(0,("ERROR shmem not consistent\n"));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static BOOL shm_initialize(int size)
|
|
||||||
{
|
|
||||||
struct ShmBlockDesc * first_free_block_p;
|
|
||||||
|
|
||||||
DEBUG(5,("shm_initialize : initializing shmem size %d\n",size));
|
|
||||||
|
|
||||||
if( !shm_header_p ) {
|
|
||||||
/* not mapped yet */
|
|
||||||
DEBUG(0,("ERROR shm_initialize : shmem not mapped\n"));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
shm_header_p->shm_magic = SHM_MAGIC;
|
|
||||||
shm_header_p->shm_version = SHM_VERSION;
|
|
||||||
shm_header_p->total_size = size;
|
|
||||||
shm_header_p->first_free_off = AlignedHeaderSize;
|
|
||||||
shm_header_p->userdef_off = 0;
|
|
||||||
|
|
||||||
first_free_block_p = (struct ShmBlockDesc *)
|
|
||||||
shm_offset2addr(shm_header_p->first_free_off);
|
|
||||||
first_free_block_p->next = EOList_Off;
|
|
||||||
first_free_block_p->size =
|
|
||||||
(size - (AlignedHeaderSize+CellSize))/CellSize;
|
|
||||||
shm_header_p->statistics.cells_free = first_free_block_p->size;
|
|
||||||
shm_header_p->statistics.cells_used = 0;
|
|
||||||
shm_header_p->statistics.cells_system = 1;
|
|
||||||
|
|
||||||
shm_header_p->consistent = True;
|
|
||||||
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL shm_close( void )
|
|
||||||
{
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int shm_get_userdef_off(void)
|
|
||||||
{
|
|
||||||
if (!shm_header_p)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return shm_header_p->userdef_off;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
Lock a particular hash bucket entry.
|
|
||||||
******************************************************************/
|
|
||||||
static BOOL shm_lock_hash_entry(unsigned int entry)
|
|
||||||
{
|
|
||||||
return sem_change(entry+1, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
Unlock a particular hash bucket entry.
|
|
||||||
******************************************************************/
|
|
||||||
static BOOL shm_unlock_hash_entry(unsigned int entry)
|
|
||||||
{
|
|
||||||
return sem_change(entry+1, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
Gather statistics on shared memory usage.
|
|
||||||
******************************************************************/
|
|
||||||
static BOOL shm_get_usage(int *bytes_free,
|
|
||||||
int *bytes_used,
|
|
||||||
int *bytes_overhead)
|
|
||||||
{
|
|
||||||
if(!shm_header_p) {
|
|
||||||
/* not mapped yet */
|
|
||||||
DEBUG(0,("ERROR shm_free : shmem not mapped\n"));
|
|
||||||
return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
*bytes_free = shm_header_p->statistics.cells_free * CellSize;
|
|
||||||
*bytes_used = shm_header_p->statistics.cells_used * CellSize;
|
|
||||||
*bytes_overhead = shm_header_p->statistics.cells_system * CellSize +
|
|
||||||
AlignedHeaderSize;
|
|
||||||
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
hash a number into a hash_entry
|
|
||||||
******************************************************************/
|
|
||||||
static unsigned shm_hash_size(void)
|
|
||||||
{
|
|
||||||
return hash_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static struct shmem_ops shmops = {
|
|
||||||
shm_close,
|
|
||||||
shm_alloc,
|
|
||||||
shm_free,
|
|
||||||
shm_get_userdef_off,
|
|
||||||
shm_offset2addr,
|
|
||||||
shm_addr2offset,
|
|
||||||
shm_lock_hash_entry,
|
|
||||||
shm_unlock_hash_entry,
|
|
||||||
shm_get_usage,
|
|
||||||
shm_hash_size,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*******************************************************************
|
|
||||||
open the shared memory
|
|
||||||
******************************************************************/
|
|
||||||
|
|
||||||
struct shmem_ops *sysv_shm_open(int ronly)
|
|
||||||
{
|
|
||||||
BOOL other_processes;
|
|
||||||
struct shmid_ds shm_ds;
|
|
||||||
struct semid_ds sem_ds;
|
|
||||||
union semun su;
|
|
||||||
int i;
|
|
||||||
pid_t pid;
|
|
||||||
struct passwd *root_pwd = sys_getpwuid((uid_t)0);
|
|
||||||
gid_t root_gid = root_pwd ? root_pwd->pw_gid : (gid_t)0;
|
|
||||||
|
|
||||||
read_only = ronly;
|
|
||||||
|
|
||||||
shm_size = lp_shmem_size();
|
|
||||||
|
|
||||||
DEBUG(4,("Trying sysv shmem open of size %d\n", shm_size));
|
|
||||||
|
|
||||||
/* first the semaphore */
|
|
||||||
sem_id = semget(SEMAPHORE_KEY, 0, 0);
|
|
||||||
if (sem_id == -1) {
|
|
||||||
if (read_only) return NULL;
|
|
||||||
|
|
||||||
hash_size = SHMEM_HASH_SIZE;
|
|
||||||
|
|
||||||
while (hash_size > 1) {
|
|
||||||
sem_id = semget(SEMAPHORE_KEY, hash_size+1,
|
|
||||||
IPC_CREAT|IPC_EXCL| SEMAPHORE_PERMS);
|
|
||||||
if (sem_id != -1 ||
|
|
||||||
(errno != EINVAL && errno != ENOSPC)) break;
|
|
||||||
hash_size -= 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sem_id == -1) {
|
|
||||||
DEBUG(0,("Can't create or use semaphore [1]. Error was %s\n",
|
|
||||||
strerror(errno)));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sem_id != -1) {
|
|
||||||
su.val = 1;
|
|
||||||
for (i=0;i<hash_size+1;i++) {
|
|
||||||
if (semctl(sem_id, i, SETVAL, su) != 0) {
|
|
||||||
DEBUG(1,("Failed to init semaphore %d. Error was %s\n",
|
|
||||||
i, strerror(errno)));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (shm_id == -1) {
|
|
||||||
sem_id = semget(SEMAPHORE_KEY, 0, 0);
|
|
||||||
}
|
|
||||||
if (sem_id == -1) {
|
|
||||||
DEBUG(0,("Can't create or use semaphore [2]. Error was %s\n",
|
|
||||||
strerror(errno)));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
su.buf = &sem_ds;
|
|
||||||
if (semctl(sem_id, 0, IPC_STAT, su) != 0) {
|
|
||||||
DEBUG(0,("ERROR semctl: can't IPC_STAT. Error was %s\n",
|
|
||||||
strerror(errno)));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
hash_size = sem_ds.sem_nsems-1;
|
|
||||||
|
|
||||||
if (!read_only) {
|
|
||||||
if (sem_ds.sem_perm.cuid != 0 || ((sem_ds.sem_perm.cgid != root_gid) && (sem_ds.sem_perm.cgid != 0))) {
|
|
||||||
DEBUG(0,("ERROR: root did not create the semaphore: semgid=%u, rootgid=%u\n",
|
|
||||||
(unsigned int)sem_ds.sem_perm.cgid, (unsigned int)root_gid));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (semctl(sem_id, 0, GETVAL, su) == 0 &&
|
|
||||||
!process_exists((pid=(pid_t)semctl(sem_id, 0, GETPID, su)))) {
|
|
||||||
DEBUG(0,("WARNING: clearing global IPC lock set by dead process %d\n",
|
|
||||||
(int)pid));
|
|
||||||
su.val = 1;
|
|
||||||
if (semctl(sem_id, 0, SETVAL, su) != 0) {
|
|
||||||
DEBUG(0,("ERROR: Failed to clear global lock. Error was %s\n",
|
|
||||||
strerror(errno)));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sem_ds.sem_perm.mode = SEMAPHORE_PERMS;
|
|
||||||
if (semctl(sem_id, 0, IPC_SET, su) != 0) {
|
|
||||||
DEBUG(0,("ERROR shmctl : can't IPC_SET. Error was %s\n",
|
|
||||||
strerror(errno)));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!global_lock())
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
|
|
||||||
for (i=1;i<hash_size+1;i++) {
|
|
||||||
if (semctl(sem_id, i, GETVAL, su) == 0 &&
|
|
||||||
!process_exists((pid=(pid_t)semctl(sem_id, i, GETPID, su)))) {
|
|
||||||
DEBUG(1,("WARNING: clearing IPC lock %d set by dead process %d\n",
|
|
||||||
i, (int)pid));
|
|
||||||
su.val = 1;
|
|
||||||
if (semctl(sem_id, i, SETVAL, su) != 0) {
|
|
||||||
DEBUG(0,("ERROR: Failed to clear IPC lock %d. Error was %s\n",
|
|
||||||
i, strerror(errno)));
|
|
||||||
global_unlock();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try to use an existing key. Note that
|
|
||||||
* in order to use an existing key successfully
|
|
||||||
* size must be zero else shmget returns EINVAL.
|
|
||||||
* Thanks to Veselin Terzic <vterzic@systems.DHL.COM>
|
|
||||||
* for pointing this out.
|
|
||||||
*/
|
|
||||||
|
|
||||||
shm_id = shmget(SHMEM_KEY, 0, 0);
|
|
||||||
|
|
||||||
/* if that failed then create one */
|
|
||||||
if (shm_id == -1) {
|
|
||||||
if (read_only) return NULL;
|
|
||||||
while (shm_size > MIN_SHM_SIZE) {
|
|
||||||
shm_id = shmget(SHMEM_KEY, shm_size,
|
|
||||||
IPC_CREAT | IPC_EXCL | IPC_PERMS);
|
|
||||||
if (shm_id != -1 ||
|
|
||||||
(errno != EINVAL && errno != ENOSPC)) break;
|
|
||||||
shm_size *= 0.8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shm_id == -1) {
|
|
||||||
DEBUG(0,("Can't create or use IPC area. Error was %s\n", strerror(errno)));
|
|
||||||
global_unlock();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
shm_header_p = (struct ShmHeader *)shmat(shm_id, 0,
|
|
||||||
read_only?SHM_RDONLY:0);
|
|
||||||
if ((long)shm_header_p == -1) {
|
|
||||||
DEBUG(0,("Can't attach to IPC area. Error was %s\n", strerror(errno)));
|
|
||||||
global_unlock();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* to find out if some other process is already mapping the file,
|
|
||||||
we use a registration file containing the processids of the file
|
|
||||||
mapping processes */
|
|
||||||
if (shmctl(shm_id, IPC_STAT, &shm_ds) != 0) {
|
|
||||||
DEBUG(0,("ERROR shmctl : can't IPC_STAT. Error was %s\n", strerror(errno)));
|
|
||||||
global_unlock();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!read_only) {
|
|
||||||
if (shm_ds.shm_perm.cuid != 0 || ((shm_ds.shm_perm.cgid != root_gid) && (shm_ds.shm_perm.cgid != 0))) {
|
|
||||||
DEBUG(0,("ERROR: root did not create the shmem\n"));
|
|
||||||
global_unlock();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
shm_size = shm_ds.shm_segsz;
|
|
||||||
|
|
||||||
other_processes = (shm_ds.shm_nattch > 1);
|
|
||||||
|
|
||||||
if (!read_only && !other_processes) {
|
|
||||||
memset((char *)shm_header_p, 0, shm_size);
|
|
||||||
shm_initialize(shm_size);
|
|
||||||
shm_create_hash_table(hash_size);
|
|
||||||
DEBUG(3,("Initialised IPC area of size %d\n", shm_size));
|
|
||||||
} else if (!shm_validate_header(shm_size)) {
|
|
||||||
/* existing file is corrupt, samba admin should remove
|
|
||||||
it by hand */
|
|
||||||
DEBUG(0,("ERROR shm_open : corrupt IPC area - remove it!\n"));
|
|
||||||
global_unlock();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
global_unlock();
|
|
||||||
return &shmops;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#else
|
|
||||||
int ipc_dummy_procedure(void)
|
|
||||||
{return 0;}
|
|
||||||
#endif
|
|
||||||
@@ -628,7 +628,7 @@ BOOL change_trust_account_password( char *domain, char *remote_machine_list)
|
|||||||
unsigned char old_trust_passwd_hash[16];
|
unsigned char old_trust_passwd_hash[16];
|
||||||
unsigned char new_trust_passwd_hash[16];
|
unsigned char new_trust_passwd_hash[16];
|
||||||
time_t lct;
|
time_t lct;
|
||||||
BOOL res;
|
BOOL res = False;
|
||||||
|
|
||||||
if(!get_trust_account_password( old_trust_passwd_hash, &lct)) {
|
if(!get_trust_account_password( old_trust_passwd_hash, &lct)) {
|
||||||
DEBUG(0,("change_trust_account_password: unable to read the machine \
|
DEBUG(0,("change_trust_account_password: unable to read the machine \
|
||||||
|
|||||||
@@ -94,7 +94,6 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close)
|
|||||||
{
|
{
|
||||||
SMB_DEV_T dev = fsp->fd_ptr->dev;
|
SMB_DEV_T dev = fsp->fd_ptr->dev;
|
||||||
SMB_INO_T inode = fsp->fd_ptr->inode;
|
SMB_INO_T inode = fsp->fd_ptr->inode;
|
||||||
int token;
|
|
||||||
BOOL last_reference = False;
|
BOOL last_reference = False;
|
||||||
BOOL delete_on_close = fsp->fd_ptr->delete_on_close;
|
BOOL delete_on_close = fsp->fd_ptr->delete_on_close;
|
||||||
connection_struct *conn = fsp->conn;
|
connection_struct *conn = fsp->conn;
|
||||||
@@ -109,8 +108,8 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (lp_share_modes(SNUM(conn))) {
|
if (lp_share_modes(SNUM(conn))) {
|
||||||
lock_share_entry(conn, dev, inode, &token);
|
lock_share_entry(conn, dev, inode);
|
||||||
del_share_mode(token, fsp);
|
del_share_mode(fsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
|
if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
|
||||||
@@ -122,7 +121,7 @@ static int close_normal_file(files_struct *fsp, BOOL normal_close)
|
|||||||
fsp->fd_ptr = NULL;
|
fsp->fd_ptr = NULL;
|
||||||
|
|
||||||
if (lp_share_modes(SNUM(conn)))
|
if (lp_share_modes(SNUM(conn)))
|
||||||
unlock_share_entry(conn, dev, inode, token);
|
unlock_share_entry(conn, dev, inode);
|
||||||
|
|
||||||
/* NT uses smbclose to start a print - weird */
|
/* NT uses smbclose to start a print - weird */
|
||||||
if (normal_close && fsp->print_file)
|
if (normal_close && fsp->print_file)
|
||||||
|
|||||||
@@ -26,27 +26,6 @@ extern fstring remote_machine;
|
|||||||
|
|
||||||
extern int DEBUGLEVEL;
|
extern int DEBUGLEVEL;
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
open the connections database
|
|
||||||
****************************************************************************/
|
|
||||||
TDB_CONTEXT *open_db(char *name)
|
|
||||||
{
|
|
||||||
pstring fname;
|
|
||||||
|
|
||||||
pstrcpy(fname,lp_lockdir());
|
|
||||||
trim_string(fname,"","/");
|
|
||||||
|
|
||||||
if (!directory_exist(fname,NULL)) {
|
|
||||||
mkdir(fname,0755);
|
|
||||||
}
|
|
||||||
|
|
||||||
pstrcat(fname,"/connections.tdb");
|
|
||||||
|
|
||||||
return tdb_open(fname, 0, O_RDWR | O_CREAT, 0644);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
delete a connection record
|
delete a connection record
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -56,7 +35,8 @@ BOOL yield_connection(connection_struct *conn,char *name,int max_connections)
|
|||||||
TDB_DATA kbuf;
|
TDB_DATA kbuf;
|
||||||
TDB_CONTEXT *tdb;
|
TDB_CONTEXT *tdb;
|
||||||
|
|
||||||
if (!(tdb = open_db(name))) return False;
|
tdb = tdb_open(lock_path("connections.tdb"), 0, O_RDWR | O_CREAT, 0644);
|
||||||
|
if (!tdb) return False;
|
||||||
|
|
||||||
DEBUG(3,("Yielding connection to %s\n",name));
|
DEBUG(3,("Yielding connection to %s\n",name));
|
||||||
|
|
||||||
@@ -100,7 +80,8 @@ BOOL claim_connection(connection_struct *conn,char *name,int max_connections,BOO
|
|||||||
if (max_connections <= 0)
|
if (max_connections <= 0)
|
||||||
return(True);
|
return(True);
|
||||||
|
|
||||||
if (!(tdb = open_db(name))) return False;
|
tdb = tdb_open(lock_path("connections.tdb"), 0, O_RDWR | O_CREAT, 0644);
|
||||||
|
if (!tdb) return False;
|
||||||
|
|
||||||
DEBUG(5,("claiming %s %d\n",name,max_connections));
|
DEBUG(5,("claiming %s %d\n",name,max_connections));
|
||||||
|
|
||||||
|
|||||||
@@ -213,11 +213,11 @@ ssize_t write_file(files_struct *fsp, char *data, SMB_OFF_T pos, size_t n)
|
|||||||
int num_share_modes = 0;
|
int num_share_modes = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (lock_share_entry(fsp->conn, dev, inode, &token) == False) {
|
if (lock_share_entry(fsp->conn, dev, inode) == False) {
|
||||||
DEBUG(0,("write_file: failed to lock share mode entry for file %s.\n", fsp->fsp_name ));
|
DEBUG(0,("write_file: failed to lock share mode entry for file %s.\n", fsp->fsp_name ));
|
||||||
}
|
}
|
||||||
|
|
||||||
num_share_modes = get_share_modes(fsp->conn, token, dev, inode, &share_list);
|
num_share_modes = get_share_modes(fsp->conn, dev, inode, &share_list);
|
||||||
|
|
||||||
for(i = 0; i < num_share_modes; i++) {
|
for(i = 0; i < num_share_modes; i++) {
|
||||||
share_mode_entry *share_entry = &share_list[i];
|
share_mode_entry *share_entry = &share_list[i];
|
||||||
@@ -268,7 +268,7 @@ ssize_t write_file(files_struct *fsp, char *data, SMB_OFF_T pos, size_t n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
free((char *)share_list);
|
free((char *)share_list);
|
||||||
unlock_share_entry(fsp->conn, dev, inode, token);
|
unlock_share_entry(fsp->conn, dev, inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Paranoia check... */
|
/* Paranoia check... */
|
||||||
|
|||||||
@@ -602,7 +602,7 @@ static void truncate_unless_locked(files_struct *fsp, connection_struct *conn, i
|
|||||||
have the share entry locked. Unlock it before closing. */
|
have the share entry locked. Unlock it before closing. */
|
||||||
if (*share_locked && lp_share_modes(SNUM(conn)))
|
if (*share_locked && lp_share_modes(SNUM(conn)))
|
||||||
unlock_share_entry( conn, fsp->fd_ptr->dev,
|
unlock_share_entry( conn, fsp->fd_ptr->dev,
|
||||||
fsp->fd_ptr->inode, token);
|
fsp->fd_ptr->inode);
|
||||||
close_file(fsp,False);
|
close_file(fsp,False);
|
||||||
/* Share mode no longer locked. */
|
/* Share mode no longer locked. */
|
||||||
*share_locked = False;
|
*share_locked = False;
|
||||||
@@ -858,9 +858,9 @@ void open_file_shared(files_struct *fsp,connection_struct *conn,char *fname,int
|
|||||||
{
|
{
|
||||||
dev = sbuf.st_dev;
|
dev = sbuf.st_dev;
|
||||||
inode = sbuf.st_ino;
|
inode = sbuf.st_ino;
|
||||||
lock_share_entry(conn, dev, inode, &token);
|
lock_share_entry(conn, dev, inode);
|
||||||
share_locked = True;
|
share_locked = True;
|
||||||
num_share_modes = get_share_modes(conn, token, dev, inode, &old_shares);
|
num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -896,7 +896,7 @@ void open_file_shared(files_struct *fsp,connection_struct *conn,char *fname,int
|
|||||||
dev = %x, inode = %.0f\n", share_entry->op_type, fname, (unsigned int)dev, (double)inode));
|
dev = %x, inode = %.0f\n", share_entry->op_type, fname, (unsigned int)dev, (double)inode));
|
||||||
|
|
||||||
/* Oplock break.... */
|
/* Oplock break.... */
|
||||||
unlock_share_entry(conn, dev, inode, token);
|
unlock_share_entry(conn, dev, inode);
|
||||||
if(request_oplock_break(share_entry, dev, inode) == False)
|
if(request_oplock_break(share_entry, dev, inode) == False)
|
||||||
{
|
{
|
||||||
free((char *)old_shares);
|
free((char *)old_shares);
|
||||||
@@ -909,7 +909,7 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
|
|||||||
unix_ERR_code = ERRbadshare;
|
unix_ERR_code = ERRbadshare;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lock_share_entry(conn, dev, inode, &token);
|
lock_share_entry(conn, dev, inode);
|
||||||
broke_oplock = True;
|
broke_oplock = True;
|
||||||
all_current_opens_are_level_II = False;
|
all_current_opens_are_level_II = False;
|
||||||
break;
|
break;
|
||||||
@@ -922,7 +922,7 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
|
|||||||
if(check_share_mode(share_entry, deny_mode, fname, fcbopen, &flags) == False)
|
if(check_share_mode(share_entry, deny_mode, fname, fcbopen, &flags) == False)
|
||||||
{
|
{
|
||||||
free((char *)old_shares);
|
free((char *)old_shares);
|
||||||
unlock_share_entry(conn, dev, inode, token);
|
unlock_share_entry(conn, dev, inode);
|
||||||
errno = EACCES;
|
errno = EACCES;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -932,7 +932,7 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
|
|||||||
if(broke_oplock)
|
if(broke_oplock)
|
||||||
{
|
{
|
||||||
free((char *)old_shares);
|
free((char *)old_shares);
|
||||||
num_share_modes = get_share_modes(conn, token, dev, inode, &old_shares);
|
num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
|
||||||
oplock_contention_count++;
|
oplock_contention_count++;
|
||||||
}
|
}
|
||||||
} while(broke_oplock);
|
} while(broke_oplock);
|
||||||
@@ -973,7 +973,7 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
|
|||||||
/* We created the file - thus we must now lock the share entry before creating it. */
|
/* We created the file - thus we must now lock the share entry before creating it. */
|
||||||
dev = fsp->fd_ptr->dev;
|
dev = fsp->fd_ptr->dev;
|
||||||
inode = fsp->fd_ptr->inode;
|
inode = fsp->fd_ptr->inode;
|
||||||
lock_share_entry(conn, dev, inode, &token);
|
lock_share_entry(conn, dev, inode);
|
||||||
share_locked = True;
|
share_locked = True;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1028,7 +1028,7 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
|
|||||||
oplock_request = 0;
|
oplock_request = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_share_mode(token, fsp, port, oplock_request);
|
set_share_mode(fsp, port, oplock_request);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags2&O_TRUNC) && file_existed)
|
if ((flags2&O_TRUNC) && file_existed)
|
||||||
@@ -1036,7 +1036,7 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (share_locked && lp_share_modes(SNUM(conn)))
|
if (share_locked && lp_share_modes(SNUM(conn)))
|
||||||
unlock_share_entry( conn, dev, inode, token);
|
unlock_share_entry( conn, dev, inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -1224,7 +1224,6 @@ BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op)
|
|||||||
share_mode_entry *old_shares = 0;
|
share_mode_entry *old_shares = 0;
|
||||||
int num_share_modes;
|
int num_share_modes;
|
||||||
SMB_STRUCT_STAT sbuf;
|
SMB_STRUCT_STAT sbuf;
|
||||||
int token;
|
|
||||||
pid_t pid = getpid();
|
pid_t pid = getpid();
|
||||||
SMB_DEV_T dev;
|
SMB_DEV_T dev;
|
||||||
SMB_INO_T inode;
|
SMB_INO_T inode;
|
||||||
@@ -1237,8 +1236,8 @@ BOOL check_file_sharing(connection_struct *conn,char *fname, BOOL rename_op)
|
|||||||
dev = sbuf.st_dev;
|
dev = sbuf.st_dev;
|
||||||
inode = sbuf.st_ino;
|
inode = sbuf.st_ino;
|
||||||
|
|
||||||
lock_share_entry(conn, dev, inode, &token);
|
lock_share_entry(conn, dev, inode);
|
||||||
num_share_modes = get_share_modes(conn, token, dev, inode, &old_shares);
|
num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if the share modes will give us access.
|
* Check if the share modes will give us access.
|
||||||
@@ -1308,7 +1307,7 @@ batch oplocked file %s, dev = %x, inode = %.0f\n", fname, (unsigned int)dev, (do
|
|||||||
dev = %x, inode = %.0f\n", share_entry->op_type, fname, (unsigned int)dev, (double)inode));
|
dev = %x, inode = %.0f\n", share_entry->op_type, fname, (unsigned int)dev, (double)inode));
|
||||||
|
|
||||||
/* Oplock break.... */
|
/* Oplock break.... */
|
||||||
unlock_share_entry(conn, dev, inode, token);
|
unlock_share_entry(conn, dev, inode);
|
||||||
if(request_oplock_break(share_entry, dev, inode) == False)
|
if(request_oplock_break(share_entry, dev, inode) == False)
|
||||||
{
|
{
|
||||||
free((char *)old_shares);
|
free((char *)old_shares);
|
||||||
@@ -1318,7 +1317,7 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
|
|||||||
|
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
lock_share_entry(conn, dev, inode, &token);
|
lock_share_entry(conn, dev, inode);
|
||||||
broke_oplock = True;
|
broke_oplock = True;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1345,7 +1344,7 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
|
|||||||
if(broke_oplock)
|
if(broke_oplock)
|
||||||
{
|
{
|
||||||
free((char *)old_shares);
|
free((char *)old_shares);
|
||||||
num_share_modes = get_share_modes(conn, token, dev, inode, &old_shares);
|
num_share_modes = get_share_modes(conn, dev, inode, &old_shares);
|
||||||
}
|
}
|
||||||
} while(broke_oplock);
|
} while(broke_oplock);
|
||||||
}
|
}
|
||||||
@@ -1364,7 +1363,7 @@ dev = %x, inode = %.0f\n", old_shares[i].op_type, fname, (unsigned int)dev, (dou
|
|||||||
|
|
||||||
free_and_exit:
|
free_and_exit:
|
||||||
|
|
||||||
unlock_share_entry(conn, dev, inode, token);
|
unlock_share_entry(conn, dev, inode);
|
||||||
if(old_shares != NULL)
|
if(old_shares != NULL)
|
||||||
free((char *)old_shares);
|
free((char *)old_shares);
|
||||||
return(ret);
|
return(ret);
|
||||||
|
|||||||
@@ -406,13 +406,12 @@ static void downgrade_file_oplock(files_struct *fsp)
|
|||||||
|
|
||||||
BOOL remove_oplock(files_struct *fsp)
|
BOOL remove_oplock(files_struct *fsp)
|
||||||
{
|
{
|
||||||
int token;
|
|
||||||
SMB_DEV_T dev = fsp->fd_ptr->dev;
|
SMB_DEV_T dev = fsp->fd_ptr->dev;
|
||||||
SMB_INO_T inode = fsp->fd_ptr->inode;
|
SMB_INO_T inode = fsp->fd_ptr->inode;
|
||||||
BOOL ret = True;
|
BOOL ret = True;
|
||||||
|
|
||||||
/* Remove the oplock flag from the sharemode. */
|
/* Remove the oplock flag from the sharemode. */
|
||||||
if (lock_share_entry(fsp->conn, dev, inode, &token) == False) {
|
if (lock_share_entry(fsp->conn, dev, inode) == False) {
|
||||||
DEBUG(0,("remove_oplock: failed to lock share entry for file %s\n",
|
DEBUG(0,("remove_oplock: failed to lock share entry for file %s\n",
|
||||||
fsp->fsp_name ));
|
fsp->fsp_name ));
|
||||||
ret = False;
|
ret = False;
|
||||||
@@ -424,7 +423,7 @@ BOOL remove_oplock(files_struct *fsp)
|
|||||||
* Deal with a reply when a break-to-none was sent.
|
* Deal with a reply when a break-to-none was sent.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(remove_share_oplock(token, fsp)==False) {
|
if(remove_share_oplock(fsp)==False) {
|
||||||
DEBUG(0,("remove_oplock: failed to remove share oplock for file %s fnum %d, \
|
DEBUG(0,("remove_oplock: failed to remove share oplock for file %s fnum %d, \
|
||||||
dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)inode));
|
dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)inode));
|
||||||
ret = False;
|
ret = False;
|
||||||
@@ -438,7 +437,7 @@ dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)
|
|||||||
* Deal with a reply when a break-to-level II was sent.
|
* Deal with a reply when a break-to-level II was sent.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(downgrade_share_oplock(token, fsp)==False) {
|
if(downgrade_share_oplock(fsp)==False) {
|
||||||
DEBUG(0,("remove_oplock: failed to downgrade share oplock for file %s fnum %d, \
|
DEBUG(0,("remove_oplock: failed to downgrade share oplock for file %s fnum %d, \
|
||||||
dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)inode));
|
dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)inode));
|
||||||
ret = False;
|
ret = False;
|
||||||
@@ -447,7 +446,7 @@ dev = %x, inode = %.0f\n", fsp->fsp_name, fsp->fnum, (unsigned int)dev, (double)
|
|||||||
downgrade_file_oplock(fsp);
|
downgrade_file_oplock(fsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock_share_entry(fsp->conn, dev, inode, token);
|
unlock_share_entry(fsp->conn, dev, inode);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -792,18 +791,18 @@ BOOL oplock_break_level2(files_struct *fsp, BOOL local_request, int token)
|
|||||||
* the existing lock on the shared memory area.
|
* the existing lock on the shared memory area.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if(!local_request && lock_share_entry(fsp->conn, dev, inode, &token) == False) {
|
if(!local_request && lock_share_entry(fsp->conn, dev, inode) == False) {
|
||||||
DEBUG(0,("oplock_break_level2: unable to lock share entry for file %s\n", fsp->fsp_name ));
|
DEBUG(0,("oplock_break_level2: unable to lock share entry for file %s\n", fsp->fsp_name ));
|
||||||
} else {
|
} else {
|
||||||
got_lock = True;
|
got_lock = True;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(remove_share_oplock(token, fsp)==False) {
|
if(remove_share_oplock(fsp)==False) {
|
||||||
DEBUG(0,("oplock_break_level2: unable to remove level II oplock for file %s\n", fsp->fsp_name ));
|
DEBUG(0,("oplock_break_level2: unable to remove level II oplock for file %s\n", fsp->fsp_name ));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!local_request && got_lock)
|
if (!local_request && got_lock)
|
||||||
unlock_share_entry(fsp->conn, dev, inode, token);
|
unlock_share_entry(fsp->conn, dev, inode);
|
||||||
|
|
||||||
fsp->oplock_type = NO_OPLOCK;
|
fsp->oplock_type = NO_OPLOCK;
|
||||||
level_II_oplocks_open--;
|
level_II_oplocks_open--;
|
||||||
|
|||||||
@@ -1800,7 +1800,6 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
|
|||||||
|
|
||||||
if(delete_on_close && !GET_DELETE_ON_CLOSE_FLAG(fsp->share_mode))
|
if(delete_on_close && !GET_DELETE_ON_CLOSE_FLAG(fsp->share_mode))
|
||||||
{
|
{
|
||||||
int token;
|
|
||||||
int i;
|
int i;
|
||||||
files_struct *iterate_fsp;
|
files_struct *iterate_fsp;
|
||||||
SMB_DEV_T dev = fsp->fd_ptr->dev;
|
SMB_DEV_T dev = fsp->fd_ptr->dev;
|
||||||
@@ -1808,7 +1807,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
|
|||||||
int num_share_modes;
|
int num_share_modes;
|
||||||
share_mode_entry *current_shares = NULL;
|
share_mode_entry *current_shares = NULL;
|
||||||
|
|
||||||
if(lock_share_entry(fsp->conn, dev, inode, &token) == False)
|
if(lock_share_entry(fsp->conn, dev, inode) == False)
|
||||||
return(ERROR(ERRDOS,ERRnoaccess));
|
return(ERROR(ERRDOS,ERRnoaccess));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1818,7 +1817,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
|
|||||||
* file at this point.
|
* file at this point.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
num_share_modes = get_share_modes(conn, token, dev, inode, ¤t_shares);
|
num_share_modes = get_share_modes(conn, dev, inode, ¤t_shares);
|
||||||
for(i = 0; i < num_share_modes; i++)
|
for(i = 0; i < num_share_modes; i++)
|
||||||
{
|
{
|
||||||
if(!GET_ALLOW_SHARE_DELETE(current_shares[i].share_mode))
|
if(!GET_ALLOW_SHARE_DELETE(current_shares[i].share_mode))
|
||||||
@@ -1830,7 +1829,7 @@ file %s as a share exists that was not opened with FILE_DELETE access.\n",
|
|||||||
* Release the lock.
|
* Release the lock.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unlock_share_entry(fsp->conn, dev, inode, token);
|
unlock_share_entry(fsp->conn, dev, inode);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* current_shares was malloced by get_share_modes - free it here.
|
* current_shares was malloced by get_share_modes - free it here.
|
||||||
@@ -1875,7 +1874,7 @@ dev = %x, inode = %.0f from %x to %x\n",
|
|||||||
iterate_fsp->fnum, iterate_fsp->fsp_name, (unsigned int)dev,
|
iterate_fsp->fnum, iterate_fsp->fsp_name, (unsigned int)dev,
|
||||||
(double)inode, iterate_fsp->share_mode, new_share_mode ));
|
(double)inode, iterate_fsp->share_mode, new_share_mode ));
|
||||||
|
|
||||||
if(modify_share_mode(token, iterate_fsp, new_share_mode, iterate_fsp->oplock_type)==False)
|
if(modify_share_mode(iterate_fsp, new_share_mode, iterate_fsp->oplock_type)==False)
|
||||||
DEBUG(0,("call_trans2setfilepathinfo: failed to change delete on close for fnum %d, \
|
DEBUG(0,("call_trans2setfilepathinfo: failed to change delete on close for fnum %d, \
|
||||||
dev = %x, inode = %.0f\n", iterate_fsp->fnum, (unsigned int)dev, (double)inode));
|
dev = %x, inode = %.0f\n", iterate_fsp->fnum, (unsigned int)dev, (double)inode));
|
||||||
}
|
}
|
||||||
@@ -1887,7 +1886,7 @@ dev = %x, inode = %.0f\n", iterate_fsp->fnum, (unsigned int)dev, (double)inode))
|
|||||||
*/
|
*/
|
||||||
fsp->fd_ptr->delete_on_close = delete_on_close;
|
fsp->fd_ptr->delete_on_close = delete_on_close;
|
||||||
|
|
||||||
unlock_share_entry(fsp->conn, dev, inode, token);
|
unlock_share_entry(fsp->conn, dev, inode);
|
||||||
|
|
||||||
DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, file %s\n",
|
DEBUG(10, ("call_trans2setfilepathinfo: %s delete on close flag for fnum = %d, file %s\n",
|
||||||
delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
|
delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
|
||||||
|
|||||||
@@ -75,6 +75,26 @@ static char *memdup(char *d, int size)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* a byte range locking function - return 0 on success
|
||||||
|
this functions locks/unlocks 1 byte at the specified offset */
|
||||||
|
static int tdb_brlock(TDB_CONTEXT *tdb, tdb_off offset, int set)
|
||||||
|
{
|
||||||
|
#if !NOLOCK
|
||||||
|
struct flock fl;
|
||||||
|
|
||||||
|
fl.l_type = set?F_WRLCK:F_UNLCK;
|
||||||
|
fl.l_whence = SEEK_SET;
|
||||||
|
fl.l_start = offset;
|
||||||
|
fl.l_len = 1;
|
||||||
|
fl.l_pid = 0;
|
||||||
|
|
||||||
|
if (fcntl(tdb->fd, F_SETLKW, &fl) != 0) return -1;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* the hash algorithm - turn a key into an integer
|
/* the hash algorithm - turn a key into an integer
|
||||||
This is based on the hash agorithm from gdbm */
|
This is based on the hash agorithm from gdbm */
|
||||||
static unsigned tdb_hash(TDB_DATA *key)
|
static unsigned tdb_hash(TDB_DATA *key)
|
||||||
@@ -991,42 +1011,25 @@ int tdb_close(TDB_CONTEXT *tdb)
|
|||||||
/* lock the database. If we already have it locked then don't do anything */
|
/* lock the database. If we already have it locked then don't do anything */
|
||||||
int tdb_writelock(TDB_CONTEXT *tdb)
|
int tdb_writelock(TDB_CONTEXT *tdb)
|
||||||
{
|
{
|
||||||
#if !NOLOCK
|
return tdb_brlock(tdb, 0, 1);
|
||||||
struct flock fl;
|
|
||||||
|
|
||||||
if (tdb->write_locked) return 0;
|
|
||||||
|
|
||||||
fl.l_type = F_WRLCK;
|
|
||||||
fl.l_whence = SEEK_SET;
|
|
||||||
fl.l_start = 0;
|
|
||||||
fl.l_len = 1;
|
|
||||||
fl.l_pid = 0;
|
|
||||||
|
|
||||||
if (fcntl(tdb->fd, F_SETLKW, &fl) != 0) return -1;
|
|
||||||
|
|
||||||
tdb->write_locked = 1;
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unlock the database. If we don't have it locked then return -1 */
|
/* unlock the database. */
|
||||||
int tdb_writeunlock(TDB_CONTEXT *tdb)
|
int tdb_writeunlock(TDB_CONTEXT *tdb)
|
||||||
{
|
{
|
||||||
#if !NOLOCK
|
return tdb_brlock(tdb, 0, 0);
|
||||||
struct flock fl;
|
|
||||||
|
|
||||||
if (!tdb->write_locked) return -1;
|
|
||||||
|
|
||||||
fl.l_type = F_UNLCK;
|
|
||||||
fl.l_whence = SEEK_SET;
|
|
||||||
fl.l_start = 0;
|
|
||||||
fl.l_len = 1;
|
|
||||||
fl.l_pid = 0;
|
|
||||||
|
|
||||||
if (fcntl(tdb->fd, F_SETLK, &fl) != 0) return -1;
|
|
||||||
|
|
||||||
tdb->write_locked = 0;
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* lock one hash chain. This is meant to be used to reduce locking
|
||||||
|
contention - it cannot guarantee how many records will be locked */
|
||||||
|
int tdb_lockchain(TDB_CONTEXT *tdb, TDB_DATA key)
|
||||||
|
{
|
||||||
|
return tdb_brlock(tdb, tdb_hash_top(tdb, tdb_hash(&key)), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* unlock one hash chain */
|
||||||
|
int tdb_unlockchain(TDB_CONTEXT *tdb, TDB_DATA key)
|
||||||
|
{
|
||||||
|
return tdb_brlock(tdb, tdb_hash_top(tdb, tdb_hash(&key)), 0);
|
||||||
|
}
|
||||||
|
|||||||
@@ -165,7 +165,6 @@ static int traverse_fn1(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf)
|
|||||||
static pid_t last_pid;
|
static pid_t last_pid;
|
||||||
struct session_record *ptr;
|
struct session_record *ptr;
|
||||||
struct connections_data crec;
|
struct connections_data crec;
|
||||||
static int doneone;
|
|
||||||
|
|
||||||
memcpy(&crec, dbuf.dptr, sizeof(crec));
|
memcpy(&crec, dbuf.dptr, sizeof(crec));
|
||||||
|
|
||||||
@@ -176,13 +175,6 @@ static int traverse_fn1(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (brief) {
|
if (brief) {
|
||||||
if (!doneone) {
|
|
||||||
printf("\nSamba version %s\n",VERSION);
|
|
||||||
printf("PID Username Machine Time logged in\n");
|
|
||||||
printf("-------------------------------------------------------------------\n");
|
|
||||||
doneone = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr=srecs;
|
ptr=srecs;
|
||||||
while (ptr!=NULL) {
|
while (ptr!=NULL) {
|
||||||
if ((ptr->pid==crec.pid)&&(strncmp(ptr->machine,crec.machine,30)==0)) {
|
if ((ptr->pid==crec.pid)&&(strncmp(ptr->machine,crec.machine,30)==0)) {
|
||||||
@@ -203,13 +195,6 @@ static int traverse_fn1(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf)
|
|||||||
srecs=ptr;
|
srecs=ptr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!doneone) {
|
|
||||||
printf("\nSamba version %s\n",VERSION);
|
|
||||||
printf("Service uid gid pid machine\n");
|
|
||||||
printf("----------------------------------------------\n");
|
|
||||||
doneone = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ucrit_addPid(crec.pid);
|
Ucrit_addPid(crec.pid);
|
||||||
if (processes_only) {
|
if (processes_only) {
|
||||||
if (last_pid != crec.pid)
|
if (last_pid != crec.pid)
|
||||||
@@ -292,19 +277,13 @@ static int traverse_fn1(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf)
|
|||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
printf("using configfile = %s\n", servicesf);
|
printf("using configfile = %s\n", servicesf);
|
||||||
printf("lockdir = %s\n", *lp_lockdir() ? lp_lockdir() : "NULL");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (profile_only) {
|
if (profile_only) {
|
||||||
return profile_dump();
|
return profile_dump();
|
||||||
}
|
}
|
||||||
|
|
||||||
pstrcpy(fname,lp_lockdir());
|
tdb = tdb_open(lock_path("connections.tdb"), 0, O_RDONLY, 0);
|
||||||
standard_sub_basic(fname);
|
|
||||||
trim_string(fname,"","/");
|
|
||||||
pstrcat(fname,"/connections.tdb");
|
|
||||||
|
|
||||||
tdb = tdb_open(fname, 0, O_RDONLY, 0);
|
|
||||||
if (!tdb) {
|
if (!tdb) {
|
||||||
printf("Couldn't open status file %s\n",fname);
|
printf("Couldn't open status file %s\n",fname);
|
||||||
if (!lp_status(-1))
|
if (!lp_status(-1))
|
||||||
@@ -316,6 +295,14 @@ static int traverse_fn1(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf)
|
|||||||
|
|
||||||
if (locks_only) goto locks;
|
if (locks_only) goto locks;
|
||||||
|
|
||||||
|
printf("\nSamba version %s\n",VERSION);
|
||||||
|
if (brief) {
|
||||||
|
printf("PID Username Machine Time logged in\n");
|
||||||
|
printf("-------------------------------------------------------------------\n");
|
||||||
|
} else {
|
||||||
|
printf("Service uid gid pid machine\n");
|
||||||
|
printf("----------------------------------------------\n");
|
||||||
|
}
|
||||||
tdb_traverse(tdb, traverse_fn1);
|
tdb_traverse(tdb, traverse_fn1);
|
||||||
|
|
||||||
locks:
|
locks:
|
||||||
@@ -347,8 +334,6 @@ static int traverse_fn1(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf)
|
|||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
share_status(stdout);
|
|
||||||
|
|
||||||
locking_end();
|
locking_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,6 @@ static int traverse_fn3(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf)
|
|||||||
/* show the current server status */
|
/* show the current server status */
|
||||||
void status_page(void)
|
void status_page(void)
|
||||||
{
|
{
|
||||||
pstring fname;
|
|
||||||
char *v;
|
char *v;
|
||||||
int autorefresh=0;
|
int autorefresh=0;
|
||||||
int refresh_interval=30;
|
int refresh_interval=30;
|
||||||
@@ -173,12 +172,7 @@ void status_page(void)
|
|||||||
refresh_interval = atoi(v);
|
refresh_interval = atoi(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
pstrcpy(fname,lp_lockdir());
|
tdb = tdb_open(lock_path("connections.tdb"), 0, O_RDONLY, 0);
|
||||||
standard_sub_basic(fname);
|
|
||||||
trim_string(fname,"","/");
|
|
||||||
pstrcat(fname,"/connections.tdb");
|
|
||||||
|
|
||||||
tdb = tdb_open(fname, 0, O_RDONLY, 0);
|
|
||||||
if (tdb) tdb_traverse(tdb, traverse_fn1);
|
if (tdb) tdb_traverse(tdb, traverse_fn1);
|
||||||
|
|
||||||
printf("<H2>Server Status</H2>\n");
|
printf("<H2>Server Status</H2>\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user