summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>1999-01-08 20:16:54 +0000
committerJeremy Allison <jra@samba.org>1999-01-08 20:16:54 +0000
commitdc42a59473f000d97390e027c0ab616c7a6468cf (patch)
tree157487f6555554249842dd741c2375584cd6469e
parentf46172c75eaf9da1a32d95f4d51d36d2b9ca01b6 (diff)
downloadsamba-dc42a59473f000d97390e027c0ab616c7a6468cf.tar.gz
samba-dc42a59473f000d97390e027c0ab616c7a6468cf.tar.xz
samba-dc42a59473f000d97390e027c0ab616c7a6468cf.zip
Fixed the 16-bit app directory handle problem (this took *way* longer
than it should :-). SMBsearch now gets directory handles that are 8 bit in the range 1-255 and will close the oldest non-expect-close handle if the table gets full. findfirst gets 16 bit directory handles starting at 256 and above. Jeremy.
-rw-r--r--source/include/proto.h4
-rw-r--r--source/smbd/dir.c122
-rw-r--r--source/smbd/reply.c262
-rw-r--r--source/smbd/trans2.c18
4 files changed, 242 insertions, 164 deletions
diff --git a/source/include/proto.h b/source/include/proto.h
index f357a5b1926..bc9ea6b69e9 100644
--- a/source/include/proto.h
+++ b/source/include/proto.h
@@ -2314,11 +2314,11 @@ char *dptr_wcard(int key);
BOOL dptr_set_wcard(int key, char *wcard);
BOOL dptr_set_attr(int key, uint16 attr);
uint16 dptr_attr(int key);
-void dptr_close(int key);
+void dptr_close(int *key);
void dptr_closecnum(connection_struct *conn);
void dptr_idlecnum(connection_struct *conn);
void dptr_closepath(char *path,int pid);
-int dptr_create(connection_struct *conn,char *path, BOOL expect_close,int pid);
+int dptr_create(connection_struct *conn,char *path, BOOL old_handle, BOOL expect_close,int pid);
BOOL dptr_fill(char *buf1,unsigned int key);
BOOL dptr_zero(char *buf);
void *dptr_fetch(char *buf,int *num);
diff --git a/source/smbd/dir.c b/source/smbd/dir.c
index 30e4c67cd1d..b6adf9f20a5 100644
--- a/source/smbd/dir.c
+++ b/source/smbd/dir.c
@@ -33,7 +33,6 @@ typedef struct _dptr_struct {
int pid;
connection_struct *conn;
void *ptr;
- BOOL finished;
BOOL expect_close;
char *wcard; /* Field only used for trans2_ searches */
uint16 attr; /* Field only used for trans2_ searches */
@@ -45,6 +44,8 @@ static dptr_struct *dirptrs;
static int dptrs_open = 0;
+#define INVALID_DPTR_KEY (-3)
+
/****************************************************************************
Initialise the dir bitmap.
****************************************************************************/
@@ -93,12 +94,12 @@ static void dptr_idleoldest(void)
;
if(!dptr) {
- DEBUG(0,("No dptrs available to idle??\n"));
+ DEBUG(0,("No dptrs available to idle ?\n"));
return;
}
/*
- * Now walk back until we find a non-idle ptr.
+ * Idle the oldest pointer.
*/
for(; dptr; dptr = dptr->prev) {
@@ -227,8 +228,12 @@ static void dptr_close_internal(dptr_struct *dptr)
DLIST_REMOVE(dirptrs, dptr);
- /* Free the dnum in the bitmap. */
- bitmap_clear(dptr_bmap, dptr->dnum);
+ /*
+ * Free the dnum in the bitmap. Remember the dnum value is always
+ * biased by one with respect to the bitmap.
+ */
+
+ bitmap_clear(dptr_bmap, dptr->dnum - 1);
if (dptr->ptr) {
CloseDir(dptr->ptr);
@@ -246,21 +251,25 @@ static void dptr_close_internal(dptr_struct *dptr)
Close a dptr given a key.
****************************************************************************/
-void dptr_close(int key)
+void dptr_close(int *key)
{
dptr_struct *dptr;
+ if(*key == INVALID_DPTR_KEY)
+ return;
+
/* OS/2 seems to use -1 to indicate "close all directories" */
- if (key == -1) {
+ if (*key == -1) {
dptr_struct *next;
for(dptr = dirptrs; dptr; dptr = next) {
next = dptr->next;
dptr_close_internal(dptr);
}
+ *key = INVALID_DPTR_KEY;
return;
}
- dptr = dptr_get(key);
+ dptr = dptr_get(*key);
if (!dptr) {
DEBUG(0,("Invalid key %d given to dptr_close\n",key));
@@ -268,6 +277,8 @@ void dptr_close(int key)
}
dptr_close_internal(dptr);
+
+ *key = INVALID_DPTR_KEY;
}
/****************************************************************************
@@ -335,15 +346,52 @@ static BOOL start_dir(connection_struct *conn,char *directory)
return(False);
}
+/****************************************************************************
+ Try and close the oldest handle not marked for
+ expect close in the hope that the client has
+ finished with that one.
+****************************************************************************/
+
+static void dptr_old_close_oldest(void)
+{
+ dptr_struct *dptr;
+
+ /*
+ * Go to the end of the list.
+ */
+ for(dptr = dirptrs; dptr && dptr->next; dptr = dptr->next)
+ ;
+
+ if(!dptr) {
+ DEBUG(0,("No old dptrs available to close oldest ?\n"));
+ return;
+ }
+
+ /*
+ * Close the oldest oldhandle dnum (ie. 1 < dnum < 256) that
+ * does not have expect_close set.
+ */
+
+ for(; dptr; dptr = dptr->prev) {
+ if (dptr->dnum < 256 && !dptr->expect_close) {
+ dptr_close_internal(dptr);
+ return;
+ }
+ }
+}
/****************************************************************************
- Create a new dir ptr.
+ Create a new dir ptr. If the flag old_handle is true then we must allocate
+ from the bitmap range 0 - 255 as old SMBsearch directory handles are only
+ one byte long. If old_handle is false we allocate from the range
+ 256 - MAX_DIRECTORY_HANDLES. We bias the number we return by 1 to ensure
+ a directory handle is never zero. All the above is folklore taught to
+ me at Andrew's knee.... :-) :-). JRA.
****************************************************************************/
-int dptr_create(connection_struct *conn,char *path, BOOL expect_close,int pid)
+int dptr_create(connection_struct *conn,char *path, BOOL old_handle, BOOL expect_close,int pid)
{
dptr_struct *dptr;
- int dnum = -1;
if (!start_dir(conn,path))
return(-2); /* Code to say use a unix error return code. */
@@ -359,18 +407,56 @@ int dptr_create(connection_struct *conn,char *path, BOOL expect_close,int pid)
ZERO_STRUCTP(dptr);
- dptr->dnum= bitmap_find(dptr_bmap, 0);
- if(dptr->dnum == -1) {
- DEBUG(0,("dptr_create: Error dirptrs in use??\n"));
- free((char *)dptr);
- return -1;
+ if(old_handle) {
+
+ /*
+ * This is an old-style SMBsearch request. Ensure the
+ * value we return will fit in the range 1-255.
+ */
+
+ dptr->dnum = bitmap_find(dptr_bmap, 0);
+
+ if(dptr->dnum == -1 || dptr->dnum > 254) {
+
+ /*
+ * Try and close the oldest handle not marked for
+ * expect close in the hope that the client has
+ * finished with that one.
+ */
+
+ dptr_old_close_oldest();
+
+ /* Now try again... */
+ dptr->dnum = bitmap_find(dptr_bmap, 0);
+
+ if(dptr->dnum == -1 || dptr->dnum > 254) {
+ DEBUG(0,("dptr_create: Error - all old style dirptrs in use ?\n"));
+ free((char *)dptr);
+ return -1;
+ }
+ }
+ } else {
+
+ /*
+ * This is a new-style trans2 request. Allocate from
+ * a range that will return 256 - MAX_DIRECTORY_HANDLES.
+ */
+
+ dptr->dnum = bitmap_find(dptr_bmap, 255);
+
+ if(dptr->dnum == -1) {
+ DEBUG(0,("dptr_create: Error - all dirptrs in use ?\n"));
+ free((char *)dptr);
+ return -1;
+ }
}
bitmap_set(dptr_bmap, dptr->dnum);
+ dptr->dnum += 1; /* Always bias the dnum by one - no zero dnums allowed. */
+
dptr->ptr = conn->dirptr;
string_set(&dptr->path,path);
- dptr->finished = False;
dptr->conn = conn;
dptr->pid = pid;
dptr->expect_close = expect_close;
@@ -410,7 +496,7 @@ BOOL dptr_fill(char *buf1,unsigned int key)
/****************************************************************************
- Return True is the offset is at zero.
+ Return True if the offset is at zero.
****************************************************************************/
BOOL dptr_zero(char *buf)
diff --git a/source/smbd/reply.c b/source/smbd/reply.c
index ad317caac93..70fd3d859c6 100644
--- a/source/smbd/reply.c
+++ b/source/smbd/reply.c
@@ -1113,70 +1113,70 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
/* dirtype &= ~aDIR; */
- DEBUG(5,("path=%s status_len=%d\n",path,status_len));
+ DEBUG(5,("reply_search: path=%s status_len=%d\n",path,status_len));
if (status_len == 0)
- {
- pstring dir2;
-
- pstrcpy(directory,smb_buf(inbuf)+1);
- pstrcpy(dir2,smb_buf(inbuf)+1);
- unix_convert(directory,conn,0,&bad_path,NULL);
- unix_format(dir2);
-
- if (!check_name(directory,conn))
- can_open = False;
+ {
+ pstring dir2;
- p = strrchr(dir2,'/');
- if (p == NULL)
- {
- pstrcpy(mask,dir2);
- *dir2 = 0;
- }
- else
- {
- *p = 0;
- pstrcpy(mask,p+1);
- }
+ pstrcpy(directory,smb_buf(inbuf)+1);
+ pstrcpy(dir2,smb_buf(inbuf)+1);
+ unix_convert(directory,conn,0,&bad_path,NULL);
+ unix_format(dir2);
- p = strrchr(directory,'/');
- if (!p)
- *directory = 0;
- else
- *p = 0;
+ if (!check_name(directory,conn))
+ can_open = False;
- if (strlen(directory) == 0)
- pstrcpy(directory,"./");
- memset((char *)status,'\0',21);
- CVAL(status,0) = dirtype;
+ p = strrchr(dir2,'/');
+ if (p == NULL)
+ {
+ pstrcpy(mask,dir2);
+ *dir2 = 0;
}
- else
+ else
{
- memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
- memcpy(mask,status+1,11);
- mask[11] = 0;
- dirtype = CVAL(status,0) & 0x1F;
- conn->dirptr = dptr_fetch(status+12,&dptr_num);
- if (!conn->dirptr)
- goto SearchEmpty;
- string_set(&conn->dirpath,dptr_path(dptr_num));
- if (!case_sensitive)
- strnorm(mask);
+ *p = 0;
+ pstrcpy(mask,p+1);
}
+ p = strrchr(directory,'/');
+ if (!p)
+ *directory = 0;
+ else
+ *p = 0;
+
+ if (strlen(directory) == 0)
+ pstrcpy(directory,"./");
+ memset((char *)status,'\0',21);
+ CVAL(status,0) = dirtype;
+ }
+ else
+ {
+ memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
+ memcpy(mask,status+1,11);
+ mask[11] = 0;
+ dirtype = CVAL(status,0) & 0x1F;
+ conn->dirptr = dptr_fetch(status+12,&dptr_num);
+ if (!conn->dirptr)
+ goto SearchEmpty;
+ string_set(&conn->dirpath,dptr_path(dptr_num));
+ if (!case_sensitive)
+ strnorm(mask);
+ }
+
/* turn strings of spaces into a . */
{
trim_string(mask,NULL," ");
if ((p = strrchr(mask,' ')))
- {
- fstring ext;
- fstrcpy(ext,p+1);
- *p = 0;
- trim_string(mask,NULL," ");
- pstrcat(mask,".");
- pstrcat(mask,ext);
- }
+ {
+ fstring ext;
+ fstrcpy(ext,p+1);
+ *p = 0;
+ trim_string(mask,NULL," ");
+ pstrcat(mask,".");
+ pstrcat(mask,ext);
+ }
}
/* Convert the formatted mask. (This code lives in trans2.c) */
@@ -1204,110 +1204,104 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
}
if (!strchr(mask,'.') && strlen(mask)>8)
- {
- fstring tmp;
- fstrcpy(tmp,&mask[8]);
- mask[8] = '.';
- mask[9] = 0;
- pstrcat(mask,tmp);
- }
+ {
+ fstring tmp;
+ fstrcpy(tmp,&mask[8]);
+ mask[8] = '.';
+ mask[9] = 0;
+ pstrcat(mask,tmp);
+ }
DEBUG(5,("mask=%s directory=%s\n",mask,directory));
if (can_open)
- {
- p = smb_buf(outbuf) + 3;
-
- ok = True;
+ {
+ p = smb_buf(outbuf) + 3;
- if (status_len == 0)
- {
- dptr_num = dptr_create(conn,directory,expect_close,SVAL(inbuf,smb_pid));
- if (dptr_num < 0)
+ ok = True;
+
+ if (status_len == 0)
+ {
+ dptr_num = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid));
+ if (dptr_num < 0)
+ {
+ if(dptr_num == -2)
{
- if(dptr_num == -2)
+ if((errno == ENOENT) && bad_path)
{
- if((errno == ENOENT) && bad_path)
- {
- unix_ERR_class = ERRDOS;
- unix_ERR_code = ERRbadpath;
- }
- return (UNIXERROR(ERRDOS,ERRnofids));
+ unix_ERR_class = ERRDOS;
+ unix_ERR_code = ERRbadpath;
}
- return(ERROR(ERRDOS,ERRnofids));
+ return (UNIXERROR(ERRDOS,ERRnofids));
}
- }
-
- DEBUG(4,("dptr_num is %d\n",dptr_num));
-
- if (ok)
- {
- if ((dirtype&0x1F) == aVOLID)
- {
- memcpy(p,status,21);
- make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0);
- dptr_fill(p+12,dptr_num);
- if (dptr_zero(p+12) && (status_len==0))
- numentries = 1;
- else
- numentries = 0;
- p += DIR_STRUCT_SIZE;
- }
- else
- {
- DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
- conn->dirpath,lp_dontdescend(SNUM(conn))));
- if (in_list(conn->dirpath,
- lp_dontdescend(SNUM(conn)),True))
- check_descend = True;
-
- for (i=numentries;(i<maxentries) && !finished;i++)
- {
- finished =
- !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
- if (!finished)
- {
- memcpy(p,status,21);
- make_dir_struct(p,mask,fname,size,mode,date);
- dptr_fill(p+12,dptr_num);
- numentries++;
- }
- p += DIR_STRUCT_SIZE;
- }
- }
- }
+ return(ERROR(ERRDOS,ERRnofids));
+ }
}
+ DEBUG(4,("dptr_num is %d\n",dptr_num));
- SearchEmpty:
-
- if (numentries == 0 || !ok)
+ if (ok)
{
- CVAL(outbuf,smb_rcls) = ERRDOS;
- SSVAL(outbuf,smb_err,ERRnofiles);
- if(dptr_num != -1)
+ if ((dirtype&0x1F) == aVOLID)
+ {
+ memcpy(p,status,21);
+ make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0);
+ dptr_fill(p+12,dptr_num);
+ if (dptr_zero(p+12) && (status_len==0))
+ numentries = 1;
+ else
+ numentries = 0;
+ p += DIR_STRUCT_SIZE;
+ }
+ else
{
- dptr_close(dptr_num);
- dptr_num = -1;
+ DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
+ conn->dirpath,lp_dontdescend(SNUM(conn))));
+ if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True))
+ check_descend = True;
+
+ for (i=numentries;(i<maxentries) && !finished;i++)
+ {
+ finished =
+ !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
+ if (!finished)
+ {
+ memcpy(p,status,21);
+ make_dir_struct(p,mask,fname,size,mode,date);
+ dptr_fill(p+12,dptr_num);
+ numentries++;
+ }
+ p += DIR_STRUCT_SIZE;
+ }
}
- }
+ } /* if (ok ) */
+ }
+
+
+ SearchEmpty:
+
+ if (numentries == 0 || !ok)
+ {
+ CVAL(outbuf,smb_rcls) = ERRDOS;
+ SSVAL(outbuf,smb_err,ERRnofiles);
+ dptr_close(&dptr_num);
+ }
/* If we were called as SMBffirst with smb_search_id == NULL
and no entries were found then return error and close dirptr
(X/Open spec) */
if(ok && expect_close && numentries == 0 && status_len == 0)
- {
- CVAL(outbuf,smb_rcls) = ERRDOS;
- SSVAL(outbuf,smb_err,ERRnofiles);
- /* Also close the dptr - we know it's gone */
- dptr_close(dptr_num);
- dptr_num = -1;
- }
+ {
+ CVAL(outbuf,smb_rcls) = ERRDOS;
+ SSVAL(outbuf,smb_err,ERRnofiles);
+ /* Also close the dptr - we know it's gone */
+ dptr_close(&dptr_num);
+ }
/* If we were called as SMBfunique, then we can close the dirptr now ! */
if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique)
- dptr_close(dptr_num);
+ dptr_close(&dptr_num);
SSVAL(outbuf,smb_vwv0,numentries);
SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
@@ -1326,8 +1320,8 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
DEBUG( 4, ( "%s mask=%s path=%s dtype=%d nument=%d of %d\n",
- smb_fn_name(CVAL(inbuf,smb_com)),
- mask, directory, dirtype, numentries, maxentries ) );
+ smb_fn_name(CVAL(inbuf,smb_com)),
+ mask, directory, dirtype, numentries, maxentries ) );
return(outsize);
}
@@ -1342,7 +1336,7 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
int status_len;
char *path;
char status[21];
- int dptr_num= -1;
+ int dptr_num= -2;
outsize = set_message(outbuf,1,0,True);
path = smb_buf(inbuf) + 1;
@@ -1356,7 +1350,7 @@ int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
if(dptr_fetch(status+12,&dptr_num)) {
/* Close the dptr - we know it's gone */
- dptr_close(dptr_num);
+ dptr_close(&dptr_num);
}
SSVAL(outbuf,smb_vwv0,0);
diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c
index ef1990e803d..c9ade4b6ba1 100644
--- a/source/smbd/trans2.c
+++ b/source/smbd/trans2.c
@@ -725,7 +725,7 @@ static int call_trans2findfirst(connection_struct *conn,
if(params == NULL)
return(ERROR(ERRDOS,ERRnomem));
- dptr_num = dptr_create(conn,directory, True ,SVAL(inbuf,smb_pid));
+ dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid));
if (dptr_num < 0)
return(UNIXERROR(ERRDOS,ERRbadfile));
@@ -736,7 +736,7 @@ static int call_trans2findfirst(connection_struct *conn,
needed as lanman2 assumes these are being saved between calls */
if(!(wcard = strdup(mask))) {
- dptr_close(dptr_num);
+ dptr_close(&dptr_num);
return(ERROR(ERRDOS,ERRnomem));
}
@@ -786,9 +786,8 @@ static int call_trans2findfirst(connection_struct *conn,
/* Check if we can close the dirptr */
if(close_after_first || (finished && close_if_end))
{
- dptr_close(dptr_num);
DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
- dptr_num = -1;
+ dptr_close(&dptr_num);
}
/*
@@ -798,7 +797,7 @@ static int call_trans2findfirst(connection_struct *conn,
if(numentries == 0)
{
- dptr_close(dptr_num);
+ dptr_close(&dptr_num);
return(ERROR(ERRDOS,ERRbadfile));
}
@@ -840,7 +839,7 @@ static int call_trans2findnext(connection_struct *conn,
int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
char *params = *pparams;
char *pdata = *ppdata;
- int16 dptr_num = SVAL(params,0);
+ int dptr_num = SVAL(params,0);
int maxentries = SVAL(params,2);
uint16 info_level = SVAL(params,4);
uint32 resume_key = IVAL(params,6);
@@ -1033,9 +1032,8 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
/* Check if we can close the dirptr */
if(close_after_request || (finished && close_if_end))
{
- dptr_close(dptr_num); /* This frees up the saved mask */
DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
- dptr_num = -1;
+ dptr_close(&dptr_num); /* This frees up the saved mask */
}
@@ -1989,11 +1987,11 @@ int reply_findclose(connection_struct *conn,
char *inbuf,char *outbuf,int length,int bufsize)
{
int outsize = 0;
- int16 dptr_num=SVALS(inbuf,smb_vwv0);
+ int dptr_num=SVALS(inbuf,smb_vwv0);
DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num));
- dptr_close(dptr_num);
+ dptr_close(&dptr_num);
outsize = set_message(outbuf,0,0,True);