From 0e8fd3398771da2f016d72830179507f3edda51b Mon Sep 17 00:00:00 2001 From: Samba Release Account Date: Sat, 4 May 1996 07:50:46 +0000 Subject: Initial version imported to CVS (This used to be commit 291551d80711daab7b7581720bcd9a08d6096517) --- source3/smbd/dir.c | 955 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 955 insertions(+) create mode 100644 source3/smbd/dir.c (limited to 'source3/smbd/dir.c') diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c new file mode 100644 index 0000000000..ac6f918b9d --- /dev/null +++ b/source3/smbd/dir.c @@ -0,0 +1,955 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + Directory handling routines + Copyright (C) Andrew Tridgell 1992-1995 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "loadparm.h" + +extern int DEBUGLEVEL; +extern connection_struct Connections[]; + +/* + This module implements directory related functions for Samba. +*/ + + + +uint32 dircounter = 0; + + +#define NUMDIRPTRS 256 + + +static struct dptr_struct +{ + int pid; + int cnum; + uint32 lastused; + void *ptr; + BOOL valid; + BOOL finished; + BOOL expect_close; + char *wcard; /* Field only used for lanman2 trans2_findfirst/next searches */ + uint16 attr; /* Field only used for lanman2 trans2_findfirst/next searches */ + char *path; +} +dirptrs[NUMDIRPTRS]; + + +static int dptrs_open = 0; + +/**************************************************************************** +initialise the dir array +****************************************************************************/ +void init_dptrs(void) +{ + static BOOL dptrs_init=False; + int i; + + if (dptrs_init) return; + for (i=0;i= MAXDIR) + dptr_idleoldest(); + DEBUG(4,("Reopening dptr key %d\n",key)); + if ((dirptrs[key].ptr = OpenDir(dirptrs[key].path))) + dptrs_open++; + } + return(dirptrs[key].ptr); + } + return(NULL); +} + +/**************************************************************************** +get the dir path for a dir index +****************************************************************************/ +char *dptr_path(int key) +{ + if (dirptrs[key].valid) + return(dirptrs[key].path); + return(NULL); +} + +/**************************************************************************** +get the dir wcard for a dir index (lanman2 specific) +****************************************************************************/ +char *dptr_wcard(int key) +{ + if (dirptrs[key].valid) + return(dirptrs[key].wcard); + return(NULL); +} + +/**************************************************************************** +set the dir wcard for a dir index (lanman2 specific) +Returns 0 on ok, 1 on fail. +****************************************************************************/ +BOOL dptr_set_wcard(int key, char *wcard) +{ + if (dirptrs[key].valid) { + dirptrs[key].wcard = wcard; + return True; + } + return False; +} + +/**************************************************************************** +set the dir attrib for a dir index (lanman2 specific) +Returns 0 on ok, 1 on fail. +****************************************************************************/ +BOOL dptr_set_attr(int key, uint16 attr) +{ + if (dirptrs[key].valid) { + dirptrs[key].attr = attr; + return True; + } + return False; +} + +/**************************************************************************** +get the dir attrib for a dir index (lanman2 specific) +****************************************************************************/ +uint16 dptr_attr(int key) +{ + if (dirptrs[key].valid) + return(dirptrs[key].attr); + return(0); +} + +/**************************************************************************** +close a dptr +****************************************************************************/ +void dptr_close(int key) +{ + if (dirptrs[key].valid) { + DEBUG(4,("closing dptr key %d\n",key)); + if (dirptrs[key].ptr) { + CloseDir(dirptrs[key].ptr); + dptrs_open--; + } + /* Lanman 2 specific code */ + if (dirptrs[key].wcard) + free(dirptrs[key].wcard); + dirptrs[key].valid = False; + string_set(&dirptrs[key].path,""); + } +} + +/**************************************************************************** +close all dptrs for a cnum +****************************************************************************/ +void dptr_closecnum(int cnum) +{ + int i; + for (i=0;i= MAXDIR) + dptr_idleoldest(); + + for (i=0;ipos = dirp->numentries = dirp->mallocsize = 0; + dirp->data = dirp->current = NULL; + + while ((n = readdirname(p))) { + int l = strlen(n)+1; + if (used + l > dirp->mallocsize) { + int s = MAX(used+l,used+2000); + char *r; + r = (char *)Realloc(dirp->data,s); + if (!r) { + DEBUG(0,("Out of memory in OpenDir\n")); + break; + } + dirp->data = r; + dirp->mallocsize = s; + dirp->current = dirp->data; + } + strcpy(dirp->data+used,n); + used += l; + dirp->numentries++; + } + + closedir(p); + return((void *)dirp); +} + + +/******************************************************************* +close a directory +********************************************************************/ +void CloseDir(void *p) +{ + Dir *dirp = (Dir *)p; + if (!dirp) return; + if (dirp->data) free(dirp->data); + free(dirp); +} + +/******************************************************************* +read from a directory +********************************************************************/ +char *ReadDirName(void *p) +{ + char *ret; + Dir *dirp = (Dir *)p; + + if (!dirp || !dirp->current || dirp->pos >= dirp->numentries) return(NULL); + + ret = dirp->current; + dirp->current = skip_string(dirp->current,1); + dirp->pos++; + + return(ret); +} + + +/******************************************************************* +seek a dir +********************************************************************/ +BOOL SeekDir(void *p,int pos) +{ + Dir *dirp = (Dir *)p; + + if (!dirp) return(False); + + if (pos < dirp->pos) { + dirp->current = dirp->data; + dirp->pos = 0; + } + + while (dirp->pos < pos && ReadDirName(p)) ; + + return(dirp->pos == pos); +} + +/******************************************************************* +tell a dir position +********************************************************************/ +int TellDir(void *p) +{ + Dir *dirp = (Dir *)p; + + if (!dirp) return(-1); + + return(dirp->pos); +} + + +static int dir_cache_size = 0; +static struct dir_cache { + struct dir_cache *next; + struct dir_cache *prev; + char *path; + char *name; + char *dname; + int snum; +} *dir_cache = NULL; + +/******************************************************************* +add an entry to the directory cache +********************************************************************/ +void DirCacheAdd(char *path,char *name,char *dname,int snum) +{ + struct dir_cache *entry = (struct dir_cache *)malloc(sizeof(*entry)); + if (!entry) return; + entry->path = strdup(path); + entry->name = strdup(name); + entry->dname = strdup(dname); + entry->snum = snum; + if (!entry->path || !entry->name || !entry->dname) return; + + entry->next = dir_cache; + entry->prev = NULL; + if (entry->next) entry->next->prev = entry; + dir_cache = entry; + + DEBUG(4,("Added dir cache entry %s %s -> %s\n",path,name,dname)); + + if (dir_cache_size == DIRCACHESIZE) { + for (entry=dir_cache; entry->next; entry=entry->next) ; + free(entry->path); + free(entry->name); + free(entry->dname); + if (entry->prev) entry->prev->next = entry->next; + free(entry); + } else { + dir_cache_size++; + } +} + + +/******************************************************************* +check for an entry in the directory cache +********************************************************************/ +char *DirCacheCheck(char *path,char *name,int snum) +{ + struct dir_cache *entry; + + for (entry=dir_cache; entry; entry=entry->next) { + if (entry->snum == snum && + strcmp(path,entry->path) == 0 && + strcmp(name,entry->name) == 0) { + DEBUG(4,("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname)); + return(entry->dname); + } + } + + return(NULL); +} + +/******************************************************************* +flush entries in the dir_cache +********************************************************************/ +void DirCacheFlush(int snum) +{ + struct dir_cache *entry,*next; + + for (entry=dir_cache; entry; entry=next) { + if (entry->snum == snum) { + free(entry->path); + free(entry->dname); + free(entry->name); + next = entry->next; + if (entry->prev) entry->prev->next = entry->next; + if (entry->next) entry->next->prev = entry->prev; + if (dir_cache == entry) dir_cache = entry->next; + free(entry); + } else { + next = entry->next; + } + } +} + + +#ifdef REPLACE_GETWD +/* This is getcwd.c from bash. It is needed in Interactive UNIX. To + * add support for another OS you need to determine which of the + * conditional compilation macros you need to define. All the options + * are defined for Interactive UNIX. + */ +#ifdef ISC +#define HAVE_UNISTD_H +#define USGr3 +#define USG +#endif + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (__STDC__) +# define CONST const +# define PTR void * +#else /* !__STDC__ */ +# define CONST +# define PTR char * +#endif /* !__STDC__ */ + +#if !defined (PATH_MAX) +# if defined (MAXPATHLEN) +# define PATH_MAX MAXPATHLEN +# else /* !MAXPATHLEN */ +# define PATH_MAX 1024 +# endif /* !MAXPATHLEN */ +#endif /* !PATH_MAX */ + +#if defined (_POSIX_VERSION) || defined (USGr3) || defined (HAVE_DIRENT_H) +# if !defined (HAVE_DIRENT) +# define HAVE_DIRENT +# endif /* !HAVE_DIRENT */ +#endif /* _POSIX_VERSION || USGr3 || HAVE_DIRENT_H */ + +#if defined (HAVE_DIRENT) +# define D_NAMLEN(d) (strlen ((d)->d_name)) +#else +# define D_NAMLEN(d) ((d)->d_namlen) +#endif /* ! (_POSIX_VERSION || USGr3) */ + +#if defined (USG) || defined (USGr3) +# define d_fileno d_ino +#endif + +#if !defined (alloca) +extern char *alloca (); +#endif /* alloca */ + +/* Get the pathname of the current working directory, + and put it in SIZE bytes of BUF. Returns NULL if the + directory couldn't be determined or SIZE was too small. + If successful, returns BUF. In GNU, if BUF is NULL, + an array is allocated with `malloc'; the array is SIZE + bytes long, unless SIZE <= 0, in which case it is as + big as necessary. */ +#if defined (__STDC__) +char * +getcwd (char *buf, size_t size) +#else /* !__STDC__ */ +char * +getcwd (buf, size) + char *buf; + int size; +#endif /* !__STDC__ */ +{ + static CONST char dots[] + = "../../../../../../../../../../../../../../../../../../../../../../../\ +../../../../../../../../../../../../../../../../../../../../../../../../../../\ +../../../../../../../../../../../../../../../../../../../../../../../../../.."; + CONST char *dotp, *dotlist; + size_t dotsize; + dev_t rootdev, thisdev; + ino_t rootino, thisino; + char path[PATH_MAX + 1]; + register char *pathp; + char *pathbuf; + size_t pathsize; + struct stat st; + + if (buf != NULL && size == 0) + { + errno = EINVAL; + return ((char *)NULL); + } + + pathsize = sizeof (path); + pathp = &path[pathsize]; + *--pathp = '\0'; + pathbuf = path; + + if (stat (".", &st) < 0) + return ((char *)NULL); + thisdev = st.st_dev; + thisino = st.st_ino; + + if (stat ("/", &st) < 0) + return ((char *)NULL); + rootdev = st.st_dev; + rootino = st.st_ino; + + dotsize = sizeof (dots) - 1; + dotp = &dots[sizeof (dots)]; + dotlist = dots; + while (!(thisdev == rootdev && thisino == rootino)) + { + register DIR *dirstream; + register struct dirent *d; + dev_t dotdev; + ino_t dotino; + char mount_point; + int namlen; + + /* Look at the parent directory. */ + if (dotp == dotlist) + { + /* My, what a deep directory tree you have, Grandma. */ + char *new; + if (dotlist == dots) + { + new = malloc (dotsize * 2 + 1); + if (new == NULL) + goto lose; + memcpy (new, dots, dotsize); + } + else + { + new = realloc ((PTR) dotlist, dotsize * 2 + 1); + if (new == NULL) + goto lose; + } + memcpy (&new[dotsize], new, dotsize); + dotp = &new[dotsize]; + dotsize *= 2; + new[dotsize] = '\0'; + dotlist = new; + } + + dotp -= 3; + + /* Figure out if this directory is a mount point. */ + if (stat (dotp, &st) < 0) + goto lose; + dotdev = st.st_dev; + dotino = st.st_ino; + mount_point = dotdev != thisdev; + + /* Search for the last directory. */ + dirstream = opendir(dotp); + if (dirstream == NULL) + goto lose; + while ((d = (struct dirent *)readdir(dirstream)) != NULL) + { + if (d->d_name[0] == '.' && + (d->d_name[1] == '\0' || + (d->d_name[1] == '.' && d->d_name[2] == '\0'))) + continue; + if (mount_point || d->d_fileno == thisino) + { + char *name; + + namlen = D_NAMLEN(d); + name = (char *) + alloca (dotlist + dotsize - dotp + 1 + namlen + 1); + memcpy (name, dotp, dotlist + dotsize - dotp); + name[dotlist + dotsize - dotp] = '/'; + memcpy (&name[dotlist + dotsize - dotp + 1], + d->d_name, namlen + 1); + if (lstat (name, &st) < 0) + { + int save = errno; + closedir(dirstream); + errno = save; + goto lose; + } + if (st.st_dev == thisdev && st.st_ino == thisino) + break; + } + } + if (d == NULL) + { + int save = errno; + closedir(dirstream); + errno = save; + goto lose; + } + else + { + size_t space; + + while ((space = pathp - pathbuf) <= namlen) + { + char *new; + + if (pathbuf == path) + { + new = malloc (pathsize * 2); + if (!new) + goto lose; + } + else + { + new = realloc ((PTR) pathbuf, (pathsize * 2)); + if (!new) + goto lose; + pathp = new + space; + } + (void) memcpy (new + pathsize + space, pathp, pathsize - space); + pathp = new + pathsize + space; + pathbuf = new; + pathsize *= 2; + } + + pathp -= namlen; + (void) memcpy (pathp, d->d_name, namlen); + *--pathp = '/'; + closedir(dirstream); + } + + thisdev = dotdev; + thisino = dotino; + } + + if (pathp == &path[sizeof(path) - 1]) + *--pathp = '/'; + + if (dotlist != dots) + free ((PTR) dotlist); + + { + size_t len = pathbuf + pathsize - pathp; + if (buf == NULL) + { + if (len < (size_t) size) + len = size; + buf = (char *) malloc (len); + if (buf == NULL) + goto lose2; + } + else if ((size_t) size < len) + { + errno = ERANGE; + goto lose2; + } + (void) memcpy((PTR) buf, (PTR) pathp, len); + } + + if (pathbuf != path) + free (pathbuf); + + return (buf); + + lose: + if ((dotlist != dots) && dotlist) + { + int e = errno; + free ((PTR) dotlist); + errno = e; + } + + lose2: + if ((pathbuf != path) && pathbuf) + { + int e = errno; + free ((PTR) pathbuf); + errno = e; + } + return ((char *)NULL); +} +#endif -- cgit