/* Unix SMB/Netbios implementation. Version 1.9. Directory handling routines Copyright (C) Andrew Tridgell 1992-1998 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" extern int DEBUGLEVEL; extern connection_struct Connections[]; /* This module implements directory related functions for Samba. */ static 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;ivalid) { if (lastused) dp->lastused = lastused; if (!dp->ptr) { if (dptrs_open >= MAX_OPEN_DIRECTORIES) dptr_idleoldest(); DEBUG(4,("Reopening dptr key %d\n",key)); if ((dp->ptr = OpenDir(dp->cnum, dp->path, True))) dptrs_open++; } return(dp->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) { /* OS/2 seems to use -1 to indicate "close all directories" */ if (key == -1) { int i; for (i=0;i= NUMDIRPTRS) { DEBUG(3,("Invalid key %d given to dptr_close\n",key)); return; } 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= MAX_OPEN_DIRECTORIES) 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 it's a vetoed file, pretend it doesn't even exist */ if (use_veto && IS_VETO_PATH(cnum, n)) continue; 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; } pstrcpy(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); } /* -------------------------------------------------------------------------- ** * This section manages a global directory cache. * (It should probably be split into a separate module. crh) * -------------------------------------------------------------------------- ** */ typedef struct { ubi_dlNode node; char *path; char *name; char *dname; int snum; } dir_cache_entry; static ubi_dlNewList( dir_cache ); void DirCacheAdd( char *path, char *name, char *dname, int snum ) /* ------------------------------------------------------------------------ ** * Add an entry to the directory cache. * * Input: path - * name - * dname - * snum - * * Output: None. * * ------------------------------------------------------------------------ ** */ { int pathlen; int namelen; dir_cache_entry *entry; /* Allocate the structure & string space in one go so that it can be freed * in one call to free(). */ pathlen = strlen( path ) +1; /* Bytes required to store path (with nul). */ namelen = strlen( name ) +1; /* Bytes required to store name (with nul). */ entry = (dir_cache_entry *)malloc( sizeof( dir_cache_entry ) + pathlen + namelen + strlen( dname ) +1 ); if( NULL == entry ) /* Not adding to the cache is not fatal, */ return; /* so just return as if nothing happened. */ /* Set pointers correctly and load values. */ entry->path = pstrcpy( (char *)&entry[1], path); entry->name = pstrcpy( &(entry->path[pathlen]), name); entry->dname = pstrcpy( &(entry->name[namelen]), dname); entry->snum = snum; /* Add the new entry to the linked list. */ (void)ubi_dlAddHead( dir_cache, entry ); DEBUG( 4, ("Added dir cache entry %s %s -> %s\n", path, name, dname ) ); /* Free excess cache entries. */ while( DIRCACHESIZE < dir_cache->count ) free( ubi_dlRemTail( dir_cache ) ); } /* DirCacheAdd */ char *DirCacheCheck( char *path, char *name, int snum ) /* ------------------------------------------------------------------------ ** * Search for an entry to the directory cache. * * Input: path - * name - * snum - * * Output: The dname string of the located entry, or NULL if the entry was * not found. * * Notes: This uses a linear search, which is is okay because of * the small size of the cache. Use a splay tree or hash * for large caches. * * ------------------------------------------------------------------------ ** */ { dir_cache_entry *entry; for( entry = (dir_cache_entry *)ubi_dlFirst( dir_cache ); NULL != entry; entry = (dir_cache_entry *)ubi_dlNext( entry ) ) { if( entry->snum == snum && 0 == strcmp( name, entry->name ) && 0 == strcmp( path, entry->path ) ) { DEBUG(4, ("Got dir cache hit on %s %s -> %s\n",path,name,entry->dname)); return( entry->dname ); } } return(NULL); } /* DirCacheCheck */ void DirCacheFlush(int snum) /* ------------------------------------------------------------------------ ** * Remove all cache entries which have an snum that matches the input. * * Input: snum - * * Output: None. * * ------------------------------------------------------------------------ ** */ { dir_cache_entry *entry; ubi_dlNodePtr next; for(entry = (dir_cache_entry *)ubi_dlFirst( dir_cache ); NULL != entry; ) { next = ubi_dlNext( entry ); if( entry->snum == snum ) free( ubi_dlRemThis( dir_cache, entry ) ); entry = (dir_cache_entry *)next; } } /* DirCacheFlush */ /* -------------------------------------------------------------------------- ** * End of the section that manages the global directory cache. * -------------------------------------------------------------------------- ** */