summaryrefslogtreecommitdiff
path: root/source/locking
diff options
context:
space:
mode:
authorSamba Release Account <samba-bugs@samba.org>1997-05-20 00:32:51 +0000
committerSamba Release Account <samba-bugs@samba.org>1997-05-20 00:32:51 +0000
commit2a1711eaaf08bb6776770cd3c96b3010f431a677 (patch)
tree99caacb23ae749ca87abc2ba0642bde29fcec224 /source/locking
parentc0bae276a99211c0c7149a5e4e801706870074fd (diff)
downloadsamba-2a1711eaaf08bb6776770cd3c96b3010f431a677.tar.gz
dir.c: Fixed double slash issue.
includes.h: Changed to ifdef FAST_SHARE_MODES. ipc.c: Changed lp_workgroup() to myworkgroup. loadparm.c: Added new shared mem parameters. Added Luke's fix. locking.c: Rewrite to do share modes better (both fast and slow modes). nameannounce.c: Changed lp_workgroup() to myworkgroup. Added Luke's fix. nameconf.c: Changed lp_workgroup() to myworkgroup. namedbname.c: Improved debug. namedbserver.c: Changed lp_workgroup() to myworkgroup. namedbsubnet.c: Added Luke's fix - rewritten somewhat. namedbwork.c: Changed lp_workgroup() to myworkgroup. nameelect.c: Added Luke's fix - rewritten somewhat. nameresp.c: Stoped shadowing global. nameserv.c: Added Luke's fix - Improved debug. nameservreply.c: Improved debug. namework.c: Changed lp_workgroup() to myworkgroup. nmbd.c: Added Luke's fix - Changed lp_workgroup() to myworkgroup. pipes.c: Changed lp_workgroup() to myworkgroup. proto.h: Added Luke's fix, added smb_shm_ proto's. reply.c: Changed lp_workgroup() to myworkgroup. server.c: Rewrite to do share modes better (both fast and slow modes). shmem.c: Rewrite to do share modes better (both fast and slow modes). smb.h: Rewrite to do share modes better (both fast and slow modes). status.c: Rewrite to do share modes better (both fast and slow modes). trans2.c: Fixed double slash issue. util.c: Tidied up, created myworkgroup. Jeremy Allison (jallison@whistle.com).
Diffstat (limited to 'source/locking')
-rw-r--r--source/locking/locking.c1323
-rw-r--r--source/locking/shmem.c261
2 files changed, 1184 insertions, 400 deletions
diff --git a/source/locking/locking.c b/source/locking/locking.c
index 7c23e5b3cab..e63e347a262 100644
--- a/source/locking/locking.c
+++ b/source/locking/locking.c
@@ -22,6 +22,9 @@
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.
*/
#include "includes.h"
@@ -29,9 +32,6 @@ extern int DEBUGLEVEL;
extern connection_struct Connections[];
extern files_struct Files[];
-pstring share_del_pending="";
-
-
/****************************************************************************
utility function called to see if a file region is locked
****************************************************************************/
@@ -100,7 +100,7 @@ BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *
return True; /* Did unlock */
}
-#if FAST_SHARE_MODES
+#ifdef FAST_SHARE_MODES
/*******************************************************************
initialize the shared memory for share_mode management
******************************************************************/
@@ -114,7 +114,7 @@ BOOL start_share_mode_mgmt(void)
trim_string(shmem_file_name,"","/");
if (!*shmem_file_name) return(False);
strcat(shmem_file_name, "/SHARE_MEM_FILE");
- return smb_shm_open(shmem_file_name, SHMEM_SIZE);
+ return smb_shm_open(shmem_file_name, lp_shmem_size());
}
@@ -126,459 +126,1118 @@ BOOL stop_share_mode_mgmt(void)
return smb_shm_close();
}
-#else
-
-/* SHARE MODE LOCKS USING SLOW DESCRIPTION FILES */
-
-/*******************************************************************
- name a share file
- ******************************************************************/
-static BOOL share_name(int cnum,struct stat *st,char *name)
-{
- strcpy(name,lp_lockdir());
- standard_sub(cnum,name);
- trim_string(name,"","/");
- if (!*name) return(False);
- name += strlen(name);
-
- sprintf(name,"/share.%d.%d",(int)st->st_dev,(int)st->st_ino);
- return(True);
-}
-
/*******************************************************************
- use the fnum to get the share file name
+ lock a hash bucket entry in shared memory for share_mode management
******************************************************************/
-static BOOL share_name_fnum(int fnum,char *name)
+BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *ptok)
{
- struct stat st;
- if (fstat(Files[fnum].fd_ptr->fd,&st) != 0) return(False);
- return(share_name(Files[fnum].cnum,&st,name));
+ return smb_shm_lock_hash_entry(HASH_ENTRY(dev, inode));
}
-#endif
-
/*******************************************************************
- get the share mode of a file using the fnum
+ unlock a hash bucket entry in shared memory for share_mode management
******************************************************************/
-int get_share_mode_by_fnum(int cnum,int fnum,int *pid)
+BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token token)
{
- struct stat sbuf;
- if (fstat(Files[fnum].fd_ptr->fd,&sbuf) == -1) return(0);
- return(get_share_mode(cnum,&sbuf,pid));
+ return smb_shm_unlock_hash_entry(HASH_ENTRY(dev, inode));
}
/*******************************************************************
- get the share mode of a file using the files name
- ******************************************************************/
-int get_share_mode_byname(int cnum,char *fname,int *pid)
-{
- struct stat sbuf;
- if (stat(fname,&sbuf) == -1) return(0);
- return(get_share_mode(cnum,&sbuf,pid));
-}
-
-
-/*******************************************************************
-get the share mode of a file
+get all share mode entries in shared memory for a dev/inode pair.
********************************************************************/
-int get_share_mode(int cnum,struct stat *sbuf,int *pid)
+int get_share_modes(int cnum, share_lock_token token, uint32 dev, uint32 inode,
+ min_share_mode_entry **old_shares)
{
-#if FAST_SHARE_MODES
- share_mode_record *scanner_p;
- share_mode_record *prev_p;
- int ret;
+ smb_shm_offset_t *mode_array;
+ unsigned int hash_entry = HASH_ENTRY(dev, inode);
+ share_mode_record *file_scanner_p;
+ share_mode_record *file_prev_p;
+ share_mode_entry *entry_scanner_p;
+ share_mode_entry *entry_prev_p;
+ int num_entries;
+ int num_entries_copied;
BOOL found = False;
+ min_share_mode_entry *share_array = (min_share_mode_entry *)0;
- *pid = 0;
+ *old_shares = 0;
- if(!smb_shm_lock()) return (0);
+ if(hash_entry > lp_shmem_hash_size() )
+ {
+ DEBUG(0,
+ ("PANIC ERROR : get_share_modes (FAST_SHARE_MODES): hash_entry %d too large \
+(max = %d)\n",
+ hash_entry, lp_shmem_hash_size() ));
+ abort();
+ }
- scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off());
- prev_p = scanner_p;
- while(scanner_p)
+ mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
+
+ if(mode_array[hash_entry] == NULL_OFFSET)
{
- if( (scanner_p->st_dev == sbuf->st_dev) && (scanner_p->st_ino == sbuf->st_ino) )
+ DEBUG(5,("get_share_modes (FAST_SHARE_MODES): hash bucket %d empty\n", hash_entry));
+ return 0;
+ }
+
+ file_scanner_p = (share_mode_record *)smb_shm_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
{
- prev_p = scanner_p ;
- scanner_p = (share_mode_record *)smb_shm_offset2addr(scanner_p->next_offset);
+ file_prev_p = file_scanner_p ;
+ file_scanner_p = (share_mode_record *)smb_shm_offset2addr(
+ file_scanner_p->next_offset);
}
}
if(!found)
{
- smb_shm_unlock();
+ DEBUG(5,("get_share_modes (FAST_SHARE_MODES): no entry for \
+file dev = %d, ino = %d in hash_bucket %d\n", dev, inode, hash_entry));
return (0);
}
- if(scanner_p->locking_version != LOCKING_VERSION)
+ if(file_scanner_p->locking_version != LOCKING_VERSION)
{
- DEBUG(2,("Deleting old share mode record due to old locking version %d",scanner_p->locking_version));
- if(prev_p == scanner_p)
- smb_shm_set_userdef_off(scanner_p->next_offset);
+ DEBUG(0,("ERROR:get_share_modes (FAST_SHARE_MODES): Deleting old share mode \
+record due to old locking version %d for file dev = %d, inode = %d in hash \
+bucket %d",file_scanner_p->locking_version, dev, inode, hash_entry));
+ if(file_prev_p == file_scanner_p)
+ mode_array[hash_entry] = file_scanner_p->next_offset;
else
- prev_p->next_offset = scanner_p->next_offset;
- smb_shm_free(smb_shm_addr2offset(scanner_p));
- *pid = 0;
-
- smb_shm_unlock();
+ file_prev_p->next_offset = file_scanner_p->next_offset;
+ smb_shm_free(smb_shm_addr2offset(file_scanner_p));
return (0);
}
-
- *pid = scanner_p->pid;
- ret = scanner_p->share_mode;
- if (*pid && !process_exists(*pid))
+ /* Allocate the old_shares array */
+ num_entries = file_scanner_p->num_share_mode_entries;
+ if(num_entries)
{
- ret = 0;
- *pid = 0;
+ *old_shares = share_array = (min_share_mode_entry *)
+ malloc(num_entries * sizeof(min_share_mode_entry));
+ if(*old_shares == 0)
+ {
+ DEBUG(0,("get_share_modes (FAST_SHARE_MODES): malloc fail !\n"));
+ return 0;
+ }
}
+
+ num_entries_copied = 0;
- if (! *pid)
+ entry_scanner_p = (share_mode_entry*)smb_shm_offset2addr(
+ file_scanner_p->share_mode_entries);
+ entry_prev_p = entry_scanner_p;
+ while(entry_scanner_p)
{
- if(prev_p == scanner_p)
- smb_shm_set_userdef_off(scanner_p->next_offset);
- else
- prev_p->next_offset = scanner_p->next_offset;
- smb_shm_free(smb_shm_addr2offset(scanner_p));
+ int pid = entry_scanner_p->pid;
+
+ if (pid && !process_exists(pid))
+ {
+ /* Delete this share mode entry */
+ 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 = (share_mode_entry*)smb_shm_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 = (share_mode_entry*)
+ smb_shm_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 (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
+for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
+ dev, inode, hash_entry));
+ abort();
+ }
+
+ DEBUG(0,("get_share_modes (FAST_SHARE_MODES): process %d no longer exists and \
+it left a share mode entry with mode 0x%X for file dev = %d, ino = %d in hash \
+bucket (number of entries now = %d)\n",
+ pid, entry_scanner_p->share_mode, dev, inode, hash_entry,
+ file_scanner_p->num_share_mode_entries));
+
+ smb_shm_free(smb_shm_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->pid;
+ share_array[num_entries_copied].share_mode = entry_scanner_p->share_mode;
+ memcpy(&share_array[num_entries_copied].time, &entry_scanner_p->time,
+ sizeof(struct timeval));
+ num_entries_copied++;
+ DEBUG(5,("get_share_modes (FAST_SHARE_MODES): Read share mode \
+record mode 0x%X pid=%d\n", entry_scanner_p->share_mode, entry_scanner_p->pid));
+ entry_prev_p = entry_scanner_p;
+ entry_scanner_p = (share_mode_entry *)
+ smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
+ }
}
- if (*pid)
- DEBUG(5,("Read share mode record mode 0x%X pid=%d\n",ret,*pid));
+ /* If no valid share mode entries were found then this record shouldn't exist ! */
+ if(num_entries_copied == 0)
+ {
+ DEBUG(0,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \
+hash bucket %d has a share mode record but no entries - deleting\n",
+ dev, inode, hash_entry));
+ 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;
+ smb_shm_free(smb_shm_addr2offset(file_scanner_p));
+ }
- if(!smb_shm_unlock()) return (0);
-
- return(ret);
-
-#else
- pstring fname;
- int fd2;
- char buf[20];
- int ret;
- struct timeval t;
+ DEBUG(5,("get_share_modes (FAST_SHARE_MODES): file with dev %d, inode %d in \
+hash bucket %d returning %d entries\n", dev, inode, hash_entry,
+ num_entries_copied));
+
+ return(num_entries_copied);
+}
- *pid = 0;
+/*******************************************************************
+del the share mode of a file.
+********************************************************************/
+void del_share_mode(share_lock_token token, int fnum)
+{
+ uint32 dev, inode;
+ smb_shm_offset_t *mode_array;
+ unsigned int hash_entry;
+ share_mode_record *file_scanner_p;
+ share_mode_record *file_prev_p;
+ share_mode_entry *entry_scanner_p;
+ share_mode_entry *entry_prev_p;
+ BOOL found = False;
+ int pid = getpid();
- if (!share_name(cnum,sbuf,fname)) return(0);
+ dev = Files[fnum].fd_ptr->dev;
+ inode = Files[fnum].fd_ptr->inode;
- fd2 = open(fname,O_RDONLY,0);
- if (fd2 < 0) return(0);
+ hash_entry = HASH_ENTRY(dev, inode);
- if (read(fd2,buf,20) != 20) {
- DEBUG(2,("Failed to read share file %s\n",fname));
- close(fd2);
- unlink(fname);
- return(0);
+ if(hash_entry > lp_shmem_hash_size() )
+ {
+ DEBUG(0,
+ ("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): hash_entry %d too large \
+(max = %d)\n",
+ hash_entry, lp_shmem_hash_size() ));
+ abort();
}
- close(fd2);
- t.tv_sec = IVAL(buf,4);
- t.tv_usec = IVAL(buf,8);
- ret = IVAL(buf,12);
- *pid = IVAL(buf,16);
+ mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
+
+ if(mode_array[hash_entry] == NULL_OFFSET)
+ {
+ DEBUG(0,("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): hash bucket %d empty\n",
+ hash_entry));
+ abort();
+ }
- if (IVAL(buf,0) != LOCKING_VERSION) {
- if (!unlink(fname)) DEBUG(2,("Deleted old locking file %s",fname));
- *pid = 0;
- return(0);
- }
+ file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]);
+ file_prev_p = file_scanner_p;
- if (*pid && !process_exists(*pid)) {
- ret=0;
- *pid = 0;
+ 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 *)
+ smb_shm_offset2addr(file_scanner_p->next_offset);
+ }
+ }
+
+ if(!found)
+ {
+ DEBUG(0,("ERROR:del_share_mode (FAST_SHARE_MODES): no entry found for dev %d, \
+inode %d in hash bucket %d\n", dev, inode, hash_entry));
+ return;
+ }
+
+ if(file_scanner_p->locking_version != LOCKING_VERSION)
+ {
+ DEBUG(0,("ERROR: del_share_modes (FAST_SHARE_MODES): Deleting old share mode \
+record due to old locking version %d for file dev %d, inode %d hash bucket %d\n",
+ file_scanner_p->locking_version, dev, inode, hash_entry ));
+ 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;
+ smb_shm_free(smb_shm_addr2offset(file_scanner_p));
+ return;
}
- if (! *pid) unlink(fname); /* XXXXX race, race */
+ found = False;
+ entry_scanner_p = (share_mode_entry*)smb_shm_offset2addr(
+ file_scanner_p->share_mode_entries);
+ entry_prev_p = entry_scanner_p;
+ while(entry_scanner_p)
+ {
+ if( (pid == entry_scanner_p->pid) &&
+ (memcmp(&entry_scanner_p->time,
+ &Files[fnum].open_time,sizeof(struct timeval)) == 0) )
+ {
+ found = True;
+ break;
+ }
+ else
+ {
+ entry_prev_p = entry_scanner_p;
+ entry_scanner_p = (share_mode_entry *)
+ smb_shm_offset2addr(entry_scanner_p->next_share_mode_entry);
+ }
+ }
- if (*pid)
- DEBUG(5,("Read share file %s mode 0x%X pid=%d\n",fname,ret,*pid));
+ if (found)
+ {
+ /* Decrement the number of entries in the record. */
+ file_scanner_p->num_share_mode_entries -= 1;
+
+ DEBUG(2,("del_share_modes (FAST_SHARE_MODES): \
+Deleting share mode entry dev = %d, inode = %d in hash bucket %d (num entries now = %d)\n",
+ dev, inode, hash_entry, file_scanner_p->num_share_mode_entries));
+ 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;
+ smb_shm_free(smb_shm_addr2offset(entry_scanner_p));
+
+ /* PARANOIA TEST */
+ if(file_scanner_p->num_share_mode_entries < 0)
+ {
+ DEBUG(0,("PANIC ERROR:del_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
+for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
+ dev, inode, hash_entry));
+ abort();
+ }
- return(ret);
-#endif
+ /* 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 (FAST_SHARE_MODES): num entries = 0, deleting share_mode \
+record dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
+ 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;
+ smb_shm_free(smb_shm_addr2offset(file_scanner_p));
+ }
+ }
+ else
+ {
+ DEBUG(0,("ERROR: del_share_modes (FAST_SHARE_MODES): No share mode record found \
+dev = %d, inode = %d in hash bucket %d\n", dev, inode, hash_entry));
+ }
}
-
/*******************************************************************
-del the share mode of a file, if we set it last
+set the share mode of a file. Return False on fail, True on success.
********************************************************************/
-void del_share_mode(int fnum)
+BOOL set_share_mode(share_lock_token token, int fnum)
{
-#if FAST_SHARE_MODES
- struct stat st;
- struct timeval t;
- int pid=0;
- BOOL del = False;
- share_mode_record *scanner_p;
- share_mode_record *prev_p;
+ files_struct *fs_p = &Files[fnum];
+ int32 dev, inode;
+ smb_shm_offset_t *mode_array;
+ unsigned int hash_entry;
+ share_mode_record *file_scanner_p;
+ share_mode_record *file_prev_p;
+ share_mode_entry *new_entry_p;
+ smb_shm_offset_t new_entry_offset;
BOOL found = False;
- t.tv_sec = t.tv_usec = 0;
-
- if (fstat(Files[fnum].fd_ptr->fd,&st) != 0) return;
-
- if (!smb_shm_lock()) return;
+ dev = fs_p->fd_ptr->dev;
+ inode = fs_p->fd_ptr->inode;
+
+ hash_entry = HASH_ENTRY(dev, inode);
+ if(hash_entry > lp_shmem_hash_size() )
+ {
+ DEBUG(0,
+ ("PANIC ERROR:set_share_mode (FAST_SHARE_MODES): hash_entry %d too large \
+(max = %d)\n",
+ hash_entry, lp_shmem_hash_size() ));
+ abort();
+ }
+
+ mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off());
+
+ file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[hash_entry]);
+ file_prev_p = file_scanner_p;
- scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off());
- prev_p = scanner_p;
- while(scanner_p)
+ while(file_scanner_p)
{
- if( (scanner_p->st_dev == st.st_dev) && (scanner_p->st_ino == st.st_ino) )
+ if( (file_scanner_p->st_dev == dev) && (file_scanner_p->st_ino == inode) )
{
- found = True;
- break;
+ found = True;
+ break;
}
else
{
- prev_p = scanner_p ;
- scanner_p = (share_mode_record *)smb_shm_offset2addr(scanner_p->next_offset);
+ file_prev_p = file_scanner_p ;
+ file_scanner_p = (share_mode_record *)
+ smb_shm_offset2addr(file_scanner_p->next_offset);
}
}
-
+
if(!found)
{
- smb_shm_unlock();
- return;
+ /* We must create a share_mode_record */
+ share_mode_record *new_mode_p = NULL;
+ smb_shm_offset_t new_offset = smb_shm_alloc( sizeof(share_mode_record) +
+ strlen(fs_p->name) + 1);
+ if(new_offset == NULL_OFFSET)
+ {
+ DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): smb_shm_alloc fail !\n"));
+ return False;
+ }
+ new_mode_p = smb_shm_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 = NULL_OFFSET;
+ strcpy(new_mode_p->file_name, fs_p->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 (FAST_SHARE_MODES): Created share record for %s (dev %d \
+inode %d in hash bucket %d\n", fs_p->name, dev, inode, hash_entry));
+ }
+
+ /* Now create the share mode entry */
+ new_entry_offset = smb_shm_alloc( sizeof(share_mode_entry));
+ if(new_entry_offset == NULL_OFFSET)
+ {
+ smb_shm_offset_t delete_offset = mode_array[hash_entry];
+ DEBUG(0,("ERROR:set_share_mode (FAST_SHARE_MODES): smb_shm_alloc fail 1!\n"));
+ /* Unlink the damaged record */
+ mode_array[hash_entry] = file_scanner_p->next_offset;
+ /* And delete it */
+ smb_shm_free( delete_offset );
+ return False;
}
-
- t.tv_sec = scanner_p->time.tv_sec;
- t.tv_usec = scanner_p->time.tv_usec;
- pid = scanner_p->pid;
-
- if( (scanner_p->locking_version != LOCKING_VERSION) || !pid || !process_exists(pid))
- del = True;
- if (!del && (memcmp(&t,&Files[fnum].open_time,sizeof(t)) == 0)
- && pid==(int)getpid())
- del = True;
+ new_entry_p = smb_shm_offset2addr(new_entry_offset);
- if (del)
+ new_entry_p->pid = getpid();
+ new_entry_p->share_mode = fs_p->share_mode;
+ memcpy( (char *)&new_entry_p->time, (char *)&fs_p->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(2,("Deleting share mode record\n"));
- if(prev_p == scanner_p)
- smb_shm_set_userdef_off(scanner_p->next_offset);
- else
- prev_p->next_offset = scanner_p->next_offset;
- smb_shm_free(smb_shm_addr2offset(scanner_p));
-
+ DEBUG(0,("PANIC ERROR:set_share_mode (FAST_SHARE_MODES): num_share_mode_entries < 0 (%d) \
+for dev = %d, ino = %d, hashbucket %d\n", file_scanner_p->num_share_mode_entries,
+ dev, inode, hash_entry));
+ abort();
}
- smb_shm_unlock();
- return;
+ /* Increment the share_mode_entries counter */
+ file_scanner_p->num_share_mode_entries += 1;
+
+ DEBUG(3,("set_share_mode (FAST_SHARE_MODES): Created share entry for %s with mode \
+0x%X pid=%d (num_entries now = %d)\n",fs_p->name, fs_p->share_mode, new_entry_p->pid,
+ file_scanner_p->num_share_mode_entries));
+
+ return(True);
+}
+
+#else /* FAST_SHARE_MODES */
+
+/* SHARE MODE LOCKS USING SLOW DESCRIPTION FILES */
-#else
+/*******************************************************************
+ name a share file
+ ******************************************************************/
+static BOOL share_name(int cnum, uint32 dev, uint32 inode, char *name)
+{
+ strcpy(name,lp_lockdir());
+ standard_sub(cnum,name);
+ trim_string(name,"","/");
+ if (!*name) return(False);
+ name += strlen(name);
+
+ sprintf(name,"/share.%u.%u",dev,inode);
+ return(True);
+}
+
+/*******************************************************************
+ lock a share mode file.
+ ******************************************************************/
+BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *ptok)
+{
pstring fname;
- int fd2;
- char buf[20];
- struct timeval t;
- int pid=0;
- BOOL del = False;
-
- t.tv_sec = t.tv_usec = 0;
- if (!share_name_fnum(fnum,fname)) return;
-
- fd2 = open(fname,O_RDONLY,0);
- if (fd2 < 0) return;
- if (read(fd2,buf,20) != 20)
- del = True;
- close(fd2);
-
- if (!del) {
- t.tv_sec = IVAL(buf,4);
- t.tv_usec = IVAL(buf,8);
- pid = IVAL(buf,16);
- }
-
- if (!del)
- if (IVAL(buf,0) != LOCKING_VERSION || !pid || !process_exists(pid))
- del = True;
-
- if (!del && (memcmp(&t,&Files[fnum].open_time,sizeof(t)) == 0) && (pid==(int)getpid()))
- del = True;
-
- if (del) {
- if (!unlink(fname))
- DEBUG(2,("Deleted share file %s\n",fname));
- else {
- DEBUG(3,("Pending delete share file %s\n",fname));
- if (*share_del_pending) DEBUG(0,("Share del clash!\n"));
- strcpy(share_del_pending,fname);
+ int fd;
+
+ *ptok = (share_lock_token)-1;
+
+ if(!share_name(cnum, dev, inode, fname))
+ return False;
+
+ {
+ int old_umask;
+ unbecome_user();
+ old_umask = umask(0);
+#ifdef SECURE_SHARE_MODES
+ fd = (share_lock_token)open(fname,O_RDWR|O_CREAT,0600);
+#else /* SECURE_SHARE_MODES */
+ fd = (share_lock_token)open(fname,O_RDWR|O_CREAT,0644);
+#endif /* SECURE_SHARE_MODES */
+ umask(old_umask);
+ if(!become_user(cnum,Connections[cnum].vuid))
+ {
+ DEBUG(0,("lock_share_entry: Can't become connected user!\n"));
+ close(fd);
+ return False;
+ }
+ /* We need to change directory back to the connection root. */
+ if (ChDir(Connections[cnum].connectpath) != 0)
+ {
+ DEBUG(0,("lock_share_entry: Can't change directory to %s (%s)\n",
+ Connections[cnum].connectpath, strerror(errno)));
+ close(fd);
+ return False;
}
}
-#endif
+
+ /* At this point we have an open fd to the share mode file.
+ Lock the first byte exclusively to signify a lock. */
+ if(fcntl_lock(fd, F_SETLKW, 0, 1, F_WRLCK) == False)
+ {
+ DEBUG(0,("ERROR lock_share_entry: fcntl_lock failed with %s\n",
+ strerror(errno)));
+ close(fd);
+ return False;
+ }
+
+ *ptok = (share_lock_token)fd;
+ return True;
}
-
/*******************************************************************
-set the share mode of a file
+ unlock a share mode file.
+ ******************************************************************/
+BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token token)
+{
+ int fd = (int)token;
+ int ret = True;
+
+ /* token is the fd of the open share mode file. */
+ /* Unlock the first byte. */
+ if(fcntl_lock(fd, F_SETLKW, 0, 1, F_UNLCK) == False)
+ {
+ DEBUG(0,("ERROR unlock_share_entry: fcntl_lock failed with %s\n",
+ strerror(errno)));
+ ret = False;
+ }
+
+ close((int)token);
+ return ret;
+}
+
+/*******************************************************************
+Force a share file to be deleted.
********************************************************************/
-BOOL set_share_mode(int fnum,int mode)
+
+static int delete_share_file( int cnum, char *fname )
{
-#if FAST_SHARE_MODES
- int pid = (int)getpid();
- struct stat st;
- smb_shm_offset_t new_off;
- share_mode_record *new_p;
+ unbecome_user();
+ if(unlink(fname) != 0)
+ {
+ DEBUG(0,("delete_share_file: Can't delete share file %s (%s)\n",
+ fname, strerror(errno)));
+ }
+
+ DEBUG(5,("delete_share_file: Deleted share file %s\n", fname));
+
+ if(!become_user(cnum,Connections[cnum].vuid))
+ {
+ DEBUG(0,("delete_share_file: Can't become connected user!\n"));
+ return -1;
+ }
+ /* We need to change directory back to the connection root. */
+ if (ChDir(Connections[cnum].connectpath) != 0)
+ {
+ DEBUG(0,("delete_share_file: Can't change directory to %s (%s)\n",
+ Connections[cnum].connectpath, strerror(errno)));
+ return -1;
+ }
+ return 0;
+}
+
+/*******************************************************************
+Read a share file into a buffer.
+********************************************************************/
+
+static int read_share_file(int cnum, int fd, char *fname, char **out, BOOL *p_new_file)
+{
+ struct stat sb;
+ char *buf;
+ int size;
+
+ *out = 0;
+ *p_new_file = False;
+
+ if(fstat(fd, &sb) != 0)
+ {
+ DEBUG(0,("ERROR: read_share_file: Failed to do stat on share file %s (%s)\n",
+ fname, strerror(errno)));
+ return -1;
+ }
+
+ if(sb.st_size == 0)
+ {
+ *p_new_file = True;
+ return 0;
+ }
+
+ /* Allocate space for the file */
+ if((buf = (char *)malloc(sb.st_size)) == NULL)
+ {
+ DEBUG(0,("read_share_file: malloc for file size %d fail !\n", sb.st_size));
+ return -1;
+ }
+ if(lseek(fd, 0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: read_share_file: Failed to reset position to 0 \
+for share file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return -1;
+ }
- if (fstat(Files[fnum].fd_ptr->fd,&st) != 0) return(False);
+ if (read(fd,buf,sb.st_size) != sb.st_size)
+ {
+ DEBUG(0,("ERROR: read_share_file: Failed to read share file %s (%s)\n",
+ fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return -1;
+ }
- if (!smb_shm_lock()) return (False);
- new_off = smb_shm_alloc(sizeof(share_mode_record) + strlen(Files[fnum].name) );
- if (new_off == NULL_OFFSET) return (False);
- new_p = (share_mode_record *)smb_shm_offset2addr(new_off);
- new_p->locking_version = LOCKING_VERSION;
- new_p->share_mode = mode;
- new_p->time.tv_sec = Files[fnum].open_time.tv_sec;
- new_p->time.tv_usec = Files[fnum].open_time.tv_usec;
- new_p->pid = pid;
- new_p->st_dev = st.st_dev;
- new_p->st_ino = st.st_ino;
- strcpy(new_p->file_name,Files[fnum].name);
- new_p->next_offset = smb_shm_get_userdef_off();
- smb_shm_set_userdef_off(new_off);
-
-
- DEBUG(3,("Created share record for %s with mode 0x%X pid=%d\n",Files[fnum].name,mode,pid));
-
- if (!smb_shm_unlock()) return (False);
- return(True);
+ if (IVAL(buf,0) != LOCKING_VERSION) {
+ DEBUG(0,("ERROR: read_share_file: share file %s has incorrect \
+locking version (was %d, should be %d).\n",fname, IVAL(buf,0), LOCKING_VERSION));
+ if(buf)
+ free(buf);
+ delete_share_file(cnum, fname);
+ return -1;
+ }
+
+ /* Sanity check for file contents */
+ size = sb.st_size;
+ size -= 10; /* Remove the header */
+
+ /* Remove the filename component. */
+ size -= SVAL(buf, 8);
+
+ /* The remaining size must be a multiple of 16 - error if not. */
+ if((size % 16) != 0)
+ {
+ DEBUG(0,("ERROR: read_share_file: share file %s is an incorrect length - \
+deleting it.\n", fname));
+ if(buf)
+ free(buf);
+ delete_share_file(cnum, fname);
+ return -1;
+ }
-#else
+ *out = buf;
+ return 0;
+}
+
+/*******************************************************************
+get all share mode entries in a share file for a dev/inode pair.
+********************************************************************/
+int get_share_modes(int cnum, share_lock_token token, uint32 dev, uint32 inode,
+ min_share_mode_entry **old_shares)
+{
+ int fd = (int)token;
pstring fname;
- int fd2;
- char buf[20];
- int pid = (int)getpid();
+ int i;
+ int num_entries;
+ int num_entries_copied;
+ int newsize;
+ min_share_mode_entry *share_array;
+ char *buf = 0;
+ char *base = 0;
+ BOOL new_file;
+
+ *old_shares = 0;
+
+ /* Read the share file header - this is of the form:
+ 0 - locking version.
+ 4 - number of share mode entries.
+ 8 - 2 byte name length
+ [n bytes] file name (zero terminated).
- if (!share_name_fnum(fnum,fname)) return(False);
+ Followed by <n> share mode entries of the form :
+ 0 - tv_sec
+ 4 - tv_usec
+ 8 - share_mode
+ 12 - pid
+
+ */
+
+ share_name(cnum, dev, inode, fname);
+
+ if(read_share_file( cnum, fd, fname, &buf, &new_file) != 0)
{
- int old_umask = umask(0);
- fd2 = open(fname,O_WRONLY|O_CREAT|O_TRUNC,0644);
- umask(old_umask);
+ DEBUG(0,("ERROR: get_share_modes: Failed to read share file %s\n",
+ fname));
+ return 0;
}
- if (fd2 < 0) {
- DEBUG(2,("Failed to create share file %s\n",fname));
- return(False);
+
+ if(new_file == True)
+ return 0;
+
+ num_entries = IVAL(buf,4);
+
+ DEBUG(5,("get_share_modes: share file %s has %d share mode entries.\n",
+ fname, num_entries));
+
+ /* PARANOIA TEST */
+ if(num_entries < 0)
+ {
+ DEBUG(0,("PANIC ERROR:get_share_mode: num_share_mode_entries < 0 (%d) \
+for share file %d\n", num_entries, fname));
+ abort();
}
- SIVAL(buf,0,LOCKING_VERSION);
- SIVAL(buf,4,Files[fnum].open_time.tv_sec);
- SIVAL(buf,8,Files[fnum].open_time.tv_usec);
- SIVAL(buf,12,mode);
- SIVAL(buf,16,pid);
+ if(num_entries)
+ {
+ *old_shares = share_array = (min_share_mode_entry *)
+ malloc(num_entries * sizeof(min_share_mode_entry));
+ if(*old_shares == 0)
+ {
+ DEBUG(0,("get_share_modes: malloc fail !\n"));
+ return 0;
+ }
+ }
+ else
+ {
+ /* No entries - just delete the file. */
+ DEBUG(0,("get_share_modes: share file %s has no share mode entries - deleting.\n",
+ fname));
+ if(buf)
+ free(buf);
+ delete_share_file(cnum, fname);
+ return 0;
+ }
- if (write(fd2,buf,20) != 20) {
- DEBUG(2,("Failed to write share file %s\n",fname));
- close(fd2);
- unlink(fname);
- return(False);
+ num_entries_copied = 0;
+ base = buf + 10 + SVAL(buf,8);
+
+ for( i = 0; i < num_entries; i++)
+ {
+ int pid;
+ char *p = base + (i*16);
+
+ pid = IVAL(p,12);
+
+ if(!process_exists(pid))
+ {
+ DEBUG(0,("get_share_modes: process %d no longer exists and \
+it left a share mode entry with mode 0x%X in share file %s\n",
+ pid, IVAL(p,8), fname));
+ continue;
+ }
+ share_array[num_entries_copied].time.tv_sec = IVAL(p,0);
+ share_array[num_entries_copied].time.tv_usec = IVAL(p,4);
+ share_array[num_entries_copied].share_mode = IVAL(p,8);
+ share_array[num_entries_copied].pid = pid;
+
+ num_entries_copied++;
}
- write(fd2,Files[fnum].name,strlen(Files[fnum].name)+1);
+ if(num_entries_copied == 0)
+ {
+ /* Delete the whole file. */
+ DEBUG(0,("get_share_modes: share file %s had no valid entries - deleting it !\n",
+ fname));
+ if(*old_shares)
+ free((char *)old_shares);
+ if(buf)
+ free(buf);
+ delete_share_file(cnum, fname);
+ return 0;
+ }
- close(fd2);
+ /* If we deleted some entries we need to re-write the whole number of
+ share mode entries back into the file. */
- DEBUG(3,("Created share file %s with mode 0x%X pid=%d\n",fname,mode,pid));
+ if(num_entries_copied != num_entries)
+ {
+ if(lseek(fd, 0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: get_share_modes: lseek failed to reset to \
+position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
+ if(*old_shares)
+ free((char *)old_shares);
+ if(buf)
+ free(buf);
+ return 0;
+ }
- return(True);
-#endif
+ SIVAL(buf, 4, num_entries_copied);
+ for( i = 0; i < num_entries_copied; i++)
+ {
+ char *p = base + (i*16);
+
+ SIVAL(p,12,share_array[i].pid);
+ SIVAL(p,8,share_array[i].share_mode);
+ SIVAL(p,0,share_array[i].time.tv_sec);
+ SIVAL(p,4,share_array[i].time.tv_usec);
+ }
+
+ newsize = (base - buf) + (16*num_entries_copied);
+ if(write(fd, buf, newsize) != newsize)
+ {
+ DEBUG(0,("ERROR: get_share_modes: failed to re-write share \
+mode file %s (%s)\n", fname, strerror(errno)));
+ if(*old_shares)
+ free((char *)old_shares);
+ if(buf)
+ free(buf);
+ return 0;
+ }
+ /* Now truncate the file at this point. */
+ if(ftruncate(fd, newsize)!= 0)
+ {
+ DEBUG(0,("ERROR: get_share_modes: failed to ftruncate share \
+mode file %s to size %d (%s)\n", fname, newsize, strerror(errno)));
+ if(*old_shares)
+ free((char *)old_shares);
+ if(buf)
+ free(buf);
+ return 0;
+ }
+ }
+
+ if(buf)
+ free(buf);
+
+ DEBUG(5,("get_share_modes: Read share file %s returning %d entries\n",fname,
+ num_entries_copied));
+
+ return num_entries_copied;
}
-
/*******************************************************************
-cleanup any stale share files
+del a share mode from a share mode file.
********************************************************************/
-void clean_share_modes(void)
+void del_share_mode(share_lock_token token, int fnum)
{
-#ifdef USE_SHMEM
- share_mode_record *scanner_p;
- share_mode_record *prev_p;
+ pstring fname;
+ int fd = (int)token;
+ char *buf = 0;
+ char *base = 0;
+ int num_entries;
+ int newsize;
+ int i;
+ files_struct *fs_p = &Files[fnum];
int pid;
-
- if (!smb_shm_lock()) return;
-
- scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off());
- prev_p = scanner_p;
- while(scanner_p)
+ BOOL deleted = False;
+ BOOL new_file;
+
+ share_name(fs_p->cnum, fs_p->fd_ptr->dev,
+ fs_p->fd_ptr->inode, fname);
+
+ if(read_share_file( fs_p->cnum, fd, fname, &buf, &new_file) != 0)
{
- pid = scanner_p->pid;
-
- if( (scanner_p->locking_version != LOCKING_VERSION) || !process_exists(pid))
- {
- DEBUG(2,("Deleting stale share mode record"));
- if(prev_p == scanner_p)
- {
- smb_shm_set_userdef_off(scanner_p->next_offset);
- smb_shm_free(smb_shm_addr2offset(scanner_p));
- scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off());
- prev_p = scanner_p;
- }
- else
- {
- prev_p->next_offset = scanner_p->next_offset;
- smb_shm_free(smb_shm_addr2offset(scanner_p));
- scanner_p = (share_mode_record *)smb_shm_offset2addr(prev_p->next_offset);
- }
-
- }
- else
- {
- prev_p = scanner_p ;
- scanner_p = (share_mode_record *)smb_shm_offset2addr(scanner_p->next_offset);
- }
+ DEBUG(0,("ERROR: del_share_mode: Failed to read share file %s\n",
+ fname));
+ return;
}
-
- smb_shm_unlock();
- return;
-
-#else
- char *lockdir = lp_lockdir();
- void *dir;
- char *s;
+ if(new_file == True)
+ {
+ DEBUG(0,("ERROR:del_share_mode: share file %s is new (size zero), deleting it.\n",
+ fname));
+ delete_share_file(fs_p->cnum, fname);
+ return;
+ }
- if (!*lockdir) return;
+ num_entries = IVAL(buf,4);
- dir = opendir(lockdir);
- if (!dir) return;
+ DEBUG(5,("del_share_mode: share file %s has %d share mode entries.\n",
+ fname, num_entries));
- while ((s=readdirname(dir))) {
- char buf[20];
- int pid;
- int fd;
- pstring lname;
- int dev,inode;
+ /* PARANOIA TEST */
+ if(num_entries < 0)
+ {
+ DEBUG(0,("PANIC ERROR:del_share_mode: num_share_mode_entries < 0 (%d) \
+for share file %d\n", num_entries, fname));
+ abort();
+ }
- if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue;
+ if(num_entries == 0)
+ {
+ /* No entries - just delete the file. */
+ DEBUG(0,("del_share_mode: share file %s has no share mode entries - deleting.\n",
+ fname));
+ if(buf)
+ free(buf);
+ delete_share_file(fs_p->cnum, fname);
+ return;
+ }
- strcpy(lname,lp_lockdir());
- trim_string(lname,NULL,"/");
- strcat(lname,"/");
- strcat(lname,s);
+ pid = getpid();
- fd = open(lname,O_RDONLY,0);
- if (fd < 0) continue;
+ /* Go through the entries looking for the particular one
+ we have set - delete it.
+ */
- if (read(fd,buf,20) != 20) {
- close(fd);
- if (!unlink(lname))
- printf("Deleted corrupt share file %s\n",s);
+ base = buf + 10 + SVAL(buf,8);
+
+ for(i = 0; i < num_entries; i++)
+ {
+ char *p = base + (i*16);
+
+ if((IVAL(p,0) != fs_p->open_time.tv_sec) || (IVAL(p,4) != fs_p->open_time.tv_usec) ||
+ (IVAL(p,8) != fs_p->share_mode) || (IVAL(p,12) != pid))
continue;
+
+ DEBUG(5,("del_share_mode: deleting entry number %d (of %d) from the share file %s\n",
+ i, num_entries, fname));
+
+ /* Remove this entry. */
+ if(i != num_entries - 1)
+ memcpy(p, p + 16, (num_entries - i - 1)*16);
+
+ deleted = True;
+ break;
+ }
+
+ if(!deleted)
+ {
+ DEBUG(0,("del_share_mode: entry not found in share file %s\n", fname));
+ if(buf)
+ free(buf);
+ return;
+ }
+
+ num_entries--;
+ SIVAL(buf,4, num_entries);
+
+ if(num_entries == 0)
+ {
+ /* Deleted the last entry - remove the file. */
+ DEBUG(5,("del_share_mode: removed last entry in share file - deleting share file %s\n",
+ fname));
+ if(buf)
+ free(buf);
+ delete_share_file(fs_p->cnum,fname);
+ return;
+ }
+
+ /* Re-write the file - and truncate it at the correct point. */
+ if(lseek(fd, 0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: del_share_mode: lseek failed to reset to \
+position 0 for share mode file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return;
}
- close(fd);
- pid = IVAL(buf,16);
+ newsize = (base - buf) + (16*num_entries);
+ if(write(fd, buf, newsize) != newsize)
+ {
+ DEBUG(0,("ERROR: del_share_mode: failed to re-write share \
+mode file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return;
+ }
+ /* Now truncate the file at this point. */
+ if(ftruncate(fd, newsize) != 0)
+ {
+ DEBUG(0,("ERROR: del_share_mode: failed to ftruncate share \
+mode file %s to size %d (%s)\n", fname, newsize, strerror(errno)));
+ if(buf)
+ free(buf);
+ return;
+ }
+}
+
+/*******************************************************************
+set the share mode of a file
+********************************************************************/
+BOOL set_share_mode(share_lock_token token,int fnum)
+{
+ files_struct *fs_p = &Files[fnum];
+ pstring fname;
+ int fd = (int)token;
+ int pid = (int)getpid();
+ struct stat sb;
+ char *buf;
+ int num_entries;
+ int header_size;
+ char *p;
+
+ share_name(fs_p->cnum, fs_p->fd_ptr->dev,
+ fs_p->fd_ptr->inode, fname);
+
+ if(fstat(fd, &sb) != 0)
+ {
+ DEBUG(0,("ERROR: set_share_mode: Failed to do stat on share file %s\n",
+ fname));
+ return False;
+ }
- if (IVAL(buf,0) != LOCKING_VERSION || !process_exists(pid)) {
- if (!unlink(lname))
- printf("Deleted stale share file %s\n",s);
+ /* Sanity check for file contents (if it's not a new share file). */
+ if(sb.st_size != 0)
+ {
+ int size = sb.st_size;
+
+ /* Allocate space for the file plus one extra entry */
+ if((buf = (char *)malloc(sb.st_size + 16)) == NULL)
+ {
+ DEBUG(0,("set_share_mode: malloc for file size %d fail !\n", sb.st_size + 16));
+ return False;
+ }
+
+ if(lseek(fd, 0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: set_share_mode: Failed to reset position \
+to 0 for share file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
}
+
+ if (read(fd,buf,sb.st_size) != sb.st_size)
+ {
+ DEBUG(0,("ERROR: set_share_mode: Failed to read share file %s (%s)\n",
+ fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ if (IVAL(buf,0) != LOCKING_VERSION)
+ {
+ DEBUG(0,("ERROR: set_share_mode: share file %s has incorrect \
+locking version (was %d, should be %d).\n",fname, IVAL(buf,0), LOCKING_VERSION));
+ if(buf)
+ free(buf);
+ delete_share_file(fs_p->cnum, fname);
+ return False;
+ }
+
+ size -= (10 + SVAL(buf, 8)); /* Remove the header */
+
+ /* The remaining size must be a multiple of 16 - error if not. */
+ if((size % 16) != 0)
+ {
+ DEBUG(0,("ERROR: set_share_mode: share file %s is an incorrect length - \
+deleting it.\n", fname));
+ if(buf)
+ free(buf);
+ delete_share_file(fs_p->cnum, fname);
+ return False;
+ }
+
}
+ else
+ {
+ /* New file - just use a single_entry. */
+ if((buf = (char *)malloc(10 + strlen(fs_p->name) + 1 + 16)) == NULL)
+ {
+ DEBUG(0,("ERROR: set_share_mode: malloc failed for single entry.\n"));
+ return False;
+ }
+ SIVAL(buf,0,LOCKING_VERSION);
+ SIVAL(buf,4,0);
+ SSVAL(buf,8,strlen(fs_p->name) + 1);
+ strcpy(buf + 10, fs_p->name);
+ }
+
+ num_entries = IVAL(buf,4);
+ header_size = 10 + SVAL(buf,8);
+ p = buf + header_size + (num_entries * 16);
+ SIVAL(p,0,fs_p->open_time.tv_sec);
+ SIVAL(p,4,fs_p->open_time.tv_usec);
+ SIVAL(p,8,fs_p->share_mode);
+ SIVAL(p,12,pid);
+
+ num_entries++;
+
+ SIVAL(buf,4,num_entries);
+
+ if(lseek(fd, 0, SEEK_SET) != 0)
+ {
+ DEBUG(0,("ERROR: set_share_mode: (1) Failed to reset position to \
+0 for share file %s (%s)\n", fname, strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ if (write(fd,buf,header_size + (num_entries*16)) != (header_size + (num_entries*16)))
+ {
+ DEBUG(2,("ERROR: set_share_mode: Failed to write share file %s - \
+deleting it (%s).\n",fname, strerror(errno)));
+ delete_share_file(fs_p->cnum, fname);
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ /* Now truncate the file at this point - just for safety. */
+ if(ftruncate(fd, header_size + (16*num_entries))!= 0)
+ {
+ DEBUG(0,("ERROR: set_share_mode: failed to ftruncate share \
+mode file %s to size %d (%s)\n", fname, header_size + (16*num_entries), strerror(errno)));
+ if(buf)
+ free(buf);
+ return False;
+ }
+
+ if(buf)
+ free(buf);
+
+ DEBUG(3,("set_share_mode: Created share file %s with \
+mode 0x%X pid=%d\n",fname,fs_p->share_mode,pid));
- closedir(dir);
-#endif
+ return True;
}
+#endif /* FAST_SHARE_MODES */
diff --git a/source/locking/shmem.c b/source/locking/shmem.c
index 2c02982d04a..9d4e62bdd78 100644
--- a/source/locking/shmem.c
+++ b/source/locking/shmem.c
@@ -23,7 +23,7 @@
#include "includes.h"
-#if FAST_SHARE_MODES
+#ifdef FAST_SHARE_MODES
extern int DEBUGLEVEL;
@@ -32,7 +32,7 @@ extern int DEBUGLEVEL;
#define SMB_SHM_MAGIC 0x53484100
/* = "SHM" in hex */
-#define SMB_SHM_VERSION 1
+#define SMB_SHM_VERSION 2
/* WARNING : offsets are used because mmap() does not guarantee that all processes have the
shared memory mapped to the same address */
@@ -73,15 +73,109 @@ 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 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(2,("smb_shm_global_lock : locked %d times\n",smb_shm_times_locked));
+ return True;
+ }
+
+ /* Do an exclusive wait lock on the first byte of the file */
+ if (fcntl_lock(smb_shm_fd, F_SETLKW, 0, 1, F_WRLCK) == False)
+ {
+ DEBUG(0,("ERROR smb_shm_global_lock : fcntl_lock failed with code %d\n",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",smb_shm_fd));
+ return False;
+ }
+
+ smb_shm_times_locked--;
+
+ if(smb_shm_times_locked > 0)
+ {
+ DEBUG(2,("smb_shm_global_unlock : still locked %d times\n",smb_shm_times_locked));
+ return True;
+ }
+
+ /* Do a wait unlock on the first byte of the file */
+ if (fcntl_lock(smb_shm_fd, F_SETLKW, 0, 1, F_UNLCK) == False)
+ {
+ DEBUG(0,("ERROR smb_shm_global_unlock : fcntl_lock failed with code %d\n",errno));
+ smb_shm_times_locked++;
+ return False;
+ }
+
+ return True;
+
+}
+
+/*
+ * Function to create the hash table for the share mode entries. Called
+ * when smb shared memory is global locked.
+ */
+
+BOOL smb_shm_create_hash_table( unsigned int size )
+{
+ size *= sizeof(smb_shm_offset_t);
+
+ smb_shm_global_lock();
+ smb_shm_header_p->userdef_off = smb_shm_alloc( size );
+
+ if(smb_shm_header_p->userdef_off == NULL_OFFSET)
+ {
+ 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;
+ int seek_back = -sizeof(other_pid);
int free_slot = -1;
int erased_slot;
+#ifndef SECURE_SHARE_MODES
smb_shm_processes_fd = open(processreg_file, O_RDWR | O_CREAT, 0666);
+#else /* SECURE_SHARE_MODES */
+ smb_shm_processes_fd = open(processreg_file, O_RDWR | O_CREAT, 0600);
+#endif /* SECURE_SHARE_MODES */
if ( smb_shm_processes_fd < 0 )
{
DEBUG(0,("ERROR smb_shm_register_process : processreg_file open failed with code %d\n",errno));
@@ -99,9 +193,10 @@ static BOOL smb_shm_register_process(char *processreg_file, pid_t pid, BOOL *oth
else
{
/* erase old pid */
- DEBUG(2,("smb_shm_register_process : erasing stale record for pid %d\n",other_pid));
+ DEBUG(2,("smb_shm_register_process : erasing stale record for pid %d (seek_back = %d)\n",
+ other_pid, seek_back));
other_pid = (pid_t)0;
- erased_slot = lseek(smb_shm_processes_fd, -sizeof(other_pid), SEEK_CUR);
+ erased_slot = lseek(smb_shm_processes_fd, seek_back, SEEK_CUR);
write(smb_shm_processes_fd, &other_pid, sizeof(other_pid));
if(free_slot < 0)
free_slot = erased_slot;
@@ -109,7 +204,7 @@ static BOOL smb_shm_register_process(char *processreg_file, pid_t pid, BOOL *oth
}
else
if(free_slot < 0)
- free_slot = lseek(smb_shm_processes_fd, -sizeof(other_pid), SEEK_CUR);
+ free_slot = lseek(smb_shm_processes_fd, seek_back, SEEK_CUR);
}
if (nb_read < 0)
{
@@ -141,6 +236,7 @@ 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;
+ int seek_back = -sizeof(other_pid);
int erased_slot;
BOOL found = False;
@@ -156,12 +252,14 @@ static BOOL smb_shm_unregister_process(char *processreg_file, pid_t pid)
while ((nb_read = read(smb_shm_processes_fd, &other_pid, sizeof(other_pid))) > 0)
{
+ DEBUG(2,("smb_shm_unregister_process : read record for pid %d\n",other_pid));
if(other_pid == pid)
{
/* erase pid */
- DEBUG(2,("smb_shm_unregister_process : erasing record for pid %d\n",other_pid));
+ DEBUG(2,("smb_shm_unregister_process : erasing record for pid %d (seek_val = %d)\n",
+ other_pid, seek_back));
other_pid = (pid_t)0;
- erased_slot = lseek(smb_shm_processes_fd, -sizeof(other_pid), SEEK_CUR);
+ erased_slot = lseek(smb_shm_processes_fd, seek_back, SEEK_CUR);
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 %d\n",errno));
@@ -257,6 +355,8 @@ static BOOL smb_shm_initialize(int size)
smb_shm_header_p->consistent = True;
+ smb_shm_initialize_called = True;
+
return True;
}
@@ -291,7 +391,11 @@ BOOL smb_shm_open( char *file_name, int size)
DEBUG(2,("smb_shm_open : using shmem file %s to be of size %d\n",file_name,size));
old_umask = umask(0);
+#ifndef SECURE_SHARE_MODES
smb_shm_fd = open(file_name, O_RDWR | O_CREAT, 0666);
+#else /* SECURE_SHARE_MODES */
+ smb_shm_fd = open(file_name, O_RDWR | O_CREAT, 0600);
+#endif /* SECURE_SHARE_MODE */
umask(old_umask);
if ( smb_shm_fd < 0 )
{
@@ -299,16 +403,16 @@ BOOL smb_shm_open( char *file_name, int size)
return False;
}
- if (!smb_shm_lock())
+ if (!smb_shm_global_lock())
{
- DEBUG(0,("ERROR smb_shm_open : can't do smb_shm_lock\n"));
+ DEBUG(0,("ERROR smb_shm_open : can't do smb_shm_global_lock\n"));
return False;
}
if( (filesize = lseek(smb_shm_fd, 0, SEEK_END)) < 0)
{
DEBUG(0,("ERROR smb_shm_open : lseek failed with code %d\n",errno));
- smb_shm_unlock();
+ smb_shm_global_unlock();
close(smb_shm_fd);
return False;
}
@@ -332,7 +436,7 @@ BOOL smb_shm_open( char *file_name, int size)
if (! smb_shm_register_process(smb_shm_processreg_name, getpid(), &other_processes))
{
- smb_shm_unlock();
+ smb_shm_global_unlock();
close(smb_shm_fd);
return False;
}
@@ -344,7 +448,7 @@ BOOL smb_shm_open( char *file_name, int size)
{
DEBUG(0,("ERROR smb_shm_open : ftruncate failed with code %d\n",errno));
smb_shm_unregister_process(smb_shm_processreg_name, getpid());
- smb_shm_unlock();
+ smb_shm_global_unlock();
close(smb_shm_fd);
return False;
}
@@ -369,7 +473,7 @@ BOOL smb_shm_open( char *file_name, int size)
{
DEBUG(0,("ERROR smb_shm_open : mmap failed with code %d\n",errno));
smb_shm_unregister_process(smb_shm_processreg_name, getpid());
- smb_shm_unlock();
+ smb_shm_global_unlock();
close(smb_shm_fd);
return False;
}
@@ -378,6 +482,8 @@ BOOL smb_shm_open( char *file_name, int size)
if (created_new || !other_processes)
{
smb_shm_initialize(size);
+ /* Create the hash buckets for the share file entries. */
+ smb_shm_create_hash_table( lp_shmem_hash_size() );
}
else if (!smb_shm_validate_header(size) )
{
@@ -385,12 +491,12 @@ BOOL smb_shm_open( char *file_name, int size)
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_unlock();
+ smb_shm_global_unlock();
close(smb_shm_fd);
return False;
}
- smb_shm_unlock();
+ smb_shm_global_unlock();
return True;
}
@@ -399,17 +505,22 @@ BOOL smb_shm_open( char *file_name, int size)
BOOL smb_shm_close( void )
{
+ if(smb_shm_initialize_called == False)
+ return True;
+
DEBUG(2,("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 ( munmap((caddr_t)smb_shm_header_p, smb_shm_header_p->total_size) < 0)
+ 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 %d\n",errno));
}
- smb_shm_lock();
+ smb_shm_global_lock();
+ DEBUG(2,("calling smb_shm_unregister_process(%s, %d)\n", smb_shm_processreg_name, getpid()));
smb_shm_unregister_process(smb_shm_processreg_name, getpid());
- smb_shm_unlock();
+ smb_shm_global_unlock();
close(smb_shm_fd);
@@ -438,9 +549,12 @@ smb_shm_offset_t smb_shm_alloc(int size)
return NULL_OFFSET;
}
+ 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 NULL_OFFSET;
}
@@ -463,6 +577,7 @@ smb_shm_offset_t smb_shm_alloc(int size)
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 (NULL_OFFSET);
}
@@ -516,6 +631,7 @@ smb_shm_offset_t smb_shm_alloc(int size)
DEBUG(2,("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 );
}
@@ -534,9 +650,12 @@ BOOL smb_shm_free(smb_shm_offset_t offset)
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;
}
@@ -545,6 +664,7 @@ BOOL smb_shm_free(smb_shm_offset_t offset)
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;
}
@@ -577,6 +697,7 @@ BOOL smb_shm_free(smb_shm_offset_t offset)
smb_shm_solve_neighbors( header_p ); /* if neighbors then link them */
smb_shm_header_p->consistent = True;
+ smb_shm_global_unlock();
return True;
}
else
@@ -590,6 +711,7 @@ BOOL smb_shm_free(smb_shm_offset_t offset)
smb_shm_solve_neighbors(prev_p) ;
smb_shm_header_p->consistent = True;
+ smb_shm_global_unlock();
return True;
}
}
@@ -633,68 +755,71 @@ smb_shm_offset_t smb_shm_addr2offset(void *addr)
return (smb_shm_offset_t)((char *)addr - (char *)smb_shm_header_p);
}
-BOOL smb_shm_lock(void)
+/*******************************************************************
+ Lock a particular hash bucket entry.
+ ******************************************************************/
+
+BOOL smb_shm_lock_hash_entry( unsigned int entry)
{
- if (smb_shm_fd < 0)
- {
- DEBUG(0,("ERROR smb_shm_lock : bad smb_shm_fd (%d)\n",smb_shm_fd));
+ int start = (smb_shm_header_p->userdef_off + (entry * sizeof(smb_shm_offset_t)));
+
+ if (smb_shm_fd < 0)
+ {
+ DEBUG(0,("ERROR smb_shm_lock_hash_entry : bad smb_shm_fd (%d)\n",smb_shm_fd));
return False;
- }
-
- smb_shm_times_locked++;
-
- if(smb_shm_times_locked > 1)
- {
- DEBUG(2,("smb_shm_lock : locked %d times\n",smb_shm_times_locked));
- return True;
- }
-
- if (lockf(smb_shm_fd, F_LOCK, 0) < 0)
- {
- DEBUG(0,("ERROR smb_shm_lock : lockf failed with code %d\n",errno));
- smb_shm_times_locked--;
+ }
+
+ if(entry >= lp_shmem_hash_size())
+ {
+ DEBUG(0,("ERROR smb_shm_lock_hash_entry : hash entry size too big (%d)\n", entry));
return False;
- }
-
- return True;
-
+ }
+
+ /* Do an exclusive wait lock on the 4 byte region mapping into this entry */
+ if (fcntl_lock(smb_shm_fd, F_SETLKW, start, sizeof(smb_shm_offset_t), F_WRLCK) == False)
+ {
+ DEBUG(0,("ERROR smb_shm_lock_hash_entry : fcntl_lock failed with code %d\n",errno));
+ return False;
+ }
+
+ DEBUG(9,("smb_shm_lock_hash_entry: locked hash bucket %d\n", entry));
+ return True;
}
+/*******************************************************************
+ Unlock a particular hash bucket entry.
+ ******************************************************************/
-
-BOOL smb_shm_unlock(void)
+BOOL smb_shm_unlock_hash_entry( unsigned int entry )
{
- if (smb_shm_fd < 0)
- {
- DEBUG(0,("ERROR smb_shm_unlock : bad smb_shm_fd (%d)\n",smb_shm_fd));
+ int start = (smb_shm_header_p->userdef_off + (entry * sizeof(smb_shm_offset_t)));
+
+ 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(smb_shm_times_locked == 0)
- {
- DEBUG(0,("ERROR smb_shm_unlock : shmem not locked\n",smb_shm_fd));
+ if(entry >= lp_shmem_hash_size())
+ {
+ DEBUG(0,("ERROR smb_shm_unlock_hash_entry : hash entry size too big (%d)\n", entry));
return False;
- }
-
- smb_shm_times_locked--;
-
- if(smb_shm_times_locked > 0)
- {
- DEBUG(2,("smb_shm_unlock : still locked %d times\n",smb_shm_times_locked));
- return True;
- }
-
- if (lockf(smb_shm_fd, F_ULOCK, 0) < 0)
- {
- DEBUG(0,("ERROR smb_shm_unlock : lockf failed with code %d\n",errno));
- smb_shm_times_locked++;
+ }
+
+ /* Do a wait lock on the 4 byte region mapping into this entry */
+ if (fcntl_lock(smb_shm_fd, F_SETLKW, start, sizeof(smb_shm_offset_t), F_UNLCK) == False)
+ {
+ DEBUG(0,("ERROR smb_shm_unlock_hash_entry : fcntl_lock failed with code %d\n",errno));
return False;
- }
-
- return True;
-
+ }
+
+ DEBUG(9,("smb_shm_unlock_hash_entry: unlocked hash bucket %d\n", entry));
+ return True;
}
+/*******************************************************************
+ Gather statistics on shared memory usage.
+ ******************************************************************/
BOOL smb_shm_get_usage(int *bytes_free,
int *bytes_used,
@@ -716,4 +841,4 @@ BOOL smb_shm_get_usage(int *bytes_free,
#else /* FAST_SHARE_MODES */
int shmem_dummy_procedure(void)
{return 0;}
-#endif
+#endif /* FAST_SHARE_MODES */