Unix SMB/Netbios implementation.
Version 1.9.
Samba utility functions
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1997
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
pstring user_socket_options="";
pstring sesssetup_user="";
pstring myname = "";
+fstring myworkgroup = "";
int smb_read_error = 0;
/*******************************************************************
case insensitive string compararison
********************************************************************/
-int StrCaseCmp(char *s, char *t)
+int StrCaseCmp(const char *s, const char *t)
{
- for (; tolower(*s) == tolower(*t); ++s, ++t)
- if (!*s) return 0;
+ /* compare until we run out of string, either t or s, or find a difference */
+ while (*s && *t && tolower(*s) == tolower(*t))
+ {
+ s++; t++;
+ }
- return tolower(*s) - tolower(*t);
+ return(tolower(*s) - tolower(*t));
}
/*******************************************************************
case insensitive string compararison, length limited
********************************************************************/
-int StrnCaseCmp(char *s, char *t, int n)
+int StrnCaseCmp(const char *s, const char *t, int n)
{
- while (n-- && *s && *t) {
- if (tolower(*s) != tolower(*t)) return(tolower(*s) - tolower(*t));
+ /* compare until we run out of string, either t or s, or chars */
+ while (n-- && *s && *t && tolower(*s) == tolower(*t))
+ {
s++; t++;
}
+
+ /* not run out of chars - strings are different lengths */
if (n) return(tolower(*s) - tolower(*t));
+ /* identical up to where we run out of chars, and strings are same length */
return(0);
}
{
pstring namecopy;
string_replace(fname,'\\','/');
-#ifndef KANJI
- dos2unix_format(fname, True);
-#endif /* KANJI */
if (*fname == '/')
{
****************************************************************************/
void dos_format(char *fname)
{
-#ifndef KANJI
- unix2dos_format(fname, True);
-#endif /* KANJI */
string_replace(fname,'/','\\');
}
/* remove any double slashes */
string_sub(s, "//","/");
+ /* Remove leading ./ characters */
+ if(strncmp(s, "./", 2) == 0) {
+ trim_string(s, "./", NULL);
+ if(*s == 0)
+ strcpy(s,"./");
+ }
+
while ((p = strstr(s,"/../")) != NULL)
{
pstring s1;
DEBUG(3,("Illegal file name? (%s)\n",s));
return(False);
}
+
+ if (strlen(s) == 0)
+ strcpy(s,"./");
+
return(True);
}
connect_again:
ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out));
- if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY) && loops--) {
+ /* Some systems return EAGAIN when they mean EINPROGRESS */
+ if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+ errno == EAGAIN) && loops--) {
msleep(connect_loop);
goto connect_again;
}
- if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY)) {
+ if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
+ errno == EAGAIN)) {
DEBUG(1,("timeout connecting to %s:%d\n",inet_ntoa(*addr),port));
close(res);
return -1;
}
-/* matchname - determine if host name matches IP address */
+/*******************************************************************
+ matchname - determine if host name matches IP address
+ ******************************************************************/
static BOOL matchname(char *remotehost,struct in_addr addr)
{
struct hostent *hp;
return False;
}
-/* return the DNS name of the client */
+/*******************************************************************
+ Reset the 'done' variables so after a client process is created
+ from a fork call these calls will be re-done. This should be
+ expanded if more variables need reseting.
+ ******************************************************************/
+
+static BOOL global_client_name_done = False;
+static BOOL global_client_addr_done = False;
+
+void reset_globals_after_fork()
+{
+ global_client_name_done = False;
+ global_client_addr_done = False;
+}
+
+/*******************************************************************
+ return the DNS name of the client
+ ******************************************************************/
char *client_name(void)
{
extern int Client;
struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
int length = sizeof(sa);
static pstring name_buf;
- static BOOL done = False;
struct hostent *hp;
- if (done)
+ if (global_client_name_done)
return name_buf;
- done = True;
strcpy(name_buf,"UNKNOWN");
if (getpeername(Client, &sa, &length) < 0) {
strcpy(name_buf,"UNKNOWN");
}
}
+ global_client_name_done = True;
return name_buf;
}
-/* return the IP addr of the client as a string */
+/*******************************************************************
+ return the IP addr of the client as a string
+ ******************************************************************/
char *client_addr(void)
{
extern int Client;
struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
int length = sizeof(sa);
static fstring addr_buf;
- static BOOL done = False;
- if (done)
+ if (global_client_addr_done)
return addr_buf;
- done = True;
strcpy(addr_buf,"0.0.0.0");
if (getpeername(Client, &sa, &length) < 0) {
strcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
+ global_client_addr_done = True;
return addr_buf;
}
return(NULL);
}
- ret = gethostbyname(name2);
+ ret = sys_gethostbyname(name2);
if (ret != NULL)
{
free(name2);
/* try with all lowercase */
strlower(name2);
- ret = gethostbyname(name2);
+ ret = sys_gethostbyname(name2);
if (ret != NULL)
{
free(name2);
/* try with all uppercase */
strupper(name2);
- ret = gethostbyname(name2);
+ ret = sys_gethostbyname(name2);
if (ret != NULL)
{
free(name2);
fstring s;
if (!tested) {
tested = True;
- sprintf(s,"/proc/%05d",getpid());
+ sprintf(s,"/proc/%05d",(int)getpid());
ok = file_exist(s,NULL);
}
if (ok) {
dname = ptr->d_name;
-#ifdef KANJI
{
static pstring buf;
strcpy(buf, dname);
unix_to_dos(buf, True);
dname = buf;
}
-#endif
#ifdef NEXT2
if (telldir(p) < 0) return(NULL);
}
+BOOL is_vetoed_name(char *name)
+{
+ char *namelist = lp_veto_files();
+ char *nameptr = namelist;
+ char *name_end;
+
+ /* if we have no list it's obviously not vetoed */
+ if((nameptr == NULL ) || (*nameptr == '\0'))
+ return 0;
+
+ /* if the name doesn't exist in the list, it's obviously ok too */
+ if(strstr(namelist,name) == NULL )
+ return 0;
+
+ /* now, we need to find the names one by one and check them
+ they can contain spaces and all sorts of stuff so we
+ separate them with of all things '/' which can never be in a filename
+ I could use "" but then I have to break them all out
+ maybe such a routine exists somewhere?
+ */
+ while(*nameptr)
+ {
+ if ( *nameptr == '/' )
+ {
+ nameptr++;
+ continue;
+ }
+ if((name_end = strchr(nameptr,'/'))!=NULL)
+ {
+ *name_end = 0;
+ }
+ /* a match! it's veto'd */
+ if(strcmp(name,nameptr) == 0)
+ return 1;
+ if(name_end == NULL)
+ return 0;
+ /* next segment please */
+ nameptr = name_end + 1;
+ }
+ return 0;
+}
+
+static BOOL is_in_path(char *name, char *namelist)
+{
+ char *nameptr = namelist;
+ char *sub;
+ char *name_end;
+ int len;
+
+ /* if we have no list it's obviously not vetoed */
+ if((nameptr == NULL ) || (*nameptr == '\0'))
+ return 0;
+
+
+ /* now, we need to find the names one by one and check them
+ they can contain spaces and all sorts of stuff so we
+ separate them with of all things '/' which can never be in a filename
+ I could use "" but then I have to break them all out
+ maybe such a routine exists somewhere?
+ */
+ while(*nameptr)
+ {
+ if ( *nameptr == '/' )
+ {
+ nameptr++;
+ continue;
+ }
+ if((name_end = strchr(nameptr,'/'))!=NULL)
+ {
+ *name_end = 0;
+ }
+
+ len = strlen(nameptr);
+ sub = name;
+ /* If the name doesn't exist in the path, try the next name.. */
+ while( sub && ((sub = strstr(sub,nameptr)) != NULL))
+ {
+ /* Is it a whole component? */
+ if(((sub == name) || (sub[-1] == '/'))
+ && ((sub[len] == '\0') || (sub[len] == '/')))
+ {
+ return 1;
+ }
+ /* skip to the next component of the path */
+ sub =strchr(sub,'/');
+ }
+ if(name_end == NULL)
+ return 0;
+ /* next segment please */
+ nameptr = name_end + 1;
+ }
+ return 0;
+}
+
+/****************************************************************************
+used to make files hidden, but still accessible
+****************************************************************************/
+BOOL is_hidden_path(char *path)
+{
+ return is_in_path(path, lp_hide_files());
+}
+
+/****************************************************************************
+used to make files _completely_ inaccessible
+****************************************************************************/
+BOOL is_vetoed_path(char *path)
+{
+ return is_in_path(path, lp_veto_files());
+}
+
+/****************************************************************************
+routine to do file locking
+****************************************************************************/
+BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type)
+{
+#if HAVE_FCNTL_LOCK
+ struct flock lock;
+ int ret;
+
+#if 1
+ uint32 mask = 0xC0000000;
+
+ /* make sure the count is reasonable, we might kill the lockd otherwise */
+ count &= ~mask;
+
+ /* the offset is often strange - remove 2 of its bits if either of
+ the top two bits are set. Shift the top ones by two bits. This
+ still allows OLE2 apps to operate, but should stop lockd from
+ dieing */
+ if ((offset & mask) != 0)
+ offset = (offset & ~mask) | ((offset & mask) >> 2);
+#else
+ uint32 mask = ((unsigned)1<<31);
+
+ /* interpret negative counts as large numbers */
+ if (count < 0)
+ count &= ~mask;
+
+ /* no negative offsets */
+ offset &= ~mask;
+
+ /* count + offset must be in range */
+ while ((offset < 0 || (offset + count < 0)) && mask)
+ {
+ offset &= ~mask;
+ mask = mask >> 1;
+ }
+#endif
+
+
+ DEBUG(5,("fcntl_lock %d %d %d %d %d\n",fd,op,(int)offset,(int)count,type));
+
+ lock.l_type = type;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = (int)offset;
+ lock.l_len = (int)count;
+ lock.l_pid = 0;
+
+ errno = 0;
+
+ ret = fcntl(fd,op,&lock);
+
+ if (errno != 0)
+ DEBUG(3,("fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
+
+ /* a lock query */
+ if (op == F_GETLK)
+ {
+ if ((ret != -1) &&
+ (lock.l_type != F_UNLCK) &&
+ (lock.l_pid != 0) &&
+ (lock.l_pid != getpid()))
+ {
+ DEBUG(3,("fd %d is locked by pid %d\n",fd,lock.l_pid));
+ return(True);
+ }
+
+ /* it must be not locked or locked by me */
+ return(False);
+ }
+
+ /* a lock set or unset */
+ if (ret == -1)
+ {
+ DEBUG(3,("lock failed at offset %d count %d op %d type %d (%s)\n",
+ offset,count,op,type,strerror(errno)));
+
+ /* perhaps it doesn't support this sort of locking?? */
+ if (errno == EINVAL)
+ {
+ DEBUG(3,("locking not supported? returning True\n"));
+ return(True);
+ }
+
+ return(False);
+ }
+
+ /* everything went OK */
+ DEBUG(5,("Lock call successful\n"));
+
+ return(True);
+#else
+ return(False);
+#endif
+}
+
+/*******************************************************************
+lock a file - returning a open file descriptor or -1 on failure
+The timeout is in seconds. 0 means no timeout
+********************************************************************/
+int file_lock(char *name,int timeout)
+{
+ int fd = open(name,O_RDWR|O_CREAT,0666);
+ time_t t=0;
+ if (fd < 0) return(-1);
+
+#if HAVE_FCNTL_LOCK
+ if (timeout) t = time(NULL);
+ while (!timeout || (time(NULL)-t < timeout)) {
+ if (fcntl_lock(fd,F_SETLK,0,1,F_WRLCK)) return(fd);
+ msleep(LOCK_RETRY_TIMEOUT);
+ }
+ return(-1);
+#else
+ return(fd);
+#endif
+}
+
+/*******************************************************************
+unlock a file locked by file_lock
+********************************************************************/
+void file_unlock(int fd)
+{
+ if (fd<0) return;
+#if HAVE_FCNTL_LOCK
+ fcntl_lock(fd,F_SETLK,0,1,F_UNLCK);
+#endif
+ close(fd);
+}
+