diff options
Diffstat (limited to 'source4/ntvfs/posix/pvfs_dirlist.c')
-rw-r--r-- | source4/ntvfs/posix/pvfs_dirlist.c | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/source4/ntvfs/posix/pvfs_dirlist.c b/source4/ntvfs/posix/pvfs_dirlist.c new file mode 100644 index 0000000000..1b4d01c197 --- /dev/null +++ b/source4/ntvfs/posix/pvfs_dirlist.c @@ -0,0 +1,126 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Andrew Tridgell 2004 + + 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. +*/ +/* + directory listing functions for posix backend +*/ + +#include "includes.h" +#include "vfs_posix.h" + +/* + 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 +*/ +static NTSTATUS pvfs_list_no_wildcard(struct pvfs_state *pvfs, struct pvfs_filename *name, + const char *pattern, struct pvfs_dir *dir) +{ + if (!name->exists) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + dir->count = 0; + dir->unix_path = name->full_name; + + dir->names = talloc_array_p(dir, const char *, 1); + if (!dir->names) { + return NT_STATUS_NO_MEMORY; + } + + dir->names[0] = talloc_strdup(dir, pattern); + if (!dir->names[0]) { + return NT_STATUS_NO_MEMORY; + } + + dir->count = 1; + + return NT_STATUS_OK; +} + +/* + read a directory and find all matching file names, returning them in + the structure *dir. The returned names are relative to the directory + + if the pattern matches no files then we return NT_STATUS_OK, with dir->count = 0 +*/ +NTSTATUS pvfs_list(struct pvfs_state *pvfs, struct pvfs_filename *name, struct pvfs_dir *dir) +{ + DIR *odir; + struct dirent *dent; + uint_t allocated = 0; + char *pattern; + + /* split the unix path into a directory + pattern */ + pattern = strrchr(name->full_name, '/'); + if (!pattern) { + /* this should not happen, as pvfs_unix_path is supposed to + return an absolute path */ + return NT_STATUS_UNSUCCESSFUL; + } + + *pattern++ = 0; + + if (!name->has_wildcard) { + return pvfs_list_no_wildcard(pvfs, name, pattern, dir); + } + + dir->count = 0; + dir->unix_path = name->full_name; + dir->names = talloc(dir, 0); + if (!dir->names) { + return NT_STATUS_NO_MEMORY; + } + + odir = opendir(name->full_name); + if (!odir) { + return pvfs_map_errno(pvfs, errno); + } + + while ((dent = readdir(odir))) { + uint_t i = dir->count; + const char *dname = dent->d_name; + + /* check it matches the wildcard pattern */ + if (ms_fnmatch(pattern, dname, PROTOCOL_NT1) != 0) { + continue; + } + + if (dir->count >= allocated) { + allocated = (allocated + 100) * 1.2; + dir->names = talloc_realloc_p(dir->names, const char *, allocated); + if (!dir->names) { + closedir(odir); + return NT_STATUS_NO_MEMORY; + } + } + + dir->names[i] = talloc_strdup(dir, dname); + if (!dir->names[i]) { + closedir(odir); + return NT_STATUS_NO_MEMORY; + } + + dir->count++; + } + + closedir(odir); + + return NT_STATUS_OK; +} + |