2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2004
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 directory listing functions for posix backend
25 #include "vfs_posix.h"
26 #include "system/dir.h"
29 struct pvfs_state *pvfs;
35 const char *unix_path;
40 a special directory listing case where the pattern has no wildcard. We can just do a single stat()
41 thus avoiding the more expensive directory scan
43 static NTSTATUS pvfs_list_no_wildcard(struct pvfs_state *pvfs, struct pvfs_filename *name,
44 const char *pattern, struct pvfs_dir *dir)
47 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
51 dir->no_wildcard = True;
52 dir->end_of_search = False;
53 dir->unix_path = talloc_strdup(dir, name->full_name);
54 if (!dir->unix_path) {
55 return NT_STATUS_NO_MEMORY;
58 dir->last_name = talloc_strdup(dir, pattern);
59 if (!dir->last_name) {
60 return NT_STATUS_NO_MEMORY;
71 destroy an open search
73 static int pvfs_dirlist_destructor(void *ptr)
75 struct pvfs_dir *dir = ptr;
76 if (dir->dir) closedir(dir->dir);
81 start to read a directory
83 if the pattern matches no files then we return NT_STATUS_OK, with dir->count = 0
85 NTSTATUS pvfs_list_start(struct pvfs_state *pvfs, struct pvfs_filename *name,
86 TALLOC_CTX *mem_ctx, struct pvfs_dir **dirp)
91 (*dirp) = talloc_p(mem_ctx, struct pvfs_dir);
93 return NT_STATUS_NO_MEMORY;
98 /* split the unix path into a directory + pattern */
99 pattern = strrchr(name->full_name, '/');
101 /* this should not happen, as pvfs_unix_path is supposed to
102 return an absolute path */
103 return NT_STATUS_UNSUCCESSFUL;
108 if (!name->has_wildcard) {
109 return pvfs_list_no_wildcard(pvfs, name, pattern, dir);
112 dir->unix_path = talloc_strdup(dir, name->full_name);
113 if (!dir->unix_path) {
114 return NT_STATUS_NO_MEMORY;
117 dir->pattern = talloc_strdup(dir, pattern);
118 if (dir->pattern == NULL) {
119 return NT_STATUS_NO_MEMORY;
122 dir->dir = opendir(name->full_name);
124 return pvfs_map_errno(pvfs, errno);
128 dir->no_wildcard = False;
129 dir->last_name = NULL;
130 dir->end_of_search = False;
133 talloc_set_destructor(dir, pvfs_dirlist_destructor);
139 return the next entry
141 const char *pvfs_list_next(struct pvfs_dir *dir, uint_t *ofs)
145 /* non-wildcard searches are easy */
146 if (dir->no_wildcard) {
147 dir->end_of_search = True;
148 if (*ofs != 0) return NULL;
150 return dir->last_name;
153 if (*ofs != dir->offset) {
154 seekdir(dir->dir, *ofs);
158 while ((de = readdir(dir->dir))) {
159 const char *dname = de->d_name;
161 if (ms_fnmatch(dir->pattern, dname,
162 dir->pvfs->tcon->smb_conn->negotiate.protocol) != 0) {
163 char *short_name = pvfs_short_name_component(dir->pvfs, dname);
164 if (short_name == NULL ||
165 ms_fnmatch(dir->pattern, short_name,
166 dir->pvfs->tcon->smb_conn->negotiate.protocol) != 0) {
167 talloc_free(short_name);
170 talloc_free(short_name);
173 dir->offset = telldir(dir->dir);
174 (*ofs) = dir->offset;
176 if (dir->last_name) talloc_free(dir->last_name);
177 dir->last_name = talloc_strdup(dir, de->d_name);
179 return dir->last_name;
182 if (dir->last_name) talloc_free(dir->last_name);
183 dir->last_name = NULL;
184 dir->end_of_search = True;
185 pvfs_list_hibernate(dir);
190 put the directory to sleep. Used between search calls to give the
191 right directory change semantics
193 void pvfs_list_hibernate(struct pvfs_dir *dir)
199 if (!dir->no_wildcard && dir->last_name) {
200 talloc_free(dir->last_name);
201 dir->last_name = NULL;
207 wake up the directory search
209 NTSTATUS pvfs_list_wakeup(struct pvfs_dir *dir, uint_t *ofs)
211 if (dir->no_wildcard ||
216 dir->dir = opendir(dir->unix_path);
217 if (dir->dir == NULL) {
218 dir->end_of_search = True;
219 return pvfs_map_errno(dir->pvfs, errno);
222 seekdir(dir->dir, *ofs);
223 dir->offset = telldir(dir->dir);
224 if (dir->offset != *ofs) {
225 DEBUG(0,("pvfs_list_wakeup: search offset changed %u -> %u\n",
226 *ofs, (unsigned)dir->offset));
235 return unix directory of an open search
237 const char *pvfs_list_unix_path(struct pvfs_dir *dir)
239 return dir->unix_path;
243 return True if end of search has been reached
245 BOOL pvfs_list_eos(struct pvfs_dir *dir, uint_t ofs)
247 return dir->end_of_search;
251 seek to the given name
253 NTSTATUS pvfs_list_seek(struct pvfs_dir *dir, const char *name, uint_t *ofs)
258 status = pvfs_list_wakeup(dir, ofs);
259 if (!NT_STATUS_IS_OK(status)) {
263 if (dir->last_name &&
264 StrCaseCmp(name, dir->last_name) == 0) {
271 while ((de = readdir(dir->dir))) {
272 if (StrCaseCmp(name, de->d_name) == 0) {
273 dir->offset = telldir(dir->dir);
275 if (dir->last_name) talloc_free(dir->last_name);
276 dir->last_name = talloc_strdup(dir, de->d_name);
281 dir->end_of_search = True;
283 pvfs_list_hibernate(dir);
285 return NT_STATUS_OBJECT_NAME_NOT_FOUND;