2 Unix SMB/CIFS implementation.
4 POSIX NTVFS backend - directory search functions
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "include/includes.h"
24 #include "vfs_posix.h"
27 fill in a single search result for a given info level
29 static NTSTATUS fill_search_info(struct pvfs_state *pvfs,
30 enum smb_search_level level,
31 const char *unix_path,
33 uint16_t search_attrib,
35 union smb_search_data *file)
37 struct pvfs_file_info *finfo;
40 finfo = talloc_p((TALLOC_CTX *)file, struct pvfs_file_info);
42 return NT_STATUS_NO_MEMORY;
45 status = pvfs_relative_file_info_cs(pvfs, unix_path, name, finfo);
46 if (!NT_STATUS_IS_OK(status)) {
53 case RAW_SEARCH_BOTH_DIRECTORY_INFO:
54 file->both_directory_info.file_index = dir_index;
55 file->both_directory_info.create_time = finfo->create_time;
56 file->both_directory_info.access_time = finfo->access_time;
57 file->both_directory_info.write_time = finfo->write_time;
58 file->both_directory_info.change_time = finfo->change_time;
59 file->both_directory_info.size = finfo->size;
60 file->both_directory_info.alloc_size = finfo->alloc_size;
61 file->both_directory_info.attrib = finfo->attrib;
62 file->both_directory_info.ea_size = finfo->ea_size;
63 file->both_directory_info.short_name.s = pvfs_short_name(pvfs, (TALLOC_CTX *)file,
65 file->both_directory_info.name.s = name;
75 return the next available search handle
77 static NTSTATUS pvfs_next_search_handle(struct pvfs_state *pvfs, uint16_t *handle)
79 struct pvfs_search_state *search;
81 if (pvfs->search.num_active_searches >= 0x10000) {
82 return NT_STATUS_INSUFFICIENT_RESOURCES;
85 (*handle) = pvfs->search.next_search_handle;
86 for (search=pvfs->search.open_searches;search;search=search->next) {
87 if (*handle == search->handle) {
88 *handle = ((*handle)+1) & 0xFFFF;
92 pvfs->search.next_search_handle = ((*handle)+1) & 0xFFFF;
98 list files in a directory matching a wildcard pattern
100 NTSTATUS pvfs_search_first(struct smbsrv_request *req, union smb_search_first *io,
101 void *search_private,
102 BOOL (*callback)(void *, union smb_search_data *))
104 struct pvfs_dir *dir;
105 struct pvfs_state *pvfs = req->tcon->ntvfs_private;
106 struct pvfs_search_state *search;
107 union smb_search_data *file;
108 uint16_t max_count, reply_count;
109 uint16_t search_attrib;
113 struct pvfs_filename *name;
115 switch (io->generic.level) {
116 case RAW_SEARCH_SEARCH:
117 max_count = io->search_first.in.max_count;
118 search_attrib = io->search_first.in.search_attrib;
119 pattern = io->search_first.in.pattern;
122 case RAW_SEARCH_STANDARD:
123 case RAW_SEARCH_EA_SIZE:
124 case RAW_SEARCH_DIRECTORY_INFO:
125 case RAW_SEARCH_FULL_DIRECTORY_INFO:
126 case RAW_SEARCH_NAME_INFO:
127 case RAW_SEARCH_BOTH_DIRECTORY_INFO:
128 case RAW_SEARCH_ID_FULL_DIRECTORY_INFO:
129 case RAW_SEARCH_ID_BOTH_DIRECTORY_INFO:
130 case RAW_SEARCH_UNIX_INFO:
131 max_count = io->t2ffirst.in.max_count;
132 search_attrib = io->t2ffirst.in.search_attrib;
133 pattern = io->t2ffirst.in.pattern;
136 case RAW_SEARCH_FCLOSE:
137 case RAW_SEARCH_GENERIC:
138 DEBUG(0,("WARNING: Invalid search class %d in pvfs_search_first\n", io->generic.level));
139 return NT_STATUS_INVALID_INFO_CLASS;
142 /* resolve the cifs name to a posix name */
143 status = pvfs_resolve_name(pvfs, req, pattern, 0, &name);
144 if (!NT_STATUS_IS_OK(status)) {
148 if (!name->has_wildcard && !name->exists) {
149 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
152 /* we initially make search a child of the request, then if we
153 need to keep it long term we steal it for the private
155 search = talloc_p(req, struct pvfs_search_state);
157 return NT_STATUS_NO_MEMORY;
160 dir = talloc_p(search, struct pvfs_dir);
162 return NT_STATUS_NO_MEMORY;
165 /* do the actual directory listing */
166 status = pvfs_list(pvfs, name, dir);
167 if (!NT_STATUS_IS_OK(status)) {
171 /* we need to give a handle back to the client so it
172 can continue a search */
173 status = pvfs_next_search_handle(pvfs, &search->handle);
174 if (!NT_STATUS_IS_OK(status)) {
179 search->current_index = 0;
180 search->search_attrib = search_attrib;
182 if (dir->count < max_count) {
183 max_count = dir->count;
186 file = talloc_p(req, union smb_search_data);
188 return NT_STATUS_NO_MEMORY;
191 /* note that fill_search_info() can fail, if for example a
192 file disappears during a search or we don't have sufficient
193 permissions to stat() it, or the search_attrib does not
194 match the files attribute. In that case the name is ignored
195 and the search continues. */
196 for (i=reply_count=0; i < dir->count && reply_count < max_count;i++) {
197 status = fill_search_info(pvfs, io->generic.level, dir->unix_path, dir->names[i],
198 search_attrib, i, file);
199 if (NT_STATUS_IS_OK(status)) {
200 if (!callback(search_private, file)) {
207 /* not matching any entries is an error */
208 if (reply_count == 0) {
209 return NT_STATUS_NO_MORE_ENTRIES;
212 search->current_index = i;
214 if (io->generic.level == RAW_SEARCH_SEARCH) {
215 io->search_first.out.count = reply_count;
216 DEBUG(0,("TODO: handle RAW_SEARCH_SEARCH continue\n"));
218 io->t2ffirst.out.count = reply_count;
219 io->t2ffirst.out.handle = search->handle;
220 io->t2ffirst.out.end_of_search = (i == dir->count) ? 1 : 0;
221 /* work out if we are going to keep the search state
222 and allow for a search continue */
223 if ((io->t2ffirst.in.flags & FLAG_TRANS2_FIND_CLOSE) ||
224 ((io->t2ffirst.in.flags & FLAG_TRANS2_FIND_CLOSE_IF_END) && (i == dir->count))) {
227 pvfs->search.num_active_searches++;
228 pvfs->search.next_search_handle++;
229 talloc_steal(pvfs, search);
230 DLIST_ADD(pvfs->search.open_searches, search);
237 /* continue a search */
238 NTSTATUS pvfs_search_next(struct smbsrv_request *req, union smb_search_next *io,
239 void *search_private,
240 BOOL (*callback)(void *, union smb_search_data *))
242 return NT_STATUS_NOT_IMPLEMENTED;
246 NTSTATUS pvfs_search_close(struct smbsrv_request *req, union smb_search_close *io)
248 return NT_STATUS_NOT_IMPLEMENTED;