2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2003
5 Copyright (C) James J Myers 2003 <myersjj@samba.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 This file handles the parsing of transact2 requests
27 /* check req->async.status and if not OK then send an error reply */
28 #define CHECK_ASYNC_STATUS do { \
29 if (!NT_STATUS_IS_OK(req->async.status)) { \
30 req_reply_error(req, req->async.status); \
35 check if the backend wants to handle the request asynchronously.
36 if it wants it handled synchronously then call the send function
39 #define REQ_ASYNC_TAIL do { \
40 if (!(req->control_flags & REQ_CONTROL_ASYNC)) { \
41 req->async.send_fn(req); \
44 /* useful wrapper for talloc with NO_MEMORY reply */
45 #define REQ_TALLOC(ptr, size) do { \
46 ptr = talloc(req->mem_ctx, size); \
48 req_reply_error(req, NT_STATUS_NO_MEMORY); \
52 #define CHECK_MIN_BLOB_SIZE(blob, size) do { \
53 if ((blob)->length < (size)) { \
54 return NT_STATUS_INFO_LENGTH_MISMATCH; \
57 /* a structure to encapsulate the state information about
58 * an in-progress search first/next operation */
60 struct request_context *req;
61 union smb_search_data *file;
62 uint16_t last_entry_offset;
66 fill a single entry in a search find reply
68 static void find_fill_info(struct request_context *req,
69 union smb_search_data *file)
71 char *p = req->out.data + req->out.data_size;
75 DEBUG(9,("find_fill_info: input file data: attr=0x%x size=%u time=0x%x name=%13s\n",
76 file->search.attrib, file->search.size,
77 (uint32_t)file->search.write_time, file->search.name));
79 p += req_append_bytes(req, file->search.search_id.data, 21);
80 p += req_append_bytes(req, (char*)&file->search.attrib, 1);
81 srv_push_dos_date3(req->smb_ctx, (uint8_t *)&dos_date, 0, file->search.write_time);
82 p += req_append_bytes(req, (char*)&dos_date, 4);
83 p += req_append_bytes(req, (char*)&file->search.size, 4);
84 memset(&search_name[0], ' ', 13);
85 memcpy(&search_name[0], file->search.name,
86 MAX(13, strlen(file->search.name)));
87 p += req_append_bytes(req, &search_name[0], 13);
90 /* callback function for search first/next */
91 static BOOL find_callback(void *private, union smb_search_data *file)
93 struct search_state *state = (struct search_state *)private;
95 find_fill_info(state->req, file);
100 /****************************************************************************
102 ****************************************************************************/
103 void reply_search(struct request_context *req)
105 union smb_search_first *sf;
106 union smb_search_next *sn;
107 DATA_BLOB resume_key;
108 uint16_t resume_key_length;
109 struct search_state state;
112 REQ_TALLOC(sf, sizeof(*sf));
115 if (req->in.wct != 2) {
116 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
121 p += req_pull_ascii4(req, &sf->search_first.in.pattern,
123 if (!sf->search_first.in.pattern) {
124 req_reply_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
127 /* pull in type 5 byte and length */
128 if (!req_pull_blob(req, p, 3, &resume_key))
129 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
130 resume_key_length = SVAL(resume_key.data, 1);
132 DEBUG(19,("reply_search: pattern=%s, key_length=%d\n",
133 sf->search_first.in.pattern, resume_key_length));
135 /* setup state for callback */
138 state.last_entry_offset = 0;
140 /* construct reply */
141 req_setup_reply(req, 1, 0);
142 req_append_var_block(req, NULL, 0);
144 if (resume_key_length > 0) {
145 /* do a search next operation */
146 REQ_TALLOC(sn, sizeof(*sn));
147 sn->search_next.level = RAW_SEARCH_SEARCH;
148 req->async.private = sn;
149 if (!req_pull_blob(req, req->in.data, resume_key_length,
150 &(sn->search_next.in.search_id)))
151 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
152 sn->search_next.in.search_attrib = SVAL(req->in.vwv, VWV(1));
153 sn->search_next.in.max_count = SVAL(req->in.vwv, VWV(0));
156 req->async.status = req->conn->ntvfs_ops->search_next(req,
157 sn, &state, find_callback);
158 SSVAL(req->out.vwv, VWV(0), sn->search_next.out.count);
160 /* do a search first operation */
161 req->async.private = sf;
162 sf->search_first.level = RAW_SEARCH_SEARCH;
163 sf->search_first.in.search_attrib = SVAL(req->in.vwv, VWV(1));
164 sf->search_first.in.max_count = SVAL(req->in.vwv, VWV(0));
167 req->async.status = req->conn->ntvfs_ops->search_first(req,
168 sf, &state, find_callback);
169 SSVAL(req->out.vwv, VWV(0), sf->search_first.out.count);
176 /****************************************************************************
177 Reply to a fclose (async reply)
178 ****************************************************************************/
179 static void reply_fclose_send(struct request_context *req)
183 /* construct reply */
184 req_setup_reply(req, 1, 0);
190 /****************************************************************************
191 Reply to fclose (stop directory search).
192 ****************************************************************************/
193 void reply_fclose(struct request_context *req)
195 union smb_search_next *sn;
196 DATA_BLOB resume_key;
197 uint16_t resume_key_length;
199 REQ_TALLOC(sn, sizeof(*sn));
202 if (req->in.wct != 2) {
203 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
207 sn->search_next.level = RAW_SEARCH_FCLOSE;
209 /* pull in type 5 byte and length */
210 if (!req_pull_blob(req, req->in.data, 3, &resume_key))
211 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
212 resume_key_length = SVAL(resume_key.data, 1);
213 if (resume_key_length > 0) {
214 /* do a search close operation */
215 if (!req_pull_blob(req, req->in.data, resume_key_length,
216 &(sn->search_next.in.search_id)))
217 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
219 req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
221 req->async.send_fn = reply_fclose_send;
222 req->async.private = sn;
225 req->async.status = req->conn->ntvfs_ops->search_next(req, sn,