Author: tridge Date: 2005-07-25 10:40:17 +0000 (Mon, 25 Jul 2005) New Revision: 8753
WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=8753 Log: fixed directory handling on systems that do not return . and .. as the first two entries in a directory. This is what caused the FC3 system shelob in the build farm to fail the RAW-UNLINK and RAW-SEARCH tests. Modified: branches/SAMBA_4_0/source/ntvfs/posix/pvfs_dirlist.c Changeset: Modified: branches/SAMBA_4_0/source/ntvfs/posix/pvfs_dirlist.c =================================================================== --- branches/SAMBA_4_0/source/ntvfs/posix/pvfs_dirlist.c 2005-07-25 06:33:51 UTC (rev 8752) +++ branches/SAMBA_4_0/source/ntvfs/posix/pvfs_dirlist.c 2005-07-25 10:40:17 UTC (rev 8753) @@ -45,6 +45,11 @@ uint32_t name_cache_index; }; +#define DIR_OFFSET_DOT 0 +#define DIR_OFFSET_DOTDOT 1 +#define DIR_OFFSET_BASE 2 + + /* a special directory listing case where the pattern has no wildcard. We can just do a single stat() thus avoiding the more expensive directory scan @@ -150,12 +155,29 @@ return NT_STATUS_OK; } +/* + add an entry to the local cache +*/ +static void dcache_add(struct pvfs_dir *dir, const char *name) +{ + struct name_cache_entry *e; + + dir->name_cache_index = (dir->name_cache_index+1) % NAME_CACHE_SIZE; + e = &dir->name_cache[dir->name_cache_index]; + + if (e->name) talloc_free(e->name); + + e->name = talloc_strdup(dir->name_cache, name); + e->offset = dir->offset; +} + /* return the next entry */ const char *pvfs_list_next(struct pvfs_dir *dir, uint_t *ofs) { struct dirent *de; + enum protocol_types protocol = dir->pvfs->tcon->smb_conn->negotiate.protocol; /* non-wildcard searches are easy */ if (dir->no_wildcard) { @@ -165,39 +187,58 @@ return dir->single_name; } - if (*ofs != dir->offset) { - seekdir(dir->dir, *ofs); + /* . and .. are handled separately as some unix systems will + not return them first in a directory, but windows client + may assume that these entries always appear first */ + if (*ofs == DIR_OFFSET_DOT) { + (*ofs)++; dir->offset = *ofs; + if (ms_fnmatch(dir->pattern, ".", protocol) == 0) { + dcache_add(dir, "."); + return "."; + } } + + if (*ofs == DIR_OFFSET_DOTDOT) { + (*ofs)++; + dir->offset = *ofs; + if (ms_fnmatch(dir->pattern, "..", protocol) == 0) { + dcache_add(dir, ".."); + return ".."; + } + } + + if (*ofs == DIR_OFFSET_BASE) { + rewinddir(dir->dir); + } else if (*ofs != dir->offset) { + seekdir(dir->dir, (*ofs) - DIR_OFFSET_BASE); + } + dir->offset = *ofs; while ((de = readdir(dir->dir))) { const char *dname = de->d_name; - struct name_cache_entry *e; - if (ms_fnmatch(dir->pattern, dname, - dir->pvfs->tcon->smb_conn->negotiate.protocol) != 0) { + if (strcmp(dname, ".") == 0 || + strcmp(dname, "..") == 0) { + continue; + } + + if (ms_fnmatch(dir->pattern, dname, protocol) != 0) { char *short_name = pvfs_short_name_component(dir->pvfs, dname); if (short_name == NULL || - ms_fnmatch(dir->pattern, short_name, - dir->pvfs->tcon->smb_conn->negotiate.protocol) != 0) { + ms_fnmatch(dir->pattern, short_name, protocol) != 0) { talloc_free(short_name); continue; } talloc_free(short_name); } - dir->offset = telldir(dir->dir); + dir->offset = telldir(dir->dir) + DIR_OFFSET_BASE; (*ofs) = dir->offset; - dir->name_cache_index = (dir->name_cache_index+1) % NAME_CACHE_SIZE; - e = &dir->name_cache[dir->name_cache_index]; + dcache_add(dir, dname); - if (e->name) talloc_free(e->name); - - e->name = talloc_strdup(dir->name_cache, de->d_name); - e->offset = dir->offset; - - return e->name; + return dname; } dir->end_of_search = True; @@ -228,6 +269,18 @@ struct dirent *de; int i; + if (strcmp(name, ".") == 0) { + dir->offset = DIR_OFFSET_DOTDOT; + *ofs = dir->offset; + return NT_STATUS_OK; + } + + if (strcmp(name, "..") == 0) { + dir->offset = DIR_OFFSET_BASE; + *ofs = dir->offset; + return NT_STATUS_OK; + } + for (i=dir->name_cache_index;i>=0;i--) { struct name_cache_entry *e = &dir->name_cache[i]; if (e->name && StrCaseCmp(name, e->name) == 0) { @@ -247,7 +300,7 @@ while ((de = readdir(dir->dir))) { if (StrCaseCmp(name, de->d_name) == 0) { - dir->offset = telldir(dir->dir); + dir->offset = telldir(dir->dir) + DIR_OFFSET_BASE; *ofs = dir->offset; return NT_STATUS_OK; }