diff options
author | Jeremy Allison <jra@samba.org> | 1999-01-08 20:16:54 +0000 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 1999-01-08 20:16:54 +0000 |
commit | dc42a59473f000d97390e027c0ab616c7a6468cf (patch) | |
tree | 157487f6555554249842dd741c2375584cd6469e | |
parent | f46172c75eaf9da1a32d95f4d51d36d2b9ca01b6 (diff) | |
download | samba-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.h | 4 | ||||
-rw-r--r-- | source/smbd/dir.c | 122 | ||||
-rw-r--r-- | source/smbd/reply.c | 262 | ||||
-rw-r--r-- | source/smbd/trans2.c | 18 |
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); |