diff -r -u source/include/smb_macros.h source-new/include/smb_macros.h --- source/include/smb_macros.h 2005-04-13 23:14:26.000000000 -0700 +++ source-new/include/smb_macros.h 2005-06-15 11:46:59.250091507 -0700 @@ -139,6 +139,7 @@ #define VALID_STAT(st) ((st).st_nlink != 0) #define VALID_STAT_OF_DIR(st) (VALID_STAT(st) && S_ISDIR((st).st_mode)) +#define SET_STAT_INVALID(st) ((st).st_nlink = 0) #ifndef MIN #define MIN(a,b) ((a)<(b)?(a):(b)) diff -r -u source/lib/util.c source-new/lib/util.c --- source/lib/util.c 2005-04-13 23:14:23.000000000 -0700 +++ source-new/lib/util.c 2005-06-15 11:58:55.000000000 -0700 @@ -613,38 +613,6 @@ trim_string(s,NULL,"/.."); } -/**************************************************************************** - Make a dir struct. -****************************************************************************/ - -void make_dir_struct(char *buf, const char *mask, const char *fname,SMB_OFF_T size,int mode,time_t date) -{ - char *p; - pstring mask2; - - pstrcpy(mask2,mask); - - if ((mode & aDIR) != 0) - size = 0; - - memset(buf+1,' ',11); - if ((p = strchr_m(mask2,'.')) != NULL) { - *p = 0; - push_ascii(buf+1,mask2,8, 0); - push_ascii(buf+9,p+1,3, 0); - *p = '.'; - } else - push_ascii(buf+1,mask2,11, 0); - - memset(buf+21,'\0',DIR_STRUCT_SIZE-21); - SCVAL(buf,21,mode); - put_dos_date(buf,22,date); - SSVAL(buf,26,size & 0xFFFF); - SSVAL(buf,28,(size >> 16)&0xFFFF); - push_ascii(buf+30,fname,12,0); - DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname)); -} - /******************************************************************* Close the low 3 fd's and open dev/null in their place. ********************************************************************/ @@ -2473,6 +2441,22 @@ } /******************************************************************* + A wrapper that handles case sensitivity and the special handling + of the ".." name. Varient that is only called by old search code which requires + pattern translation. +*******************************************************************/ + +BOOL mask_match_search(const char *string, char *pattern, BOOL is_case_sensitive) +{ + if (strcmp(string,"..") == 0) + string = "."; + if (strcmp(pattern,".") == 0) + return False; + + return ms_fnmatch(pattern, string, True, is_case_sensitive) == 0; +} + +/******************************************************************* A wrapper that handles a list of patters and calls mask_match() on each. Returns True if any of the patterns match. *******************************************************************/ diff -r -u source/smbd/dir.c source-new/smbd/dir.c --- source/smbd/dir.c 2005-04-13 23:14:20.000000000 -0700 +++ source-new/smbd/dir.c 2005-06-15 11:59:46.000000000 -0700 @@ -24,6 +24,8 @@ This module implements directory related functions for Samba. */ +extern struct current_user current_user; + /* Make directory handle internals available. */ #define NAME_CACHE_SIZE 100 @@ -40,6 +42,7 @@ char *dir_path; struct name_cache_entry *name_cache; unsigned int name_cache_index; + unsigned int file_number; }; struct dptr_struct { @@ -62,6 +65,40 @@ #define INVALID_DPTR_KEY (-3) /**************************************************************************** + Make a dir struct. +****************************************************************************/ + +void make_dir_struct(char *buf, const char *mask, const char *fname,SMB_OFF_T size,int mode,time_t date, BOOL uc) +{ + char *p; + pstring mask2; + + pstrcpy(mask2,mask); + + if ((mode & aDIR) != 0) + size = 0; + + memset(buf+1,' ',11); + if ((p = strchr_m(mask2,'.')) != NULL) { + *p = 0; + push_ascii(buf+1,mask2,8, 0); + push_ascii(buf+9,p+1,3, 0); + *p = '.'; + } else + push_ascii(buf+1,mask2,11, 0); + + memset(buf+21,'\0',DIR_STRUCT_SIZE-21); + SCVAL(buf,21,mode); + put_dos_date(buf,22,date); + SSVAL(buf,26,size & 0xFFFF); + SSVAL(buf,28,(size >> 16)&0xFFFF); + /* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf. + Strange, but verified on W2K3. Needed for OS/2. JRA. */ + push_ascii(buf+30,fname,12, uc ? STR_UPPER : 0); + DEBUG(8,("put name [%s] from [%s] into dir struct\n",buf+30, fname)); +} + +/**************************************************************************** Initialise the dir bitmap. ****************************************************************************/ @@ -524,7 +561,7 @@ { pstring pathreal; - ZERO_STRUCTP(pst); + SET_STAT_INVALID(*pst); if (dptr->has_wild) { return dptr_normal_ReadDirName(dptr, poffset, pst); @@ -593,7 +630,7 @@ BOOL dptr_SearchDir(struct dptr_struct *dptr, const char *name, long *poffset, SMB_STRUCT_STAT *pst) { - ZERO_STRUCTP(pst); + SET_STAT_INVALID(*pst); if (!dptr->has_wild && (dptr->dir_hnd->offset == -1)) { /* This is a singleton directory and we're already at the end. */ @@ -622,11 +659,11 @@ DEBUG(1,("filling null dirptr %d\n",key)); return(False); } - offset = TellDir(dptr->dir_hnd); + offset = (uint32)TellDir(dptr->dir_hnd); DEBUG(6,("fill on key %u dirptr 0x%lx now at %d\n",key, (long)dptr->dir_hnd,(int)offset)); buf[0] = key; - SIVAL(buf,1,offset | DPTR_MASK); + SIVAL(buf,1,offset); return(True); } @@ -639,16 +676,22 @@ unsigned int key = *(unsigned char *)buf; struct dptr_struct *dptr = dptr_get(key, False); uint32 offset; + long seekoff; if (!dptr) { DEBUG(3,("fetched null dirptr %d\n",key)); return(NULL); } *num = key; - offset = IVAL(buf,1)&~DPTR_MASK; - SeekDir(dptr->dir_hnd,(long)offset); + offset = IVAL(buf,1); + if (offset == (uint32)-1) { + seekoff = -1; + } else { + seekoff = (long)offset; + } + SeekDir(dptr->dir_hnd,seekoff); DEBUG(3,("fetching dirptr %d for path %s at offset %d\n", - key,dptr_path(key),offset)); + key,dptr_path(key),(int)seekoff)); return(dptr); } @@ -697,7 +740,7 @@ static BOOL mangle_mask_match(connection_struct *conn, fstring filename, char *mask) { mangle_map(filename,True,False,SNUM(conn)); - return mask_match(filename,mask,False); + return mask_match_search(filename,mask,False); } /**************************************************************************** @@ -712,16 +755,11 @@ SMB_STRUCT_STAT sbuf; pstring path; pstring pathreal; - BOOL isrootdir; pstring filename; BOOL needslash; *path = *pathreal = *filename = 0; - isrootdir = (strequal(conn->dirpath,"./") || - strequal(conn->dirpath,".") || - strequal(conn->dirpath,"/")); - needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/'); if (!conn->dirptr) @@ -744,10 +782,8 @@ see masktest for a demo */ if ((strcmp(mask,"*.*") == 0) || - mask_match(filename,mask,False) || + mask_match_search(filename,mask,False) || mangle_mask_match(conn,filename,mask)) { - if (isrootdir && (strequal(filename,"..") || strequal(filename,"."))) - continue; if (!mangle_is_8_3(filename, False)) mangle_map(filename,True,False,SNUM(conn)); @@ -792,7 +828,6 @@ static BOOL user_can_read_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst) { - extern struct current_user current_user; SEC_DESC *psd = NULL; size_t sd_size; files_struct *fsp; @@ -845,7 +880,6 @@ static BOOL user_can_write_file(connection_struct *conn, char *name, SMB_STRUCT_STAT *pst) { - extern struct current_user current_user; SEC_DESC *psd = NULL; size_t sd_size; files_struct *fsp; @@ -925,7 +959,7 @@ BOOL hide_unwriteable = lp_hideunwriteable_files(SNUM(conn)); BOOL hide_special = lp_hide_special_files(SNUM(conn)); - ZERO_STRUCTP(pst); + SET_STAT_INVALID(*pst); if ((strcmp(".",name) == 0) || (strcmp("..",name) == 0)) { return True; /* . and .. are always visible. */ @@ -953,7 +987,7 @@ return False; } /* Honour _hide_special_ option */ - if (hide_special && !file_is_special(conn, entry, pst)) { + if (hide_special && file_is_special(conn, entry, pst)) { SAFE_FREE(entry); return False; } @@ -1041,19 +1075,35 @@ const char *n; connection_struct *conn = dirp->conn; - SeekDir(dirp, *poffset); + /* Cheat to allow . and .. to be the first entries returned. */ + if ((*poffset == 0) && (dirp->file_number < 2)) { + if (dirp->file_number == 0) { + n = "."; + } else { + n = ".."; + } + dirp->file_number++; + return n; + } else { + /* A real offset, seek to it. */ + SeekDir(dirp, *poffset); + } + while ((n = vfs_readdirname(conn, dirp->dir))) { struct name_cache_entry *e; - dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir); - if (dirp->offset == -1) { - return NULL; + /* Ignore . and .. - we've already returned them. */ + if (*n == '.') { + if ((n[1] == '\0') || (n[1] == '.' && n[2] == '\0')) { + continue; + } } + dirp->offset = SMB_VFS_TELLDIR(conn, dirp->dir); dirp->name_cache_index = (dirp->name_cache_index+1) % NAME_CACHE_SIZE; - e = &dirp->name_cache[dirp->name_cache_index]; SAFE_FREE(e->name); e->name = SMB_STRDUP(n); *poffset = e->offset= dirp->offset; + dirp->file_number++; return e->name; } dirp->offset = -1; @@ -1061,13 +1111,29 @@ } /******************************************************************* + Rewind to the start. +********************************************************************/ + +void RewindDir(struct smb_Dir *dirp, long *poffset) +{ + SMB_VFS_REWINDDIR(dirp->conn, dirp->dir); + dirp->file_number = 0; + dirp->offset = 0; + *poffset = 0; +} + +/******************************************************************* Seek a dir. ********************************************************************/ void SeekDir(struct smb_Dir *dirp, long offset) { if (offset != dirp->offset) { - SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset); + if (offset == 0) { + RewindDir(dirp, &offset); + } else { + SMB_VFS_SEEKDIR(dirp->conn, dirp->dir, offset); + } dirp->offset = offset; } } @@ -1112,6 +1178,7 @@ /* Not found in the name cache. Rewind directory and start from scratch. */ SMB_VFS_REWINDDIR(conn, dirp->dir); + dirp->file_number = 0; *poffset = 0; while ((entry = ReadDirName(dirp, poffset))) { if (conn->case_sensitive ? (strcmp(entry, name) == 0) : strequal(entry, name)) { diff -r -u source/smbd/reply.c source-new/smbd/reply.c --- source/smbd/reply.c 2005-04-13 23:14:20.000000000 -0700 +++ source-new/smbd/reply.c 2005-06-15 12:03:14.000000000 -0700 @@ -821,6 +821,8 @@ BOOL can_open = True; BOOL bad_path = False; NTSTATUS nt_status; + BOOL allow_long_path_components = (SVAL(inbuf,smb_flg2) & FLAGS2_LONG_PATH_COMPONENTS) ? True : False; + START_PROFILE(SMBsearch); *mask = *directory = *fname = 0; @@ -920,7 +922,7 @@ if (ok) { if ((dirtype&0x1F) == aVOLID) { memcpy(p,status,21); - make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0); + make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0, !allow_long_path_components); dptr_fill(p+12,dptr_num); if (dptr_zero(p+12) && (status_len==0)) numentries = 1; @@ -940,7 +942,7 @@ 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); + make_dir_struct(p,mask,fname,size,mode,date,!allow_long_path_components); dptr_fill(p+12,dptr_num); numentries++; p += DIR_STRUCT_SIZE; @@ -3461,7 +3463,7 @@ struct smb_Dir *dir_hnd = OpenDir(conn, directory); if(dir_hnd != NULL) { - long dirpos = TellDir(dir_hnd); + long dirpos = 0; while ((dname = ReadDirName(dir_hnd,&dirpos))) { if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) continue; @@ -3474,7 +3476,7 @@ } if(all_veto_files) { - SeekDir(dir_hnd,dirpos); + RewindDir(dir_hnd,&dirpos); while ((dname = ReadDirName(dir_hnd,&dirpos))) { pstring fullname;