diff options
author | Samba Release Account <samba-bugs@samba.org> | 1997-05-20 00:32:51 +0000 |
---|---|---|
committer | Samba Release Account <samba-bugs@samba.org> | 1997-05-20 00:32:51 +0000 |
commit | aa864415c5183c948fe9ae221023d40265c38013 (patch) | |
tree | 29e0aa79328568d93211d175353f1fd1bc2d3737 /source3/locking | |
parent | 5495a3446d769a2501ee558bda54146bef507e78 (diff) | |
download | samba-aa864415c5183c948fe9ae221023d40265c38013.tar.gz samba-aa864415c5183c948fe9ae221023d40265c38013.tar.bz2 samba-aa864415c5183c948fe9ae221023d40265c38013.zip |
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).
(This used to be commit 2a1711eaaf08bb6776770cd3c96b3010f431a677)
Diffstat (limited to 'source3/locking')
-rw-r--r-- | source3/locking/locking.c | 1323 | ||||
-rw-r--r-- | source3/locking/shmem.c | 261 |
2 files changed, 1184 insertions, 400 deletions
diff --git a/source3/locking/locking.c b/source3/locking/locking.c index 7c23e5b3ca..e63e347a26 100644 --- a/source3/locking/locking.c +++ b/source3/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/source3/locking/shmem.c b/source3/locking/shmem.c index 2c02982d04..9d4e62bdd7 100644 --- a/source3/locking/shmem.c +++ b/source3/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 */ |