From aa864415c5183c948fe9ae221023d40265c38013 Mon Sep 17 00:00:00 2001 From: Samba Release Account Date: Tue, 20 May 1997 00:32:51 +0000 Subject: 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) --- source3/include/includes.h | 3 +- source3/include/proto.h | 25 +- source3/include/smb.h | 50 +- source3/lib/util.c | 5 +- source3/locking/locking.c | 1323 +++++++++++++++++++++++++++++++++----------- source3/locking/shmem.c | 261 ++++++--- source3/nameannounce.c | 21 +- source3/nameconf.c | 6 +- source3/namedbname.c | 7 +- source3/namedbserver.c | 3 +- source3/namedbsubnet.c | 194 ++++--- source3/namedbwork.c | 6 +- source3/nameelect.c | 248 +++++---- source3/nameresp.c | 8 +- source3/nameserv.c | 42 +- source3/nameservreply.c | 3 +- source3/namework.c | 5 +- source3/nmbd/nmbd.c | 15 +- source3/param/loadparm.c | 38 +- source3/smbd/dir.c | 7 +- source3/smbd/ipc.c | 13 +- source3/smbd/pipes.c | 3 +- source3/smbd/reply.c | 3 +- source3/smbd/server.c | 288 ++++++---- source3/smbd/trans2.c | 4 +- source3/utils/status.c | 260 ++++++--- 26 files changed, 1925 insertions(+), 916 deletions(-) diff --git a/source3/include/includes.h b/source3/include/includes.h index e1ed3a5816..265e838be0 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -481,6 +481,7 @@ char *mktemp(char *); /* No standard include */ #ifdef FreeBSD +#include #include #include #include @@ -970,7 +971,7 @@ typedef int mode_t; end of the platform specific sections ********************************************************************/ -#if defined(USE_MMAP) || FAST_SHARE_MODES +#if defined(USE_MMAP) || defined(FAST_SHARE_MODES) #include #endif diff --git a/source3/include/proto.h b/source3/include/proto.h index 973b1a15f3..1fa8c1d95e 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -149,6 +149,7 @@ char *lp_socket_address(void); char *lp_nis_home_map_name(void); BOOL lp_wins_support(void); BOOL lp_wins_proxy(void); +BOOL lp_local_master(void); BOOL lp_domain_master(void); BOOL lp_domain_logons(void); BOOL lp_preferred_master(void); @@ -176,6 +177,8 @@ int lp_maxpacket(void); int lp_keepalive(void); int lp_passwordlevel(void); int lp_readsize(void); +int lp_shmem_size(void); +int lp_shmem_hash_size(void); int lp_deadtime(void); int lp_maxprotocol(void); int lp_security(void); @@ -266,12 +269,12 @@ BOOL do_lock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ec BOOL do_unlock(int fnum,int cnum,uint32 count,uint32 offset,int *eclass,uint32 *ecode); BOOL start_share_mode_mgmt(void); BOOL stop_share_mode_mgmt(void); -int get_share_mode_by_fnum(int cnum,int fnum,int *pid); -int get_share_mode_byname(int cnum,char *fname,int *pid); -int get_share_mode(int cnum,struct stat *sbuf,int *pid); -void del_share_mode(int fnum); -BOOL set_share_mode(int fnum,int mode); -void clean_share_modes(void); +BOOL lock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token *); +BOOL unlock_share_entry(int cnum, uint32 dev, uint32 inode, share_lock_token); +int get_share_modes(int cnum, share_lock_token token, uint32 dev, uint32 inode, + min_share_mode_entry **old_shares); +void del_share_mode(share_lock_token token, int fnum); +BOOL set_share_mode(share_lock_token token, int fnum); /*The following definitions come from mangle.c */ @@ -309,7 +312,7 @@ void do_announce_host(int command, char *to_name , int to_type , struct in_addr to_ip, time_t announce_interval, char *server_name, int server_type, char *server_comment); -void remove_my_servers(void); +void announce_my_servers_removed(void); void announce_server(struct subnet_record *d, struct work_record *work, char *name, char *comment, time_t ttl, int server_type); void announce_host(time_t t); @@ -394,7 +397,7 @@ void expire_servers(time_t t); struct subnet_record *find_subnet(struct in_addr bcast_ip); struct subnet_record *find_req_subnet(struct in_addr ip, BOOL bcast); struct subnet_record *find_subnet_all(struct in_addr bcast_ip); -void add_subnet_interfaces(void); +void add_workgroup_to_subnet( struct subnet_record *d, char *group); void add_my_subnets(char *group); void write_browse_list(time_t t); @@ -406,7 +409,6 @@ struct work_record *remove_workgroup(struct subnet_record *d, struct work_record *find_workgroupstruct(struct subnet_record *d, fstring name, BOOL add); void dump_workgroups(void); -int check_work_servertype(const char *work_name, int type_mask); /*The following definitions come from nameelect.c */ @@ -724,6 +726,11 @@ BOOL smb_shm_set_userdef_off(smb_shm_offset_t userdef_off); void * smb_shm_offset2addr(smb_shm_offset_t offset); BOOL smb_shm_lock(void); BOOL smb_shm_unlock(void); +smb_shm_offset_t smb_shm_alloc(int size); +smb_shm_offset_t smb_shm_addr2offset(void *addr); +smb_shm_offset_t smb_shm_get_userdef_off(void); +BOOL smb_shm_lock_hash_entry( unsigned int entry); +BOOL smb_shm_unlock_hash_entry( unsigned int entry ); BOOL smb_shm_get_usage(int *bytes_free, int *bytes_used, int *bytes_overhead); diff --git a/source3/include/smb.h b/source3/include/smb.h index 7cd2f5b0fe..e0c08183db 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -36,11 +36,16 @@ #define BUFFER_SIZE (0xFFFF) #define SAFETY_MARGIN 1024 -/* size of shared memory used for share mode locking */ +/* Default size of shared memory used for share mode locking */ #ifndef SHMEM_SIZE #define SHMEM_SIZE 102400 #endif +/* Default number of hash buckets used in shared memory share mode */ +#ifndef SHMEM_HASH_SIZE +#define SHMEM_HASH_SIZE 113 +#endif + #define NMB_PORT 137 #define DGRAM_PORT 138 #define SMB_PORT 139 @@ -295,8 +300,8 @@ typedef struct typedef struct { uint16 ref_count; - int32 dev; - int32 inode; + uint32 dev; + uint32 inode; int fd; int fd_readonly; int fd_writeonly; @@ -320,7 +325,6 @@ typedef struct BOOL can_read; BOOL can_write; BOOL share_mode; - BOOL share_pending; BOOL print_file; BOOL modified; char *name; @@ -420,19 +424,40 @@ struct interface struct in_addr nmask; }; -/* share mode record in shared memory */ +/* share mode record pointed to in shared memory hash bucket */ typedef struct { - smb_shm_offset_t next_offset; /* offset of next record in list in shared mem */ + smb_shm_offset_t next_offset; /* offset of next record in chain from hash bucket */ int locking_version; + int32 st_dev; + int32 st_ino; + int num_share_mode_entries; + smb_shm_offset_t share_mode_entries; /* Chain of share mode entries for this file */ + char file_name[1]; +} share_mode_record; + +/* share mode entry pointed to by share_mode_record struct */ +typedef struct +{ + smb_shm_offset_t next_share_mode_entry; + int pid; int share_mode; struct timeval time; +} share_mode_entry; + +/* struct returned by get_share_modes */ +typedef struct +{ int pid; - dev_t st_dev; - ino_t st_ino; - char file_name[1]; /* dynamically allocated with correct size */ -} share_mode_record; + int share_mode; + struct timeval time; +} min_share_mode_entry; + +/* Token returned by lock_share_entry (actually ignored by FAST_SHARE_MODES code) */ +typedef int share_lock_token; +/* Conversion to hash entry index from device and inode numbers. */ +#define HASH_ENTRY(dev,ino) ((( (uint32)(dev) )* ( (uint32)(ino) )) % lp_shmem_hash_size()) /* this is used for smbstatus */ struct connect_record @@ -798,12 +823,15 @@ char *Strstr(char *s, char *p); #define SV_TYPE_DOMAIN_ENUM 0x80000000 #define SV_TYPE_ALL 0xFFFFFFFF -/* What server type are we currently - JHT Says we ARE 4.20 */ +/* what server type are we currently - JHT Says we ARE 4.20 */ +/* this was set by JHT in liaison with Jeremy Allison early 1997 */ +/* setting to 4.20 at same time as announcing ourselves as NT Server */ /* History: */ /* Version 4.0 - never made public */ /* Version 4.10 - New to 1.9.16p2, lost in space 1.9.16p3 to 1.9.16p9 */ /* - Reappeared in 1.9.16p11 with fixed smbd services */ /* Version 4.20 - To indicate that nmbd and browsing now works better */ + #define MAJOR_VERSION 0x04 #define MINOR_VERSION 0x02 diff --git a/source3/lib/util.c b/source3/lib/util.c index 3315f1a41a..0ed08405ba 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -73,6 +73,7 @@ pstring myhostname=""; pstring user_socket_options=""; pstring sesssetup_user=""; pstring myname = ""; +fstring myworkgroup = ""; int smb_read_error = 0; @@ -3431,7 +3432,7 @@ BOOL is_vetoed_name(char *name) nameptr++; continue; } - if(name_end = strchr(nameptr,'/')) + if((name_end = strchr(nameptr,'/'))!=NULL) { *name_end = 0; } @@ -3472,7 +3473,7 @@ BOOL is_vetoed_path(char *name) nameptr++; continue; } - if(name_end = strchr(nameptr,'/')) + if((name_end = strchr(nameptr,'/'))!=NULL) { *name_end = 0; } 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 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 */ diff --git a/source3/nameannounce.c b/source3/nameannounce.c index b46436168c..7d7a95334c 100644 --- a/source3/nameannounce.c +++ b/source3/nameannounce.c @@ -35,6 +35,7 @@ extern BOOL CanRecurse; extern struct in_addr ipzero; extern pstring myname; +extern fstring myworkgroup; extern int ClientDGRAM; extern int ClientNMB; @@ -185,9 +186,9 @@ void do_announce_host(int command, /**************************************************************************** - remove all samba's server entries - ****************************************************************************/ -void remove_my_servers(void) +announce all samba's server entries as 'gone'. +****************************************************************************/ +void announce_my_servers_removed(void) { struct subnet_record *d; for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d)) @@ -372,7 +373,7 @@ static time_t announce_timer_last=0; void reset_announce_timer() { - announce_timer_last = 0; + announce_timer_last = time(NULL) - (CHECK_TIME_MST_ANNOUNCE * 60); } /**************************************************************************** @@ -396,7 +397,7 @@ void announce_master(time_t t) return; } - if(wins_subnet == 0) + if(wins_subnet == NULL) { DEBUG(10,("announce_master: no wins subnet, ignoring.\n")); return; @@ -412,19 +413,19 @@ void announce_master(time_t t) if (AM_MASTER(work)) { am_master = True; + DEBUG(4,( "announce_master: am_master = %d for \ +workgroup %s\n", am_master, work->work_group)); } } } - DEBUG(4,( "announce_master: am_master = %d for workgroup %s\n", am_master, lp_workgroup())); - if (!am_master) return; /* only proceed if we are a master browser */ /* Note that we don't do this if we are domain master browser and that we *only* do this on the WINS subnet. */ /* Try and find our workgroup on the WINS subnet */ - work = find_workgroupstruct(wins_subnet, lp_workgroup(), False); + work = find_workgroupstruct(wins_subnet, myworkgroup, False); if (work) { @@ -488,7 +489,7 @@ in our own WINS database.\n", work->work_group)); /* Check that this isn't one of our addresses (ie. we are not domain master ourselves) */ - if(ismyip(nr->ip_flgs[0].ip)) + if(ismyip(nr->ip_flgs[0].ip) || ip_equal(nr->ip_flgs[0].ip, ipzero)) { DEBUG(4, ("announce_master: domain master ip found (%s) for workgroup %s \ is one of our interfaces.\n", work->work_group, inet_ntoa(nr->ip_flgs[0].ip) )); @@ -535,7 +536,7 @@ void announce_remote(time_t t) if (!*s) return; comment = lp_serverstring(); - workgroup = lp_workgroup(); + workgroup = myworkgroup; for (ptr=s; next_token(&ptr,s2,NULL); ) { /* the entries are of the form a.b.c.d/WORKGROUP with diff --git a/source3/nameconf.c b/source3/nameconf.c index 99951a3b0e..8f33419b9a 100644 --- a/source3/nameconf.c +++ b/source3/nameconf.c @@ -35,6 +35,8 @@ #include "includes.h" extern int DEBUGLEVEL; +extern fstring myworkgroup; + #if 0 struct smbbrowse_parms { @@ -104,7 +106,7 @@ static struct smbbrowse *new_workgroup(struct smbbrowse *model, StrnCpy(new->work_name, workgroup_name, 15); strupper(new->work_name); - if (strequal(lp_workgroup(), workgroup_name)) + if (strequal(myworkgroup, workgroup_name)) StrnCpy(new->browsing_alias, default_name, 15); else sprintf(new->browsing_alias, "%.14s%x", default_name, nexttoken); @@ -289,7 +291,7 @@ static void default_smbbrowse_conf(char *default_name) struct smbbrowse *w; /* The workgroup specified in smb.conf */ - w = new_workgroup((struct smbbrowse *)NULL, lp_workgroup(), default_name); + w = new_workgroup((struct smbbrowse *)NULL, myworkgroup, default_name); w->should_local_master = lp_preferred_master(); w->should_domain_master = lp_domain_master(); w->should_workgroup_member = True; diff --git a/source3/namedbname.c b/source3/namedbname.c index 2e0afc1497..aa41726450 100644 --- a/source3/namedbname.c +++ b/source3/namedbname.c @@ -153,11 +153,13 @@ struct name_record *find_name(struct name_record *n, { continue; } - DEBUG(9,("find_name: found name %s\n", name->name)); + DEBUG(9,("find_name: found name %s(%02x)\n", + name->name, name->name_type)); return ret; } } - DEBUG(9,("find_name: name %s NOT FOUND\n", name->name)); + DEBUG(9,("find_name: name %s(%02x) NOT FOUND\n", name->name, + name->name_type)); return NULL; } @@ -528,7 +530,6 @@ struct name_record *dns_name_search(struct nmb_name *question, int Time) { int name_type = question->name_type; char *qname = question->name; - char *r; BOOL dns_type = (name_type == 0x20 || name_type == 0); struct in_addr dns_ip; diff --git a/source3/namedbserver.c b/source3/namedbserver.c index 9c7bb664ab..8cad8a3a11 100644 --- a/source3/namedbserver.c +++ b/source3/namedbserver.c @@ -37,6 +37,7 @@ extern int ClientDGRAM; extern int DEBUGLEVEL; extern pstring myname; +extern fstring myworkgroup; /* this is our domain/workgroup/server database */ extern struct subnet_record *subnetlist; @@ -161,7 +162,7 @@ struct server_record *add_server_entry(struct subnet_record *d, } - if (strequal(lp_workgroup(),work->work_group)) + if (strequal(myworkgroup,work->work_group)) { if (servertype) servertype |= SV_TYPE_LOCAL_LIST_ONLY; diff --git a/source3/namedbsubnet.c b/source3/namedbsubnet.c index 25c369ab1c..393db363d8 100644 --- a/source3/namedbsubnet.c +++ b/source3/namedbsubnet.c @@ -40,6 +40,7 @@ extern struct in_addr wins_ip; extern struct in_addr ipzero; extern pstring myname; +extern fstring myworkgroup; BOOL updatedlists = True; int updatecount = 0; @@ -52,15 +53,10 @@ struct subnet_record *subnetlist = NULL; /* WINS subnet - keep this separate so enumeration code doesn't run onto it by mistake. */ -struct subnet_record *wins_subnet = 0; +struct subnet_record *wins_subnet = NULL; extern uint16 nb_type; /* samba's NetBIOS name type */ -/* Forward references. */ -static struct subnet_record *add_subnet_entry(struct in_addr bcast_ip, - struct in_addr mask_ip, - char *name, BOOL add, BOOL lmhosts); - /**************************************************************************** add a domain into the list **************************************************************************/ @@ -129,6 +125,7 @@ struct subnet_record *find_subnet_all(struct in_addr bcast_ip) struct subnet_record *d = find_subnet(bcast_ip); if(!d) return wins_subnet; + return d; } /**************************************************************************** @@ -156,121 +153,122 @@ static struct subnet_record *make_subnet(struct in_addr bcast_ip, struct in_addr return d; } - /**************************************************************************** - add the remote interfaces from lp_interfaces() - to the netbios subnet database. + add a domain entry. creates a workgroup, if necessary, and adds the domain + to the named a workgroup. ****************************************************************************/ -void add_subnet_interfaces(void) +static struct subnet_record *add_subnet_entry(struct in_addr bcast_ip, + struct in_addr mask_ip, char *name, + BOOL create_subnets, BOOL add) { - struct interface *i; + struct subnet_record *d = NULL; - /* loop on all local interfaces */ - for (i = local_interfaces; i; i = i->next) - { - /* add the interface into our subnet database */ - if (!find_subnet(i->bcast)) - { - make_subnet(i->bcast,i->nmask, True); - } - } + if (zero_ip(bcast_ip)) + bcast_ip = *iface_bcast(bcast_ip); + + /* Note that we should also add into the WINS subnet as add_subnet_entry + should be called to add NetBIOS names and server entries on all + interfaces, including the WINS interface + */ - /* add the pseudo-ip interface for WINS: 255.255.255.255 */ - if (lp_wins_support() || (*lp_wins_server())) + if(create_subnets == True) + { + /* Create new subnets. */ + if((d = make_subnet(bcast_ip, mask_ip, add)) == NULL) { - struct in_addr wins_bcast = wins_ip; - struct in_addr wins_nmask = ipzero; - wins_subnet = make_subnet(wins_bcast, wins_nmask, False); + DEBUG(0,("add_subnet_entry: Unable to create subnet %s\n", + inet_ntoa(bcast_ip) )); + return NULL; } + return d; + } + if(ip_equal(bcast_ip, wins_ip)) + return wins_subnet; + return find_subnet(bcast_ip); } - - /**************************************************************************** - add the default workgroup into the subnet lists. - **************************************************************************/ -void add_my_subnets(char *group) + Add a workgroup into a subnet, and if it's our primary workgroup, + add the required names to it. +**************************************************************************/ + +void add_workgroup_to_subnet( struct subnet_record *d, char *group) { - struct interface *i; + struct work_record *w = NULL; - /* add or find domain on our local subnet, in the default workgroup */ - - if (*group == '*') return; + DEBUG(5,("add_workgroup_to_subnet: Adding workgroup %s to subnet %s\n", + group, inet_ntoa(d->bcast_ip))); - /* the coding choice is up to you, andrew: i can see why you don't want - global access to the local_interfaces structure: so it can't get - messed up! */ - for (i = local_interfaces; i; i = i->next) - { - add_subnet_entry(i->bcast,i->nmask,group, True, False); - } + /* This next statement creates the workgroup struct if it doesn't + already exist. + */ + if((w = find_workgroupstruct(d, group, True)) == NULL) + { + DEBUG(0,("add_workgroup_to_subnet: Unable to add workgroup %s to subnet %s\n", + group, inet_ntoa(d->bcast_ip) )); + return; + } - /* If we are setup as a domain master browser, and are using - WINS, then we must add the workgroup to the WINS subnet. This - is used as a place to keep collated server lists. */ - - if(lp_domain_master() && (lp_wins_support() || lp_wins_server())) - if(find_workgroupstruct(wins_subnet, group, True) == 0) - DEBUG(0, ("add_my_subnets: Failed to add workgroup %s to \ -WINS subnet.\n", group)); - else - DEBUG(3,("add_my_subnets: Added workgroup %s to WINS subnet.\n", - group)); + /* add WORKGROUP(1e) and WORKGROUP(00) entries into name database + or register with WINS server, if it's our workgroup + */ + if (strequal(myworkgroup, group)) + { + add_my_name_entry(d,group,0x1e,nb_type|NB_ACTIVE|NB_GROUP); + add_my_name_entry(d,group,0x0 ,nb_type|NB_ACTIVE|NB_GROUP); + /* add samba server name to workgroup list. */ + add_server_entry(d,w,myname,w->ServerType,0,lp_serverstring(),True); + DEBUG(3,("add_workgroup_to_subnet: Added server name entry %s to subnet %s\n", + myname, inet_ntoa(d->bcast_ip))); + } } - /**************************************************************************** - add a domain entry. creates a workgroup, if necessary, and adds the domain - to the named a workgroup. - ****************************************************************************/ -static struct subnet_record *add_subnet_entry(struct in_addr bcast_ip, - struct in_addr mask_ip, - char *name, BOOL add, BOOL lmhosts) -{ - struct subnet_record *d; + create subnet / workgroup / server entries + + - add or create the subnet lists + - add or create the workgroup entries in each subnet entry + - register appropriate NetBIOS names for the workgroup entries + +**************************************************************************/ +void add_my_subnets(char *group) +{ + static BOOL create_subnets = True; + struct subnet_record *d = NULL; + struct interface *i = NULL; - /* XXXX andrew: struct in_addr ip appears not to be referenced at all except - in the DEBUG comment. i assume that the DEBUG comment below actually - intends to refer to bcast_ip? i don't know. + if (*group == '*') return; - struct in_addr ip = wins_ip; + /* Create subnets from all the local interfaces and thread them onto + the linked list. + */ + for (i = local_interfaces; i; i = i->next) + { + add_subnet_entry(i->bcast,i->nmask,group, create_subnets, True); + } - */ + /* If we are using WINS, then we must add the workgroup to the WINS + subnet. This is used as a place to keep collated server lists. + */ - if (zero_ip(bcast_ip)) - bcast_ip = *iface_bcast(bcast_ip); - - /* add the domain into our domain database */ - /* Note that we never add into the WINS subnet as add_subnet_entry - is only called to add our local interfaces. */ - if ((d = find_subnet(bcast_ip)) || - (d = make_subnet(bcast_ip, mask_ip, True))) - { - struct work_record *w = find_workgroupstruct(d, name, add); - - if (!w) return NULL; + /* Create the WINS subnet if we are using WINS - but don't thread it + onto the linked subnet list. + */ + if (lp_wins_support() || lp_wins_server()) + { + struct in_addr wins_nmask = ipzero; + wins_subnet = add_subnet_entry(wins_ip, wins_nmask, group, create_subnets, False); + } - /* add WORKGROUP(1e) and WORKGROUP(00) entries into name database - or register with WINS server, if it's our workgroup */ - if (strequal(lp_workgroup(), name)) - { - add_my_name_entry(d,name,0x1e,nb_type|NB_ACTIVE|NB_GROUP); - add_my_name_entry(d,name,0x0 ,nb_type|NB_ACTIVE|NB_GROUP); - } - /* add samba server name to workgroup list. don't add - lmhosts server entries to local interfaces */ - if (strequal(lp_workgroup(), name)) - { - add_server_entry(d,w,myname,w->ServerType,0,lp_serverstring(),True); - DEBUG(3,("Added server name entry %s at %s\n", - name,inet_ntoa(bcast_ip))); - } - - return d; - } - return NULL; -} + /* Ensure we only create the subnets once. */ + create_subnets = False; + /* Now we have created all the subnets - we can add the names + that make us a client member in the workgroup. + */ + for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d)) + add_workgroup_to_subnet(d, group); +} /******************************************************************* write out browse.dat diff --git a/source3/namedbwork.c b/source3/namedbwork.c index 8c249cc82c..d752916815 100644 --- a/source3/namedbwork.c +++ b/source3/namedbwork.c @@ -40,6 +40,8 @@ extern struct subnet_record *subnetlist; extern struct in_addr wins_ip; +extern fstring myworkgroup; + int workgroup_count = 0; /* unique index key: one for each workgroup */ @@ -192,8 +194,8 @@ struct work_record *find_workgroupstruct(struct subnet_record *d, if ((work = make_workgroup(name))) { if (!ip_equal(d->bcast_ip, wins_ip) && - lp_preferred_master() && - strequal(lp_workgroup(), name)) + lp_preferred_master() && lp_local_master() && + strequal(myworkgroup, name)) { DEBUG(3, ("preferred master startup for %s\n", work->work_group)); work->needelection = True; diff --git a/source3/nameelect.c b/source3/nameelect.c index 02fda9f817..82cebd3e6c 100644 --- a/source3/nameelect.c +++ b/source3/nameelect.c @@ -40,6 +40,7 @@ extern int DEBUGLEVEL; extern pstring scope; extern pstring myname; +extern fstring myworkgroup; extern struct in_addr ipzero; extern struct in_addr wins_ip; @@ -57,55 +58,59 @@ extern uint16 nb_type; /* samba's NetBIOS name type */ ******************************************************************/ void check_master_browser(time_t t) { - static time_t lastrun=0; - struct subnet_record *d; + static time_t lastrun=0; + struct subnet_record *d; - if (!lastrun) lastrun = t; - if (t < lastrun + CHECK_TIME_MST_BROWSE * 60) return; + if (!lastrun) lastrun = t; + if (t < lastrun + CHECK_TIME_MST_BROWSE * 60) return; - lastrun = t; + lastrun = t; - dump_workgroups(); + dump_workgroups(); - for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d)) - { - struct work_record *work; + for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_EXCLUDING_WINS(d)) + { + struct work_record *work; - for (work = d->workgrouplist; work; work = work->next) - { - if (strequal(work->work_group, lp_workgroup()) && !AM_MASTER(work)) - { - if (lp_preferred_master()) - { - /* preferred master - not a master browser. force - becoming a master browser, hence the log message. - */ - - DEBUG(0,("%s preferred master for %s %s - force election\n", - timestring(), work->work_group, - inet_ntoa(d->bcast_ip))); - - browser_gone(work->work_group, d->bcast_ip); - } - else - { - /* if we are not the browse master of a workgroup, - and we can't find a browser on the subnet, do - something about it. - */ - - queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK, - work->work_group,0x1d,0,0,0,NULL,NULL, - True,False,d->bcast_ip,d->bcast_ip); - } - } - } - } + for (work = d->workgrouplist; work; work = work->next) + { + if (strequal(work->work_group, myworkgroup) && !AM_MASTER(work)) + { + if (lp_local_master()) + { + /* potential master browser - not a master browser. force + becoming a master browser, hence the log message. + */ + + DEBUG(0,("%s potential master for %s %s - force election\n", + timestring(), work->work_group, + inet_ntoa(d->bcast_ip))); + + browser_gone(work->work_group, d->bcast_ip); + } + else + { + /* if we are not the browse master of a workgroup, + and we can't find a browser on the subnet, do + something about it. + */ + + queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK, + work->work_group,0x1d,0,0,0,NULL,NULL, + True,False,d->bcast_ip,d->bcast_ip); + } + } + } + } } /******************************************************************* - what to do if a master browser DOESN't exist + what to do if a master browser DOESN't exist. + + option 1: force an election, and participate in it + option 2: force an election, and let everyone else participate. + ******************************************************************/ void browser_gone(char *work_name, struct in_addr ip) { @@ -119,24 +124,37 @@ void browser_gone(char *work_name, struct in_addr ip) if (ip_equal(d->bcast_ip,wins_ip)) return; - if (strequal(work->work_group, lp_workgroup())) + if (strequal(work->work_group, myworkgroup)) { + if (lp_local_master()) + { + /* we have discovered that there is no local master + browser, and we are configured to initiate + an election under exactly such circumstances. + */ DEBUG(2,("Forcing election on %s %s\n", work->work_group,inet_ntoa(d->bcast_ip))); /* we can attempt to become master browser */ work->needelection = True; - } - else - { - /* local interfaces: force an election */ - send_election(d, work->work_group, 0, 0, myname); - - /* only removes workgroup completely on a local interface - persistent lmhosts entries on a local interface _will_ be removed). - */ - remove_workgroup(d, work,True); + } + else + { + /* we need to force an election, because we are configured + not to _become_ the local master, but we still _need_ one, + having detected that one doesn't exist. + */ + + /* local interfaces: force an election */ + send_election(d, work->work_group, 0, 0, myname); + + /* only removes workgroup completely on a local interface + persistent lmhosts entries on a local interface _will_ be removed). + */ + remove_workgroup(d, work,True); + add_workgroup_to_subnet(d, work->work_group); + } } } @@ -199,15 +217,15 @@ void name_unregister_work(struct subnet_record *d, char *name, int name_type) { remove_type_local |= SV_TYPE_MASTER_BROWSER; } - if (AM_MASTER(work) && strequal(name, lp_workgroup()) && name_type == 0x1d) + if (AM_MASTER(work) && strequal(name, myworkgroup) && name_type == 0x1d) { remove_type_local |= SV_TYPE_MASTER_BROWSER; } - if (AM_DOMMST(work) && strequal(name, lp_workgroup()) && name_type == 0x1b) + if (AM_DOMMST(work) && strequal(name, myworkgroup) && name_type == 0x1b) { remove_type_domain |= SV_TYPE_DOMAIN_MASTER; } - if (AM_DOMMEM(work) && strequal(name, lp_workgroup()) && name_type == 0x1c) + if (AM_DOMMEM(work) && strequal(name, myworkgroup) && name_type == 0x1c) { remove_type_logon|= SV_TYPE_DOMAIN_MEMBER; } @@ -228,47 +246,48 @@ void name_unregister_work(struct subnet_record *d, char *name, int name_type) void name_register_work(struct subnet_record *d, char *name, int name_type, int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast) { - enum name_source source = (ismyip(ip) || ip_equal(ip, ipzero)) ? + enum name_source source = (ismyip(ip) || ip_equal(ip, ipzero)) ? SELF : REGISTER; - if (source == SELF) - { - struct work_record *work = find_workgroupstruct(d, lp_workgroup(), False); + if (source == SELF) + { + struct work_record *work = find_workgroupstruct(d, + myworkgroup, False); - add_netbios_entry(d,name,name_type,nb_flags,ttl,source,ip,True,!bcast); + add_netbios_entry(d,name,name_type,nb_flags,ttl,source,ip,True,!bcast); - if (work) - { - int add_type_local = False; - int add_type_domain = False; - int add_type_logon = False; - - DEBUG(4,("checking next stage: name_register_work %s\n", name)); - - /* work out what to become, from the name type being added */ - - if (ms_browser_name(name, name_type)) - { - add_type_local = True; - } - if (strequal(name, lp_workgroup()) && name_type == 0x1d) - { - add_type_local = True; - } - if (strequal(name, lp_workgroup()) && name_type == 0x1b) - { - add_type_domain = True; - } - if (strequal(name, lp_workgroup()) && name_type == 0x1c) - { - add_type_logon = True; - } - - if (add_type_local ) become_local_master (d, work); - if (add_type_domain) become_domain_master(d, work); - if (add_type_logon ) become_logon_server (d, work); - } - } + if (work) + { + int add_type_local = False; + int add_type_domain = False; + int add_type_logon = False; + + DEBUG(4,("checking next stage: name_register_work %s\n", name)); + + /* work out what to become, from the name type being added */ + + if (ms_browser_name(name, name_type)) + { + add_type_local = True; + } + if (strequal(name, myworkgroup) && name_type == 0x1d) + { + add_type_local = True; + } + if (strequal(name, myworkgroup) && name_type == 0x1b) + { + add_type_domain = True; + } + if (strequal(name, myworkgroup) && name_type == 0x1c) + { + add_type_logon = True; + } + + if (add_type_local ) become_local_master (d, work); + if (add_type_domain) become_domain_master(d, work); + if (add_type_logon ) become_logon_server (d, work); + } + } } @@ -303,17 +322,18 @@ void become_local_master(struct subnet_record *d, struct work_record *work) */ uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT; - if (!work || !d) return; + if (!work || !d) + return; DEBUG(2,("Becoming master for %s %s (currently at stage %d)\n", - work->work_group,inet_ntoa(d->bcast_ip),work->mst_state)); + work->work_group,inet_ntoa(d->bcast_ip),work->mst_state)); switch (work->mst_state) { case MST_POTENTIAL: /* while we were nothing but a server... */ { DEBUG(3,("go to first stage: register ^1^2__MSBROWSE__^2^1\n")); - work->mst_state = MST_BACK; /* ... an election win was successful */ + work->mst_state = MST_BACK; /* an election win was successful */ work->ElectionCriterion |= 0x5; @@ -322,7 +342,7 @@ void become_local_master(struct subnet_record *d, struct work_record *work) add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True); /* add special browser name */ - add_my_name_entry(d,MSBROWSE ,0x01,nb_type|NB_ACTIVE|NB_GROUP); + add_my_name_entry(d,MSBROWSE,0x01,nb_type|NB_ACTIVE|NB_GROUP); /* DON'T do anything else after calling add_my_name_entry() */ break; @@ -331,7 +351,7 @@ void become_local_master(struct subnet_record *d, struct work_record *work) case MST_BACK: /* while nothing had happened except we won an election... */ { DEBUG(3,("go to second stage: register as master browser\n")); - work->mst_state = MST_MSB; /* ... registering MSBROWSE was successful */ + work->mst_state = MST_MSB; /* registering MSBROWSE was successful */ /* add server entry on successful registration of MSBROWSE */ add_server_entry(d,work,work->work_group,domain_type,0,myname,True); @@ -346,49 +366,33 @@ void become_local_master(struct subnet_record *d, struct work_record *work) case MST_MSB: /* while we were still only registered MSBROWSE state... */ { DEBUG(3,("2nd stage complete: registered as master browser\n")); - work->mst_state = MST_BROWSER; /* ... registering WORKGROUP(1d) succeeded */ + work->mst_state = MST_BROWSER; /* registering WORKGROUP(1d) succeeded */ /* update our server status */ work->ServerType |= SV_TYPE_MASTER_BROWSER; - DEBUG(3,("become_local_master: updating our server %s to type %x\n", myname, work->ServerType)); + DEBUG(3,("become_local_master: updating our server %s to type %x\n", + myname, work->ServerType)); add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True); if (work->serverlist == NULL) /* no servers! */ { /* ask all servers on our local net to announce to us */ - /* XXXX OOPS! add_server_entry will always add one entry - our own. */ + /* XXXX OOPS! add_server_entry always adds one entry - ours. */ announce_request(work, d->bcast_ip); } - /* If we have WINS support or are a WINS server we must add - the workgroup we just became master browser for to the - WINS subnet. This is needed so we have somewhere to save - server lists when we do browser synchronization. */ - if(wins_subnet != 0) - { - if(find_workgroupstruct(wins_subnet, work->work_group, True) == 0) - DEBUG(0, ("become_local_master: \ -Failed to add workgroup %s to WINS subnet.\n", - work->work_group)); - else - DEBUG(3, ("become_local_master: Added workgroup %s to WINS subnet.\n", - work->work_group)); - - /* Reset the announce master timer so that we do an announce as soon as possible - now we are a master. */ - reset_announce_timer(); - } + /* Reset the announce master timer so that we do an announce as soon as possible + now we are a master. */ + reset_announce_timer(); break; - } case MST_BROWSER: { /* don't have to do anything: just report success */ DEBUG(3,("3rd stage: become master browser!\n")); - break; } } @@ -438,7 +442,7 @@ void become_domain_master(struct subnet_record *d, struct work_record *work) work->dom_state = DOMAIN_WAIT; /* XXXX the 0x1b is domain master browser name */ - add_my_name_entry(d, lp_workgroup(),0x1b,nb_type|NB_ACTIVE|NB_GROUP); + add_my_name_entry(d, myworkgroup,0x1b,nb_type|NB_ACTIVE|NB_GROUP); /* DON'T do anything else after calling add_my_name_entry() */ break; @@ -505,7 +509,7 @@ void become_logon_server(struct subnet_record *d, struct work_record *work) work->log_state = LOGON_WAIT; /* XXXX the 0x1c is apparently something to do with domain logons */ - add_my_name_entry(d, lp_workgroup(),0x1c,nb_type|NB_ACTIVE|NB_GROUP); + add_my_name_entry(d, myworkgroup,0x1c,nb_type|NB_ACTIVE|NB_GROUP); /* DON'T do anything else after calling add_my_name_entry() */ break; @@ -749,7 +753,7 @@ void process_election(struct packet_struct *p,char *buf) for (work = d->workgrouplist; work; work = work->next) { - if (!strequal(work->work_group, lp_workgroup())) + if (!strequal(work->work_group, myworkgroup)) continue; if (win_election(work, version,criterion,timeup,name)) { diff --git a/source3/nameresp.c b/source3/nameresp.c index f2b3ba167a..27796ec07c 100644 --- a/source3/nameresp.c +++ b/source3/nameresp.c @@ -263,13 +263,13 @@ struct response_record *queue_netbios_pkt_wins( if ((!lp_wins_support()) && (*lp_wins_server())) { /* samba is not a WINS server, and we are using a WINS server */ - struct in_addr wins_ip; - wins_ip = *interpret_addr2(lp_wins_server()); + struct in_addr real_wins_ip; + real_wins_ip = *interpret_addr2(lp_wins_server()); - if (!zero_ip(wins_ip)) + if (!zero_ip(real_wins_ip)) { bcast = False; - send_ip = wins_ip; + send_ip = real_wins_ip; } else { diff --git a/source3/nameserv.c b/source3/nameserv.c index 022b5521a2..9163642896 100644 --- a/source3/nameserv.c +++ b/source3/nameserv.c @@ -37,6 +37,7 @@ extern int DEBUGLEVEL; extern pstring scope; extern pstring myname; +extern fstring myworkgroup; extern struct in_addr ipzero; extern struct in_addr wins_ip; @@ -141,6 +142,9 @@ void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags) } else { + DEBUG(4,("add_my_name_entry registering name %s with WINS server.\n", + name)); + /* a time-to-live allows us to refresh this name with the WINS server. */ queue_netbios_pkt_wins(ClientNMB, re_reg ? NMB_REG_REFRESH : NMB_REG, NAME_REGISTER, @@ -179,33 +183,32 @@ void add_domain_names(time_t t) for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d)) { - work = find_workgroupstruct(d, lp_workgroup(), False); + work = find_workgroupstruct(d, myworkgroup, False); if (lp_domain_logons() && work && work->log_state == LOGON_NONE) { - make_nmb_name(&n,lp_workgroup(),0x1c,scope); + make_nmb_name(&n,myworkgroup,0x1c,scope); if (!find_name(d->namelist, &n, FIND_SELF)) { /* logon servers are group names - we don't expect this to fail. */ DEBUG(0,("%s attempting to become logon server for %s %s\n", - timestring(), lp_workgroup(), inet_ntoa(d->bcast_ip))); + timestring(), myworkgroup, inet_ntoa(d->bcast_ip))); become_logon_server(d, work); } } } - if(wins_subnet != 0) - work = find_workgroupstruct(wins_subnet, lp_workgroup(), False); - - if (lp_domain_master() && work && work->dom_state == DOMAIN_NONE) - { - - DEBUG(0,("add_domain_names:Checking for domain master on workgroup %s\n", lp_workgroup())); + for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d)) + { + work = find_workgroupstruct(d, myworkgroup, True); - make_nmb_name(&n,lp_workgroup(),0x1b,scope); - if (!find_name(wins_subnet->namelist, &n, FIND_SELF)) + if (lp_domain_master() && work && work->dom_state == DOMAIN_NONE) + { + make_nmb_name(&n,myworkgroup,0x1b,scope); + if (!find_name(d->namelist, &n, FIND_SELF)) { - DEBUG(0,("add_domain_names: attempting to become domain master browser on workgroup %s\n", - lp_workgroup())); + DEBUG(0,("%s add_domain_names: attempting to become domain master \ +browser on workgroup %s %s\n", + timestring(), myworkgroup, inet_ntoa(d->bcast_ip))); if (lp_wins_support()) { @@ -216,8 +219,8 @@ void add_domain_names(time_t t) */ DEBUG(1,("%s initiating becoming domain master for %s\n", - timestring(), lp_workgroup())); - become_domain_master(wins_subnet, work); + timestring(), myworkgroup)); + become_domain_master(d, work); } else { @@ -228,15 +231,17 @@ void add_domain_names(time_t t) NetBIOS name 0x1b. */ - DEBUG(0,("add_domain_names:querying WINS for domain master on workgroup %s\n", lp_workgroup())); + DEBUG(0,("add_domain_names:querying WINS for domain master \ +on workgroup %s\n", myworkgroup)); queue_netbios_pkt_wins(ClientNMB,NMB_QUERY,NAME_QUERY_DOMAIN, - lp_workgroup(), 0x1b, + myworkgroup, 0x1b, 0, 0,0,NULL,NULL, False, False, ipzero, ipzero); } } } + } } @@ -255,7 +260,6 @@ void add_my_names(void) for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d)) { BOOL wins = (lp_wins_support() && (d == wins_subnet)); - struct work_record *work = find_workgroupstruct(d, lp_workgroup(), False); add_my_name_entry(d, myname,0x20,nb_type|NB_ACTIVE); add_my_name_entry(d, myname,0x03,nb_type|NB_ACTIVE); diff --git a/source3/nameservreply.c b/source3/nameservreply.c index e1738007df..00e940df67 100644 --- a/source3/nameservreply.c +++ b/source3/nameservreply.c @@ -528,7 +528,8 @@ void reply_name_query(struct packet_struct *p) } } - DEBUG(3,("Name query ")); + DEBUG(3,("Name query from %s for name %s<0x%x>\n", + inet_ntoa(p->ip), question->name, question->name_type)); if (search == 0) { diff --git a/source3/namework.c b/source3/namework.c index 218a7a349e..23d48d9ced 100644 --- a/source3/namework.c +++ b/source3/namework.c @@ -37,6 +37,7 @@ extern pstring scope; extern BOOL CanRecurse; extern pstring myname; +extern fstring myworkgroup; extern int ClientNMB; extern int ClientDGRAM; @@ -603,7 +604,7 @@ static void process_reset_browser(struct packet_struct *p,char *buf) struct work_record *work; for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True)); } - add_my_subnets(lp_workgroup()); + add_my_subnets(myworkgroup); } /* stop browsing altogether. i don't think this is a good idea! */ @@ -639,7 +640,7 @@ static void process_announce_request(struct packet_struct *p,char *buf) this workgroup before announcing, particularly as we only respond on local interfaces anyway. - if (strequal(dgram->dest_name, lp_workgroup()) return; ??? + if (strequal(dgram->dest_name, myworkgroup) return; ??? */ if (!d) diff --git a/source3/nmbd/nmbd.c b/source3/nmbd/nmbd.c index 550f3198f7..11f005b785 100644 --- a/source3/nmbd/nmbd.c +++ b/source3/nmbd/nmbd.c @@ -40,6 +40,7 @@ int ClientDGRAM = -1; extern pstring myhostname; static pstring host_file; extern pstring myname; +extern fstring myworkgroup; /* are we running as a daemon ? */ static BOOL is_daemon = False; @@ -67,7 +68,7 @@ static int sig_term() /* announce all server entries as 0 time-to-live, 0 type */ /* XXXX don't care if we never receive a response back... yet */ - remove_my_servers(); + announce_my_servers_removed(); /* XXXX other things: if we are a master browser, force an election? */ @@ -203,9 +204,6 @@ BOOL reload_services(BOOL test) reload_services(True); } - load_interfaces(); - add_subnet_interfaces(); - /* Do a sanity check for a misconfigured nmbd */ if(lp_wins_support() && *lp_wins_server()) { DEBUG(0,("ERROR: both 'wins support = true' and 'wins server = ' \ @@ -502,6 +500,8 @@ static void usage(char *pname) reload_services(True); + strcpy(myworkgroup, lp_workgroup()); + set_samba_nb_type(); if (!is_daemon && !is_a_socket(0)) { @@ -549,15 +549,16 @@ static void usage(char *pname) DEBUG(3,("Loaded hosts file\n")); } + load_interfaces(); + add_my_subnets(myworkgroup); + add_my_names(); - if (strequal(lp_workgroup(),"*")) { + if (strequal(myworkgroup,"*")) { DEBUG(0,("ERROR: a workgroup name of * is no longer supported\n")); exit(1); } - add_my_subnets(lp_workgroup()); - DEBUG(3,("Checked names\n")); load_netbios_names(); diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 40611e4c3a..af0b05bb5d 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -152,8 +152,11 @@ typedef struct int os_level; int max_ttl; int ReadSize; + int shmem_size; + int shmem_hash_size; BOOL bWINSsupport; BOOL bWINSproxy; + BOOL bLocalMaster; BOOL bPreferredMaster; BOOL bDomainMaster; BOOL bDomainLogons; @@ -427,6 +430,8 @@ struct parm_struct {"deadtime", P_INTEGER, P_GLOBAL, &Globals.deadtime, NULL}, {"time offset", P_INTEGER, P_GLOBAL, &extra_time_offset, NULL}, {"read size", P_INTEGER, P_GLOBAL, &Globals.ReadSize, NULL}, + {"shared mem size", P_INTEGER, P_GLOBAL, &Globals.shmem_size, NULL}, + {"shared file entries", P_INTEGER, P_GLOBAL, &Globals.shmem_hash_size, NULL}, #ifdef KANJI {"coding system", P_INTEGER, P_GLOBAL, &coding_system, handle_coding_system}, #endif /* KANJI */ @@ -437,6 +442,7 @@ struct parm_struct {"wins server", P_STRING, P_GLOBAL, &Globals.szWINSserver, NULL}, {"preferred master", P_BOOL, P_GLOBAL, &Globals.bPreferredMaster, NULL}, {"prefered master", P_BOOL, P_GLOBAL, &Globals.bPreferredMaster, NULL}, + {"local master", P_BOOL, P_GLOBAL, &Globals.bLocalMaster, NULL}, {"domain master", P_BOOL, P_GLOBAL, &Globals.bDomainMaster, NULL}, {"domain logons", P_BOOL, P_GLOBAL, &Globals.bDomainLogons, NULL}, {"browse list", P_BOOL, P_GLOBAL, &Globals.bBrowseList, NULL}, @@ -601,15 +607,11 @@ static void init_globals(void) Globals.bSyslogOnly = False; Globals.os_level = 0; Globals.max_ttl = 60*60*4; /* 2 hours default */ - Globals.bPreferredMaster = True; - Globals.bDomainMaster = False; - Globals.bDomainLogons = False; - Globals.bBrowseList = True; - Globals.bWINSsupport = False; - Globals.bWINSproxy = False; Globals.ReadSize = 16*1024; + Globals.shmem_size = SHMEM_SIZE; + Globals.shmem_hash_size = SHMEM_HASH_SIZE; Globals.bUnixRealname = False; -#ifdef NETGROUP +#if (defined(NETGROUP) && defined(AUTOMOUNT)) Globals.bNISHomeMap = False; string_set(&Globals.szNISHomeMapName, "auto.home"); #endif @@ -617,6 +619,25 @@ static void init_globals(void) coding_system = interpret_coding_system (KANJI, SJIS_CODE); #endif /* KANJI */ +/* these parameters are set to defaults that are more appropriate + for the increasing samba install base: + + as a member of the workgroup, that will possibly become a + _local_ master browser (lm = True). this is opposed to a forced + local master browser startup (pm = True). + + doesn't provide WINS server service by default (wsupp = False), + and doesn't provide domain master browser services by default, either. + +*/ + + Globals.bPreferredMaster = False; + Globals.bLocalMaster = True; + Globals.bDomainMaster = False; + Globals.bDomainLogons = False; + Globals.bBrowseList = True; + Globals.bWINSsupport = False; + Globals.bWINSproxy = False; } /*************************************************************************** @@ -771,6 +792,7 @@ FN_GLOBAL_STRING(lp_nis_home_map_name,&Globals.szNISHomeMapName) FN_GLOBAL_BOOL(lp_wins_support,&Globals.bWINSsupport) FN_GLOBAL_BOOL(lp_wins_proxy,&Globals.bWINSproxy) +FN_GLOBAL_BOOL(lp_local_master,&Globals.bLocalMaster) FN_GLOBAL_BOOL(lp_domain_master,&Globals.bDomainMaster) FN_GLOBAL_BOOL(lp_domain_logons,&Globals.bDomainLogons) FN_GLOBAL_BOOL(lp_preferred_master,&Globals.bPreferredMaster) @@ -799,6 +821,8 @@ FN_GLOBAL_INTEGER(lp_maxpacket,&Globals.max_packet) FN_GLOBAL_INTEGER(lp_keepalive,&keepalive) FN_GLOBAL_INTEGER(lp_passwordlevel,&Globals.pwordlevel) FN_GLOBAL_INTEGER(lp_readsize,&Globals.ReadSize) +FN_GLOBAL_INTEGER(lp_shmem_size,&Globals.shmem_size) +FN_GLOBAL_INTEGER(lp_shmem_hash_size,&Globals.shmem_hash_size) FN_GLOBAL_INTEGER(lp_deadtime,&Globals.deadtime) FN_GLOBAL_INTEGER(lp_maxprotocol,&Globals.maxprotocol) FN_GLOBAL_INTEGER(lp_security,&Globals.security) diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index 2437b8b17e..bc099dd1e8 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -433,6 +433,7 @@ BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mo BOOL isrootdir; pstring filename; BOOL matched; + BOOL needslash; *path = *pathreal = *filename = 0; @@ -440,6 +441,9 @@ BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mo strequal(Connections[cnum].dirpath,".") || strequal(Connections[cnum].dirpath,"/")); + needslash = + ( Connections[cnum].dirpath[strlen(Connections[cnum].dirpath) -1] != '/'); + if (!Connections[cnum].dirptr) return(False); @@ -467,7 +471,8 @@ BOOL get_dir_entry(int cnum,char *mask,int dirtype,char *fname,int *size,int *mo strcpy(fname,filename); *path = 0; strcpy(path,Connections[cnum].dirpath); - strcat(path,"/"); + if(needslash) + strcat(path,"/"); strcpy(pathreal,path); strcat(path,fname); strcat(pathreal,dname); diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c index 1f1ac8600a..8b9fb485ae 100644 --- a/source3/smbd/ipc.c +++ b/source3/smbd/ipc.c @@ -37,6 +37,7 @@ extern files_struct Files[]; extern connection_struct Connections[]; extern fstring local_machine; +extern fstring myworkgroup; #define NERR_Success 0 #define NERR_badpass 86 @@ -812,7 +813,7 @@ static int get_server_info(uint32 servertype, if (!next_token(&ptr,s->comment, NULL)) continue; if (!next_token(&ptr,s->domain , NULL)) { /* this allows us to cope with an old nmbd */ - strcpy(s->domain,lp_workgroup()); + strcpy(s->domain,myworkgroup); } if (sscanf(stype,"%X",&s->type) != 1) { @@ -982,7 +983,7 @@ static BOOL api_RNetServerEnum(int cnum, uint16 vuid, char *param, char *data, if (strcmp(str1, "WrLehDz") == 0) { StrnCpy(domain, p, sizeof(fstring)-1); } else { - StrnCpy(domain, lp_workgroup(), sizeof(fstring)-1); + StrnCpy(domain, myworkgroup, sizeof(fstring)-1); } if (lp_browse_list()) @@ -1668,7 +1669,7 @@ static BOOL api_RNetServerGetInfo(int cnum,uint16 vuid, char *param,char *data, strcpy(comment,lp_serverstring()); - if ((count=get_server_info(SV_TYPE_ALL,&servers,lp_workgroup()))>0) { + if ((count=get_server_info(SV_TYPE_ALL,&servers,myworkgroup))>0) { for (i=0;iref_count > 0) && - (((int32)sbuf->st_dev) == fd_ptr->dev) && - (((int32)sbuf->st_ino) == fd_ptr->inode)) { + (((uint32)sbuf->st_dev) == fd_ptr->dev) && + (((uint32)sbuf->st_ino) == fd_ptr->inode)) { fd_ptr->ref_count++; DEBUG(3, ("Re-used file_fd_struct %d, dev = %x, inode = %x, ref_count = %d\n", @@ -861,8 +861,8 @@ file_fd_struct *fd_get_new() for(i = 0; i < MAX_OPEN_FILES; i++) { fd_ptr = &FileFd[i]; if(fd_ptr->ref_count == 0) { - fd_ptr->dev = (int32)-1; - fd_ptr->inode = (int32)-1; + fd_ptr->dev = (uint32)-1; + fd_ptr->inode = (uint32)-1; fd_ptr->fd = -1; fd_ptr->fd_readonly = -1; fd_ptr->fd_writeonly = -1; @@ -927,8 +927,8 @@ int fd_attempt_close(file_fd_struct *fd_ptr) fd_ptr->fd_readonly = -1; fd_ptr->fd_writeonly = -1; fd_ptr->real_open_flags = -1; - fd_ptr->dev = -1; - fd_ptr->inode = -1; + fd_ptr->dev = (uint32)-1; + fd_ptr->inode = (uint32)-1; } } return fd_ptr->ref_count; @@ -1124,8 +1124,8 @@ void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct stat *s sbuf = &statbuf; } /* Set the correct entries in fd_ptr. */ - fd_ptr->dev = (int32)sbuf->st_dev; - fd_ptr->inode = (int32)sbuf->st_ino; + fd_ptr->dev = (uint32)sbuf->st_dev; + fd_ptr->inode = (uint32)sbuf->st_ino; Files[fnum].fd_ptr = fd_ptr; Connections[cnum].num_files_open++; @@ -1141,7 +1141,6 @@ void open_file(int fnum,int cnum,char *fname1,int flags,int mode, struct stat *s Files[fnum].can_read = ((flags & O_WRONLY)==0); Files[fnum].can_write = ((flags & (O_WRONLY|O_RDWR))!=0); Files[fnum].share_mode = 0; - Files[fnum].share_pending = False; Files[fnum].print_file = Connections[cnum].printer; Files[fnum].modified = False; Files[fnum].cnum = cnum; @@ -1241,38 +1240,49 @@ close a file - possibly invalidating the read prediction ****************************************************************************/ void close_file(int fnum) { - int cnum = Files[fnum].cnum; - invalidate_read_prediction(Files[fnum].fd_ptr->fd); - Files[fnum].open = False; + files_struct *fs_p = &Files[fnum]; + int cnum = fs_p->cnum; + uint32 dev = fs_p->fd_ptr->dev; + uint32 inode = fs_p->fd_ptr->inode; + share_lock_token token; + + invalidate_read_prediction(fs_p->fd_ptr->fd); + fs_p->open = False; Connections[cnum].num_files_open--; - if(Files[fnum].wbmpx_ptr) + if(fs_p->wbmpx_ptr) { - free((char *)Files[fnum].wbmpx_ptr); - Files[fnum].wbmpx_ptr = NULL; + free((char *)fs_p->wbmpx_ptr); + fs_p->wbmpx_ptr = NULL; } #if USE_MMAP - if(Files[fnum].mmap_ptr) + if(fs_p->mmap_ptr) { - munmap(Files[fnum].mmap_ptr,Files[fnum].mmap_size); - Files[fnum].mmap_ptr = NULL; + munmap(fs_p->mmap_ptr,fs_p->mmap_size); + fs_p->mmap_ptr = NULL; } #endif if (lp_share_modes(SNUM(cnum))) - del_share_mode(fnum); + { + lock_share_entry( cnum, dev, inode, &token); + del_share_mode(token, fnum); + } + + fd_attempt_close(fs_p->fd_ptr); - fd_attempt_close(Files[fnum].fd_ptr); + if (lp_share_modes(SNUM(cnum))) + unlock_share_entry( cnum, dev, inode, token); /* NT uses smbclose to start a print - weird */ - if (Files[fnum].print_file) + if (fs_p->print_file) print_file(fnum); /* check for magic scripts */ check_magic(fnum,cnum); DEBUG(2,("%s %s closed file %s (numopen=%d)\n", - timestring(),Connections[cnum].user,Files[fnum].name, + timestring(),Connections[cnum].user,fs_p->name, Connections[cnum].num_files_open)); } @@ -1334,17 +1344,44 @@ return True if sharing doesn't prevent the operation ********************************************************************/ BOOL check_file_sharing(int cnum,char *fname) { - int pid=0; - int share_mode = get_share_mode_byname(cnum,fname,&pid); + int i; + int ret = False; + min_share_mode_entry *old_shares = 0; + int num_share_modes; + struct stat sbuf; + share_lock_token token; + int pid = getpid(); - if (!pid || !share_mode) return(True); - - if (share_mode == DENY_DOS) - return(pid == getpid()); + if(!lp_share_modes(SNUM(cnum))) + return True; + + if (stat(fname,&sbuf) == -1) return(True); + + lock_share_entry(cnum, (uint32)sbuf.st_dev, (uint32)sbuf.st_ino, &token); + num_share_modes = get_share_modes(cnum, token, + (uint32)sbuf.st_dev, (uint32)sbuf.st_ino, &old_shares); + + for( i = 0; i < num_share_modes; i++) + { + if (old_shares[i].share_mode != DENY_DOS) + goto free_and_exit; + + if(old_shares[i].pid != pid); + goto free_and_exit; + } /* XXXX exactly what share mode combinations should be allowed for deleting/renaming? */ - return(False); + /* If we got here then either there were no share modes or + all share modes were DENY_DOS and the pid == getpid() */ + ret = True; + +free_and_exit: + + unlock_share_entry(cnum, (uint32)sbuf.st_dev, (uint32)sbuf.st_ino, token); + if(old_shares != NULL) + free((char *)old_shares); + return(ret); } /**************************************************************************** @@ -1373,25 +1410,31 @@ open a file with a share mode void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun, int mode,int *Access,int *action) { + files_struct *fs_p = &Files[fnum]; int flags=0; int flags2=0; int deny_mode = (share_mode>>4)&7; struct stat sbuf; BOOL file_existed = file_exist(fname,&sbuf); + BOOL share_locked = False; BOOL fcbopen = False; - int share_pid=0; + share_lock_token token; + uint32 dev = 0; + uint32 inode = 0; - Files[fnum].open = False; - Files[fnum].fd_ptr = 0; + fs_p->open = False; + fs_p->fd_ptr = 0; /* this is for OS/2 EAs - try and say we don't support them */ - if (strstr(fname,".+,;=[].")) { + if (strstr(fname,".+,;=[].")) + { unix_ERR_class = ERRDOS; unix_ERR_code = ERROR_EAS_NOT_SUPPORTED; return; } - if ((ofun & 0x3) == 0 && file_existed) { + if ((ofun & 0x3) == 0 && file_existed) + { errno = EEXIST; return; } @@ -1405,7 +1448,7 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun, append does not mean the same thing under dos and unix */ switch (share_mode&0xF) - { + { case 1: flags = O_WRONLY; break; @@ -1419,18 +1462,21 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun, default: flags = O_RDONLY; break; - } + } if (flags != O_RDONLY && file_existed && - (!CAN_WRITE(cnum) || IS_DOS_READONLY(dos_mode(cnum,fname,&sbuf)))) { - if (!fcbopen) { + (!CAN_WRITE(cnum) || IS_DOS_READONLY(dos_mode(cnum,fname,&sbuf)))) + { + if (!fcbopen) + { errno = EACCES; return; } flags = O_RDONLY; } - if (deny_mode > DENY_NONE && deny_mode!=DENY_FCB) { + if (deny_mode > DENY_NONE && deny_mode!=DENY_FCB) + { DEBUG(2,("Invalid deny mode %d on file %s\n",deny_mode,fname)); errno = EINVAL; return; @@ -1438,21 +1484,36 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun, if (deny_mode == DENY_FCB) deny_mode = DENY_DOS; - if (lp_share_modes(SNUM(cnum))) { - int old_share=0; + if (lp_share_modes(SNUM(cnum))) + { + int num_shares = 0; + int i; + min_share_mode_entry *old_shares = 0; + if (file_existed) - old_share = get_share_mode(cnum,&sbuf,&share_pid); + { + dev = (uint32)sbuf.st_dev; + inode = (uint32)sbuf.st_ino; + lock_share_entry(cnum, dev, inode, &token); + share_locked = True; + num_shares = get_share_modes(cnum, token, dev, inode, &old_shares); + } - if (share_pid) { + for(i = 0; i < num_shares; i++) + { /* someone else has a share lock on it, check to see if we can too */ - int old_open_mode = old_share&0xF; - int old_deny_mode = (old_share>>4)&7; + int old_open_mode = old_shares[i].share_mode &0xF; + int old_deny_mode = (old_shares[i].share_mode >>4)&7; - if (deny_mode > 4 || old_deny_mode > 4 || old_open_mode > 2) { + if (deny_mode > 4 || old_deny_mode > 4 || old_open_mode > 2) + { DEBUG(2,("Invalid share mode (%d,%d,%d) on file %s\n", deny_mode,old_deny_mode,old_open_mode,fname)); + free((char *)old_shares); + if(share_locked) + unlock_share_entry(cnum, dev, inode, token); errno = EACCES; unix_ERR_class = ERRDOS; unix_ERR_code = ERRbadshare; @@ -1461,21 +1522,25 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun, { int access_allowed = access_table(deny_mode,old_deny_mode,old_open_mode, - share_pid,fname); + old_shares[i].pid,fname); if ((access_allowed == AFAIL) || (!fcbopen && (access_allowed == AREAD && flags == O_RDWR)) || (access_allowed == AREAD && flags == O_WRONLY) || - (access_allowed == AWRITE && flags == O_RDONLY)) { + (access_allowed == AWRITE && flags == O_RDONLY)) + { DEBUG(2,("Share violation on file (%d,%d,%d,%d,%s) = %d\n", deny_mode,old_deny_mode,old_open_mode, - share_pid,fname, + old_shares[i].pid,fname, access_allowed)); + free((char *)old_shares); + if(share_locked) + unlock_share_entry(cnum, dev, inode, token); errno = EACCES; unix_ERR_class = ERRDOS; unix_ERR_code = ERRbadshare; return; - } + } if (access_allowed == AREAD) flags = O_RDONLY; @@ -1484,76 +1549,69 @@ void open_file_shared(int fnum,int cnum,char *fname,int share_mode,int ofun, flags = O_WRONLY; } } + if(old_shares != 0) + free((char *)old_shares); } DEBUG(4,("calling open_file with flags=0x%X flags2=0x%X mode=0%o\n", flags,flags2,mode)); open_file(fnum,cnum,fname,flags|(flags2&~(O_TRUNC)),mode,file_existed ? &sbuf : 0); - if (!Files[fnum].open && flags==O_RDWR && errno!=ENOENT && fcbopen) { + if (!fs_p->open && flags==O_RDWR && errno!=ENOENT && fcbopen) + { flags = O_RDONLY; open_file(fnum,cnum,fname,flags,mode,file_existed ? &sbuf : 0 ); } - if (Files[fnum].open) { + if (fs_p->open) + { int open_mode=0; - switch (flags) { - case O_RDONLY: - open_mode = 0; - break; - case O_RDWR: - open_mode = 2; - break; - case O_WRONLY: - open_mode = 1; - break; + + if((share_locked == False) && lp_share_modes(SNUM(cnum))) + { + /* We created the file - thus we must now lock the share entry before creating it. */ + dev = fs_p->fd_ptr->dev; + inode = fs_p->fd_ptr->inode; + lock_share_entry(cnum, dev, inode, &token); + share_locked = True; } - Files[fnum].share_mode = (deny_mode<<4) | open_mode; - Files[fnum].share_pending = True; + switch (flags) + { + case O_RDONLY: + open_mode = 0; + break; + case O_RDWR: + open_mode = 2; + break; + case O_WRONLY: + open_mode = 1; + break; + } + + fs_p->share_mode = (deny_mode<<4) | open_mode; - if (Access) { + if (Access) (*Access) = open_mode; - } - - if (action) { + + if (action) + { if (file_existed && !(flags2 & O_TRUNC)) *action = 1; if (!file_existed) *action = 2; if (file_existed && (flags2 & O_TRUNC)) *action = 3; } - if (!share_pid) - share_mode_pending = True; - if ((flags2&O_TRUNC) && file_existed) truncate_unless_locked(fnum,cnum); - } -} - + if (lp_share_modes(SNUM(cnum))) + set_share_mode(token, fnum); + } -/******************************************************************* -check for files that we should now set our share modes on -********************************************************************/ -static void check_share_modes(void) -{ - int i; - for (i=0;i= IDLE_CLOSED_TIMEOUT) { @@ -4082,6 +4124,8 @@ static void usage(char *pname) if (!reload_services(False)) return(-1); + strcpy(myworkgroup, lp_workgroup()); + #ifndef NO_SIGNAL_TEST signal(SIGHUP,SIGNAL_CAST sig_hup); #endif @@ -4128,10 +4172,10 @@ static void usage(char *pname) if (!open_sockets(is_daemon,port)) exit(1); -#if FAST_SHARE_MODES +#ifdef FAST_SHARE_MODES if (!start_share_mode_mgmt()) exit(1); -#endif +#endif /* FAST_SHARE_MODES */ /* possibly reload the services file. */ reload_services(True); diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 38c7031b66..1d9977c66e 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -277,6 +277,7 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l strequal(Connections[cnum].dirpath,"/")); BOOL was_8_3; int nt_extmode; /* Used for NT connections instead of mode */ + BOOL needslash = ( Connections[cnum].dirpath[strlen(Connections[cnum].dirpath) -1] != '/'); *fname = 0; *out_of_space = False; @@ -323,7 +324,8 @@ static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_l continue; strcpy(pathreal,Connections[cnum].dirpath); - strcat(pathreal,"/"); + if(needslash) + strcat(pathreal,"/"); strcat(pathreal,fname); if (sys_stat(pathreal,&sbuf) != 0) { diff --git a/source3/utils/status.c b/source3/utils/status.c index e8e57b3dd7..b439741e6c 100644 --- a/source3/utils/status.c +++ b/source3/utils/status.c @@ -53,6 +53,81 @@ int Ucrit_pid[100]; /* Ugly !!! */ /* added by OH */ int Ucrit_MaxPid=0; /* added by OH */ unsigned int Ucrit_IsActive = 0; /* added by OH */ +#ifndef FAST_SHARE_MODES +static char *read_share_file(int fd, char *fname, char *progname) +{ + struct stat sb; + char *buf; + int size; + + if(fstat(fd, &sb) != 0) + { + printf("%s: ERROR: read_share_file: Failed to do stat on share file %s (%s)\n", + progname, fname, strerror(errno)); + return 0; + } + + if(sb.st_size == 0) + { + return 0; + } + + /* Allocate space for the file */ + if((buf = (char *)malloc(sb.st_size)) == NULL) + { + printf("%s: read_share_file: malloc for file size %d fail !\n", + progname, (int)sb.st_size); + return 0; + } + + if(lseek(fd, 0, SEEK_SET) != 0) + { + printf("%s: ERROR: read_share_file: Failed to reset position to 0 \ +for share file %s (%s)\n", progname, fname, strerror(errno)); + if(buf) + free(buf); + return 0; + } + + if (read(fd,buf,sb.st_size) != sb.st_size) + { + printf("%s: ERROR: read_share_file: Failed to read share file %s (%s)\n", + progname, fname, strerror(errno)); + if(buf) + free(buf); + return 0; + } + + if (IVAL(buf,0) != LOCKING_VERSION) { + printf("%s: ERROR: read_share_file: share file %s has incorrect \ +locking version (was %d, should be %d).\n",fname, + progname, IVAL(buf,0), LOCKING_VERSION); + if(buf) + free(buf); + return 0; + } + + /* 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) + { + printf("%s: ERROR: read_share_file: share file %s is an incorrect length.\n", + progname, fname); + if(buf) + free(buf); + return 0; + } + + return buf; +} +#endif /* FAST_SHARE_MODES */ + int main(int argc, char *argv[]) { FILE *f; @@ -64,16 +139,16 @@ unsigned int Ucrit_IsActive = 0; /* added by OH */ BOOL firstopen=True; BOOL processes_only=False; int last_pid=0; -#if FAST_SHARE_MODES +#ifdef FAST_SHARE_MODES pstring shmem_file_name; - share_mode_record *scanner_p; - share_mode_record *prev_p; + share_mode_record *file_scanner_p; + smb_shm_offset_t *mode_array; int bytes_free, bytes_used, bytes_overhead, bytes_total; -#else - int n; +#else /* FAST_SHARE_MODES */ void *dir; char *s; -#endif +#endif /* FAST_SHARE_MODES */ + int i; struct session_record *ptr; @@ -226,101 +301,110 @@ unsigned int Ucrit_IsActive = 0; /* added by OH */ printf("\n"); -#if FAST_SHARE_MODES +#ifdef FAST_SHARE_MODES /******************************************************************* initialize the shared memory for share_mode management ******************************************************************/ - strcpy(shmem_file_name,lp_lockdir()); trim_string(shmem_file_name,"","/"); if (!*shmem_file_name) exit(-1); strcat(shmem_file_name, "/SHARE_MEM_FILE"); - if(!smb_shm_open(shmem_file_name, SHMEM_SIZE)) exit(-1); + if(!smb_shm_open(shmem_file_name, lp_shmem_size())) exit(-1); - if(!smb_shm_lock()) + mode_array = (smb_shm_offset_t *)smb_shm_offset2addr(smb_shm_get_userdef_off()); + if(mode_array == NULL) { - smb_shm_close(); - exit (-1); + printf("%s: base of shared memory hash array == 0! Exiting.\n", argv[0]); + smb_shm_close(); + exit(-1); } - scanner_p = (share_mode_record *)smb_shm_offset2addr(smb_shm_get_userdef_off()); - prev_p = scanner_p; - while(scanner_p) + for( i = 0; i < lp_shmem_hash_size(); i++) { - int pid,mode; - struct timeval t; - - pid = scanner_p->pid; - - if ( !Ucrit_checkPid(pid) ) - { - prev_p = scanner_p ; - scanner_p = (share_mode_record *)smb_shm_offset2addr(scanner_p->next_offset); - continue; - } + smb_shm_lock_hash_entry(i); + if(mode_array[i] == NULL_OFFSET) + { + smb_shm_unlock_hash_entry(i); + continue; + } + file_scanner_p = (share_mode_record *)smb_shm_offset2addr(mode_array[i]); + while((file_scanner_p != 0) && (file_scanner_p->num_share_mode_entries != 0)) + { + share_mode_entry *entry_scanner_p = + (share_mode_entry *)smb_shm_offset2addr( + file_scanner_p->share_mode_entries); + + while(entry_scanner_p != 0) + { + struct timeval t; + int pid = entry_scanner_p->pid; + int mode = entry_scanner_p->share_mode; - if( (scanner_p->locking_version != LOCKING_VERSION) || !process_exists(pid)) + t.tv_sec = entry_scanner_p->time.tv_sec; + t.tv_usec = entry_scanner_p->time.tv_usec; + strcpy(fname, file_scanner_p->file_name); +#else /* FAST_SHARE_MODES */ + + /* For slow share modes go through all the files in + the share mode directory and read the entries in + each. + */ + + dir = opendir(lp_lockdir()); + if (!dir) { - 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); - } - continue; + printf("%s: Unable to open lock directory %s.\n", argv[0], lp_lockdir()); + return(0); } - t.tv_sec = scanner_p->time.tv_sec; - t.tv_usec = scanner_p->time.tv_usec; - mode = scanner_p->share_mode; - strcpy(fname, scanner_p->file_name); -#else - dir = opendir(lp_lockdir()); - if (!dir) return(0); while ((s=readdirname(dir))) { - char buf[20]; - int pid,mode; - struct timeval t; + char *buf; + char *base; int fd; pstring lname; - int dev,inode; + uint32 dev,inode; - if (sscanf(s,"share.%d.%d",&dev,&inode)!=2) continue; + if (sscanf(s,"share.%u.%u",&dev,&inode)!=2) continue; strcpy(lname,lp_lockdir()); trim_string(lname,NULL,"/"); strcat(lname,"/"); strcat(lname,s); - fd = open(lname,O_RDONLY,0); - if (fd < 0) continue; - if (read(fd,buf,20) != 20) continue; - n = read(fd,fname,sizeof(fname)); - fname[MAX(n,0)]=0; - close(fd); - - t.tv_sec = IVAL(buf,4); - t.tv_usec = IVAL(buf,8); - mode = IVAL(buf,12); - pid = IVAL(buf,16); - - if ( !Ucrit_checkPid(pid) ) /* added by OH */ - continue; - - if (IVAL(buf,0) != LOCKING_VERSION || !process_exists(pid)) { - if (unlink(lname)==0) - printf("Deleted stale share file %s\n",s); - continue; + fd = open(lname,O_RDWR,0); + if (fd < 0) + { + printf("%s: Unable to open share file %s.\n", argv[0], lname); + continue; } -#endif + + /* Lock the share mode file while we read it. */ + if(fcntl_lock(fd, F_SETLKW, 0, 1, F_WRLCK) == False) + { + printf("%s: Unable to lock open share file %s.\n", argv[0], lname); + close(fd); + continue; + } + + if(( buf = read_share_file( fd, lname, argv[0] )) == NULL) + { + close(fd); + continue; + } + strcpy( fname, &buf[10]); + close(fd); + + base = buf + 10 + SVAL(buf,8); + for( i = 0; i < IVAL(buf, 4); i++) + { + char *p = base + (i*16); + struct timeval t; + int pid = IVAL(p,12); + int mode = IVAL(p,8); + + t.tv_sec = IVAL(p,0); + t.tv_usec = IVAL(p,4); +#endif /* FAST_SHARE_MODES */ fname[sizeof(fname)-1] = 0; @@ -349,28 +433,38 @@ unsigned int Ucrit_IsActive = 0; /* added by OH */ } printf(" %s %s",fname,asctime(LocalTime((time_t *)&t.tv_sec))); -#if FAST_SHARE_MODES - prev_p = scanner_p ; - scanner_p = (share_mode_record *)smb_shm_offset2addr(scanner_p->next_offset); - } /* end while */ +#ifdef FAST_SHARE_MODES + + entry_scanner_p = (share_mode_entry *)smb_shm_offset2addr( + entry_scanner_p->next_share_mode_entry); + } /* end while entry_scanner_p */ + file_scanner_p = (share_mode_record *)smb_shm_offset2addr( + file_scanner_p->next_offset); + } /* end while file_scanner_p */ + smb_shm_unlock_hash_entry(i); + } /* end for */ smb_shm_get_usage(&bytes_free, &bytes_used, &bytes_overhead); bytes_total = bytes_free + bytes_used + bytes_overhead; - smb_shm_unlock(); /******************************************************************* deinitialize the shared memory for share_mode management ******************************************************************/ smb_shm_close(); -#else +#else /* FAST_SHARE_MODES */ + } /* end for i */ + + if(buf) + free(buf); + base = 0; } /* end while */ closedir(dir); -#endif +#endif /* FAST_SHARE_MODES */ if (firstopen) printf("No locked files\n"); -#if FAST_SHARE_MODES +#ifdef FAST_SHARE_MODES printf("\nShare mode memory usage (bytes):\n"); printf(" %d(%d%%) free + %d(%d%%) used + %d(%d%%) overhead = %d(100%%) total\n", bytes_free, (bytes_free * 100)/bytes_total, @@ -378,7 +472,7 @@ unsigned int Ucrit_IsActive = 0; /* added by OH */ bytes_overhead, (bytes_overhead * 100)/bytes_total, bytes_total); -#endif +#endif /* FAST_SHARE_MODES */ return (0); } -- cgit