blob: f2fa05bbcb475ea854b3f98931c3cdaea4bba89f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve French12b3b8f2006-02-09 21:12:47 +00004 * Copyright (C) International Business Machines Corp., 2002,2006
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
27 /* treated slightly different for reconnection purposes since we never want */
28 /* to reuse a stale file handle and the caller knows the file handle */
29
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
33#include <linux/posix_acl_xattr.h>
34#include <asm/uaccess.h>
35#include "cifspdu.h"
36#include "cifsglob.h"
37#include "cifsproto.h"
38#include "cifs_unicode.h"
39#include "cifs_debug.h"
Steve Frencheeac8042006-01-13 21:34:58 -080040#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#ifdef CONFIG_CIFS_POSIX
43static struct {
44 int index;
45 char *name;
46} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000047#ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000049 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000050#endif /* weak password hashing for legacy clients */
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000052 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 {BAD_PROT, "\2"}
54};
55#else
56static struct {
57 int index;
58 char *name;
59} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000060#ifdef CONFIG_CIFS_WEAK_PW_HASH
61 {LANMAN_PROT, "\2LM1.2X002"},
62#endif /* weak password hashing for legacy clients */
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 {CIFS_PROT, "\2NT LM 0.12"},
64 {BAD_PROT, "\2"}
65};
66#endif
67
Steve French39798772006-05-31 22:40:51 +000068/* define the number of elements in the cifs dialect array */
69#ifdef CONFIG_CIFS_POSIX
70#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000071#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000072#else
73#define CIFS_NUM_PROT 2
74#endif /* CIFS_WEAK_PW_HASH */
75#else /* not posix */
76#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000077#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000078#else
79#define CIFS_NUM_PROT 1
80#endif /* CONFIG_CIFS_WEAK_PW_HASH */
81#endif /* CIFS_POSIX */
82
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
84/* Mark as invalid, all open files on tree connections since they
85 were closed when session to server was lost */
86static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
87{
88 struct cifsFileInfo *open_file = NULL;
89 struct list_head * tmp;
90 struct list_head * tmp1;
91
92/* list all files open on tree connection and mark them invalid */
93 write_lock(&GlobalSMBSeslock);
94 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
95 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
96 if(open_file) {
97 open_file->invalidHandle = TRUE;
98 }
99 }
100 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700101 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
102 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103}
104
105/* If the return code is zero, this function must fill in request_buf pointer */
106static int
107small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
108 void **request_buf /* returned */)
109{
110 int rc = 0;
111
112 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
113 check for tcp and smb session status done differently
114 for those three - in the calling routine */
115 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800116 if(tcon->tidStatus == CifsExiting) {
117 /* only tree disconnect, open, and write,
118 (and ulogoff which does not have tcon)
119 are allowed as we start force umount */
120 if((smb_command != SMB_COM_WRITE_ANDX) &&
121 (smb_command != SMB_COM_OPEN_ANDX) &&
122 (smb_command != SMB_COM_TREE_DISCONNECT)) {
123 cFYI(1,("can not send cmd %d while umounting",
124 smb_command));
125 return -ENODEV;
126 }
127 }
Steve French31ca3bc2005-04-28 22:41:11 -0700128 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
129 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 struct nls_table *nls_codepage;
131 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700132 reconnect, should be greater than cifs socket
133 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
135 wait_event_interruptible_timeout(tcon->ses->server->response_q,
136 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
137 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
138 /* on "soft" mounts we wait once */
139 if((tcon->retry == FALSE) ||
140 (tcon->ses->status == CifsExiting)) {
141 cFYI(1,("gave up waiting on reconnect in smb_init"));
142 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700143 } /* else "hard" mount - keep retrying
144 until process is killed or server
145 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 } else /* TCP session is reestablished now */
147 break;
148
149 }
150
151 nls_codepage = load_nls_default();
152 /* need to prevent multiple threads trying to
153 simultaneously reconnect the same SMB session */
154 down(&tcon->ses->sesSem);
155 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700156 rc = cifs_setup_session(0, tcon->ses,
157 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
159 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700160 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
161 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700163 /* BB FIXME add code to check if wsize needs
164 update due to negotiated smb buffer size
165 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 if(rc == 0)
167 atomic_inc(&tconInfoReconnectCount);
168
169 cFYI(1, ("reconnect tcon rc = %d", rc));
170 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700171 it is safer (and faster) to reopen files
172 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
174 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700175 know whether we can continue or not without
176 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 switch(smb_command) {
178 case SMB_COM_READ_ANDX:
179 case SMB_COM_WRITE_ANDX:
180 case SMB_COM_CLOSE:
181 case SMB_COM_FIND_CLOSE2:
182 case SMB_COM_LOCKING_ANDX: {
183 unload_nls(nls_codepage);
184 return -EAGAIN;
185 }
186 }
187 } else {
188 up(&tcon->ses->sesSem);
189 }
190 unload_nls(nls_codepage);
191
192 } else {
193 return -EIO;
194 }
195 }
196 if(rc)
197 return rc;
198
199 *request_buf = cifs_small_buf_get();
200 if (*request_buf == NULL) {
201 /* BB should we add a retry in here if not a writepage? */
202 return -ENOMEM;
203 }
204
205 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
206
Steve Frencha4544342005-08-24 13:59:35 -0700207 if(tcon != NULL)
208 cifs_stats_inc(&tcon->num_smbs_sent);
209
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000211}
212
Steve French12b3b8f2006-02-09 21:12:47 +0000213int
Steve French5815449d2006-02-14 01:36:20 +0000214small_smb_init_no_tc(const int smb_command, const int wct,
215 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000216{
217 int rc;
218 struct smb_hdr * buffer;
219
Steve French5815449d2006-02-14 01:36:20 +0000220 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French12b3b8f2006-02-09 21:12:47 +0000221 if(rc)
222 return rc;
223
Steve French04fdabe2006-02-10 05:52:50 +0000224 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000225 buffer->Mid = GetNextMid(ses->server);
226 if (ses->capabilities & CAP_UNICODE)
227 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000228 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000229 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
230
231 /* uid, tid can stay at zero as set in header assemble */
232
233 /* BB add support for turning on the signing when
234 this function is used after 1st of session setup requests */
235
236 return rc;
237}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
239/* If the return code is zero, this function must fill in request_buf pointer */
240static int
241smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
242 void **request_buf /* returned */ ,
243 void **response_buf /* returned */ )
244{
245 int rc = 0;
246
247 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
248 check for tcp and smb session status done differently
249 for those three - in the calling routine */
250 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800251 if(tcon->tidStatus == CifsExiting) {
252 /* only tree disconnect, open, and write,
253 (and ulogoff which does not have tcon)
254 are allowed as we start force umount */
255 if((smb_command != SMB_COM_WRITE_ANDX) &&
256 (smb_command != SMB_COM_OPEN_ANDX) &&
257 (smb_command != SMB_COM_TREE_DISCONNECT)) {
258 cFYI(1,("can not send cmd %d while umounting",
259 smb_command));
260 return -ENODEV;
261 }
262 }
263
Steve French31ca3bc2005-04-28 22:41:11 -0700264 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
265 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700267 /* Give Demultiplex thread up to 10 seconds to
268 reconnect, should be greater than cifs socket
269 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
271 wait_event_interruptible_timeout(tcon->ses->server->response_q,
272 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
Steve French09d1db52005-04-28 22:41:08 -0700273 if(tcon->ses->server->tcpStatus ==
274 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 /* on "soft" mounts we wait once */
276 if((tcon->retry == FALSE) ||
277 (tcon->ses->status == CifsExiting)) {
278 cFYI(1,("gave up waiting on reconnect in smb_init"));
279 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700280 } /* else "hard" mount - keep retrying
281 until process is killed or server
282 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 } else /* TCP session is reestablished now */
284 break;
285
286 }
287
288 nls_codepage = load_nls_default();
289 /* need to prevent multiple threads trying to
290 simultaneously reconnect the same SMB session */
291 down(&tcon->ses->sesSem);
292 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700293 rc = cifs_setup_session(0, tcon->ses,
294 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
296 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700297 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
298 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700300 /* BB FIXME add code to check if wsize needs
301 update due to negotiated smb buffer size
302 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 if(rc == 0)
304 atomic_inc(&tconInfoReconnectCount);
305
306 cFYI(1, ("reconnect tcon rc = %d", rc));
307 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700308 it is safer (and faster) to reopen files
309 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
311 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700312 know whether we can continue or not without
313 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 switch(smb_command) {
315 case SMB_COM_READ_ANDX:
316 case SMB_COM_WRITE_ANDX:
317 case SMB_COM_CLOSE:
318 case SMB_COM_FIND_CLOSE2:
319 case SMB_COM_LOCKING_ANDX: {
320 unload_nls(nls_codepage);
321 return -EAGAIN;
322 }
323 }
324 } else {
325 up(&tcon->ses->sesSem);
326 }
327 unload_nls(nls_codepage);
328
329 } else {
330 return -EIO;
331 }
332 }
333 if(rc)
334 return rc;
335
336 *request_buf = cifs_buf_get();
337 if (*request_buf == NULL) {
338 /* BB should we add a retry in here if not a writepage? */
339 return -ENOMEM;
340 }
341 /* Although the original thought was we needed the response buf for */
342 /* potential retries of smb operations it turns out we can determine */
343 /* from the mid flags when the request buffer can be resent without */
344 /* having to use a second distinct buffer for the response */
Steve French39798772006-05-31 22:40:51 +0000345 if(response_buf)
346 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347
348 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
349 wct /*wct */ );
350
Steve Frencha4544342005-08-24 13:59:35 -0700351 if(tcon != NULL)
352 cifs_stats_inc(&tcon->num_smbs_sent);
353
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 return rc;
355}
356
357static int validate_t2(struct smb_t2_rsp * pSMB)
358{
359 int rc = -EINVAL;
360 int total_size;
361 char * pBCC;
362
363 /* check for plausible wct, bcc and t2 data and parm sizes */
364 /* check for parm and data offset going beyond end of smb */
365 if(pSMB->hdr.WordCount >= 10) {
366 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
367 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
368 /* check that bcc is at least as big as parms + data */
369 /* check that bcc is less than negotiated smb buffer */
370 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
371 if(total_size < 512) {
372 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
373 /* BCC le converted in SendReceive */
Steve French09d1db52005-04-28 22:41:08 -0700374 pBCC = (pSMB->hdr.WordCount * 2) +
375 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 (char *)pSMB;
377 if((total_size <= (*(u16 *)pBCC)) &&
378 (total_size <
379 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
380 return 0;
381 }
382
383 }
384 }
385 }
386 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
387 sizeof(struct smb_t2_rsp) + 16);
388 return rc;
389}
390int
391CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
392{
393 NEGOTIATE_REQ *pSMB;
394 NEGOTIATE_RSP *pSMBr;
395 int rc = 0;
396 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000397 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 struct TCP_Server_Info * server;
399 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000400 unsigned int secFlags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401
402 if(ses->server)
403 server = ses->server;
404 else {
405 rc = -EIO;
406 return rc;
407 }
408 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
409 (void **) &pSMB, (void **) &pSMBr);
410 if (rc)
411 return rc;
Steve French750d1152006-06-27 06:28:30 +0000412
413 /* if any of auth flags (ie not sign or seal) are overriden use them */
414 if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
415 secFlags = ses->overrideSecFlg;
416 else /* if override flags set only sign/seal OR them with global auth */
417 secFlags = extended_security | ses->overrideSecFlg;
418
Steve Frenchf40c5622006-06-28 00:13:38 +0000419 cFYI(1,("secFlags 0x%x",secFlags));
420
Steve French1982c342005-08-17 12:38:22 -0700421 pSMB->hdr.Mid = GetNextMid(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
Steve French750d1152006-06-27 06:28:30 +0000423 if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000424 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve French39798772006-05-31 22:40:51 +0000425
426 count = 0;
427 for(i=0;i<CIFS_NUM_PROT;i++) {
428 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
429 count += strlen(protocols[i].name) + 1;
430 /* null at end of source and target buffers anyway */
431 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 pSMB->hdr.smb_buf_length += count;
433 pSMB->ByteCount = cpu_to_le16(count);
434
435 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
436 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French254e55e2006-06-04 05:53:15 +0000437 if (rc != 0)
438 goto neg_err_exit;
439
440 cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
441 /* Check wct = 1 error case */
442 if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) {
443 /* core returns wct = 1, but we do not ask for core - otherwise
444 small wct just comes when dialect index is -1 indicating we
445 could not negotiate a common dialect */
446 rc = -EOPNOTSUPP;
447 goto neg_err_exit;
448#ifdef CONFIG_CIFS_WEAK_PW_HASH
449 } else if((pSMBr->hdr.WordCount == 13)
Steve French9ac00b72006-09-30 04:13:17 +0000450 && ((pSMBr->DialectIndex == LANMAN_PROT)
451 || (pSMBr->DialectIndex == LANMAN2_PROT))) {
Steve French25ee4a92006-09-30 00:54:23 +0000452 int tmp, adjust;
Steve French254e55e2006-06-04 05:53:15 +0000453 struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
454
Steve French750d1152006-06-27 06:28:30 +0000455 if((secFlags & CIFSSEC_MAY_LANMAN) ||
456 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000457 server->secType = LANMAN;
458 else {
459 cERROR(1, ("mount failed weak security disabled"
460 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000461 rc = -EOPNOTSUPP;
462 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000463 }
464 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
465 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
466 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000467 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000468 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
469 /* even though we do not use raw we might as well set this
470 accurately, in case we ever find a need for it */
471 if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
472 server->maxRw = 0xFF00;
473 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
474 } else {
475 server->maxRw = 0;/* we do not need to use raw anyway */
476 server->capabilities = CAP_MPX_MODE;
477 }
Steve French25ee4a92006-09-30 00:54:23 +0000478 tmp = le16_to_cpu(rsp->ServerTimeZone);
479 if (tmp == (int)0xffff) {
480 /* OS/2 often does not set timezone therefore
481 * we must use server time to calc time zone.
482 * Could deviate slightly from the right zone. Not easy
483 * to adjust, since timezones are not always a multiple
484 * of 60 (sometimes 30 minutes - are there smaller?)
485 */
486 struct timespec ts, utc;
487 utc = CURRENT_TIME;
488 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
489 le16_to_cpu(rsp->SrvTime.Time));
490 cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
491 (int)ts.tv_sec, (int)utc.tv_sec,
492 (int)(utc.tv_sec - ts.tv_sec)));
493 tmp = (int)(utc.tv_sec - ts.tv_sec);
494 adjust = tmp < 0 ? -29 : 29;
495 tmp = ((tmp + adjust) / 60) * 60;
Steve French175ec9e2006-09-30 01:07:38 +0000496 server->timeAdj = tmp;
Steve French25ee4a92006-09-30 00:54:23 +0000497 } else {
Steve French175ec9e2006-09-30 01:07:38 +0000498 server->timeAdj = tmp * 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000499 }
Steve French175ec9e2006-09-30 01:07:38 +0000500 cFYI(1,("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000501
Steve French39798772006-05-31 22:40:51 +0000502
Steve French254e55e2006-06-04 05:53:15 +0000503 /* BB get server time for time conversions and add
504 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000505
Steve French25ee4a92006-09-30 00:54:23 +0000506 if (rsp->EncryptionKeyLength ==
507 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000508 memcpy(server->cryptKey, rsp->EncryptionKey,
509 CIFS_CRYPTO_KEY_SIZE);
510 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
511 rc = -EIO; /* need cryptkey unless plain text */
512 goto neg_err_exit;
513 }
Steve French39798772006-05-31 22:40:51 +0000514
Steve French254e55e2006-06-04 05:53:15 +0000515 cFYI(1,("LANMAN negotiated"));
516 /* we will not end up setting signing flags - as no signing
517 was in LANMAN and server did not return the flags on */
518 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000519#else /* weak security disabled */
Steve French254e55e2006-06-04 05:53:15 +0000520 } else if(pSMBr->hdr.WordCount == 13) {
521 cERROR(1,("mount failed, cifs module not built "
522 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000523 rc = -EOPNOTSUPP;
524#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000525 goto neg_err_exit;
526 } else if(pSMBr->hdr.WordCount != 17) {
527 /* unknown wct */
528 rc = -EOPNOTSUPP;
529 goto neg_err_exit;
530 }
531 /* else wct == 17 NTLM */
532 server->secMode = pSMBr->SecurityMode;
533 if((server->secMode & SECMODE_USER) == 0)
534 cFYI(1,("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000535
Steve French254e55e2006-06-04 05:53:15 +0000536 if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000537#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000538 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000539#endif /* CIFS_WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000540 cERROR(1,("Server requests plain text password"
541 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000542
Steve Frenchf40c5622006-06-28 00:13:38 +0000543 if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000544 server->secType = NTLMv2;
Steve Frenchf40c5622006-06-28 00:13:38 +0000545 else if(secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000546 server->secType = NTLM;
Steve Frenchf40c5622006-06-28 00:13:38 +0000547 else if(secFlags & CIFSSEC_MAY_NTLMV2)
548 server->secType = NTLMv2;
549 /* else krb5 ... any others ... */
Steve French7c7b25b2006-06-01 19:20:10 +0000550
Steve French254e55e2006-06-04 05:53:15 +0000551 /* one byte, so no need to convert this or EncryptionKeyLen from
552 little endian */
553 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
554 /* probably no need to store and check maxvcs */
555 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000557 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
558 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
559 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
560 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve French175ec9e2006-09-30 01:07:38 +0000561 server->timeAdj = le16_to_cpu(pSMBr->ServerTimeZone) * 60;
Steve French254e55e2006-06-04 05:53:15 +0000562 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
563 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
564 CIFS_CRYPTO_KEY_SIZE);
565 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
566 && (pSMBr->EncryptionKeyLength == 0)) {
567 /* decode security blob */
568 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
569 rc = -EIO; /* no crypt key only if plain text pwd */
570 goto neg_err_exit;
571 }
572
573 /* BB might be helpful to save off the domain of server here */
574
575 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
576 (server->capabilities & CAP_EXTENDED_SECURITY)) {
577 count = pSMBr->ByteCount;
578 if (count < 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 rc = -EIO;
Steve French254e55e2006-06-04 05:53:15 +0000580 else if (count == 16) {
581 server->secType = RawNTLMSSP;
582 if (server->socketUseCount.counter > 1) {
583 if (memcmp(server->server_GUID,
584 pSMBr->u.extended_response.
585 GUID, 16) != 0) {
586 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 memcpy(server->server_GUID,
Steve French254e55e2006-06-04 05:53:15 +0000588 pSMBr->u.extended_response.GUID,
589 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 }
Steve French254e55e2006-06-04 05:53:15 +0000591 } else
592 memcpy(server->server_GUID,
593 pSMBr->u.extended_response.GUID, 16);
594 } else {
595 rc = decode_negTokenInit(pSMBr->u.extended_response.
596 SecurityBlob,
597 count - 16,
598 &server->secType);
599 if(rc == 1) {
600 /* BB Need to fill struct for sessetup here */
601 rc = -EOPNOTSUPP;
602 } else {
603 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 }
Steve French254e55e2006-06-04 05:53:15 +0000606 } else
607 server->capabilities &= ~CAP_EXTENDED_SECURITY;
608
Steve French6344a422006-06-12 04:18:35 +0000609#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000610signing_check:
Steve French6344a422006-06-12 04:18:35 +0000611#endif
Steve French254e55e2006-06-04 05:53:15 +0000612 if(sign_CIFS_PDUs == FALSE) {
613 if(server->secMode & SECMODE_SIGN_REQUIRED)
614 cERROR(1,("Server requires "
615 "/proc/fs/cifs/PacketSigningEnabled to be on"));
616 server->secMode &=
617 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
618 } else if(sign_CIFS_PDUs == 1) {
619 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
620 server->secMode &=
621 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
622 } else if(sign_CIFS_PDUs == 2) {
623 if((server->secMode &
624 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
625 cERROR(1,("signing required but server lacks support"));
626 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 }
Steve French39798772006-05-31 22:40:51 +0000628neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700629 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000630
631 cFYI(1,("negprot rc %d",rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 return rc;
633}
634
635int
636CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
637{
638 struct smb_hdr *smb_buffer;
639 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
640 int rc = 0;
641 int length;
642
643 cFYI(1, ("In tree disconnect"));
644 /*
645 * If last user of the connection and
646 * connection alive - disconnect it
647 * If this is the last connection on the server session disconnect it
648 * (and inside session disconnect we should check if tcp socket needs
649 * to be freed and kernel thread woken up).
650 */
651 if (tcon)
652 down(&tcon->tconSem);
653 else
654 return -EIO;
655
656 atomic_dec(&tcon->useCount);
657 if (atomic_read(&tcon->useCount) > 0) {
658 up(&tcon->tconSem);
659 return -EBUSY;
660 }
661
662 /* No need to return error on this operation if tid invalidated and
663 closed on server already e.g. due to tcp session crashing */
664 if(tcon->tidStatus == CifsNeedReconnect) {
665 up(&tcon->tconSem);
666 return 0;
667 }
668
669 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
670 up(&tcon->tconSem);
671 return -EIO;
672 }
Steve French09d1db52005-04-28 22:41:08 -0700673 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
674 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if (rc) {
676 up(&tcon->tconSem);
677 return rc;
678 } else {
679 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
682 &length, 0);
683 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700684 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
686 if (smb_buffer)
687 cifs_small_buf_release(smb_buffer);
688 up(&tcon->tconSem);
689
690 /* No need to return error on this operation if tid invalidated and
691 closed on server already e.g. due to tcp session crashing */
692 if (rc == -EAGAIN)
693 rc = 0;
694
695 return rc;
696}
697
698int
699CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
700{
701 struct smb_hdr *smb_buffer_response;
702 LOGOFF_ANDX_REQ *pSMB;
703 int rc = 0;
704 int length;
705
706 cFYI(1, ("In SMBLogoff for session disconnect"));
707 if (ses)
708 down(&ses->sesSem);
709 else
710 return -EIO;
711
712 atomic_dec(&ses->inUse);
713 if (atomic_read(&ses->inUse) > 0) {
714 up(&ses->sesSem);
715 return -EBUSY;
716 }
717 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
718 if (rc) {
719 up(&ses->sesSem);
720 return rc;
721 }
722
723 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
724
725 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700726 pSMB->hdr.Mid = GetNextMid(ses->server);
727
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 if(ses->server->secMode &
729 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
730 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
731 }
732
733 pSMB->hdr.Uid = ses->Suid;
734
735 pSMB->AndXCommand = 0xFF;
736 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
737 smb_buffer_response, &length, 0);
738 if (ses->server) {
739 atomic_dec(&ses->server->socketUseCount);
740 if (atomic_read(&ses->server->socketUseCount) == 0) {
741 spin_lock(&GlobalMid_Lock);
742 ses->server->tcpStatus = CifsExiting;
743 spin_unlock(&GlobalMid_Lock);
744 rc = -ESHUTDOWN;
745 }
746 }
Steve Frencha59c6582005-08-17 12:12:19 -0700747 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700748 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
750 /* if session dead then we do not need to do ulogoff,
751 since server closed smb session, no sense reporting
752 error */
753 if (rc == -EAGAIN)
754 rc = 0;
755 return rc;
756}
757
758int
Steve French737b7582005-04-28 22:41:06 -0700759CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
760 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761{
762 DELETE_FILE_REQ *pSMB = NULL;
763 DELETE_FILE_RSP *pSMBr = NULL;
764 int rc = 0;
765 int bytes_returned;
766 int name_len;
767
768DelFileRetry:
769 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
770 (void **) &pSMBr);
771 if (rc)
772 return rc;
773
774 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
775 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500776 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700777 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 name_len++; /* trailing null */
779 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700780 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 name_len = strnlen(fileName, PATH_MAX);
782 name_len++; /* trailing null */
783 strncpy(pSMB->fileName, fileName, name_len);
784 }
785 pSMB->SearchAttributes =
786 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
787 pSMB->BufferFormat = 0x04;
788 pSMB->hdr.smb_buf_length += name_len + 1;
789 pSMB->ByteCount = cpu_to_le16(name_len + 1);
790 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
791 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700792 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 if (rc) {
794 cFYI(1, ("Error in RMFile = %d", rc));
795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796
797 cifs_buf_release(pSMB);
798 if (rc == -EAGAIN)
799 goto DelFileRetry;
800
801 return rc;
802}
803
804int
Steve French737b7582005-04-28 22:41:06 -0700805CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
806 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807{
808 DELETE_DIRECTORY_REQ *pSMB = NULL;
809 DELETE_DIRECTORY_RSP *pSMBr = NULL;
810 int rc = 0;
811 int bytes_returned;
812 int name_len;
813
814 cFYI(1, ("In CIFSSMBRmDir"));
815RmDirRetry:
816 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
817 (void **) &pSMBr);
818 if (rc)
819 return rc;
820
821 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700822 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
823 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 name_len++; /* trailing null */
825 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700826 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 name_len = strnlen(dirName, PATH_MAX);
828 name_len++; /* trailing null */
829 strncpy(pSMB->DirName, dirName, name_len);
830 }
831
832 pSMB->BufferFormat = 0x04;
833 pSMB->hdr.smb_buf_length += name_len + 1;
834 pSMB->ByteCount = cpu_to_le16(name_len + 1);
835 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
836 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700837 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 if (rc) {
839 cFYI(1, ("Error in RMDir = %d", rc));
840 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841
842 cifs_buf_release(pSMB);
843 if (rc == -EAGAIN)
844 goto RmDirRetry;
845 return rc;
846}
847
848int
849CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700850 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851{
852 int rc = 0;
853 CREATE_DIRECTORY_REQ *pSMB = NULL;
854 CREATE_DIRECTORY_RSP *pSMBr = NULL;
855 int bytes_returned;
856 int name_len;
857
858 cFYI(1, ("In CIFSSMBMkDir"));
859MkDirRetry:
860 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
861 (void **) &pSMBr);
862 if (rc)
863 return rc;
864
865 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500866 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700867 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 name_len++; /* trailing null */
869 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700870 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 name_len = strnlen(name, PATH_MAX);
872 name_len++; /* trailing null */
873 strncpy(pSMB->DirName, name, name_len);
874 }
875
876 pSMB->BufferFormat = 0x04;
877 pSMB->hdr.smb_buf_length += name_len + 1;
878 pSMB->ByteCount = cpu_to_le16(name_len + 1);
879 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
880 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700881 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 if (rc) {
883 cFYI(1, ("Error in Mkdir = %d", rc));
884 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700885
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 cifs_buf_release(pSMB);
887 if (rc == -EAGAIN)
888 goto MkDirRetry;
889 return rc;
890}
891
Steve Frencha9d02ad2005-08-24 23:06:05 -0700892static __u16 convert_disposition(int disposition)
893{
894 __u16 ofun = 0;
895
896 switch (disposition) {
897 case FILE_SUPERSEDE:
898 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
899 break;
900 case FILE_OPEN:
901 ofun = SMBOPEN_OAPPEND;
902 break;
903 case FILE_CREATE:
904 ofun = SMBOPEN_OCREATE;
905 break;
906 case FILE_OPEN_IF:
907 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
908 break;
909 case FILE_OVERWRITE:
910 ofun = SMBOPEN_OTRUNC;
911 break;
912 case FILE_OVERWRITE_IF:
913 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
914 break;
915 default:
916 cFYI(1,("unknown disposition %d",disposition));
917 ofun = SMBOPEN_OAPPEND; /* regular open */
918 }
919 return ofun;
920}
921
922int
923SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
924 const char *fileName, const int openDisposition,
925 const int access_flags, const int create_options, __u16 * netfid,
926 int *pOplock, FILE_ALL_INFO * pfile_info,
927 const struct nls_table *nls_codepage, int remap)
928{
929 int rc = -EACCES;
930 OPENX_REQ *pSMB = NULL;
931 OPENX_RSP *pSMBr = NULL;
932 int bytes_returned;
933 int name_len;
934 __u16 count;
935
936OldOpenRetry:
937 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
938 (void **) &pSMBr);
939 if (rc)
940 return rc;
941
942 pSMB->AndXCommand = 0xFF; /* none */
943
944 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
945 count = 1; /* account for one byte pad to word boundary */
946 name_len =
947 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
948 fileName, PATH_MAX, nls_codepage, remap);
949 name_len++; /* trailing null */
950 name_len *= 2;
951 } else { /* BB improve check for buffer overruns BB */
952 count = 0; /* no pad */
953 name_len = strnlen(fileName, PATH_MAX);
954 name_len++; /* trailing null */
955 strncpy(pSMB->fileName, fileName, name_len);
956 }
957 if (*pOplock & REQ_OPLOCK)
958 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
959 else if (*pOplock & REQ_BATCHOPLOCK) {
960 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
961 }
962 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
963 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
964 /* 0 = read
965 1 = write
966 2 = rw
967 3 = execute
968 */
969 pSMB->Mode = cpu_to_le16(2);
970 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
971 /* set file as system file if special file such
972 as fifo and server expecting SFU style and
973 no Unix extensions */
974
975 if(create_options & CREATE_OPTION_SPECIAL)
976 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
977 else
Steve French3e87d802005-09-18 20:49:21 -0700978 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700979
980 /* if ((omode & S_IWUGO) == 0)
981 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
982 /* Above line causes problems due to vfs splitting create into two
983 pieces - need to set mode after file created not while it is
984 being created */
985
986 /* BB FIXME BB */
987/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
988 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700989
990 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700991 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700992 count += name_len;
993 pSMB->hdr.smb_buf_length += count;
994
995 pSMB->ByteCount = cpu_to_le16(count);
996 /* long_op set to 1 to allow for oplock break timeouts */
997 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
998 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
999 cifs_stats_inc(&tcon->num_opens);
1000 if (rc) {
1001 cFYI(1, ("Error in Open = %d", rc));
1002 } else {
1003 /* BB verify if wct == 15 */
1004
1005/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1006
1007 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1008 /* Let caller know file was created so we can set the mode. */
1009 /* Do we care about the CreateAction in any other cases? */
1010 /* BB FIXME BB */
1011/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1012 *pOplock |= CIFS_CREATE_ACTION; */
1013 /* BB FIXME END */
1014
1015 if(pfile_info) {
1016 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1017 pfile_info->LastAccessTime = 0; /* BB fixme */
1018 pfile_info->LastWriteTime = 0; /* BB fixme */
1019 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001020 pfile_info->Attributes =
1021 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001022 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001023 pfile_info->AllocationSize =
1024 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1025 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001026 pfile_info->NumberOfLinks = cpu_to_le32(1);
1027 }
1028 }
1029
1030 cifs_buf_release(pSMB);
1031 if (rc == -EAGAIN)
1032 goto OldOpenRetry;
1033 return rc;
1034}
1035
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036int
1037CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1038 const char *fileName, const int openDisposition,
1039 const int access_flags, const int create_options, __u16 * netfid,
1040 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001041 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042{
1043 int rc = -EACCES;
1044 OPEN_REQ *pSMB = NULL;
1045 OPEN_RSP *pSMBr = NULL;
1046 int bytes_returned;
1047 int name_len;
1048 __u16 count;
1049
1050openRetry:
1051 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1052 (void **) &pSMBr);
1053 if (rc)
1054 return rc;
1055
1056 pSMB->AndXCommand = 0xFF; /* none */
1057
1058 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1059 count = 1; /* account for one byte pad to word boundary */
1060 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001061 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001062 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063 name_len++; /* trailing null */
1064 name_len *= 2;
1065 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001066 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 count = 0; /* no pad */
1068 name_len = strnlen(fileName, PATH_MAX);
1069 name_len++; /* trailing null */
1070 pSMB->NameLength = cpu_to_le16(name_len);
1071 strncpy(pSMB->fileName, fileName, name_len);
1072 }
1073 if (*pOplock & REQ_OPLOCK)
1074 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1075 else if (*pOplock & REQ_BATCHOPLOCK) {
1076 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1077 }
1078 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1079 pSMB->AllocationSize = 0;
Steve Frencheda3c022005-07-21 15:20:28 -07001080 /* set file as system file if special file such
1081 as fifo and server expecting SFU style and
1082 no Unix extensions */
1083 if(create_options & CREATE_OPTION_SPECIAL)
1084 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1085 else
1086 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 /* XP does not handle ATTR_POSIX_SEMANTICS */
1088 /* but it helps speed up case sensitive checks for other
1089 servers such as Samba */
1090 if (tcon->ses->capabilities & CAP_UNIX)
1091 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1092
1093 /* if ((omode & S_IWUGO) == 0)
1094 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1095 /* Above line causes problems due to vfs splitting create into two
1096 pieces - need to set mode after file created not while it is
1097 being created */
1098 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1099 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -07001100 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001101 /* BB Expirement with various impersonation levels and verify */
1102 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 pSMB->SecurityFlags =
1104 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1105
1106 count += name_len;
1107 pSMB->hdr.smb_buf_length += count;
1108
1109 pSMB->ByteCount = cpu_to_le16(count);
1110 /* long_op set to 1 to allow for oplock break timeouts */
1111 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1112 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001113 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 if (rc) {
1115 cFYI(1, ("Error in Open = %d", rc));
1116 } else {
Steve French09d1db52005-04-28 22:41:08 -07001117 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1119 /* Let caller know file was created so we can set the mode. */
1120 /* Do we care about the CreateAction in any other cases? */
1121 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1122 *pOplock |= CIFS_CREATE_ACTION;
1123 if(pfile_info) {
1124 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1125 36 /* CreationTime to Attributes */);
1126 /* the file_info buf is endian converted by caller */
1127 pfile_info->AllocationSize = pSMBr->AllocationSize;
1128 pfile_info->EndOfFile = pSMBr->EndOfFile;
1129 pfile_info->NumberOfLinks = cpu_to_le32(1);
1130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001132
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 cifs_buf_release(pSMB);
1134 if (rc == -EAGAIN)
1135 goto openRetry;
1136 return rc;
1137}
1138
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139int
1140CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001141 const int netfid, const unsigned int count,
1142 const __u64 lseek, unsigned int *nbytes, char **buf,
1143 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144{
1145 int rc = -EACCES;
1146 READ_REQ *pSMB = NULL;
1147 READ_RSP *pSMBr = NULL;
1148 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001149 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001150 int resp_buf_type = 0;
1151 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
1153 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001154 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1155 wct = 12;
1156 else
1157 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158
1159 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001160 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 if (rc)
1162 return rc;
1163
1164 /* tcon and ses pointer are checked in smb_init */
1165 if (tcon->ses->server == NULL)
1166 return -ECONNABORTED;
1167
Steve Frenchec637e32005-12-12 20:53:18 -08001168 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 pSMB->Fid = netfid;
1170 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001171 if(wct == 12)
1172 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001173 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1174 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001175
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 pSMB->Remaining = 0;
1177 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1178 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001179 if(wct == 12)
1180 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1181 else {
1182 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001183 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001184 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001185 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001186 }
Steve Frenchec637e32005-12-12 20:53:18 -08001187
1188 iov[0].iov_base = (char *)pSMB;
1189 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1190 rc = SendReceive2(xid, tcon->ses, iov,
1191 1 /* num iovecs */,
1192 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001193 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001194 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 if (rc) {
1196 cERROR(1, ("Send error in read = %d", rc));
1197 } else {
1198 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1199 data_length = data_length << 16;
1200 data_length += le16_to_cpu(pSMBr->DataLength);
1201 *nbytes = data_length;
1202
1203 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001204 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 || (data_length > count)) {
1206 cFYI(1,("bad length %d for count %d",data_length,count));
1207 rc = -EIO;
1208 *nbytes = 0;
1209 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001210 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001212/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1213 cERROR(1,("Faulting on read rc = %d",rc));
1214 rc = -EFAULT;
1215 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001217 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 }
1219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220
Steve French4b8f9302006-02-26 16:41:18 +00001221/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001222 if(*buf) {
1223 if(resp_buf_type == CIFS_SMALL_BUFFER)
1224 cifs_small_buf_release(iov[0].iov_base);
1225 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1226 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001227 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1228 /* return buffer to caller to free */
1229 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001230 if(resp_buf_type == CIFS_SMALL_BUFFER)
1231 *pbuf_type = CIFS_SMALL_BUFFER;
1232 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1233 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001234 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001235
1236 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 since file handle passed in no longer valid */
1238 return rc;
1239}
1240
Steve Frenchec637e32005-12-12 20:53:18 -08001241
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242int
1243CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1244 const int netfid, const unsigned int count,
1245 const __u64 offset, unsigned int *nbytes, const char *buf,
1246 const char __user * ubuf, const int long_op)
1247{
1248 int rc = -EACCES;
1249 WRITE_REQ *pSMB = NULL;
1250 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001251 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 __u32 bytes_sent;
1253 __u16 byte_count;
1254
1255 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001256 if(tcon->ses == NULL)
1257 return -ECONNABORTED;
1258
1259 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1260 wct = 14;
1261 else
1262 wct = 12;
1263
1264 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 (void **) &pSMBr);
1266 if (rc)
1267 return rc;
1268 /* tcon and ses pointer are checked in smb_init */
1269 if (tcon->ses->server == NULL)
1270 return -ECONNABORTED;
1271
1272 pSMB->AndXCommand = 0xFF; /* none */
1273 pSMB->Fid = netfid;
1274 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001275 if(wct == 14)
1276 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1277 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1278 return -EIO;
1279
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 pSMB->Reserved = 0xFFFFFFFF;
1281 pSMB->WriteMode = 0;
1282 pSMB->Remaining = 0;
1283
1284 /* Can increase buffer size if buffer is big enough in some cases - ie we
1285 can send more if LARGE_WRITE_X capability returned by the server and if
1286 our buffer is big enough or if we convert to iovecs on socket writes
1287 and eliminate the copy to the CIFS buffer */
1288 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1289 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1290 } else {
1291 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1292 & ~0xFF;
1293 }
1294
1295 if (bytes_sent > count)
1296 bytes_sent = count;
1297 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001298 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299 if(buf)
1300 memcpy(pSMB->Data,buf,bytes_sent);
1301 else if(ubuf) {
1302 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1303 cifs_buf_release(pSMB);
1304 return -EFAULT;
1305 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001306 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 /* No buffer */
1308 cifs_buf_release(pSMB);
1309 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001310 } /* else setting file size with write of zero bytes */
1311 if(wct == 14)
1312 byte_count = bytes_sent + 1; /* pad */
1313 else /* wct == 12 */ {
1314 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1317 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001318 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001319
1320 if(wct == 14)
1321 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001322 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001323 struct smb_com_writex_req * pSMBW =
1324 (struct smb_com_writex_req *)pSMB;
1325 pSMBW->ByteCount = cpu_to_le16(byte_count);
1326 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
1328 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1329 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001330 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 if (rc) {
1332 cFYI(1, ("Send error in write = %d", rc));
1333 *nbytes = 0;
1334 } else {
1335 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1336 *nbytes = (*nbytes) << 16;
1337 *nbytes += le16_to_cpu(pSMBr->Count);
1338 }
1339
1340 cifs_buf_release(pSMB);
1341
1342 /* Note: On -EAGAIN error only caller can retry on handle based calls
1343 since file handle passed in no longer valid */
1344
1345 return rc;
1346}
1347
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001348int
1349CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001351 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1352 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353{
1354 int rc = -EACCES;
1355 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001356 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001357 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001358 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359
Steve Frenchff7feac2005-11-15 16:45:16 -08001360 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1361
Steve French8cc64c62005-10-03 13:49:43 -07001362 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1363 wct = 14;
1364 else
1365 wct = 12;
1366 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001367 if (rc)
1368 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 /* tcon and ses pointer are checked in smb_init */
1370 if (tcon->ses->server == NULL)
1371 return -ECONNABORTED;
1372
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001373 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 pSMB->Fid = netfid;
1375 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001376 if(wct == 14)
1377 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1378 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1379 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 pSMB->Reserved = 0xFFFFFFFF;
1381 pSMB->WriteMode = 0;
1382 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001383
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 pSMB->DataOffset =
1385 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1386
Steve French3e844692005-10-03 13:37:24 -07001387 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1388 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001389 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001390 if(wct == 14)
1391 pSMB->hdr.smb_buf_length += count+1;
1392 else /* wct == 12 */
1393 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1394 if(wct == 14)
1395 pSMB->ByteCount = cpu_to_le16(count + 1);
1396 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1397 struct smb_com_writex_req * pSMBW =
1398 (struct smb_com_writex_req *)pSMB;
1399 pSMBW->ByteCount = cpu_to_le16(count + 5);
1400 }
Steve French3e844692005-10-03 13:37:24 -07001401 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001402 if(wct == 14)
1403 iov[0].iov_len = smb_hdr_len + 4;
1404 else /* wct == 12 pad bigger by four bytes */
1405 iov[0].iov_len = smb_hdr_len + 8;
1406
Steve French3e844692005-10-03 13:37:24 -07001407
Steve Frenchec637e32005-12-12 20:53:18 -08001408 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001409 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001410 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001412 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001414 } else if(resp_buf_type == 0) {
1415 /* presumably this can not happen, but best to be safe */
1416 rc = -EIO;
1417 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001418 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001419 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001420 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1421 *nbytes = (*nbytes) << 16;
1422 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424
Steve French4b8f9302006-02-26 16:41:18 +00001425/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001426 if(resp_buf_type == CIFS_SMALL_BUFFER)
1427 cifs_small_buf_release(iov[0].iov_base);
1428 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1429 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430
1431 /* Note: On -EAGAIN error only caller can retry on handle based calls
1432 since file handle passed in no longer valid */
1433
1434 return rc;
1435}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001436
1437
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438int
1439CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1440 const __u16 smb_file_id, const __u64 len,
1441 const __u64 offset, const __u32 numUnlock,
1442 const __u32 numLock, const __u8 lockType, const int waitFlag)
1443{
1444 int rc = 0;
1445 LOCK_REQ *pSMB = NULL;
1446 LOCK_RSP *pSMBr = NULL;
1447 int bytes_returned;
1448 int timeout = 0;
1449 __u16 count;
1450
1451 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001452 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1453
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454 if (rc)
1455 return rc;
1456
Steve French46810cb2005-04-28 22:41:09 -07001457 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1458
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1460 timeout = -1; /* no response expected */
1461 pSMB->Timeout = 0;
1462 } else if (waitFlag == TRUE) {
1463 timeout = 3; /* blocking operation, no timeout */
1464 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1465 } else {
1466 pSMB->Timeout = 0;
1467 }
1468
1469 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1470 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1471 pSMB->LockType = lockType;
1472 pSMB->AndXCommand = 0xFF; /* none */
1473 pSMB->Fid = smb_file_id; /* netfid stays le */
1474
1475 if((numLock != 0) || (numUnlock != 0)) {
1476 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1477 /* BB where to store pid high? */
1478 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1479 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1480 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1481 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1482 count = sizeof(LOCKING_ANDX_RANGE);
1483 } else {
1484 /* oplock break */
1485 count = 0;
1486 }
1487 pSMB->hdr.smb_buf_length += count;
1488 pSMB->ByteCount = cpu_to_le16(count);
1489
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001490 if (waitFlag) {
1491 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1492 (struct smb_hdr *) pSMBr, &bytes_returned);
1493 } else {
1494 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001496 }
Steve Frencha4544342005-08-24 13:59:35 -07001497 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 if (rc) {
1499 cFYI(1, ("Send error in Lock = %d", rc));
1500 }
Steve French46810cb2005-04-28 22:41:09 -07001501 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502
1503 /* Note: On -EAGAIN error only caller can retry on handle based calls
1504 since file handle passed in no longer valid */
1505 return rc;
1506}
1507
1508int
Steve French08547b02006-02-28 22:39:25 +00001509CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1510 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001511 struct file_lock *pLockData, const __u16 lock_type,
1512 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001513{
1514 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1515 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1516 char *data_offset;
1517 struct cifs_posix_lock *parm_data;
1518 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001519 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001520 int bytes_returned = 0;
1521 __u16 params, param_offset, offset, byte_count, count;
1522
1523 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001524
1525 if(pLockData == NULL)
1526 return EINVAL;
1527
Steve French08547b02006-02-28 22:39:25 +00001528 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1529
1530 if (rc)
1531 return rc;
1532
1533 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1534
1535 params = 6;
1536 pSMB->MaxSetupCount = 0;
1537 pSMB->Reserved = 0;
1538 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001539 pSMB->Reserved2 = 0;
1540 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1541 offset = param_offset + params;
1542
1543 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1544
1545 count = sizeof(struct cifs_posix_lock);
1546 pSMB->MaxParameterCount = cpu_to_le16(2);
1547 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1548 pSMB->SetupCount = 1;
1549 pSMB->Reserved3 = 0;
1550 if(get_flag)
1551 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1552 else
1553 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1554 byte_count = 3 /* pad */ + params + count;
1555 pSMB->DataCount = cpu_to_le16(count);
1556 pSMB->ParameterCount = cpu_to_le16(params);
1557 pSMB->TotalDataCount = pSMB->DataCount;
1558 pSMB->TotalParameterCount = pSMB->ParameterCount;
1559 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1560 parm_data = (struct cifs_posix_lock *)
1561 (((char *) &pSMB->hdr.Protocol) + offset);
1562
1563 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French3a5ff612006-07-14 22:37:11 +00001564 if(waitFlag) {
1565 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001566 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001567 pSMB->Timeout = cpu_to_le32(-1);
1568 } else
1569 pSMB->Timeout = 0;
1570
Steve French08547b02006-02-28 22:39:25 +00001571 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001572 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001573 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001574
1575 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001576 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001577 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1578 pSMB->Reserved4 = 0;
1579 pSMB->hdr.smb_buf_length += byte_count;
1580 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001581 if (waitFlag) {
1582 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1583 (struct smb_hdr *) pSMBr, &bytes_returned);
1584 } else {
1585 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001586 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001587 }
1588
Steve French08547b02006-02-28 22:39:25 +00001589 if (rc) {
1590 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001591 } else if (get_flag) {
1592 /* lock structure can be returned on get */
1593 __u16 data_offset;
1594 __u16 data_count;
1595 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001596
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001597 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1598 rc = -EIO; /* bad smb */
1599 goto plk_err_exit;
1600 }
1601 if(pLockData == NULL) {
1602 rc = -EINVAL;
1603 goto plk_err_exit;
1604 }
1605 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1606 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1607 if(data_count < sizeof(struct cifs_posix_lock)) {
1608 rc = -EIO;
1609 goto plk_err_exit;
1610 }
1611 parm_data = (struct cifs_posix_lock *)
1612 ((char *)&pSMBr->hdr.Protocol + data_offset);
1613 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1614 pLockData->fl_type = F_UNLCK;
1615 }
1616
1617plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001618 if (pSMB)
1619 cifs_small_buf_release(pSMB);
1620
1621 /* Note: On -EAGAIN error only caller can retry on handle based calls
1622 since file handle passed in no longer valid */
1623
1624 return rc;
1625}
1626
1627
1628int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1630{
1631 int rc = 0;
1632 CLOSE_REQ *pSMB = NULL;
1633 CLOSE_RSP *pSMBr = NULL;
1634 int bytes_returned;
1635 cFYI(1, ("In CIFSSMBClose"));
1636
1637/* do not retry on dead session on close */
1638 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1639 if(rc == -EAGAIN)
1640 return 0;
1641 if (rc)
1642 return rc;
1643
1644 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1645
1646 pSMB->FileID = (__u16) smb_file_id;
1647 pSMB->LastWriteTime = 0;
1648 pSMB->ByteCount = 0;
1649 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1650 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001651 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 if (rc) {
1653 if(rc!=-EINTR) {
1654 /* EINTR is expected when user ctl-c to kill app */
1655 cERROR(1, ("Send error in Close = %d", rc));
1656 }
1657 }
1658
1659 cifs_small_buf_release(pSMB);
1660
1661 /* Since session is dead, file will be closed on server already */
1662 if(rc == -EAGAIN)
1663 rc = 0;
1664
1665 return rc;
1666}
1667
1668int
1669CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1670 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001671 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672{
1673 int rc = 0;
1674 RENAME_REQ *pSMB = NULL;
1675 RENAME_RSP *pSMBr = NULL;
1676 int bytes_returned;
1677 int name_len, name_len2;
1678 __u16 count;
1679
1680 cFYI(1, ("In CIFSSMBRename"));
1681renameRetry:
1682 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1683 (void **) &pSMBr);
1684 if (rc)
1685 return rc;
1686
1687 pSMB->BufferFormat = 0x04;
1688 pSMB->SearchAttributes =
1689 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1690 ATTR_DIRECTORY);
1691
1692 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1693 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001694 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001695 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 name_len++; /* trailing null */
1697 name_len *= 2;
1698 pSMB->OldFileName[name_len] = 0x04; /* pad */
1699 /* protocol requires ASCII signature byte on Unicode string */
1700 pSMB->OldFileName[name_len + 1] = 0x00;
1701 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001702 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001703 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1705 name_len2 *= 2; /* convert to bytes */
1706 } else { /* BB improve the check for buffer overruns BB */
1707 name_len = strnlen(fromName, PATH_MAX);
1708 name_len++; /* trailing null */
1709 strncpy(pSMB->OldFileName, fromName, name_len);
1710 name_len2 = strnlen(toName, PATH_MAX);
1711 name_len2++; /* trailing null */
1712 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1713 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1714 name_len2++; /* trailing null */
1715 name_len2++; /* signature byte */
1716 }
1717
1718 count = 1 /* 1st signature byte */ + name_len + name_len2;
1719 pSMB->hdr.smb_buf_length += count;
1720 pSMB->ByteCount = cpu_to_le16(count);
1721
1722 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1723 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001724 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 if (rc) {
1726 cFYI(1, ("Send error in rename = %d", rc));
1727 }
1728
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 cifs_buf_release(pSMB);
1730
1731 if (rc == -EAGAIN)
1732 goto renameRetry;
1733
1734 return rc;
1735}
1736
1737int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001738 int netfid, char * target_name,
1739 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740{
1741 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1742 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1743 struct set_file_rename * rename_info;
1744 char *data_offset;
1745 char dummy_string[30];
1746 int rc = 0;
1747 int bytes_returned = 0;
1748 int len_of_str;
1749 __u16 params, param_offset, offset, count, byte_count;
1750
1751 cFYI(1, ("Rename to File by handle"));
1752 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1753 (void **) &pSMBr);
1754 if (rc)
1755 return rc;
1756
1757 params = 6;
1758 pSMB->MaxSetupCount = 0;
1759 pSMB->Reserved = 0;
1760 pSMB->Flags = 0;
1761 pSMB->Timeout = 0;
1762 pSMB->Reserved2 = 0;
1763 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1764 offset = param_offset + params;
1765
1766 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1767 rename_info = (struct set_file_rename *) data_offset;
1768 pSMB->MaxParameterCount = cpu_to_le16(2);
1769 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1770 pSMB->SetupCount = 1;
1771 pSMB->Reserved3 = 0;
1772 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1773 byte_count = 3 /* pad */ + params;
1774 pSMB->ParameterCount = cpu_to_le16(params);
1775 pSMB->TotalParameterCount = pSMB->ParameterCount;
1776 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1777 pSMB->DataOffset = cpu_to_le16(offset);
1778 /* construct random name ".cifs_tmp<inodenum><mid>" */
1779 rename_info->overwrite = cpu_to_le32(1);
1780 rename_info->root_fid = 0;
1781 /* unicode only call */
1782 if(target_name == NULL) {
1783 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001784 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001785 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001787 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001788 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 }
1790 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1791 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1792 byte_count += count;
1793 pSMB->DataCount = cpu_to_le16(count);
1794 pSMB->TotalDataCount = pSMB->DataCount;
1795 pSMB->Fid = netfid;
1796 pSMB->InformationLevel =
1797 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1798 pSMB->Reserved4 = 0;
1799 pSMB->hdr.smb_buf_length += byte_count;
1800 pSMB->ByteCount = cpu_to_le16(byte_count);
1801 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1802 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001803 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804 if (rc) {
1805 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1806 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001807
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 cifs_buf_release(pSMB);
1809
1810 /* Note: On -EAGAIN error only caller can retry on handle based calls
1811 since file handle passed in no longer valid */
1812
1813 return rc;
1814}
1815
1816int
1817CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1818 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001819 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820{
1821 int rc = 0;
1822 COPY_REQ *pSMB = NULL;
1823 COPY_RSP *pSMBr = NULL;
1824 int bytes_returned;
1825 int name_len, name_len2;
1826 __u16 count;
1827
1828 cFYI(1, ("In CIFSSMBCopy"));
1829copyRetry:
1830 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1831 (void **) &pSMBr);
1832 if (rc)
1833 return rc;
1834
1835 pSMB->BufferFormat = 0x04;
1836 pSMB->Tid2 = target_tid;
1837
1838 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1839
1840 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001841 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001842 fromName, PATH_MAX, nls_codepage,
1843 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 name_len++; /* trailing null */
1845 name_len *= 2;
1846 pSMB->OldFileName[name_len] = 0x04; /* pad */
1847 /* protocol requires ASCII signature byte on Unicode string */
1848 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001849 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001850 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1852 name_len2 *= 2; /* convert to bytes */
1853 } else { /* BB improve the check for buffer overruns BB */
1854 name_len = strnlen(fromName, PATH_MAX);
1855 name_len++; /* trailing null */
1856 strncpy(pSMB->OldFileName, fromName, name_len);
1857 name_len2 = strnlen(toName, PATH_MAX);
1858 name_len2++; /* trailing null */
1859 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1860 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1861 name_len2++; /* trailing null */
1862 name_len2++; /* signature byte */
1863 }
1864
1865 count = 1 /* 1st signature byte */ + name_len + name_len2;
1866 pSMB->hdr.smb_buf_length += count;
1867 pSMB->ByteCount = cpu_to_le16(count);
1868
1869 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1870 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1871 if (rc) {
1872 cFYI(1, ("Send error in copy = %d with %d files copied",
1873 rc, le16_to_cpu(pSMBr->CopyCount)));
1874 }
1875 if (pSMB)
1876 cifs_buf_release(pSMB);
1877
1878 if (rc == -EAGAIN)
1879 goto copyRetry;
1880
1881 return rc;
1882}
1883
1884int
1885CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1886 const char *fromName, const char *toName,
1887 const struct nls_table *nls_codepage)
1888{
1889 TRANSACTION2_SPI_REQ *pSMB = NULL;
1890 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1891 char *data_offset;
1892 int name_len;
1893 int name_len_target;
1894 int rc = 0;
1895 int bytes_returned = 0;
1896 __u16 params, param_offset, offset, byte_count;
1897
1898 cFYI(1, ("In Symlink Unix style"));
1899createSymLinkRetry:
1900 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1901 (void **) &pSMBr);
1902 if (rc)
1903 return rc;
1904
1905 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1906 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001907 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 /* find define for this maxpathcomponent */
1909 , nls_codepage);
1910 name_len++; /* trailing null */
1911 name_len *= 2;
1912
1913 } else { /* BB improve the check for buffer overruns BB */
1914 name_len = strnlen(fromName, PATH_MAX);
1915 name_len++; /* trailing null */
1916 strncpy(pSMB->FileName, fromName, name_len);
1917 }
1918 params = 6 + name_len;
1919 pSMB->MaxSetupCount = 0;
1920 pSMB->Reserved = 0;
1921 pSMB->Flags = 0;
1922 pSMB->Timeout = 0;
1923 pSMB->Reserved2 = 0;
1924 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1925 InformationLevel) - 4;
1926 offset = param_offset + params;
1927
1928 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1929 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1930 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001931 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 /* find define for this maxpathcomponent */
1933 , nls_codepage);
1934 name_len_target++; /* trailing null */
1935 name_len_target *= 2;
1936 } else { /* BB improve the check for buffer overruns BB */
1937 name_len_target = strnlen(toName, PATH_MAX);
1938 name_len_target++; /* trailing null */
1939 strncpy(data_offset, toName, name_len_target);
1940 }
1941
1942 pSMB->MaxParameterCount = cpu_to_le16(2);
1943 /* BB find exact max on data count below from sess */
1944 pSMB->MaxDataCount = cpu_to_le16(1000);
1945 pSMB->SetupCount = 1;
1946 pSMB->Reserved3 = 0;
1947 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1948 byte_count = 3 /* pad */ + params + name_len_target;
1949 pSMB->DataCount = cpu_to_le16(name_len_target);
1950 pSMB->ParameterCount = cpu_to_le16(params);
1951 pSMB->TotalDataCount = pSMB->DataCount;
1952 pSMB->TotalParameterCount = pSMB->ParameterCount;
1953 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1954 pSMB->DataOffset = cpu_to_le16(offset);
1955 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1956 pSMB->Reserved4 = 0;
1957 pSMB->hdr.smb_buf_length += byte_count;
1958 pSMB->ByteCount = cpu_to_le16(byte_count);
1959 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1960 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001961 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 if (rc) {
1963 cFYI(1,
1964 ("Send error in SetPathInfo (create symlink) = %d",
1965 rc));
1966 }
1967
1968 if (pSMB)
1969 cifs_buf_release(pSMB);
1970
1971 if (rc == -EAGAIN)
1972 goto createSymLinkRetry;
1973
1974 return rc;
1975}
1976
1977int
1978CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1979 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001980 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981{
1982 TRANSACTION2_SPI_REQ *pSMB = NULL;
1983 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1984 char *data_offset;
1985 int name_len;
1986 int name_len_target;
1987 int rc = 0;
1988 int bytes_returned = 0;
1989 __u16 params, param_offset, offset, byte_count;
1990
1991 cFYI(1, ("In Create Hard link Unix style"));
1992createHardLinkRetry:
1993 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1994 (void **) &pSMBr);
1995 if (rc)
1996 return rc;
1997
1998 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001999 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002000 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 name_len++; /* trailing null */
2002 name_len *= 2;
2003
2004 } else { /* BB improve the check for buffer overruns BB */
2005 name_len = strnlen(toName, PATH_MAX);
2006 name_len++; /* trailing null */
2007 strncpy(pSMB->FileName, toName, name_len);
2008 }
2009 params = 6 + name_len;
2010 pSMB->MaxSetupCount = 0;
2011 pSMB->Reserved = 0;
2012 pSMB->Flags = 0;
2013 pSMB->Timeout = 0;
2014 pSMB->Reserved2 = 0;
2015 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2016 InformationLevel) - 4;
2017 offset = param_offset + params;
2018
2019 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2020 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2021 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002022 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002023 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 name_len_target++; /* trailing null */
2025 name_len_target *= 2;
2026 } else { /* BB improve the check for buffer overruns BB */
2027 name_len_target = strnlen(fromName, PATH_MAX);
2028 name_len_target++; /* trailing null */
2029 strncpy(data_offset, fromName, name_len_target);
2030 }
2031
2032 pSMB->MaxParameterCount = cpu_to_le16(2);
2033 /* BB find exact max on data count below from sess*/
2034 pSMB->MaxDataCount = cpu_to_le16(1000);
2035 pSMB->SetupCount = 1;
2036 pSMB->Reserved3 = 0;
2037 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2038 byte_count = 3 /* pad */ + params + name_len_target;
2039 pSMB->ParameterCount = cpu_to_le16(params);
2040 pSMB->TotalParameterCount = pSMB->ParameterCount;
2041 pSMB->DataCount = cpu_to_le16(name_len_target);
2042 pSMB->TotalDataCount = pSMB->DataCount;
2043 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2044 pSMB->DataOffset = cpu_to_le16(offset);
2045 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2046 pSMB->Reserved4 = 0;
2047 pSMB->hdr.smb_buf_length += byte_count;
2048 pSMB->ByteCount = cpu_to_le16(byte_count);
2049 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2050 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002051 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 if (rc) {
2053 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2054 }
2055
2056 cifs_buf_release(pSMB);
2057 if (rc == -EAGAIN)
2058 goto createHardLinkRetry;
2059
2060 return rc;
2061}
2062
2063int
2064CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2065 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002066 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067{
2068 int rc = 0;
2069 NT_RENAME_REQ *pSMB = NULL;
2070 RENAME_RSP *pSMBr = NULL;
2071 int bytes_returned;
2072 int name_len, name_len2;
2073 __u16 count;
2074
2075 cFYI(1, ("In CIFSCreateHardLink"));
2076winCreateHardLinkRetry:
2077
2078 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2079 (void **) &pSMBr);
2080 if (rc)
2081 return rc;
2082
2083 pSMB->SearchAttributes =
2084 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2085 ATTR_DIRECTORY);
2086 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2087 pSMB->ClusterCount = 0;
2088
2089 pSMB->BufferFormat = 0x04;
2090
2091 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2092 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002093 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002094 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 name_len++; /* trailing null */
2096 name_len *= 2;
2097 pSMB->OldFileName[name_len] = 0; /* pad */
2098 pSMB->OldFileName[name_len + 1] = 0x04;
2099 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002100 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002101 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2103 name_len2 *= 2; /* convert to bytes */
2104 } else { /* BB improve the check for buffer overruns BB */
2105 name_len = strnlen(fromName, PATH_MAX);
2106 name_len++; /* trailing null */
2107 strncpy(pSMB->OldFileName, fromName, name_len);
2108 name_len2 = strnlen(toName, PATH_MAX);
2109 name_len2++; /* trailing null */
2110 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2111 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2112 name_len2++; /* trailing null */
2113 name_len2++; /* signature byte */
2114 }
2115
2116 count = 1 /* string type byte */ + name_len + name_len2;
2117 pSMB->hdr.smb_buf_length += count;
2118 pSMB->ByteCount = cpu_to_le16(count);
2119
2120 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2121 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002122 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 if (rc) {
2124 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2125 }
2126 cifs_buf_release(pSMB);
2127 if (rc == -EAGAIN)
2128 goto winCreateHardLinkRetry;
2129
2130 return rc;
2131}
2132
2133int
2134CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2135 const unsigned char *searchName,
2136 char *symlinkinfo, const int buflen,
2137 const struct nls_table *nls_codepage)
2138{
2139/* SMB_QUERY_FILE_UNIX_LINK */
2140 TRANSACTION2_QPI_REQ *pSMB = NULL;
2141 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2142 int rc = 0;
2143 int bytes_returned;
2144 int name_len;
2145 __u16 params, byte_count;
2146
2147 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2148
2149querySymLinkRetry:
2150 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2151 (void **) &pSMBr);
2152 if (rc)
2153 return rc;
2154
2155 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2156 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002157 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 /* find define for this maxpathcomponent */
2159 , nls_codepage);
2160 name_len++; /* trailing null */
2161 name_len *= 2;
2162 } else { /* BB improve the check for buffer overruns BB */
2163 name_len = strnlen(searchName, PATH_MAX);
2164 name_len++; /* trailing null */
2165 strncpy(pSMB->FileName, searchName, name_len);
2166 }
2167
2168 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2169 pSMB->TotalDataCount = 0;
2170 pSMB->MaxParameterCount = cpu_to_le16(2);
2171 /* BB find exact max data count below from sess structure BB */
2172 pSMB->MaxDataCount = cpu_to_le16(4000);
2173 pSMB->MaxSetupCount = 0;
2174 pSMB->Reserved = 0;
2175 pSMB->Flags = 0;
2176 pSMB->Timeout = 0;
2177 pSMB->Reserved2 = 0;
2178 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2179 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2180 pSMB->DataCount = 0;
2181 pSMB->DataOffset = 0;
2182 pSMB->SetupCount = 1;
2183 pSMB->Reserved3 = 0;
2184 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2185 byte_count = params + 1 /* pad */ ;
2186 pSMB->TotalParameterCount = cpu_to_le16(params);
2187 pSMB->ParameterCount = pSMB->TotalParameterCount;
2188 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2189 pSMB->Reserved4 = 0;
2190 pSMB->hdr.smb_buf_length += byte_count;
2191 pSMB->ByteCount = cpu_to_le16(byte_count);
2192
2193 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2194 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2195 if (rc) {
2196 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2197 } else {
2198 /* decode response */
2199
2200 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2201 if (rc || (pSMBr->ByteCount < 2))
2202 /* BB also check enough total bytes returned */
2203 rc = -EIO; /* bad smb */
2204 else {
2205 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2206 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2207
2208 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2209 name_len = UniStrnlen((wchar_t *) ((char *)
2210 &pSMBr->hdr.Protocol +data_offset),
2211 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002212 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002214 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 data_offset),
2216 name_len, nls_codepage);
2217 } else {
2218 strncpy(symlinkinfo,
2219 (char *) &pSMBr->hdr.Protocol +
2220 data_offset,
2221 min_t(const int, buflen, count));
2222 }
2223 symlinkinfo[buflen] = 0;
2224 /* just in case so calling code does not go off the end of buffer */
2225 }
2226 }
2227 cifs_buf_release(pSMB);
2228 if (rc == -EAGAIN)
2229 goto querySymLinkRetry;
2230 return rc;
2231}
2232
Steve French0a4b92c2006-01-12 15:44:21 -08002233/* Initialize NT TRANSACT SMB into small smb request buffer.
2234 This assumes that all NT TRANSACTS that we init here have
2235 total parm and data under about 400 bytes (to fit in small cifs
2236 buffer size), which is the case so far, it easily fits. NB:
2237 Setup words themselves and ByteCount
2238 MaxSetupCount (size of returned setup area) and
2239 MaxParameterCount (returned parms size) must be set by caller */
2240static int
2241smb_init_ntransact(const __u16 sub_command, const int setup_count,
2242 const int parm_len, struct cifsTconInfo *tcon,
2243 void ** ret_buf)
2244{
2245 int rc;
2246 __u32 temp_offset;
2247 struct smb_com_ntransact_req * pSMB;
2248
2249 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2250 (void **)&pSMB);
2251 if (rc)
2252 return rc;
2253 *ret_buf = (void *)pSMB;
2254 pSMB->Reserved = 0;
2255 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2256 pSMB->TotalDataCount = 0;
2257 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2258 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2259 pSMB->ParameterCount = pSMB->TotalParameterCount;
2260 pSMB->DataCount = pSMB->TotalDataCount;
2261 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2262 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2263 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2264 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2265 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2266 pSMB->SubCommand = cpu_to_le16(sub_command);
2267 return 0;
2268}
2269
2270static int
2271validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2272 int * pdatalen, int * pparmlen)
2273{
2274 char * end_of_smb;
2275 __u32 data_count, data_offset, parm_count, parm_offset;
2276 struct smb_com_ntransact_rsp * pSMBr;
2277
2278 if(buf == NULL)
2279 return -EINVAL;
2280
2281 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2282
2283 /* ByteCount was converted from little endian in SendReceive */
2284 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2285 (char *)&pSMBr->ByteCount;
2286
2287
2288 data_offset = le32_to_cpu(pSMBr->DataOffset);
2289 data_count = le32_to_cpu(pSMBr->DataCount);
2290 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2291 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2292
2293 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2294 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2295
2296 /* should we also check that parm and data areas do not overlap? */
2297 if(*ppparm > end_of_smb) {
2298 cFYI(1,("parms start after end of smb"));
2299 return -EINVAL;
2300 } else if(parm_count + *ppparm > end_of_smb) {
2301 cFYI(1,("parm end after end of smb"));
2302 return -EINVAL;
2303 } else if(*ppdata > end_of_smb) {
2304 cFYI(1,("data starts after end of smb"));
2305 return -EINVAL;
2306 } else if(data_count + *ppdata > end_of_smb) {
2307 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2308 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2309 return -EINVAL;
2310 } else if(parm_count + data_count > pSMBr->ByteCount) {
2311 cFYI(1,("parm count and data count larger than SMB"));
2312 return -EINVAL;
2313 }
2314 return 0;
2315}
2316
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317int
2318CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2319 const unsigned char *searchName,
2320 char *symlinkinfo, const int buflen,__u16 fid,
2321 const struct nls_table *nls_codepage)
2322{
2323 int rc = 0;
2324 int bytes_returned;
2325 int name_len;
2326 struct smb_com_transaction_ioctl_req * pSMB;
2327 struct smb_com_transaction_ioctl_rsp * pSMBr;
2328
2329 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2330 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2331 (void **) &pSMBr);
2332 if (rc)
2333 return rc;
2334
2335 pSMB->TotalParameterCount = 0 ;
2336 pSMB->TotalDataCount = 0;
2337 pSMB->MaxParameterCount = cpu_to_le32(2);
2338 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002339 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2340 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 pSMB->MaxSetupCount = 4;
2342 pSMB->Reserved = 0;
2343 pSMB->ParameterOffset = 0;
2344 pSMB->DataCount = 0;
2345 pSMB->DataOffset = 0;
2346 pSMB->SetupCount = 4;
2347 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2348 pSMB->ParameterCount = pSMB->TotalParameterCount;
2349 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2350 pSMB->IsFsctl = 1; /* FSCTL */
2351 pSMB->IsRootFlag = 0;
2352 pSMB->Fid = fid; /* file handle always le */
2353 pSMB->ByteCount = 0;
2354
2355 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2356 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2357 if (rc) {
2358 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2359 } else { /* decode response */
2360 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2361 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2362 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2363 /* BB also check enough total bytes returned */
2364 rc = -EIO; /* bad smb */
2365 else {
2366 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002367 char * end_of_smb = 2 /* sizeof byte count */ +
2368 pSMBr->ByteCount +
2369 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002370
2371 struct reparse_data * reparse_buf = (struct reparse_data *)
2372 ((char *)&pSMBr->hdr.Protocol + data_offset);
2373 if((char*)reparse_buf >= end_of_smb) {
2374 rc = -EIO;
2375 goto qreparse_out;
2376 }
2377 if((reparse_buf->LinkNamesBuf +
2378 reparse_buf->TargetNameOffset +
2379 reparse_buf->TargetNameLen) >
2380 end_of_smb) {
2381 cFYI(1,("reparse buf extended beyond SMB"));
2382 rc = -EIO;
2383 goto qreparse_out;
2384 }
2385
2386 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2387 name_len = UniStrnlen((wchar_t *)
2388 (reparse_buf->LinkNamesBuf +
2389 reparse_buf->TargetNameOffset),
2390 min(buflen/2, reparse_buf->TargetNameLen / 2));
2391 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002392 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393 reparse_buf->TargetNameOffset),
2394 name_len, nls_codepage);
2395 } else { /* ASCII names */
2396 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2397 reparse_buf->TargetNameOffset,
2398 min_t(const int, buflen, reparse_buf->TargetNameLen));
2399 }
2400 } else {
2401 rc = -EIO;
2402 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2403 }
2404 symlinkinfo[buflen] = 0; /* just in case so the caller
2405 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002406 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 }
2408 }
2409qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002410 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411
2412 /* Note: On -EAGAIN error only caller can retry on handle based calls
2413 since file handle passed in no longer valid */
2414
2415 return rc;
2416}
2417
2418#ifdef CONFIG_CIFS_POSIX
2419
2420/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2421static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2422{
2423 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002424 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2425 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2426 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2428
2429 return;
2430}
2431
2432/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002433static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2434 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435{
2436 int size = 0;
2437 int i;
2438 __u16 count;
2439 struct cifs_posix_ace * pACE;
2440 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2441 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2442
2443 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2444 return -EOPNOTSUPP;
2445
2446 if(acl_type & ACL_TYPE_ACCESS) {
2447 count = le16_to_cpu(cifs_acl->access_entry_count);
2448 pACE = &cifs_acl->ace_array[0];
2449 size = sizeof(struct cifs_posix_acl);
2450 size += sizeof(struct cifs_posix_ace) * count;
2451 /* check if we would go beyond end of SMB */
2452 if(size_of_data_area < size) {
2453 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2454 return -EINVAL;
2455 }
2456 } else if(acl_type & ACL_TYPE_DEFAULT) {
2457 count = le16_to_cpu(cifs_acl->access_entry_count);
2458 size = sizeof(struct cifs_posix_acl);
2459 size += sizeof(struct cifs_posix_ace) * count;
2460/* skip past access ACEs to get to default ACEs */
2461 pACE = &cifs_acl->ace_array[count];
2462 count = le16_to_cpu(cifs_acl->default_entry_count);
2463 size += sizeof(struct cifs_posix_ace) * count;
2464 /* check if we would go beyond end of SMB */
2465 if(size_of_data_area < size)
2466 return -EINVAL;
2467 } else {
2468 /* illegal type */
2469 return -EINVAL;
2470 }
2471
2472 size = posix_acl_xattr_size(count);
2473 if((buflen == 0) || (local_acl == NULL)) {
2474 /* used to query ACL EA size */
2475 } else if(size > buflen) {
2476 return -ERANGE;
2477 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002478 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 for(i = 0;i < count ;i++) {
2480 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2481 pACE ++;
2482 }
2483 }
2484 return size;
2485}
2486
2487static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2488 const posix_acl_xattr_entry * local_ace)
2489{
2490 __u16 rc = 0; /* 0 = ACL converted ok */
2491
Steve Frenchff7feac2005-11-15 16:45:16 -08002492 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2493 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002494 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002495 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496 /* Probably no need to le convert -1 on any arch but can not hurt */
2497 cifs_ace->cifs_uid = cpu_to_le64(-1);
2498 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002499 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2501 return rc;
2502}
2503
2504/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2505static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2506 const int acl_type)
2507{
2508 __u16 rc = 0;
2509 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2510 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2511 int count;
2512 int i;
2513
2514 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2515 return 0;
2516
2517 count = posix_acl_xattr_count((size_t)buflen);
2518 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002519 count, buflen, le32_to_cpu(local_acl->a_version)));
2520 if(le32_to_cpu(local_acl->a_version) != 2) {
2521 cFYI(1,("unknown POSIX ACL version %d",
2522 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 return 0;
2524 }
2525 cifs_acl->version = cpu_to_le16(1);
2526 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002527 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002529 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 else {
2531 cFYI(1,("unknown ACL type %d",acl_type));
2532 return 0;
2533 }
2534 for(i=0;i<count;i++) {
2535 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2536 &local_acl->a_entries[i]);
2537 if(rc != 0) {
2538 /* ACE not converted */
2539 break;
2540 }
2541 }
2542 if(rc == 0) {
2543 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2544 rc += sizeof(struct cifs_posix_acl);
2545 /* BB add check to make sure ACL does not overflow SMB */
2546 }
2547 return rc;
2548}
2549
2550int
2551CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2552 const unsigned char *searchName,
2553 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002554 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555{
2556/* SMB_QUERY_POSIX_ACL */
2557 TRANSACTION2_QPI_REQ *pSMB = NULL;
2558 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2559 int rc = 0;
2560 int bytes_returned;
2561 int name_len;
2562 __u16 params, byte_count;
2563
2564 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2565
2566queryAclRetry:
2567 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2568 (void **) &pSMBr);
2569 if (rc)
2570 return rc;
2571
2572 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2573 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002574 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002575 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 name_len++; /* trailing null */
2577 name_len *= 2;
2578 pSMB->FileName[name_len] = 0;
2579 pSMB->FileName[name_len+1] = 0;
2580 } else { /* BB improve the check for buffer overruns BB */
2581 name_len = strnlen(searchName, PATH_MAX);
2582 name_len++; /* trailing null */
2583 strncpy(pSMB->FileName, searchName, name_len);
2584 }
2585
2586 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2587 pSMB->TotalDataCount = 0;
2588 pSMB->MaxParameterCount = cpu_to_le16(2);
2589 /* BB find exact max data count below from sess structure BB */
2590 pSMB->MaxDataCount = cpu_to_le16(4000);
2591 pSMB->MaxSetupCount = 0;
2592 pSMB->Reserved = 0;
2593 pSMB->Flags = 0;
2594 pSMB->Timeout = 0;
2595 pSMB->Reserved2 = 0;
2596 pSMB->ParameterOffset = cpu_to_le16(
2597 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2598 pSMB->DataCount = 0;
2599 pSMB->DataOffset = 0;
2600 pSMB->SetupCount = 1;
2601 pSMB->Reserved3 = 0;
2602 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2603 byte_count = params + 1 /* pad */ ;
2604 pSMB->TotalParameterCount = cpu_to_le16(params);
2605 pSMB->ParameterCount = pSMB->TotalParameterCount;
2606 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2607 pSMB->Reserved4 = 0;
2608 pSMB->hdr.smb_buf_length += byte_count;
2609 pSMB->ByteCount = cpu_to_le16(byte_count);
2610
2611 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2612 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002613 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 if (rc) {
2615 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2616 } else {
2617 /* decode response */
2618
2619 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2620 if (rc || (pSMBr->ByteCount < 2))
2621 /* BB also check enough total bytes returned */
2622 rc = -EIO; /* bad smb */
2623 else {
2624 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2625 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2626 rc = cifs_copy_posix_acl(acl_inf,
2627 (char *)&pSMBr->hdr.Protocol+data_offset,
2628 buflen,acl_type,count);
2629 }
2630 }
2631 cifs_buf_release(pSMB);
2632 if (rc == -EAGAIN)
2633 goto queryAclRetry;
2634 return rc;
2635}
2636
2637int
2638CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2639 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002640 const char *local_acl, const int buflen,
2641 const int acl_type,
2642 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643{
2644 struct smb_com_transaction2_spi_req *pSMB = NULL;
2645 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2646 char *parm_data;
2647 int name_len;
2648 int rc = 0;
2649 int bytes_returned = 0;
2650 __u16 params, byte_count, data_count, param_offset, offset;
2651
2652 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2653setAclRetry:
2654 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2655 (void **) &pSMBr);
2656 if (rc)
2657 return rc;
2658 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2659 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002660 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002661 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 name_len++; /* trailing null */
2663 name_len *= 2;
2664 } else { /* BB improve the check for buffer overruns BB */
2665 name_len = strnlen(fileName, PATH_MAX);
2666 name_len++; /* trailing null */
2667 strncpy(pSMB->FileName, fileName, name_len);
2668 }
2669 params = 6 + name_len;
2670 pSMB->MaxParameterCount = cpu_to_le16(2);
2671 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2672 pSMB->MaxSetupCount = 0;
2673 pSMB->Reserved = 0;
2674 pSMB->Flags = 0;
2675 pSMB->Timeout = 0;
2676 pSMB->Reserved2 = 0;
2677 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2678 InformationLevel) - 4;
2679 offset = param_offset + params;
2680 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2681 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2682
2683 /* convert to on the wire format for POSIX ACL */
2684 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2685
2686 if(data_count == 0) {
2687 rc = -EOPNOTSUPP;
2688 goto setACLerrorExit;
2689 }
2690 pSMB->DataOffset = cpu_to_le16(offset);
2691 pSMB->SetupCount = 1;
2692 pSMB->Reserved3 = 0;
2693 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2694 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2695 byte_count = 3 /* pad */ + params + data_count;
2696 pSMB->DataCount = cpu_to_le16(data_count);
2697 pSMB->TotalDataCount = pSMB->DataCount;
2698 pSMB->ParameterCount = cpu_to_le16(params);
2699 pSMB->TotalParameterCount = pSMB->ParameterCount;
2700 pSMB->Reserved4 = 0;
2701 pSMB->hdr.smb_buf_length += byte_count;
2702 pSMB->ByteCount = cpu_to_le16(byte_count);
2703 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2704 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2705 if (rc) {
2706 cFYI(1, ("Set POSIX ACL returned %d", rc));
2707 }
2708
2709setACLerrorExit:
2710 cifs_buf_release(pSMB);
2711 if (rc == -EAGAIN)
2712 goto setAclRetry;
2713 return rc;
2714}
2715
Steve Frenchf654bac2005-04-28 22:41:04 -07002716/* BB fix tabs in this function FIXME BB */
2717int
2718CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2719 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2720{
2721 int rc = 0;
2722 struct smb_t2_qfi_req *pSMB = NULL;
2723 struct smb_t2_qfi_rsp *pSMBr = NULL;
2724 int bytes_returned;
2725 __u16 params, byte_count;
2726
2727 cFYI(1,("In GetExtAttr"));
2728 if(tcon == NULL)
2729 return -ENODEV;
2730
2731GetExtAttrRetry:
2732 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2733 (void **) &pSMBr);
2734 if (rc)
2735 return rc;
2736
Steve Frenchc67593a2005-04-28 22:41:04 -07002737 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002738 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002739 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002740 /* BB find exact max data count below from sess structure BB */
2741 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2742 pSMB->t2.MaxSetupCount = 0;
2743 pSMB->t2.Reserved = 0;
2744 pSMB->t2.Flags = 0;
2745 pSMB->t2.Timeout = 0;
2746 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002747 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2748 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002749 pSMB->t2.DataCount = 0;
2750 pSMB->t2.DataOffset = 0;
2751 pSMB->t2.SetupCount = 1;
2752 pSMB->t2.Reserved3 = 0;
2753 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002754 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002755 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2756 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2757 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002758 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002759 pSMB->Fid = netfid;
2760 pSMB->hdr.smb_buf_length += byte_count;
2761 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2762
2763 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2764 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2765 if (rc) {
2766 cFYI(1, ("error %d in GetExtAttr", rc));
2767 } else {
2768 /* decode response */
2769 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2770 if (rc || (pSMBr->ByteCount < 2))
2771 /* BB also check enough total bytes returned */
2772 /* If rc should we check for EOPNOSUPP and
2773 disable the srvino flag? or in caller? */
2774 rc = -EIO; /* bad smb */
2775 else {
2776 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2777 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2778 struct file_chattr_info * pfinfo;
2779 /* BB Do we need a cast or hash here ? */
2780 if(count != 16) {
2781 cFYI(1, ("Illegal size ret in GetExtAttr"));
2782 rc = -EIO;
2783 goto GetExtAttrOut;
2784 }
2785 pfinfo = (struct file_chattr_info *)
2786 (data_offset + (char *) &pSMBr->hdr.Protocol);
2787 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2788 *pMask = le64_to_cpu(pfinfo->mask);
2789 }
2790 }
2791GetExtAttrOut:
2792 cifs_buf_release(pSMB);
2793 if (rc == -EAGAIN)
2794 goto GetExtAttrRetry;
2795 return rc;
2796}
2797
2798
2799#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800
Steve Frencheeac8042006-01-13 21:34:58 -08002801
2802/* security id for everyone */
Steve French2cd646a2006-09-28 19:43:08 +00002803const static struct cifs_sid sid_everyone =
2804 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002805/* group users */
Steve French2cd646a2006-09-28 19:43:08 +00002806const static struct cifs_sid sid_user =
2807 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002808
Steve French0a4b92c2006-01-12 15:44:21 -08002809/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002810static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002811{
Steve French0a4b92c2006-01-12 15:44:21 -08002812 return 0;
2813}
2814
2815/* Get Security Descriptor (by handle) from remote server for a file or dir */
2816int
2817CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2818 /* BB fix up return info */ char *acl_inf, const int buflen,
2819 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2820{
2821 int rc = 0;
2822 int buf_type = 0;
2823 QUERY_SEC_DESC_REQ * pSMB;
2824 struct kvec iov[1];
2825
2826 cFYI(1, ("GetCifsACL"));
2827
2828 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2829 8 /* parm len */, tcon, (void **) &pSMB);
2830 if (rc)
2831 return rc;
2832
2833 pSMB->MaxParameterCount = cpu_to_le32(4);
2834 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2835 pSMB->MaxSetupCount = 0;
2836 pSMB->Fid = fid; /* file handle always le */
2837 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2838 CIFS_ACL_DACL);
2839 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2840 pSMB->hdr.smb_buf_length += 11;
2841 iov[0].iov_base = (char *)pSMB;
2842 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2843
2844 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2845 cifs_stats_inc(&tcon->num_acl_get);
2846 if (rc) {
2847 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2848 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002849 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002850 __le32 * parm;
2851 int parm_len;
2852 int data_len;
2853 int acl_len;
2854 struct smb_com_ntransact_rsp * pSMBr;
2855
2856/* validate_nttransact */
2857 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2858 (char **)&psec_desc,
2859 &parm_len, &data_len);
2860
2861 if(rc)
2862 goto qsec_out;
2863 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2864
2865 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2866
2867 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2868 rc = -EIO; /* bad smb */
2869 goto qsec_out;
2870 }
2871
2872/* BB check that data area is minimum length and as big as acl_len */
2873
2874 acl_len = le32_to_cpu(*(__le32 *)parm);
2875 /* BB check if(acl_len > bufsize) */
2876
2877 parse_sec_desc(psec_desc, acl_len);
2878 }
2879qsec_out:
2880 if(buf_type == CIFS_SMALL_BUFFER)
2881 cifs_small_buf_release(iov[0].iov_base);
2882 else if(buf_type == CIFS_LARGE_BUFFER)
2883 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00002884/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08002885 return rc;
2886}
2887
Steve French6b8edfe2005-08-23 20:26:03 -07002888/* Legacy Query Path Information call for lookup to old servers such
2889 as Win9x/WinME */
2890int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2891 const unsigned char *searchName,
2892 FILE_ALL_INFO * pFinfo,
2893 const struct nls_table *nls_codepage, int remap)
2894{
2895 QUERY_INFORMATION_REQ * pSMB;
2896 QUERY_INFORMATION_RSP * pSMBr;
2897 int rc = 0;
2898 int bytes_returned;
2899 int name_len;
2900
2901 cFYI(1, ("In SMBQPath path %s", searchName));
2902QInfRetry:
2903 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2904 (void **) &pSMBr);
2905 if (rc)
2906 return rc;
2907
2908 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2909 name_len =
2910 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2911 PATH_MAX, nls_codepage, remap);
2912 name_len++; /* trailing null */
2913 name_len *= 2;
2914 } else {
2915 name_len = strnlen(searchName, PATH_MAX);
2916 name_len++; /* trailing null */
2917 strncpy(pSMB->FileName, searchName, name_len);
2918 }
2919 pSMB->BufferFormat = 0x04;
2920 name_len++; /* account for buffer type byte */
2921 pSMB->hdr.smb_buf_length += (__u16) name_len;
2922 pSMB->ByteCount = cpu_to_le16(name_len);
2923
2924 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2925 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2926 if (rc) {
2927 cFYI(1, ("Send error in QueryInfo = %d", rc));
2928 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00002929 struct timespec ts;
2930 __u32 time = le32_to_cpu(pSMBr->last_write_time);
2931 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07002932 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00002933 ts.tv_nsec = 0;
2934 ts.tv_sec = time;
2935 /* decode time fields */
2936 pFinfo->ChangeTime = cifs_UnixTimeToNT(ts);
2937 pFinfo->LastWriteTime = pFinfo->ChangeTime;
2938 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07002939 pFinfo->AllocationSize =
2940 cpu_to_le64(le32_to_cpu(pSMBr->size));
2941 pFinfo->EndOfFile = pFinfo->AllocationSize;
2942 pFinfo->Attributes =
2943 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002944 } else
2945 rc = -EIO; /* bad buffer passed in */
2946
2947 cifs_buf_release(pSMB);
2948
2949 if (rc == -EAGAIN)
2950 goto QInfRetry;
2951
2952 return rc;
2953}
2954
2955
2956
2957
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958int
2959CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2960 const unsigned char *searchName,
2961 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002962 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002963{
2964/* level 263 SMB_QUERY_FILE_ALL_INFO */
2965 TRANSACTION2_QPI_REQ *pSMB = NULL;
2966 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2967 int rc = 0;
2968 int bytes_returned;
2969 int name_len;
2970 __u16 params, byte_count;
2971
2972/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2973QPathInfoRetry:
2974 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2975 (void **) &pSMBr);
2976 if (rc)
2977 return rc;
2978
2979 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2980 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002981 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002982 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 name_len++; /* trailing null */
2984 name_len *= 2;
2985 } else { /* BB improve the check for buffer overruns BB */
2986 name_len = strnlen(searchName, PATH_MAX);
2987 name_len++; /* trailing null */
2988 strncpy(pSMB->FileName, searchName, name_len);
2989 }
2990
2991 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2992 pSMB->TotalDataCount = 0;
2993 pSMB->MaxParameterCount = cpu_to_le16(2);
2994 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2995 pSMB->MaxSetupCount = 0;
2996 pSMB->Reserved = 0;
2997 pSMB->Flags = 0;
2998 pSMB->Timeout = 0;
2999 pSMB->Reserved2 = 0;
3000 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3001 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3002 pSMB->DataCount = 0;
3003 pSMB->DataOffset = 0;
3004 pSMB->SetupCount = 1;
3005 pSMB->Reserved3 = 0;
3006 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3007 byte_count = params + 1 /* pad */ ;
3008 pSMB->TotalParameterCount = cpu_to_le16(params);
3009 pSMB->ParameterCount = pSMB->TotalParameterCount;
3010 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
3011 pSMB->Reserved4 = 0;
3012 pSMB->hdr.smb_buf_length += byte_count;
3013 pSMB->ByteCount = cpu_to_le16(byte_count);
3014
3015 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3016 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3017 if (rc) {
3018 cFYI(1, ("Send error in QPathInfo = %d", rc));
3019 } else { /* decode response */
3020 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3021
3022 if (rc || (pSMBr->ByteCount < 40))
3023 rc = -EIO; /* bad smb */
3024 else if (pFindData){
3025 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3026 memcpy((char *) pFindData,
3027 (char *) &pSMBr->hdr.Protocol +
3028 data_offset, sizeof (FILE_ALL_INFO));
3029 } else
3030 rc = -ENOMEM;
3031 }
3032 cifs_buf_release(pSMB);
3033 if (rc == -EAGAIN)
3034 goto QPathInfoRetry;
3035
3036 return rc;
3037}
3038
3039int
3040CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3041 const unsigned char *searchName,
3042 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003043 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044{
3045/* SMB_QUERY_FILE_UNIX_BASIC */
3046 TRANSACTION2_QPI_REQ *pSMB = NULL;
3047 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3048 int rc = 0;
3049 int bytes_returned = 0;
3050 int name_len;
3051 __u16 params, byte_count;
3052
3053 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3054UnixQPathInfoRetry:
3055 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3056 (void **) &pSMBr);
3057 if (rc)
3058 return rc;
3059
3060 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3061 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003062 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003063 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 name_len++; /* trailing null */
3065 name_len *= 2;
3066 } else { /* BB improve the check for buffer overruns BB */
3067 name_len = strnlen(searchName, PATH_MAX);
3068 name_len++; /* trailing null */
3069 strncpy(pSMB->FileName, searchName, name_len);
3070 }
3071
3072 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3073 pSMB->TotalDataCount = 0;
3074 pSMB->MaxParameterCount = cpu_to_le16(2);
3075 /* BB find exact max SMB PDU from sess structure BB */
3076 pSMB->MaxDataCount = cpu_to_le16(4000);
3077 pSMB->MaxSetupCount = 0;
3078 pSMB->Reserved = 0;
3079 pSMB->Flags = 0;
3080 pSMB->Timeout = 0;
3081 pSMB->Reserved2 = 0;
3082 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3083 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3084 pSMB->DataCount = 0;
3085 pSMB->DataOffset = 0;
3086 pSMB->SetupCount = 1;
3087 pSMB->Reserved3 = 0;
3088 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3089 byte_count = params + 1 /* pad */ ;
3090 pSMB->TotalParameterCount = cpu_to_le16(params);
3091 pSMB->ParameterCount = pSMB->TotalParameterCount;
3092 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3093 pSMB->Reserved4 = 0;
3094 pSMB->hdr.smb_buf_length += byte_count;
3095 pSMB->ByteCount = cpu_to_le16(byte_count);
3096
3097 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3098 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3099 if (rc) {
3100 cFYI(1, ("Send error in QPathInfo = %d", rc));
3101 } else { /* decode response */
3102 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3103
3104 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3105 rc = -EIO; /* bad smb */
3106 } else {
3107 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3108 memcpy((char *) pFindData,
3109 (char *) &pSMBr->hdr.Protocol +
3110 data_offset,
3111 sizeof (FILE_UNIX_BASIC_INFO));
3112 }
3113 }
3114 cifs_buf_release(pSMB);
3115 if (rc == -EAGAIN)
3116 goto UnixQPathInfoRetry;
3117
3118 return rc;
3119}
3120
3121#if 0 /* function unused at present */
3122int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3123 const char *searchName, FILE_ALL_INFO * findData,
3124 const struct nls_table *nls_codepage)
3125{
3126/* level 257 SMB_ */
3127 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3128 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3129 int rc = 0;
3130 int bytes_returned;
3131 int name_len;
3132 __u16 params, byte_count;
3133
3134 cFYI(1, ("In FindUnique"));
3135findUniqueRetry:
3136 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3137 (void **) &pSMBr);
3138 if (rc)
3139 return rc;
3140
3141 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3142 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003143 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 /* find define for this maxpathcomponent */
3145 , nls_codepage);
3146 name_len++; /* trailing null */
3147 name_len *= 2;
3148 } else { /* BB improve the check for buffer overruns BB */
3149 name_len = strnlen(searchName, PATH_MAX);
3150 name_len++; /* trailing null */
3151 strncpy(pSMB->FileName, searchName, name_len);
3152 }
3153
3154 params = 12 + name_len /* includes null */ ;
3155 pSMB->TotalDataCount = 0; /* no EAs */
3156 pSMB->MaxParameterCount = cpu_to_le16(2);
3157 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3158 pSMB->MaxSetupCount = 0;
3159 pSMB->Reserved = 0;
3160 pSMB->Flags = 0;
3161 pSMB->Timeout = 0;
3162 pSMB->Reserved2 = 0;
3163 pSMB->ParameterOffset = cpu_to_le16(
3164 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3165 pSMB->DataCount = 0;
3166 pSMB->DataOffset = 0;
3167 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3168 pSMB->Reserved3 = 0;
3169 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3170 byte_count = params + 1 /* pad */ ;
3171 pSMB->TotalParameterCount = cpu_to_le16(params);
3172 pSMB->ParameterCount = pSMB->TotalParameterCount;
3173 pSMB->SearchAttributes =
3174 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3175 ATTR_DIRECTORY);
3176 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3177 pSMB->SearchFlags = cpu_to_le16(1);
3178 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3179 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3180 pSMB->hdr.smb_buf_length += byte_count;
3181 pSMB->ByteCount = cpu_to_le16(byte_count);
3182
3183 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3184 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3185
3186 if (rc) {
3187 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3188 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003189 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190 /* BB fill in */
3191 }
3192
3193 cifs_buf_release(pSMB);
3194 if (rc == -EAGAIN)
3195 goto findUniqueRetry;
3196
3197 return rc;
3198}
3199#endif /* end unused (temporarily) function */
3200
3201/* xid, tcon, searchName and codepage are input parms, rest are returned */
3202int
3203CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3204 const char *searchName,
3205 const struct nls_table *nls_codepage,
3206 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003207 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003208{
3209/* level 257 SMB_ */
3210 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3211 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3212 T2_FFIRST_RSP_PARMS * parms;
3213 int rc = 0;
3214 int bytes_returned = 0;
3215 int name_len;
3216 __u16 params, byte_count;
3217
Steve French737b7582005-04-28 22:41:06 -07003218 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219
3220findFirstRetry:
3221 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3222 (void **) &pSMBr);
3223 if (rc)
3224 return rc;
3225
3226 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3227 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003228 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003229 PATH_MAX, nls_codepage, remap);
3230 /* We can not add the asterik earlier in case
3231 it got remapped to 0xF03A as if it were part of the
3232 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003234 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003235 pSMB->FileName[name_len+1] = 0;
3236 pSMB->FileName[name_len+2] = '*';
3237 pSMB->FileName[name_len+3] = 0;
3238 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3240 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003241 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 } else { /* BB add check for overrun of SMB buf BB */
3243 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244/* BB fix here and in unicode clause above ie
3245 if(name_len > buffersize-header)
3246 free buffer exit; BB */
3247 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003248 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003249 pSMB->FileName[name_len+1] = '*';
3250 pSMB->FileName[name_len+2] = 0;
3251 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003252 }
3253
3254 params = 12 + name_len /* includes null */ ;
3255 pSMB->TotalDataCount = 0; /* no EAs */
3256 pSMB->MaxParameterCount = cpu_to_le16(10);
3257 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3258 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3259 pSMB->MaxSetupCount = 0;
3260 pSMB->Reserved = 0;
3261 pSMB->Flags = 0;
3262 pSMB->Timeout = 0;
3263 pSMB->Reserved2 = 0;
3264 byte_count = params + 1 /* pad */ ;
3265 pSMB->TotalParameterCount = cpu_to_le16(params);
3266 pSMB->ParameterCount = pSMB->TotalParameterCount;
3267 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003268 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3269 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 pSMB->DataCount = 0;
3271 pSMB->DataOffset = 0;
3272 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3273 pSMB->Reserved3 = 0;
3274 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3275 pSMB->SearchAttributes =
3276 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3277 ATTR_DIRECTORY);
3278 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3279 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3280 CIFS_SEARCH_RETURN_RESUME);
3281 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3282
3283 /* BB what should we set StorageType to? Does it matter? BB */
3284 pSMB->SearchStorageType = 0;
3285 pSMB->hdr.smb_buf_length += byte_count;
3286 pSMB->ByteCount = cpu_to_le16(byte_count);
3287
3288 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3289 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003290 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291
Steve French88274812006-03-09 22:21:45 +00003292 if (rc) {/* BB add logic to retry regular search if Unix search
3293 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 /* BB Add code to handle unsupported level rc */
3295 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003296
Steve French88274812006-03-09 22:21:45 +00003297 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298
3299 /* BB eventually could optimize out free and realloc of buf */
3300 /* for this case */
3301 if (rc == -EAGAIN)
3302 goto findFirstRetry;
3303 } else { /* decode response */
3304 /* BB remember to free buffer if error BB */
3305 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3306 if(rc == 0) {
3307 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3308 psrch_inf->unicode = TRUE;
3309 else
3310 psrch_inf->unicode = FALSE;
3311
3312 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003313 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314 psrch_inf->srch_entries_start =
3315 (char *) &pSMBr->hdr.Protocol +
3316 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3318 le16_to_cpu(pSMBr->t2.ParameterOffset));
3319
3320 if(parms->EndofSearch)
3321 psrch_inf->endOfSearch = TRUE;
3322 else
3323 psrch_inf->endOfSearch = FALSE;
3324
3325 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003326 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003328 *pnetfid = parms->SearchHandle;
3329 } else {
3330 cifs_buf_release(pSMB);
3331 }
3332 }
3333
3334 return rc;
3335}
3336
3337int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3338 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3339{
3340 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3341 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3342 T2_FNEXT_RSP_PARMS * parms;
3343 char *response_data;
3344 int rc = 0;
3345 int bytes_returned, name_len;
3346 __u16 params, byte_count;
3347
3348 cFYI(1, ("In FindNext"));
3349
3350 if(psrch_inf->endOfSearch == TRUE)
3351 return -ENOENT;
3352
3353 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3354 (void **) &pSMBr);
3355 if (rc)
3356 return rc;
3357
3358 params = 14; /* includes 2 bytes of null string, converted to LE below */
3359 byte_count = 0;
3360 pSMB->TotalDataCount = 0; /* no EAs */
3361 pSMB->MaxParameterCount = cpu_to_le16(8);
3362 pSMB->MaxDataCount =
3363 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3364 pSMB->MaxSetupCount = 0;
3365 pSMB->Reserved = 0;
3366 pSMB->Flags = 0;
3367 pSMB->Timeout = 0;
3368 pSMB->Reserved2 = 0;
3369 pSMB->ParameterOffset = cpu_to_le16(
3370 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3371 pSMB->DataCount = 0;
3372 pSMB->DataOffset = 0;
3373 pSMB->SetupCount = 1;
3374 pSMB->Reserved3 = 0;
3375 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3376 pSMB->SearchHandle = searchHandle; /* always kept as le */
3377 pSMB->SearchCount =
3378 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3379 /* test for Unix extensions */
3380/* if (tcon->ses->capabilities & CAP_UNIX) {
3381 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3382 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3383 } else {
3384 pSMB->InformationLevel =
3385 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3386 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3387 } */
3388 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3389 pSMB->ResumeKey = psrch_inf->resume_key;
3390 pSMB->SearchFlags =
3391 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3392
3393 name_len = psrch_inf->resume_name_len;
3394 params += name_len;
3395 if(name_len < PATH_MAX) {
3396 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3397 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003398 /* 14 byte parm len above enough for 2 byte null terminator */
3399 pSMB->ResumeFileName[name_len] = 0;
3400 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003401 } else {
3402 rc = -EINVAL;
3403 goto FNext2_err_exit;
3404 }
3405 byte_count = params + 1 /* pad */ ;
3406 pSMB->TotalParameterCount = cpu_to_le16(params);
3407 pSMB->ParameterCount = pSMB->TotalParameterCount;
3408 pSMB->hdr.smb_buf_length += byte_count;
3409 pSMB->ByteCount = cpu_to_le16(byte_count);
3410
3411 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3412 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003413 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414 if (rc) {
3415 if (rc == -EBADF) {
3416 psrch_inf->endOfSearch = TRUE;
3417 rc = 0; /* search probably was closed at end of search above */
3418 } else
3419 cFYI(1, ("FindNext returned = %d", rc));
3420 } else { /* decode response */
3421 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3422
3423 if(rc == 0) {
3424 /* BB fixme add lock for file (srch_info) struct here */
3425 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3426 psrch_inf->unicode = TRUE;
3427 else
3428 psrch_inf->unicode = FALSE;
3429 response_data = (char *) &pSMBr->hdr.Protocol +
3430 le16_to_cpu(pSMBr->t2.ParameterOffset);
3431 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3432 response_data = (char *)&pSMBr->hdr.Protocol +
3433 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003434 if(psrch_inf->smallBuf)
3435 cifs_small_buf_release(
3436 psrch_inf->ntwrk_buf_start);
3437 else
3438 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 psrch_inf->srch_entries_start = response_data;
3440 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003441 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442 if(parms->EndofSearch)
3443 psrch_inf->endOfSearch = TRUE;
3444 else
3445 psrch_inf->endOfSearch = FALSE;
3446
3447 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3448 psrch_inf->index_of_last_entry +=
3449 psrch_inf->entries_in_buffer;
3450/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3451
3452 /* BB fixme add unlock here */
3453 }
3454
3455 }
3456
3457 /* BB On error, should we leave previous search buf (and count and
3458 last entry fields) intact or free the previous one? */
3459
3460 /* Note: On -EAGAIN error only caller can retry on handle based calls
3461 since file handle passed in no longer valid */
3462FNext2_err_exit:
3463 if (rc != 0)
3464 cifs_buf_release(pSMB);
3465
3466 return rc;
3467}
3468
3469int
3470CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3471{
3472 int rc = 0;
3473 FINDCLOSE_REQ *pSMB = NULL;
3474 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3475 int bytes_returned;
3476
3477 cFYI(1, ("In CIFSSMBFindClose"));
3478 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3479
3480 /* no sense returning error if session restarted
3481 as file handle has been closed */
3482 if(rc == -EAGAIN)
3483 return 0;
3484 if (rc)
3485 return rc;
3486
3487 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3488 pSMB->FileID = searchHandle;
3489 pSMB->ByteCount = 0;
3490 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3491 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3492 if (rc) {
3493 cERROR(1, ("Send error in FindClose = %d", rc));
3494 }
Steve Frencha4544342005-08-24 13:59:35 -07003495 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 cifs_small_buf_release(pSMB);
3497
3498 /* Since session is dead, search handle closed on server already */
3499 if (rc == -EAGAIN)
3500 rc = 0;
3501
3502 return rc;
3503}
3504
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505int
3506CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3507 const unsigned char *searchName,
3508 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003509 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510{
3511 int rc = 0;
3512 TRANSACTION2_QPI_REQ *pSMB = NULL;
3513 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3514 int name_len, bytes_returned;
3515 __u16 params, byte_count;
3516
3517 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3518 if(tcon == NULL)
3519 return -ENODEV;
3520
3521GetInodeNumberRetry:
3522 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3523 (void **) &pSMBr);
3524 if (rc)
3525 return rc;
3526
3527
3528 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3529 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003530 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003531 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003532 name_len++; /* trailing null */
3533 name_len *= 2;
3534 } else { /* BB improve the check for buffer overruns BB */
3535 name_len = strnlen(searchName, PATH_MAX);
3536 name_len++; /* trailing null */
3537 strncpy(pSMB->FileName, searchName, name_len);
3538 }
3539
3540 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3541 pSMB->TotalDataCount = 0;
3542 pSMB->MaxParameterCount = cpu_to_le16(2);
3543 /* BB find exact max data count below from sess structure BB */
3544 pSMB->MaxDataCount = cpu_to_le16(4000);
3545 pSMB->MaxSetupCount = 0;
3546 pSMB->Reserved = 0;
3547 pSMB->Flags = 0;
3548 pSMB->Timeout = 0;
3549 pSMB->Reserved2 = 0;
3550 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3551 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3552 pSMB->DataCount = 0;
3553 pSMB->DataOffset = 0;
3554 pSMB->SetupCount = 1;
3555 pSMB->Reserved3 = 0;
3556 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3557 byte_count = params + 1 /* pad */ ;
3558 pSMB->TotalParameterCount = cpu_to_le16(params);
3559 pSMB->ParameterCount = pSMB->TotalParameterCount;
3560 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3561 pSMB->Reserved4 = 0;
3562 pSMB->hdr.smb_buf_length += byte_count;
3563 pSMB->ByteCount = cpu_to_le16(byte_count);
3564
3565 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3566 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3567 if (rc) {
3568 cFYI(1, ("error %d in QueryInternalInfo", rc));
3569 } else {
3570 /* decode response */
3571 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3572 if (rc || (pSMBr->ByteCount < 2))
3573 /* BB also check enough total bytes returned */
3574 /* If rc should we check for EOPNOSUPP and
3575 disable the srvino flag? or in caller? */
3576 rc = -EIO; /* bad smb */
3577 else {
3578 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3579 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3580 struct file_internal_info * pfinfo;
3581 /* BB Do we need a cast or hash here ? */
3582 if(count < 8) {
3583 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3584 rc = -EIO;
3585 goto GetInodeNumOut;
3586 }
3587 pfinfo = (struct file_internal_info *)
3588 (data_offset + (char *) &pSMBr->hdr.Protocol);
3589 *inode_number = pfinfo->UniqueId;
3590 }
3591 }
3592GetInodeNumOut:
3593 cifs_buf_release(pSMB);
3594 if (rc == -EAGAIN)
3595 goto GetInodeNumberRetry;
3596 return rc;
3597}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598
3599int
3600CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3601 const unsigned char *searchName,
3602 unsigned char **targetUNCs,
3603 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003604 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003605{
3606/* TRANS2_GET_DFS_REFERRAL */
3607 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3608 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3609 struct dfs_referral_level_3 * referrals = NULL;
3610 int rc = 0;
3611 int bytes_returned;
3612 int name_len;
3613 unsigned int i;
3614 char * temp;
3615 __u16 params, byte_count;
3616 *number_of_UNC_in_array = 0;
3617 *targetUNCs = NULL;
3618
3619 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3620 if (ses == NULL)
3621 return -ENODEV;
3622getDFSRetry:
3623 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3624 (void **) &pSMBr);
3625 if (rc)
3626 return rc;
Steve French1982c342005-08-17 12:38:22 -07003627
3628 /* server pointer checked in called function,
3629 but should never be null here anyway */
3630 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003631 pSMB->hdr.Tid = ses->ipc_tid;
3632 pSMB->hdr.Uid = ses->Suid;
3633 if (ses->capabilities & CAP_STATUS32) {
3634 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3635 }
3636 if (ses->capabilities & CAP_DFS) {
3637 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3638 }
3639
3640 if (ses->capabilities & CAP_UNICODE) {
3641 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3642 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003643 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003644 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 name_len++; /* trailing null */
3646 name_len *= 2;
3647 } else { /* BB improve the check for buffer overruns BB */
3648 name_len = strnlen(searchName, PATH_MAX);
3649 name_len++; /* trailing null */
3650 strncpy(pSMB->RequestFileName, searchName, name_len);
3651 }
3652
3653 params = 2 /* level */ + name_len /*includes null */ ;
3654 pSMB->TotalDataCount = 0;
3655 pSMB->DataCount = 0;
3656 pSMB->DataOffset = 0;
3657 pSMB->MaxParameterCount = 0;
3658 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3659 pSMB->MaxSetupCount = 0;
3660 pSMB->Reserved = 0;
3661 pSMB->Flags = 0;
3662 pSMB->Timeout = 0;
3663 pSMB->Reserved2 = 0;
3664 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3665 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3666 pSMB->SetupCount = 1;
3667 pSMB->Reserved3 = 0;
3668 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3669 byte_count = params + 3 /* pad */ ;
3670 pSMB->ParameterCount = cpu_to_le16(params);
3671 pSMB->TotalParameterCount = pSMB->ParameterCount;
3672 pSMB->MaxReferralLevel = cpu_to_le16(3);
3673 pSMB->hdr.smb_buf_length += byte_count;
3674 pSMB->ByteCount = cpu_to_le16(byte_count);
3675
3676 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3677 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3678 if (rc) {
3679 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3680 } else { /* decode response */
3681/* BB Add logic to parse referrals here */
3682 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3683
3684 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3685 rc = -EIO; /* bad smb */
3686 else {
3687 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3688 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3689
3690 cFYI(1,
3691 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3692 pSMBr->ByteCount, data_offset));
3693 referrals =
3694 (struct dfs_referral_level_3 *)
3695 (8 /* sizeof start of data block */ +
3696 data_offset +
3697 (char *) &pSMBr->hdr.Protocol);
3698 cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",
3699 le16_to_cpu(pSMBr->NumberOfReferrals),le16_to_cpu(pSMBr->DFSFlags), le16_to_cpu(referrals->ReferralSize),le16_to_cpu(referrals->ServerType),le16_to_cpu(referrals->ReferralFlags),le16_to_cpu(referrals->TimeToLive)));
3700 /* BB This field is actually two bytes in from start of
3701 data block so we could do safety check that DataBlock
3702 begins at address of pSMBr->NumberOfReferrals */
3703 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3704
3705 /* BB Fix below so can return more than one referral */
3706 if(*number_of_UNC_in_array > 1)
3707 *number_of_UNC_in_array = 1;
3708
3709 /* get the length of the strings describing refs */
3710 name_len = 0;
3711 for(i=0;i<*number_of_UNC_in_array;i++) {
3712 /* make sure that DfsPathOffset not past end */
3713 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3714 if (offset > data_count) {
3715 /* if invalid referral, stop here and do
3716 not try to copy any more */
3717 *number_of_UNC_in_array = i;
3718 break;
3719 }
3720 temp = ((char *)referrals) + offset;
3721
3722 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3723 name_len += UniStrnlen((wchar_t *)temp,data_count);
3724 } else {
3725 name_len += strnlen(temp,data_count);
3726 }
3727 referrals++;
3728 /* BB add check that referral pointer does not fall off end PDU */
3729
3730 }
3731 /* BB add check for name_len bigger than bcc */
3732 *targetUNCs =
3733 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3734 if(*targetUNCs == NULL) {
3735 rc = -ENOMEM;
3736 goto GetDFSRefExit;
3737 }
3738 /* copy the ref strings */
3739 referrals =
3740 (struct dfs_referral_level_3 *)
3741 (8 /* sizeof data hdr */ +
3742 data_offset +
3743 (char *) &pSMBr->hdr.Protocol);
3744
3745 for(i=0;i<*number_of_UNC_in_array;i++) {
3746 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3747 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3748 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003749 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750 } else {
3751 strncpy(*targetUNCs,temp,name_len);
3752 }
3753 /* BB update target_uncs pointers */
3754 referrals++;
3755 }
3756 temp = *targetUNCs;
3757 temp[name_len] = 0;
3758 }
3759
3760 }
3761GetDFSRefExit:
3762 if (pSMB)
3763 cifs_buf_release(pSMB);
3764
3765 if (rc == -EAGAIN)
3766 goto getDFSRetry;
3767
3768 return rc;
3769}
3770
Steve French20962432005-09-21 22:05:57 -07003771/* Query File System Info such as free space to old servers such as Win 9x */
3772int
3773SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3774{
3775/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3776 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3777 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3778 FILE_SYSTEM_ALLOC_INFO *response_data;
3779 int rc = 0;
3780 int bytes_returned = 0;
3781 __u16 params, byte_count;
3782
3783 cFYI(1, ("OldQFSInfo"));
3784oldQFSInfoRetry:
3785 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3786 (void **) &pSMBr);
3787 if (rc)
3788 return rc;
3789 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3790 (void **) &pSMBr);
3791 if (rc)
3792 return rc;
3793
3794 params = 2; /* level */
3795 pSMB->TotalDataCount = 0;
3796 pSMB->MaxParameterCount = cpu_to_le16(2);
3797 pSMB->MaxDataCount = cpu_to_le16(1000);
3798 pSMB->MaxSetupCount = 0;
3799 pSMB->Reserved = 0;
3800 pSMB->Flags = 0;
3801 pSMB->Timeout = 0;
3802 pSMB->Reserved2 = 0;
3803 byte_count = params + 1 /* pad */ ;
3804 pSMB->TotalParameterCount = cpu_to_le16(params);
3805 pSMB->ParameterCount = pSMB->TotalParameterCount;
3806 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3807 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3808 pSMB->DataCount = 0;
3809 pSMB->DataOffset = 0;
3810 pSMB->SetupCount = 1;
3811 pSMB->Reserved3 = 0;
3812 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3813 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3814 pSMB->hdr.smb_buf_length += byte_count;
3815 pSMB->ByteCount = cpu_to_le16(byte_count);
3816
3817 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3818 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3819 if (rc) {
3820 cFYI(1, ("Send error in QFSInfo = %d", rc));
3821 } else { /* decode response */
3822 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3823
3824 if (rc || (pSMBr->ByteCount < 18))
3825 rc = -EIO; /* bad smb */
3826 else {
3827 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3828 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3829 pSMBr->ByteCount, data_offset));
3830
3831 response_data =
3832 (FILE_SYSTEM_ALLOC_INFO *)
3833 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3834 FSData->f_bsize =
3835 le16_to_cpu(response_data->BytesPerSector) *
3836 le32_to_cpu(response_data->
3837 SectorsPerAllocationUnit);
3838 FSData->f_blocks =
3839 le32_to_cpu(response_data->TotalAllocationUnits);
3840 FSData->f_bfree = FSData->f_bavail =
3841 le32_to_cpu(response_data->FreeAllocationUnits);
3842 cFYI(1,
3843 ("Blocks: %lld Free: %lld Block size %ld",
3844 (unsigned long long)FSData->f_blocks,
3845 (unsigned long long)FSData->f_bfree,
3846 FSData->f_bsize));
3847 }
3848 }
3849 cifs_buf_release(pSMB);
3850
3851 if (rc == -EAGAIN)
3852 goto oldQFSInfoRetry;
3853
3854 return rc;
3855}
3856
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857int
Steve French737b7582005-04-28 22:41:06 -07003858CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859{
3860/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3861 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3862 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3863 FILE_SYSTEM_INFO *response_data;
3864 int rc = 0;
3865 int bytes_returned = 0;
3866 __u16 params, byte_count;
3867
3868 cFYI(1, ("In QFSInfo"));
3869QFSInfoRetry:
3870 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3871 (void **) &pSMBr);
3872 if (rc)
3873 return rc;
3874
3875 params = 2; /* level */
3876 pSMB->TotalDataCount = 0;
3877 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003878 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003879 pSMB->MaxSetupCount = 0;
3880 pSMB->Reserved = 0;
3881 pSMB->Flags = 0;
3882 pSMB->Timeout = 0;
3883 pSMB->Reserved2 = 0;
3884 byte_count = params + 1 /* pad */ ;
3885 pSMB->TotalParameterCount = cpu_to_le16(params);
3886 pSMB->ParameterCount = pSMB->TotalParameterCount;
3887 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3888 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3889 pSMB->DataCount = 0;
3890 pSMB->DataOffset = 0;
3891 pSMB->SetupCount = 1;
3892 pSMB->Reserved3 = 0;
3893 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3894 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3895 pSMB->hdr.smb_buf_length += byte_count;
3896 pSMB->ByteCount = cpu_to_le16(byte_count);
3897
3898 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3899 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3900 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003901 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902 } else { /* decode response */
3903 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3904
Steve French20962432005-09-21 22:05:57 -07003905 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 rc = -EIO; /* bad smb */
3907 else {
3908 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909
3910 response_data =
3911 (FILE_SYSTEM_INFO
3912 *) (((char *) &pSMBr->hdr.Protocol) +
3913 data_offset);
3914 FSData->f_bsize =
3915 le32_to_cpu(response_data->BytesPerSector) *
3916 le32_to_cpu(response_data->
3917 SectorsPerAllocationUnit);
3918 FSData->f_blocks =
3919 le64_to_cpu(response_data->TotalAllocationUnits);
3920 FSData->f_bfree = FSData->f_bavail =
3921 le64_to_cpu(response_data->FreeAllocationUnits);
3922 cFYI(1,
3923 ("Blocks: %lld Free: %lld Block size %ld",
3924 (unsigned long long)FSData->f_blocks,
3925 (unsigned long long)FSData->f_bfree,
3926 FSData->f_bsize));
3927 }
3928 }
3929 cifs_buf_release(pSMB);
3930
3931 if (rc == -EAGAIN)
3932 goto QFSInfoRetry;
3933
3934 return rc;
3935}
3936
3937int
Steve French737b7582005-04-28 22:41:06 -07003938CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939{
3940/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3941 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3942 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3943 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3944 int rc = 0;
3945 int bytes_returned = 0;
3946 __u16 params, byte_count;
3947
3948 cFYI(1, ("In QFSAttributeInfo"));
3949QFSAttributeRetry:
3950 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3951 (void **) &pSMBr);
3952 if (rc)
3953 return rc;
3954
3955 params = 2; /* level */
3956 pSMB->TotalDataCount = 0;
3957 pSMB->MaxParameterCount = cpu_to_le16(2);
3958 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3959 pSMB->MaxSetupCount = 0;
3960 pSMB->Reserved = 0;
3961 pSMB->Flags = 0;
3962 pSMB->Timeout = 0;
3963 pSMB->Reserved2 = 0;
3964 byte_count = params + 1 /* pad */ ;
3965 pSMB->TotalParameterCount = cpu_to_le16(params);
3966 pSMB->ParameterCount = pSMB->TotalParameterCount;
3967 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3968 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3969 pSMB->DataCount = 0;
3970 pSMB->DataOffset = 0;
3971 pSMB->SetupCount = 1;
3972 pSMB->Reserved3 = 0;
3973 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3974 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3975 pSMB->hdr.smb_buf_length += byte_count;
3976 pSMB->ByteCount = cpu_to_le16(byte_count);
3977
3978 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3979 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3980 if (rc) {
3981 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3982 } else { /* decode response */
3983 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3984
3985 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3986 rc = -EIO; /* bad smb */
3987 } else {
3988 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3989 response_data =
3990 (FILE_SYSTEM_ATTRIBUTE_INFO
3991 *) (((char *) &pSMBr->hdr.Protocol) +
3992 data_offset);
3993 memcpy(&tcon->fsAttrInfo, response_data,
3994 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3995 }
3996 }
3997 cifs_buf_release(pSMB);
3998
3999 if (rc == -EAGAIN)
4000 goto QFSAttributeRetry;
4001
4002 return rc;
4003}
4004
4005int
Steve French737b7582005-04-28 22:41:06 -07004006CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007{
4008/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4009 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4010 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4011 FILE_SYSTEM_DEVICE_INFO *response_data;
4012 int rc = 0;
4013 int bytes_returned = 0;
4014 __u16 params, byte_count;
4015
4016 cFYI(1, ("In QFSDeviceInfo"));
4017QFSDeviceRetry:
4018 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4019 (void **) &pSMBr);
4020 if (rc)
4021 return rc;
4022
4023 params = 2; /* level */
4024 pSMB->TotalDataCount = 0;
4025 pSMB->MaxParameterCount = cpu_to_le16(2);
4026 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4027 pSMB->MaxSetupCount = 0;
4028 pSMB->Reserved = 0;
4029 pSMB->Flags = 0;
4030 pSMB->Timeout = 0;
4031 pSMB->Reserved2 = 0;
4032 byte_count = params + 1 /* pad */ ;
4033 pSMB->TotalParameterCount = cpu_to_le16(params);
4034 pSMB->ParameterCount = pSMB->TotalParameterCount;
4035 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4036 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4037
4038 pSMB->DataCount = 0;
4039 pSMB->DataOffset = 0;
4040 pSMB->SetupCount = 1;
4041 pSMB->Reserved3 = 0;
4042 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4043 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4044 pSMB->hdr.smb_buf_length += byte_count;
4045 pSMB->ByteCount = cpu_to_le16(byte_count);
4046
4047 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4048 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4049 if (rc) {
4050 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4051 } else { /* decode response */
4052 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4053
4054 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4055 rc = -EIO; /* bad smb */
4056 else {
4057 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4058 response_data =
Steve French737b7582005-04-28 22:41:06 -07004059 (FILE_SYSTEM_DEVICE_INFO *)
4060 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 data_offset);
4062 memcpy(&tcon->fsDevInfo, response_data,
4063 sizeof (FILE_SYSTEM_DEVICE_INFO));
4064 }
4065 }
4066 cifs_buf_release(pSMB);
4067
4068 if (rc == -EAGAIN)
4069 goto QFSDeviceRetry;
4070
4071 return rc;
4072}
4073
4074int
Steve French737b7582005-04-28 22:41:06 -07004075CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076{
4077/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4078 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4079 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4080 FILE_SYSTEM_UNIX_INFO *response_data;
4081 int rc = 0;
4082 int bytes_returned = 0;
4083 __u16 params, byte_count;
4084
4085 cFYI(1, ("In QFSUnixInfo"));
4086QFSUnixRetry:
4087 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4088 (void **) &pSMBr);
4089 if (rc)
4090 return rc;
4091
4092 params = 2; /* level */
4093 pSMB->TotalDataCount = 0;
4094 pSMB->DataCount = 0;
4095 pSMB->DataOffset = 0;
4096 pSMB->MaxParameterCount = cpu_to_le16(2);
4097 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4098 pSMB->MaxSetupCount = 0;
4099 pSMB->Reserved = 0;
4100 pSMB->Flags = 0;
4101 pSMB->Timeout = 0;
4102 pSMB->Reserved2 = 0;
4103 byte_count = params + 1 /* pad */ ;
4104 pSMB->ParameterCount = cpu_to_le16(params);
4105 pSMB->TotalParameterCount = pSMB->ParameterCount;
4106 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4107 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4108 pSMB->SetupCount = 1;
4109 pSMB->Reserved3 = 0;
4110 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4111 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4112 pSMB->hdr.smb_buf_length += byte_count;
4113 pSMB->ByteCount = cpu_to_le16(byte_count);
4114
4115 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4116 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4117 if (rc) {
4118 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4119 } else { /* decode response */
4120 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4121
4122 if (rc || (pSMBr->ByteCount < 13)) {
4123 rc = -EIO; /* bad smb */
4124 } else {
4125 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4126 response_data =
4127 (FILE_SYSTEM_UNIX_INFO
4128 *) (((char *) &pSMBr->hdr.Protocol) +
4129 data_offset);
4130 memcpy(&tcon->fsUnixInfo, response_data,
4131 sizeof (FILE_SYSTEM_UNIX_INFO));
4132 }
4133 }
4134 cifs_buf_release(pSMB);
4135
4136 if (rc == -EAGAIN)
4137 goto QFSUnixRetry;
4138
4139
4140 return rc;
4141}
4142
Jeremy Allisonac670552005-06-22 17:26:35 -07004143int
Steve French45abc6e2005-06-23 13:42:03 -05004144CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004145{
4146/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4147 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4148 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4149 int rc = 0;
4150 int bytes_returned = 0;
4151 __u16 params, param_offset, offset, byte_count;
4152
4153 cFYI(1, ("In SETFSUnixInfo"));
4154SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004155 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004156 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4157 (void **) &pSMBr);
4158 if (rc)
4159 return rc;
4160
4161 params = 4; /* 2 bytes zero followed by info level. */
4162 pSMB->MaxSetupCount = 0;
4163 pSMB->Reserved = 0;
4164 pSMB->Flags = 0;
4165 pSMB->Timeout = 0;
4166 pSMB->Reserved2 = 0;
4167 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4168 offset = param_offset + params;
4169
4170 pSMB->MaxParameterCount = cpu_to_le16(4);
4171 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4172 pSMB->SetupCount = 1;
4173 pSMB->Reserved3 = 0;
4174 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4175 byte_count = 1 /* pad */ + params + 12;
4176
4177 pSMB->DataCount = cpu_to_le16(12);
4178 pSMB->ParameterCount = cpu_to_le16(params);
4179 pSMB->TotalDataCount = pSMB->DataCount;
4180 pSMB->TotalParameterCount = pSMB->ParameterCount;
4181 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4182 pSMB->DataOffset = cpu_to_le16(offset);
4183
4184 /* Params. */
4185 pSMB->FileNum = 0;
4186 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4187
4188 /* Data. */
4189 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4190 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4191 pSMB->ClientUnixCap = cpu_to_le64(cap);
4192
4193 pSMB->hdr.smb_buf_length += byte_count;
4194 pSMB->ByteCount = cpu_to_le16(byte_count);
4195
4196 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4197 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4198 if (rc) {
4199 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4200 } else { /* decode response */
4201 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4202 if (rc) {
4203 rc = -EIO; /* bad smb */
4204 }
4205 }
4206 cifs_buf_release(pSMB);
4207
4208 if (rc == -EAGAIN)
4209 goto SETFSUnixRetry;
4210
4211 return rc;
4212}
4213
4214
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215
4216int
4217CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004218 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219{
4220/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4221 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4222 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4223 FILE_SYSTEM_POSIX_INFO *response_data;
4224 int rc = 0;
4225 int bytes_returned = 0;
4226 __u16 params, byte_count;
4227
4228 cFYI(1, ("In QFSPosixInfo"));
4229QFSPosixRetry:
4230 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4231 (void **) &pSMBr);
4232 if (rc)
4233 return rc;
4234
4235 params = 2; /* level */
4236 pSMB->TotalDataCount = 0;
4237 pSMB->DataCount = 0;
4238 pSMB->DataOffset = 0;
4239 pSMB->MaxParameterCount = cpu_to_le16(2);
4240 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4241 pSMB->MaxSetupCount = 0;
4242 pSMB->Reserved = 0;
4243 pSMB->Flags = 0;
4244 pSMB->Timeout = 0;
4245 pSMB->Reserved2 = 0;
4246 byte_count = params + 1 /* pad */ ;
4247 pSMB->ParameterCount = cpu_to_le16(params);
4248 pSMB->TotalParameterCount = pSMB->ParameterCount;
4249 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4250 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4251 pSMB->SetupCount = 1;
4252 pSMB->Reserved3 = 0;
4253 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4254 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4255 pSMB->hdr.smb_buf_length += byte_count;
4256 pSMB->ByteCount = cpu_to_le16(byte_count);
4257
4258 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4259 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4260 if (rc) {
4261 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4262 } else { /* decode response */
4263 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4264
4265 if (rc || (pSMBr->ByteCount < 13)) {
4266 rc = -EIO; /* bad smb */
4267 } else {
4268 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4269 response_data =
4270 (FILE_SYSTEM_POSIX_INFO
4271 *) (((char *) &pSMBr->hdr.Protocol) +
4272 data_offset);
4273 FSData->f_bsize =
4274 le32_to_cpu(response_data->BlockSize);
4275 FSData->f_blocks =
4276 le64_to_cpu(response_data->TotalBlocks);
4277 FSData->f_bfree =
4278 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004279 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280 FSData->f_bavail = FSData->f_bfree;
4281 } else {
4282 FSData->f_bavail =
4283 le64_to_cpu(response_data->UserBlocksAvail);
4284 }
Steve French70ca7342005-09-22 16:32:06 -07004285 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286 FSData->f_files =
4287 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004288 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 FSData->f_ffree =
4290 le64_to_cpu(response_data->FreeFileNodes);
4291 }
4292 }
4293 cifs_buf_release(pSMB);
4294
4295 if (rc == -EAGAIN)
4296 goto QFSPosixRetry;
4297
4298 return rc;
4299}
4300
4301
4302/* We can not use write of zero bytes trick to
4303 set file size due to need for large file support. Also note that
4304 this SetPathInfo is preferred to SetFileInfo based method in next
4305 routine which is only needed to work around a sharing violation bug
4306 in Samba which this routine can run into */
4307
4308int
4309CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004310 __u64 size, int SetAllocation,
4311 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312{
4313 struct smb_com_transaction2_spi_req *pSMB = NULL;
4314 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4315 struct file_end_of_file_info *parm_data;
4316 int name_len;
4317 int rc = 0;
4318 int bytes_returned = 0;
4319 __u16 params, byte_count, data_count, param_offset, offset;
4320
4321 cFYI(1, ("In SetEOF"));
4322SetEOFRetry:
4323 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4324 (void **) &pSMBr);
4325 if (rc)
4326 return rc;
4327
4328 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4329 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004330 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004331 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 name_len++; /* trailing null */
4333 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004334 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 name_len = strnlen(fileName, PATH_MAX);
4336 name_len++; /* trailing null */
4337 strncpy(pSMB->FileName, fileName, name_len);
4338 }
4339 params = 6 + name_len;
4340 data_count = sizeof (struct file_end_of_file_info);
4341 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004342 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 pSMB->MaxSetupCount = 0;
4344 pSMB->Reserved = 0;
4345 pSMB->Flags = 0;
4346 pSMB->Timeout = 0;
4347 pSMB->Reserved2 = 0;
4348 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4349 InformationLevel) - 4;
4350 offset = param_offset + params;
4351 if(SetAllocation) {
4352 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4353 pSMB->InformationLevel =
4354 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4355 else
4356 pSMB->InformationLevel =
4357 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4358 } else /* Set File Size */ {
4359 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4360 pSMB->InformationLevel =
4361 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4362 else
4363 pSMB->InformationLevel =
4364 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4365 }
4366
4367 parm_data =
4368 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4369 offset);
4370 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4371 pSMB->DataOffset = cpu_to_le16(offset);
4372 pSMB->SetupCount = 1;
4373 pSMB->Reserved3 = 0;
4374 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4375 byte_count = 3 /* pad */ + params + data_count;
4376 pSMB->DataCount = cpu_to_le16(data_count);
4377 pSMB->TotalDataCount = pSMB->DataCount;
4378 pSMB->ParameterCount = cpu_to_le16(params);
4379 pSMB->TotalParameterCount = pSMB->ParameterCount;
4380 pSMB->Reserved4 = 0;
4381 pSMB->hdr.smb_buf_length += byte_count;
4382 parm_data->FileSize = cpu_to_le64(size);
4383 pSMB->ByteCount = cpu_to_le16(byte_count);
4384 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4385 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4386 if (rc) {
4387 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4388 }
4389
4390 cifs_buf_release(pSMB);
4391
4392 if (rc == -EAGAIN)
4393 goto SetEOFRetry;
4394
4395 return rc;
4396}
4397
4398int
4399CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4400 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4401{
4402 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4403 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4404 char *data_offset;
4405 struct file_end_of_file_info *parm_data;
4406 int rc = 0;
4407 int bytes_returned = 0;
4408 __u16 params, param_offset, offset, byte_count, count;
4409
4410 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4411 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004412 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4413
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 if (rc)
4415 return rc;
4416
Steve Frenchcd634992005-04-28 22:41:10 -07004417 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4418
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4420 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4421
4422 params = 6;
4423 pSMB->MaxSetupCount = 0;
4424 pSMB->Reserved = 0;
4425 pSMB->Flags = 0;
4426 pSMB->Timeout = 0;
4427 pSMB->Reserved2 = 0;
4428 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4429 offset = param_offset + params;
4430
4431 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4432
4433 count = sizeof(struct file_end_of_file_info);
4434 pSMB->MaxParameterCount = cpu_to_le16(2);
4435 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4436 pSMB->SetupCount = 1;
4437 pSMB->Reserved3 = 0;
4438 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4439 byte_count = 3 /* pad */ + params + count;
4440 pSMB->DataCount = cpu_to_le16(count);
4441 pSMB->ParameterCount = cpu_to_le16(params);
4442 pSMB->TotalDataCount = pSMB->DataCount;
4443 pSMB->TotalParameterCount = pSMB->ParameterCount;
4444 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4445 parm_data =
4446 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4447 offset);
4448 pSMB->DataOffset = cpu_to_le16(offset);
4449 parm_data->FileSize = cpu_to_le64(size);
4450 pSMB->Fid = fid;
4451 if(SetAllocation) {
4452 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4453 pSMB->InformationLevel =
4454 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4455 else
4456 pSMB->InformationLevel =
4457 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4458 } else /* Set File Size */ {
4459 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4460 pSMB->InformationLevel =
4461 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4462 else
4463 pSMB->InformationLevel =
4464 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4465 }
4466 pSMB->Reserved4 = 0;
4467 pSMB->hdr.smb_buf_length += byte_count;
4468 pSMB->ByteCount = cpu_to_le16(byte_count);
4469 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4470 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4471 if (rc) {
4472 cFYI(1,
4473 ("Send error in SetFileInfo (SetFileSize) = %d",
4474 rc));
4475 }
4476
4477 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004478 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479
4480 /* Note: On -EAGAIN error only caller can retry on handle based calls
4481 since file handle passed in no longer valid */
4482
4483 return rc;
4484}
4485
4486/* Some legacy servers such as NT4 require that the file times be set on
4487 an open handle, rather than by pathname - this is awkward due to
4488 potential access conflicts on the open, but it is unavoidable for these
4489 old servers since the only other choice is to go from 100 nanosecond DCE
4490 time and resort to the original setpathinfo level which takes the ancient
4491 DOS time format with 2 second granularity */
4492int
4493CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4494 __u16 fid)
4495{
4496 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4497 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4498 char *data_offset;
4499 int rc = 0;
4500 int bytes_returned = 0;
4501 __u16 params, param_offset, offset, byte_count, count;
4502
4503 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004504 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4505
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506 if (rc)
4507 return rc;
4508
Steve Frenchcd634992005-04-28 22:41:10 -07004509 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4510
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511 /* At this point there is no need to override the current pid
4512 with the pid of the opener, but that could change if we someday
4513 use an existing handle (rather than opening one on the fly) */
4514 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4515 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4516
4517 params = 6;
4518 pSMB->MaxSetupCount = 0;
4519 pSMB->Reserved = 0;
4520 pSMB->Flags = 0;
4521 pSMB->Timeout = 0;
4522 pSMB->Reserved2 = 0;
4523 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4524 offset = param_offset + params;
4525
4526 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4527
4528 count = sizeof (FILE_BASIC_INFO);
4529 pSMB->MaxParameterCount = cpu_to_le16(2);
4530 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4531 pSMB->SetupCount = 1;
4532 pSMB->Reserved3 = 0;
4533 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4534 byte_count = 3 /* pad */ + params + count;
4535 pSMB->DataCount = cpu_to_le16(count);
4536 pSMB->ParameterCount = cpu_to_le16(params);
4537 pSMB->TotalDataCount = pSMB->DataCount;
4538 pSMB->TotalParameterCount = pSMB->ParameterCount;
4539 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4540 pSMB->DataOffset = cpu_to_le16(offset);
4541 pSMB->Fid = fid;
4542 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4543 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4544 else
4545 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4546 pSMB->Reserved4 = 0;
4547 pSMB->hdr.smb_buf_length += byte_count;
4548 pSMB->ByteCount = cpu_to_le16(byte_count);
4549 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4550 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4551 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4552 if (rc) {
4553 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4554 }
4555
Steve Frenchcd634992005-04-28 22:41:10 -07004556 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557
4558 /* Note: On -EAGAIN error only caller can retry on handle based calls
4559 since file handle passed in no longer valid */
4560
4561 return rc;
4562}
4563
4564
4565int
4566CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4567 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004568 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569{
4570 TRANSACTION2_SPI_REQ *pSMB = NULL;
4571 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4572 int name_len;
4573 int rc = 0;
4574 int bytes_returned = 0;
4575 char *data_offset;
4576 __u16 params, param_offset, offset, byte_count, count;
4577
4578 cFYI(1, ("In SetTimes"));
4579
4580SetTimesRetry:
4581 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4582 (void **) &pSMBr);
4583 if (rc)
4584 return rc;
4585
4586 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4587 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004588 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004589 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 name_len++; /* trailing null */
4591 name_len *= 2;
4592 } else { /* BB improve the check for buffer overruns BB */
4593 name_len = strnlen(fileName, PATH_MAX);
4594 name_len++; /* trailing null */
4595 strncpy(pSMB->FileName, fileName, name_len);
4596 }
4597
4598 params = 6 + name_len;
4599 count = sizeof (FILE_BASIC_INFO);
4600 pSMB->MaxParameterCount = cpu_to_le16(2);
4601 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4602 pSMB->MaxSetupCount = 0;
4603 pSMB->Reserved = 0;
4604 pSMB->Flags = 0;
4605 pSMB->Timeout = 0;
4606 pSMB->Reserved2 = 0;
4607 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4608 InformationLevel) - 4;
4609 offset = param_offset + params;
4610 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4611 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4612 pSMB->DataOffset = cpu_to_le16(offset);
4613 pSMB->SetupCount = 1;
4614 pSMB->Reserved3 = 0;
4615 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4616 byte_count = 3 /* pad */ + params + count;
4617
4618 pSMB->DataCount = cpu_to_le16(count);
4619 pSMB->ParameterCount = cpu_to_le16(params);
4620 pSMB->TotalDataCount = pSMB->DataCount;
4621 pSMB->TotalParameterCount = pSMB->ParameterCount;
4622 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4623 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4624 else
4625 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4626 pSMB->Reserved4 = 0;
4627 pSMB->hdr.smb_buf_length += byte_count;
4628 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4629 pSMB->ByteCount = cpu_to_le16(byte_count);
4630 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4631 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4632 if (rc) {
4633 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4634 }
4635
4636 cifs_buf_release(pSMB);
4637
4638 if (rc == -EAGAIN)
4639 goto SetTimesRetry;
4640
4641 return rc;
4642}
4643
4644/* Can not be used to set time stamps yet (due to old DOS time format) */
4645/* Can be used to set attributes */
4646#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4647 handling it anyway and NT4 was what we thought it would be needed for
4648 Do not delete it until we prove whether needed for Win9x though */
4649int
4650CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4651 __u16 dos_attrs, const struct nls_table *nls_codepage)
4652{
4653 SETATTR_REQ *pSMB = NULL;
4654 SETATTR_RSP *pSMBr = NULL;
4655 int rc = 0;
4656 int bytes_returned;
4657 int name_len;
4658
4659 cFYI(1, ("In SetAttrLegacy"));
4660
4661SetAttrLgcyRetry:
4662 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4663 (void **) &pSMBr);
4664 if (rc)
4665 return rc;
4666
4667 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4668 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004669 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004670 PATH_MAX, nls_codepage);
4671 name_len++; /* trailing null */
4672 name_len *= 2;
4673 } else { /* BB improve the check for buffer overruns BB */
4674 name_len = strnlen(fileName, PATH_MAX);
4675 name_len++; /* trailing null */
4676 strncpy(pSMB->fileName, fileName, name_len);
4677 }
4678 pSMB->attr = cpu_to_le16(dos_attrs);
4679 pSMB->BufferFormat = 0x04;
4680 pSMB->hdr.smb_buf_length += name_len + 1;
4681 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4682 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4683 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4684 if (rc) {
4685 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4686 }
4687
4688 cifs_buf_release(pSMB);
4689
4690 if (rc == -EAGAIN)
4691 goto SetAttrLgcyRetry;
4692
4693 return rc;
4694}
4695#endif /* temporarily unneeded SetAttr legacy function */
4696
4697int
4698CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004699 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4700 dev_t device, const struct nls_table *nls_codepage,
4701 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702{
4703 TRANSACTION2_SPI_REQ *pSMB = NULL;
4704 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4705 int name_len;
4706 int rc = 0;
4707 int bytes_returned = 0;
4708 FILE_UNIX_BASIC_INFO *data_offset;
4709 __u16 params, param_offset, offset, count, byte_count;
4710
4711 cFYI(1, ("In SetUID/GID/Mode"));
4712setPermsRetry:
4713 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4714 (void **) &pSMBr);
4715 if (rc)
4716 return rc;
4717
4718 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4719 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004720 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004721 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722 name_len++; /* trailing null */
4723 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004724 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725 name_len = strnlen(fileName, PATH_MAX);
4726 name_len++; /* trailing null */
4727 strncpy(pSMB->FileName, fileName, name_len);
4728 }
4729
4730 params = 6 + name_len;
4731 count = sizeof (FILE_UNIX_BASIC_INFO);
4732 pSMB->MaxParameterCount = cpu_to_le16(2);
4733 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4734 pSMB->MaxSetupCount = 0;
4735 pSMB->Reserved = 0;
4736 pSMB->Flags = 0;
4737 pSMB->Timeout = 0;
4738 pSMB->Reserved2 = 0;
4739 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4740 InformationLevel) - 4;
4741 offset = param_offset + params;
4742 data_offset =
4743 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4744 offset);
4745 memset(data_offset, 0, count);
4746 pSMB->DataOffset = cpu_to_le16(offset);
4747 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4748 pSMB->SetupCount = 1;
4749 pSMB->Reserved3 = 0;
4750 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4751 byte_count = 3 /* pad */ + params + count;
4752 pSMB->ParameterCount = cpu_to_le16(params);
4753 pSMB->DataCount = cpu_to_le16(count);
4754 pSMB->TotalParameterCount = pSMB->ParameterCount;
4755 pSMB->TotalDataCount = pSMB->DataCount;
4756 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4757 pSMB->Reserved4 = 0;
4758 pSMB->hdr.smb_buf_length += byte_count;
4759 data_offset->Uid = cpu_to_le64(uid);
4760 data_offset->Gid = cpu_to_le64(gid);
4761 /* better to leave device as zero when it is */
4762 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4763 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4764 data_offset->Permissions = cpu_to_le64(mode);
4765
4766 if(S_ISREG(mode))
4767 data_offset->Type = cpu_to_le32(UNIX_FILE);
4768 else if(S_ISDIR(mode))
4769 data_offset->Type = cpu_to_le32(UNIX_DIR);
4770 else if(S_ISLNK(mode))
4771 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4772 else if(S_ISCHR(mode))
4773 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4774 else if(S_ISBLK(mode))
4775 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4776 else if(S_ISFIFO(mode))
4777 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4778 else if(S_ISSOCK(mode))
4779 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4780
4781
4782 pSMB->ByteCount = cpu_to_le16(byte_count);
4783 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4784 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4785 if (rc) {
4786 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4787 }
4788
4789 if (pSMB)
4790 cifs_buf_release(pSMB);
4791 if (rc == -EAGAIN)
4792 goto setPermsRetry;
4793 return rc;
4794}
4795
4796int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004797 const int notify_subdirs, const __u16 netfid,
4798 __u32 filter, struct file * pfile, int multishot,
4799 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800{
4801 int rc = 0;
4802 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004803 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004804 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 int bytes_returned;
4806
4807 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4808 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4809 (void **) &pSMBr);
4810 if (rc)
4811 return rc;
4812
4813 pSMB->TotalParameterCount = 0 ;
4814 pSMB->TotalDataCount = 0;
4815 pSMB->MaxParameterCount = cpu_to_le32(2);
4816 /* BB find exact data count max from sess structure BB */
4817 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004818/* BB VERIFY verify which is correct for above BB */
4819 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4820 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4821
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822 pSMB->MaxSetupCount = 4;
4823 pSMB->Reserved = 0;
4824 pSMB->ParameterOffset = 0;
4825 pSMB->DataCount = 0;
4826 pSMB->DataOffset = 0;
4827 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4828 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4829 pSMB->ParameterCount = pSMB->TotalParameterCount;
4830 if(notify_subdirs)
4831 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4832 pSMB->Reserved2 = 0;
4833 pSMB->CompletionFilter = cpu_to_le32(filter);
4834 pSMB->Fid = netfid; /* file handle always le */
4835 pSMB->ByteCount = 0;
4836
4837 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4838 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4839 if (rc) {
4840 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004841 } else {
4842 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004843 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004844 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004845 sizeof(struct dir_notify_req),
4846 GFP_KERNEL);
4847 if(dnotify_req) {
4848 dnotify_req->Pid = pSMB->hdr.Pid;
4849 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4850 dnotify_req->Mid = pSMB->hdr.Mid;
4851 dnotify_req->Tid = pSMB->hdr.Tid;
4852 dnotify_req->Uid = pSMB->hdr.Uid;
4853 dnotify_req->netfid = netfid;
4854 dnotify_req->pfile = pfile;
4855 dnotify_req->filter = filter;
4856 dnotify_req->multishot = multishot;
4857 spin_lock(&GlobalMid_Lock);
4858 list_add_tail(&dnotify_req->lhead,
4859 &GlobalDnotifyReqList);
4860 spin_unlock(&GlobalMid_Lock);
4861 } else
4862 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 }
4864 cifs_buf_release(pSMB);
4865 return rc;
4866}
4867#ifdef CONFIG_CIFS_XATTR
4868ssize_t
4869CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4870 const unsigned char *searchName,
4871 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004872 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873{
4874 /* BB assumes one setup word */
4875 TRANSACTION2_QPI_REQ *pSMB = NULL;
4876 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4877 int rc = 0;
4878 int bytes_returned;
4879 int name_len;
4880 struct fea * temp_fea;
4881 char * temp_ptr;
4882 __u16 params, byte_count;
4883
4884 cFYI(1, ("In Query All EAs path %s", searchName));
4885QAllEAsRetry:
4886 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4887 (void **) &pSMBr);
4888 if (rc)
4889 return rc;
4890
4891 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4892 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004893 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004894 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004895 name_len++; /* trailing null */
4896 name_len *= 2;
4897 } else { /* BB improve the check for buffer overruns BB */
4898 name_len = strnlen(searchName, PATH_MAX);
4899 name_len++; /* trailing null */
4900 strncpy(pSMB->FileName, searchName, name_len);
4901 }
4902
4903 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4904 pSMB->TotalDataCount = 0;
4905 pSMB->MaxParameterCount = cpu_to_le16(2);
4906 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4907 pSMB->MaxSetupCount = 0;
4908 pSMB->Reserved = 0;
4909 pSMB->Flags = 0;
4910 pSMB->Timeout = 0;
4911 pSMB->Reserved2 = 0;
4912 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4913 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4914 pSMB->DataCount = 0;
4915 pSMB->DataOffset = 0;
4916 pSMB->SetupCount = 1;
4917 pSMB->Reserved3 = 0;
4918 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4919 byte_count = params + 1 /* pad */ ;
4920 pSMB->TotalParameterCount = cpu_to_le16(params);
4921 pSMB->ParameterCount = pSMB->TotalParameterCount;
4922 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4923 pSMB->Reserved4 = 0;
4924 pSMB->hdr.smb_buf_length += byte_count;
4925 pSMB->ByteCount = cpu_to_le16(byte_count);
4926
4927 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4928 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4929 if (rc) {
4930 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4931 } else { /* decode response */
4932 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4933
4934 /* BB also check enough total bytes returned */
4935 /* BB we need to improve the validity checking
4936 of these trans2 responses */
4937 if (rc || (pSMBr->ByteCount < 4))
4938 rc = -EIO; /* bad smb */
4939 /* else if (pFindData){
4940 memcpy((char *) pFindData,
4941 (char *) &pSMBr->hdr.Protocol +
4942 data_offset, kl);
4943 }*/ else {
4944 /* check that length of list is not more than bcc */
4945 /* check that each entry does not go beyond length
4946 of list */
4947 /* check that each element of each entry does not
4948 go beyond end of list */
4949 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4950 struct fealist * ea_response_data;
4951 rc = 0;
4952 /* validate_trans2_offsets() */
4953 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4954 ea_response_data = (struct fealist *)
4955 (((char *) &pSMBr->hdr.Protocol) +
4956 data_offset);
4957 name_len = le32_to_cpu(ea_response_data->list_len);
4958 cFYI(1,("ea length %d", name_len));
4959 if(name_len <= 8) {
4960 /* returned EA size zeroed at top of function */
4961 cFYI(1,("empty EA list returned from server"));
4962 } else {
4963 /* account for ea list len */
4964 name_len -= 4;
4965 temp_fea = ea_response_data->list;
4966 temp_ptr = (char *)temp_fea;
4967 while(name_len > 0) {
4968 __u16 value_len;
4969 name_len -= 4;
4970 temp_ptr += 4;
4971 rc += temp_fea->name_len;
4972 /* account for prefix user. and trailing null */
4973 rc = rc + 5 + 1;
4974 if(rc<(int)buf_size) {
4975 memcpy(EAData,"user.",5);
4976 EAData+=5;
4977 memcpy(EAData,temp_ptr,temp_fea->name_len);
4978 EAData+=temp_fea->name_len;
4979 /* null terminate name */
4980 *EAData = 0;
4981 EAData = EAData + 1;
4982 } else if(buf_size == 0) {
4983 /* skip copy - calc size only */
4984 } else {
4985 /* stop before overrun buffer */
4986 rc = -ERANGE;
4987 break;
4988 }
4989 name_len -= temp_fea->name_len;
4990 temp_ptr += temp_fea->name_len;
4991 /* account for trailing null */
4992 name_len--;
4993 temp_ptr++;
4994 value_len = le16_to_cpu(temp_fea->value_len);
4995 name_len -= value_len;
4996 temp_ptr += value_len;
4997 /* BB check that temp_ptr is still within smb BB*/
4998 /* no trailing null to account for in value len */
4999 /* go on to next EA */
5000 temp_fea = (struct fea *)temp_ptr;
5001 }
5002 }
5003 }
5004 }
5005 if (pSMB)
5006 cifs_buf_release(pSMB);
5007 if (rc == -EAGAIN)
5008 goto QAllEAsRetry;
5009
5010 return (ssize_t)rc;
5011}
5012
5013ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
5014 const unsigned char * searchName,const unsigned char * ea_name,
5015 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005016 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017{
5018 TRANSACTION2_QPI_REQ *pSMB = NULL;
5019 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5020 int rc = 0;
5021 int bytes_returned;
5022 int name_len;
5023 struct fea * temp_fea;
5024 char * temp_ptr;
5025 __u16 params, byte_count;
5026
5027 cFYI(1, ("In Query EA path %s", searchName));
5028QEARetry:
5029 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5030 (void **) &pSMBr);
5031 if (rc)
5032 return rc;
5033
5034 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5035 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005036 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005037 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005038 name_len++; /* trailing null */
5039 name_len *= 2;
5040 } else { /* BB improve the check for buffer overruns BB */
5041 name_len = strnlen(searchName, PATH_MAX);
5042 name_len++; /* trailing null */
5043 strncpy(pSMB->FileName, searchName, name_len);
5044 }
5045
5046 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5047 pSMB->TotalDataCount = 0;
5048 pSMB->MaxParameterCount = cpu_to_le16(2);
5049 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5050 pSMB->MaxSetupCount = 0;
5051 pSMB->Reserved = 0;
5052 pSMB->Flags = 0;
5053 pSMB->Timeout = 0;
5054 pSMB->Reserved2 = 0;
5055 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5056 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5057 pSMB->DataCount = 0;
5058 pSMB->DataOffset = 0;
5059 pSMB->SetupCount = 1;
5060 pSMB->Reserved3 = 0;
5061 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5062 byte_count = params + 1 /* pad */ ;
5063 pSMB->TotalParameterCount = cpu_to_le16(params);
5064 pSMB->ParameterCount = pSMB->TotalParameterCount;
5065 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5066 pSMB->Reserved4 = 0;
5067 pSMB->hdr.smb_buf_length += byte_count;
5068 pSMB->ByteCount = cpu_to_le16(byte_count);
5069
5070 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5071 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5072 if (rc) {
5073 cFYI(1, ("Send error in Query EA = %d", rc));
5074 } else { /* decode response */
5075 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5076
5077 /* BB also check enough total bytes returned */
5078 /* BB we need to improve the validity checking
5079 of these trans2 responses */
5080 if (rc || (pSMBr->ByteCount < 4))
5081 rc = -EIO; /* bad smb */
5082 /* else if (pFindData){
5083 memcpy((char *) pFindData,
5084 (char *) &pSMBr->hdr.Protocol +
5085 data_offset, kl);
5086 }*/ else {
5087 /* check that length of list is not more than bcc */
5088 /* check that each entry does not go beyond length
5089 of list */
5090 /* check that each element of each entry does not
5091 go beyond end of list */
5092 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5093 struct fealist * ea_response_data;
5094 rc = -ENODATA;
5095 /* validate_trans2_offsets() */
5096 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5097 ea_response_data = (struct fealist *)
5098 (((char *) &pSMBr->hdr.Protocol) +
5099 data_offset);
5100 name_len = le32_to_cpu(ea_response_data->list_len);
5101 cFYI(1,("ea length %d", name_len));
5102 if(name_len <= 8) {
5103 /* returned EA size zeroed at top of function */
5104 cFYI(1,("empty EA list returned from server"));
5105 } else {
5106 /* account for ea list len */
5107 name_len -= 4;
5108 temp_fea = ea_response_data->list;
5109 temp_ptr = (char *)temp_fea;
5110 /* loop through checking if we have a matching
5111 name and then return the associated value */
5112 while(name_len > 0) {
5113 __u16 value_len;
5114 name_len -= 4;
5115 temp_ptr += 4;
5116 value_len = le16_to_cpu(temp_fea->value_len);
5117 /* BB validate that value_len falls within SMB,
5118 even though maximum for name_len is 255 */
5119 if(memcmp(temp_fea->name,ea_name,
5120 temp_fea->name_len) == 0) {
5121 /* found a match */
5122 rc = value_len;
5123 /* account for prefix user. and trailing null */
5124 if(rc<=(int)buf_size) {
5125 memcpy(ea_value,
5126 temp_fea->name+temp_fea->name_len+1,
5127 rc);
5128 /* ea values, unlike ea names,
5129 are not null terminated */
5130 } else if(buf_size == 0) {
5131 /* skip copy - calc size only */
5132 } else {
5133 /* stop before overrun buffer */
5134 rc = -ERANGE;
5135 }
5136 break;
5137 }
5138 name_len -= temp_fea->name_len;
5139 temp_ptr += temp_fea->name_len;
5140 /* account for trailing null */
5141 name_len--;
5142 temp_ptr++;
5143 name_len -= value_len;
5144 temp_ptr += value_len;
5145 /* no trailing null to account for in value len */
5146 /* go on to next EA */
5147 temp_fea = (struct fea *)temp_ptr;
5148 }
5149 }
5150 }
5151 }
5152 if (pSMB)
5153 cifs_buf_release(pSMB);
5154 if (rc == -EAGAIN)
5155 goto QEARetry;
5156
5157 return (ssize_t)rc;
5158}
5159
5160int
5161CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5162 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005163 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5164 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165{
5166 struct smb_com_transaction2_spi_req *pSMB = NULL;
5167 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5168 struct fealist *parm_data;
5169 int name_len;
5170 int rc = 0;
5171 int bytes_returned = 0;
5172 __u16 params, param_offset, byte_count, offset, count;
5173
5174 cFYI(1, ("In SetEA"));
5175SetEARetry:
5176 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5177 (void **) &pSMBr);
5178 if (rc)
5179 return rc;
5180
5181 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5182 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005183 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005184 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005185 name_len++; /* trailing null */
5186 name_len *= 2;
5187 } else { /* BB improve the check for buffer overruns BB */
5188 name_len = strnlen(fileName, PATH_MAX);
5189 name_len++; /* trailing null */
5190 strncpy(pSMB->FileName, fileName, name_len);
5191 }
5192
5193 params = 6 + name_len;
5194
5195 /* done calculating parms using name_len of file name,
5196 now use name_len to calculate length of ea name
5197 we are going to create in the inode xattrs */
5198 if(ea_name == NULL)
5199 name_len = 0;
5200 else
5201 name_len = strnlen(ea_name,255);
5202
5203 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5204 pSMB->MaxParameterCount = cpu_to_le16(2);
5205 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5206 pSMB->MaxSetupCount = 0;
5207 pSMB->Reserved = 0;
5208 pSMB->Flags = 0;
5209 pSMB->Timeout = 0;
5210 pSMB->Reserved2 = 0;
5211 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5212 InformationLevel) - 4;
5213 offset = param_offset + params;
5214 pSMB->InformationLevel =
5215 cpu_to_le16(SMB_SET_FILE_EA);
5216
5217 parm_data =
5218 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5219 offset);
5220 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5221 pSMB->DataOffset = cpu_to_le16(offset);
5222 pSMB->SetupCount = 1;
5223 pSMB->Reserved3 = 0;
5224 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5225 byte_count = 3 /* pad */ + params + count;
5226 pSMB->DataCount = cpu_to_le16(count);
5227 parm_data->list_len = cpu_to_le32(count);
5228 parm_data->list[0].EA_flags = 0;
5229 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005230 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 /* EA names are always ASCII */
5232 if(ea_name)
5233 strncpy(parm_data->list[0].name,ea_name,name_len);
5234 parm_data->list[0].name[name_len] = 0;
5235 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5236 /* caller ensures that ea_value_len is less than 64K but
5237 we need to ensure that it fits within the smb */
5238
5239 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5240 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5241 if(ea_value_len)
5242 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5243
5244 pSMB->TotalDataCount = pSMB->DataCount;
5245 pSMB->ParameterCount = cpu_to_le16(params);
5246 pSMB->TotalParameterCount = pSMB->ParameterCount;
5247 pSMB->Reserved4 = 0;
5248 pSMB->hdr.smb_buf_length += byte_count;
5249 pSMB->ByteCount = cpu_to_le16(byte_count);
5250 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5251 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5252 if (rc) {
5253 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5254 }
5255
5256 cifs_buf_release(pSMB);
5257
5258 if (rc == -EAGAIN)
5259 goto SetEARetry;
5260
5261 return rc;
5262}
5263
5264#endif