blob: 271a037a386ffc60017722b9f18f2cae3526c7ac [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"},
49#endif /* weak password hashing for legacy clients */
Linus Torvalds1da177e2005-04-16 15:20:36 -070050 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000051 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 {BAD_PROT, "\2"}
53};
54#else
55static struct {
56 int index;
57 char *name;
58} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000059#ifdef CONFIG_CIFS_WEAK_PW_HASH
60 {LANMAN_PROT, "\2LM1.2X002"},
61#endif /* weak password hashing for legacy clients */
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 {CIFS_PROT, "\2NT LM 0.12"},
63 {BAD_PROT, "\2"}
64};
65#endif
66
Steve French39798772006-05-31 22:40:51 +000067/* define the number of elements in the cifs dialect array */
68#ifdef CONFIG_CIFS_POSIX
69#ifdef CONFIG_CIFS_WEAK_PW_HASH
70#define CIFS_NUM_PROT 3
71#else
72#define CIFS_NUM_PROT 2
73#endif /* CIFS_WEAK_PW_HASH */
74#else /* not posix */
75#ifdef CONFIG_CIFS_WEAK_PW_HASH
76#define CIFS_NUM_PROT 2
77#else
78#define CIFS_NUM_PROT 1
79#endif /* CONFIG_CIFS_WEAK_PW_HASH */
80#endif /* CIFS_POSIX */
81
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
83/* Mark as invalid, all open files on tree connections since they
84 were closed when session to server was lost */
85static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
86{
87 struct cifsFileInfo *open_file = NULL;
88 struct list_head * tmp;
89 struct list_head * tmp1;
90
91/* list all files open on tree connection and mark them invalid */
92 write_lock(&GlobalSMBSeslock);
93 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
94 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
95 if(open_file) {
96 open_file->invalidHandle = TRUE;
97 }
98 }
99 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700100 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
101 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102}
103
104/* If the return code is zero, this function must fill in request_buf pointer */
105static int
106small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
107 void **request_buf /* returned */)
108{
109 int rc = 0;
110
111 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
112 check for tcp and smb session status done differently
113 for those three - in the calling routine */
114 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800115 if(tcon->tidStatus == CifsExiting) {
116 /* only tree disconnect, open, and write,
117 (and ulogoff which does not have tcon)
118 are allowed as we start force umount */
119 if((smb_command != SMB_COM_WRITE_ANDX) &&
120 (smb_command != SMB_COM_OPEN_ANDX) &&
121 (smb_command != SMB_COM_TREE_DISCONNECT)) {
122 cFYI(1,("can not send cmd %d while umounting",
123 smb_command));
124 return -ENODEV;
125 }
126 }
Steve French31ca3bc2005-04-28 22:41:11 -0700127 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
128 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 struct nls_table *nls_codepage;
130 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700131 reconnect, should be greater than cifs socket
132 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
134 wait_event_interruptible_timeout(tcon->ses->server->response_q,
135 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
136 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
137 /* on "soft" mounts we wait once */
138 if((tcon->retry == FALSE) ||
139 (tcon->ses->status == CifsExiting)) {
140 cFYI(1,("gave up waiting on reconnect in smb_init"));
141 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700142 } /* else "hard" mount - keep retrying
143 until process is killed or server
144 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 } else /* TCP session is reestablished now */
146 break;
147
148 }
149
150 nls_codepage = load_nls_default();
151 /* need to prevent multiple threads trying to
152 simultaneously reconnect the same SMB session */
153 down(&tcon->ses->sesSem);
154 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700155 rc = cifs_setup_session(0, tcon->ses,
156 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
158 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700159 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
160 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700162 /* BB FIXME add code to check if wsize needs
163 update due to negotiated smb buffer size
164 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 if(rc == 0)
166 atomic_inc(&tconInfoReconnectCount);
167
168 cFYI(1, ("reconnect tcon rc = %d", rc));
169 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700170 it is safer (and faster) to reopen files
171 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
173 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700174 know whether we can continue or not without
175 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 switch(smb_command) {
177 case SMB_COM_READ_ANDX:
178 case SMB_COM_WRITE_ANDX:
179 case SMB_COM_CLOSE:
180 case SMB_COM_FIND_CLOSE2:
181 case SMB_COM_LOCKING_ANDX: {
182 unload_nls(nls_codepage);
183 return -EAGAIN;
184 }
185 }
186 } else {
187 up(&tcon->ses->sesSem);
188 }
189 unload_nls(nls_codepage);
190
191 } else {
192 return -EIO;
193 }
194 }
195 if(rc)
196 return rc;
197
198 *request_buf = cifs_small_buf_get();
199 if (*request_buf == NULL) {
200 /* BB should we add a retry in here if not a writepage? */
201 return -ENOMEM;
202 }
203
204 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
205
Steve Frencha4544342005-08-24 13:59:35 -0700206 if(tcon != NULL)
207 cifs_stats_inc(&tcon->num_smbs_sent);
208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000210}
211
212#ifdef CONFIG_CIFS_EXPERIMENTAL
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}
Steve French5815449d2006-02-14 01:36:20 +0000238#endif /* CONFIG_CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
240/* If the return code is zero, this function must fill in request_buf pointer */
241static int
242smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
243 void **request_buf /* returned */ ,
244 void **response_buf /* returned */ )
245{
246 int rc = 0;
247
248 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
249 check for tcp and smb session status done differently
250 for those three - in the calling routine */
251 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800252 if(tcon->tidStatus == CifsExiting) {
253 /* only tree disconnect, open, and write,
254 (and ulogoff which does not have tcon)
255 are allowed as we start force umount */
256 if((smb_command != SMB_COM_WRITE_ANDX) &&
257 (smb_command != SMB_COM_OPEN_ANDX) &&
258 (smb_command != SMB_COM_TREE_DISCONNECT)) {
259 cFYI(1,("can not send cmd %d while umounting",
260 smb_command));
261 return -ENODEV;
262 }
263 }
264
Steve French31ca3bc2005-04-28 22:41:11 -0700265 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
266 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700268 /* Give Demultiplex thread up to 10 seconds to
269 reconnect, should be greater than cifs socket
270 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
272 wait_event_interruptible_timeout(tcon->ses->server->response_q,
273 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
Steve French09d1db52005-04-28 22:41:08 -0700274 if(tcon->ses->server->tcpStatus ==
275 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 /* on "soft" mounts we wait once */
277 if((tcon->retry == FALSE) ||
278 (tcon->ses->status == CifsExiting)) {
279 cFYI(1,("gave up waiting on reconnect in smb_init"));
280 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700281 } /* else "hard" mount - keep retrying
282 until process is killed or server
283 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 } else /* TCP session is reestablished now */
285 break;
286
287 }
288
289 nls_codepage = load_nls_default();
290 /* need to prevent multiple threads trying to
291 simultaneously reconnect the same SMB session */
292 down(&tcon->ses->sesSem);
293 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700294 rc = cifs_setup_session(0, tcon->ses,
295 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
297 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700298 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
299 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700301 /* BB FIXME add code to check if wsize needs
302 update due to negotiated smb buffer size
303 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 if(rc == 0)
305 atomic_inc(&tconInfoReconnectCount);
306
307 cFYI(1, ("reconnect tcon rc = %d", rc));
308 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700309 it is safer (and faster) to reopen files
310 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700313 know whether we can continue or not without
314 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 switch(smb_command) {
316 case SMB_COM_READ_ANDX:
317 case SMB_COM_WRITE_ANDX:
318 case SMB_COM_CLOSE:
319 case SMB_COM_FIND_CLOSE2:
320 case SMB_COM_LOCKING_ANDX: {
321 unload_nls(nls_codepage);
322 return -EAGAIN;
323 }
324 }
325 } else {
326 up(&tcon->ses->sesSem);
327 }
328 unload_nls(nls_codepage);
329
330 } else {
331 return -EIO;
332 }
333 }
334 if(rc)
335 return rc;
336
337 *request_buf = cifs_buf_get();
338 if (*request_buf == NULL) {
339 /* BB should we add a retry in here if not a writepage? */
340 return -ENOMEM;
341 }
342 /* Although the original thought was we needed the response buf for */
343 /* potential retries of smb operations it turns out we can determine */
344 /* from the mid flags when the request buffer can be resent without */
345 /* having to use a second distinct buffer for the response */
Steve French39798772006-05-31 22:40:51 +0000346 if(response_buf)
347 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
349 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
350 wct /*wct */ );
351
Steve Frencha4544342005-08-24 13:59:35 -0700352 if(tcon != NULL)
353 cifs_stats_inc(&tcon->num_smbs_sent);
354
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 return rc;
356}
357
358static int validate_t2(struct smb_t2_rsp * pSMB)
359{
360 int rc = -EINVAL;
361 int total_size;
362 char * pBCC;
363
364 /* check for plausible wct, bcc and t2 data and parm sizes */
365 /* check for parm and data offset going beyond end of smb */
366 if(pSMB->hdr.WordCount >= 10) {
367 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
368 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
369 /* check that bcc is at least as big as parms + data */
370 /* check that bcc is less than negotiated smb buffer */
371 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
372 if(total_size < 512) {
373 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
374 /* BCC le converted in SendReceive */
Steve French09d1db52005-04-28 22:41:08 -0700375 pBCC = (pSMB->hdr.WordCount * 2) +
376 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 (char *)pSMB;
378 if((total_size <= (*(u16 *)pBCC)) &&
379 (total_size <
380 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
381 return 0;
382 }
383
384 }
385 }
386 }
387 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
388 sizeof(struct smb_t2_rsp) + 16);
389 return rc;
390}
391int
392CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
393{
394 NEGOTIATE_REQ *pSMB;
395 NEGOTIATE_RSP *pSMBr;
396 int rc = 0;
397 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000398 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 struct TCP_Server_Info * server;
400 u16 count;
401
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 French1982c342005-08-17 12:38:22 -0700412 pSMB->hdr.Mid = GetNextMid(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
Steve French254e55e2006-06-04 05:53:15 +0000414 if((extended_security & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
415 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve French39798772006-05-31 22:40:51 +0000416
417 count = 0;
418 for(i=0;i<CIFS_NUM_PROT;i++) {
419 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
420 count += strlen(protocols[i].name) + 1;
421 /* null at end of source and target buffers anyway */
422 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 pSMB->hdr.smb_buf_length += count;
424 pSMB->ByteCount = cpu_to_le16(count);
425
426 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
427 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French254e55e2006-06-04 05:53:15 +0000428 if (rc != 0)
429 goto neg_err_exit;
430
431 cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
432 /* Check wct = 1 error case */
433 if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) {
434 /* core returns wct = 1, but we do not ask for core - otherwise
435 small wct just comes when dialect index is -1 indicating we
436 could not negotiate a common dialect */
437 rc = -EOPNOTSUPP;
438 goto neg_err_exit;
439#ifdef CONFIG_CIFS_WEAK_PW_HASH
440 } else if((pSMBr->hdr.WordCount == 13)
441 && (pSMBr->DialectIndex == LANMAN_PROT)) {
442 struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
443
444 if((extended_security & CIFSSEC_MAY_LANMAN) ||
445 (extended_security & CIFSSEC_MAY_PLNTXT))
446 server->secType = LANMAN;
447 else {
448 cERROR(1, ("mount failed weak security disabled"
449 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000450 rc = -EOPNOTSUPP;
451 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000452 }
453 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
454 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
455 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000456 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000457 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
458 /* even though we do not use raw we might as well set this
459 accurately, in case we ever find a need for it */
460 if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
461 server->maxRw = 0xFF00;
462 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
463 } else {
464 server->maxRw = 0;/* we do not need to use raw anyway */
465 server->capabilities = CAP_MPX_MODE;
466 }
467 server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
Steve French39798772006-05-31 22:40:51 +0000468
Steve French254e55e2006-06-04 05:53:15 +0000469 /* BB get server time for time conversions and add
470 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000471
Steve French254e55e2006-06-04 05:53:15 +0000472 if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
473 memcpy(server->cryptKey, rsp->EncryptionKey,
474 CIFS_CRYPTO_KEY_SIZE);
475 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
476 rc = -EIO; /* need cryptkey unless plain text */
477 goto neg_err_exit;
478 }
Steve French39798772006-05-31 22:40:51 +0000479
Steve French254e55e2006-06-04 05:53:15 +0000480 cFYI(1,("LANMAN negotiated"));
481 /* we will not end up setting signing flags - as no signing
482 was in LANMAN and server did not return the flags on */
483 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000484#else /* weak security disabled */
Steve French254e55e2006-06-04 05:53:15 +0000485 } else if(pSMBr->hdr.WordCount == 13) {
486 cERROR(1,("mount failed, cifs module not built "
487 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000488 rc = -EOPNOTSUPP;
489#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000490 goto neg_err_exit;
491 } else if(pSMBr->hdr.WordCount != 17) {
492 /* unknown wct */
493 rc = -EOPNOTSUPP;
494 goto neg_err_exit;
495 }
496 /* else wct == 17 NTLM */
497 server->secMode = pSMBr->SecurityMode;
498 if((server->secMode & SECMODE_USER) == 0)
499 cFYI(1,("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000500
Steve French254e55e2006-06-04 05:53:15 +0000501 if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000502#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000503 if ((extended_security & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000504#endif /* CIFS_WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000505 cERROR(1,("Server requests plain text password"
506 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000507
Steve French254e55e2006-06-04 05:53:15 +0000508 if(extended_security & CIFSSEC_MUST_NTLMV2)
509 server->secType = NTLMv2;
510 else
511 server->secType = NTLM;
512 /* else krb5 ... */
Steve French7c7b25b2006-06-01 19:20:10 +0000513
Steve French254e55e2006-06-04 05:53:15 +0000514 /* one byte, so no need to convert this or EncryptionKeyLen from
515 little endian */
516 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
517 /* probably no need to store and check maxvcs */
518 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000520 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
521 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
522 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
523 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
524 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
525 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
526 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
527 CIFS_CRYPTO_KEY_SIZE);
528 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
529 && (pSMBr->EncryptionKeyLength == 0)) {
530 /* decode security blob */
531 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
532 rc = -EIO; /* no crypt key only if plain text pwd */
533 goto neg_err_exit;
534 }
535
536 /* BB might be helpful to save off the domain of server here */
537
538 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
539 (server->capabilities & CAP_EXTENDED_SECURITY)) {
540 count = pSMBr->ByteCount;
541 if (count < 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 rc = -EIO;
Steve French254e55e2006-06-04 05:53:15 +0000543 else if (count == 16) {
544 server->secType = RawNTLMSSP;
545 if (server->socketUseCount.counter > 1) {
546 if (memcmp(server->server_GUID,
547 pSMBr->u.extended_response.
548 GUID, 16) != 0) {
549 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 memcpy(server->server_GUID,
Steve French254e55e2006-06-04 05:53:15 +0000551 pSMBr->u.extended_response.GUID,
552 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 }
Steve French254e55e2006-06-04 05:53:15 +0000554 } else
555 memcpy(server->server_GUID,
556 pSMBr->u.extended_response.GUID, 16);
557 } else {
558 rc = decode_negTokenInit(pSMBr->u.extended_response.
559 SecurityBlob,
560 count - 16,
561 &server->secType);
562 if(rc == 1) {
563 /* BB Need to fill struct for sessetup here */
564 rc = -EOPNOTSUPP;
565 } else {
566 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 }
Steve French254e55e2006-06-04 05:53:15 +0000569 } else
570 server->capabilities &= ~CAP_EXTENDED_SECURITY;
571
Steve French6344a422006-06-12 04:18:35 +0000572#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000573signing_check:
Steve French6344a422006-06-12 04:18:35 +0000574#endif
Steve French254e55e2006-06-04 05:53:15 +0000575 if(sign_CIFS_PDUs == FALSE) {
576 if(server->secMode & SECMODE_SIGN_REQUIRED)
577 cERROR(1,("Server requires "
578 "/proc/fs/cifs/PacketSigningEnabled to be on"));
579 server->secMode &=
580 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
581 } else if(sign_CIFS_PDUs == 1) {
582 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
583 server->secMode &=
584 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
585 } else if(sign_CIFS_PDUs == 2) {
586 if((server->secMode &
587 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
588 cERROR(1,("signing required but server lacks support"));
589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 }
Steve French39798772006-05-31 22:40:51 +0000591neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700592 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000593
594 cFYI(1,("negprot rc %d",rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 return rc;
596}
597
598int
599CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
600{
601 struct smb_hdr *smb_buffer;
602 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
603 int rc = 0;
604 int length;
605
606 cFYI(1, ("In tree disconnect"));
607 /*
608 * If last user of the connection and
609 * connection alive - disconnect it
610 * If this is the last connection on the server session disconnect it
611 * (and inside session disconnect we should check if tcp socket needs
612 * to be freed and kernel thread woken up).
613 */
614 if (tcon)
615 down(&tcon->tconSem);
616 else
617 return -EIO;
618
619 atomic_dec(&tcon->useCount);
620 if (atomic_read(&tcon->useCount) > 0) {
621 up(&tcon->tconSem);
622 return -EBUSY;
623 }
624
625 /* No need to return error on this operation if tid invalidated and
626 closed on server already e.g. due to tcp session crashing */
627 if(tcon->tidStatus == CifsNeedReconnect) {
628 up(&tcon->tconSem);
629 return 0;
630 }
631
632 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
633 up(&tcon->tconSem);
634 return -EIO;
635 }
Steve French09d1db52005-04-28 22:41:08 -0700636 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
637 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638 if (rc) {
639 up(&tcon->tconSem);
640 return rc;
641 } else {
642 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700643 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
645 &length, 0);
646 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700647 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648
649 if (smb_buffer)
650 cifs_small_buf_release(smb_buffer);
651 up(&tcon->tconSem);
652
653 /* No need to return error on this operation if tid invalidated and
654 closed on server already e.g. due to tcp session crashing */
655 if (rc == -EAGAIN)
656 rc = 0;
657
658 return rc;
659}
660
661int
662CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
663{
664 struct smb_hdr *smb_buffer_response;
665 LOGOFF_ANDX_REQ *pSMB;
666 int rc = 0;
667 int length;
668
669 cFYI(1, ("In SMBLogoff for session disconnect"));
670 if (ses)
671 down(&ses->sesSem);
672 else
673 return -EIO;
674
675 atomic_dec(&ses->inUse);
676 if (atomic_read(&ses->inUse) > 0) {
677 up(&ses->sesSem);
678 return -EBUSY;
679 }
680 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
681 if (rc) {
682 up(&ses->sesSem);
683 return rc;
684 }
685
686 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
687
688 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700689 pSMB->hdr.Mid = GetNextMid(ses->server);
690
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 if(ses->server->secMode &
692 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
693 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
694 }
695
696 pSMB->hdr.Uid = ses->Suid;
697
698 pSMB->AndXCommand = 0xFF;
699 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
700 smb_buffer_response, &length, 0);
701 if (ses->server) {
702 atomic_dec(&ses->server->socketUseCount);
703 if (atomic_read(&ses->server->socketUseCount) == 0) {
704 spin_lock(&GlobalMid_Lock);
705 ses->server->tcpStatus = CifsExiting;
706 spin_unlock(&GlobalMid_Lock);
707 rc = -ESHUTDOWN;
708 }
709 }
Steve Frencha59c6582005-08-17 12:12:19 -0700710 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700711 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712
713 /* if session dead then we do not need to do ulogoff,
714 since server closed smb session, no sense reporting
715 error */
716 if (rc == -EAGAIN)
717 rc = 0;
718 return rc;
719}
720
721int
Steve French737b7582005-04-28 22:41:06 -0700722CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
723 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724{
725 DELETE_FILE_REQ *pSMB = NULL;
726 DELETE_FILE_RSP *pSMBr = NULL;
727 int rc = 0;
728 int bytes_returned;
729 int name_len;
730
731DelFileRetry:
732 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
733 (void **) &pSMBr);
734 if (rc)
735 return rc;
736
737 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
738 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500739 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700740 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 name_len++; /* trailing null */
742 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700743 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 name_len = strnlen(fileName, PATH_MAX);
745 name_len++; /* trailing null */
746 strncpy(pSMB->fileName, fileName, name_len);
747 }
748 pSMB->SearchAttributes =
749 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
750 pSMB->BufferFormat = 0x04;
751 pSMB->hdr.smb_buf_length += name_len + 1;
752 pSMB->ByteCount = cpu_to_le16(name_len + 1);
753 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
754 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700755 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 if (rc) {
757 cFYI(1, ("Error in RMFile = %d", rc));
758 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
760 cifs_buf_release(pSMB);
761 if (rc == -EAGAIN)
762 goto DelFileRetry;
763
764 return rc;
765}
766
767int
Steve French737b7582005-04-28 22:41:06 -0700768CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
769 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770{
771 DELETE_DIRECTORY_REQ *pSMB = NULL;
772 DELETE_DIRECTORY_RSP *pSMBr = NULL;
773 int rc = 0;
774 int bytes_returned;
775 int name_len;
776
777 cFYI(1, ("In CIFSSMBRmDir"));
778RmDirRetry:
779 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
780 (void **) &pSMBr);
781 if (rc)
782 return rc;
783
784 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700785 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
786 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 name_len++; /* trailing null */
788 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700789 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 name_len = strnlen(dirName, PATH_MAX);
791 name_len++; /* trailing null */
792 strncpy(pSMB->DirName, dirName, name_len);
793 }
794
795 pSMB->BufferFormat = 0x04;
796 pSMB->hdr.smb_buf_length += name_len + 1;
797 pSMB->ByteCount = cpu_to_le16(name_len + 1);
798 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
799 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700800 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 if (rc) {
802 cFYI(1, ("Error in RMDir = %d", rc));
803 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804
805 cifs_buf_release(pSMB);
806 if (rc == -EAGAIN)
807 goto RmDirRetry;
808 return rc;
809}
810
811int
812CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700813 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814{
815 int rc = 0;
816 CREATE_DIRECTORY_REQ *pSMB = NULL;
817 CREATE_DIRECTORY_RSP *pSMBr = NULL;
818 int bytes_returned;
819 int name_len;
820
821 cFYI(1, ("In CIFSSMBMkDir"));
822MkDirRetry:
823 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
824 (void **) &pSMBr);
825 if (rc)
826 return rc;
827
828 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500829 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700830 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 name_len++; /* trailing null */
832 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700833 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 name_len = strnlen(name, PATH_MAX);
835 name_len++; /* trailing null */
836 strncpy(pSMB->DirName, name, name_len);
837 }
838
839 pSMB->BufferFormat = 0x04;
840 pSMB->hdr.smb_buf_length += name_len + 1;
841 pSMB->ByteCount = cpu_to_le16(name_len + 1);
842 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
843 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700844 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 if (rc) {
846 cFYI(1, ("Error in Mkdir = %d", rc));
847 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700848
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 cifs_buf_release(pSMB);
850 if (rc == -EAGAIN)
851 goto MkDirRetry;
852 return rc;
853}
854
Steve Frencha9d02ad2005-08-24 23:06:05 -0700855static __u16 convert_disposition(int disposition)
856{
857 __u16 ofun = 0;
858
859 switch (disposition) {
860 case FILE_SUPERSEDE:
861 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
862 break;
863 case FILE_OPEN:
864 ofun = SMBOPEN_OAPPEND;
865 break;
866 case FILE_CREATE:
867 ofun = SMBOPEN_OCREATE;
868 break;
869 case FILE_OPEN_IF:
870 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
871 break;
872 case FILE_OVERWRITE:
873 ofun = SMBOPEN_OTRUNC;
874 break;
875 case FILE_OVERWRITE_IF:
876 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
877 break;
878 default:
879 cFYI(1,("unknown disposition %d",disposition));
880 ofun = SMBOPEN_OAPPEND; /* regular open */
881 }
882 return ofun;
883}
884
885int
886SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
887 const char *fileName, const int openDisposition,
888 const int access_flags, const int create_options, __u16 * netfid,
889 int *pOplock, FILE_ALL_INFO * pfile_info,
890 const struct nls_table *nls_codepage, int remap)
891{
892 int rc = -EACCES;
893 OPENX_REQ *pSMB = NULL;
894 OPENX_RSP *pSMBr = NULL;
895 int bytes_returned;
896 int name_len;
897 __u16 count;
898
899OldOpenRetry:
900 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
901 (void **) &pSMBr);
902 if (rc)
903 return rc;
904
905 pSMB->AndXCommand = 0xFF; /* none */
906
907 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
908 count = 1; /* account for one byte pad to word boundary */
909 name_len =
910 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
911 fileName, PATH_MAX, nls_codepage, remap);
912 name_len++; /* trailing null */
913 name_len *= 2;
914 } else { /* BB improve check for buffer overruns BB */
915 count = 0; /* no pad */
916 name_len = strnlen(fileName, PATH_MAX);
917 name_len++; /* trailing null */
918 strncpy(pSMB->fileName, fileName, name_len);
919 }
920 if (*pOplock & REQ_OPLOCK)
921 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
922 else if (*pOplock & REQ_BATCHOPLOCK) {
923 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
924 }
925 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
926 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
927 /* 0 = read
928 1 = write
929 2 = rw
930 3 = execute
931 */
932 pSMB->Mode = cpu_to_le16(2);
933 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
934 /* set file as system file if special file such
935 as fifo and server expecting SFU style and
936 no Unix extensions */
937
938 if(create_options & CREATE_OPTION_SPECIAL)
939 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
940 else
Steve French3e87d802005-09-18 20:49:21 -0700941 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700942
943 /* if ((omode & S_IWUGO) == 0)
944 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
945 /* Above line causes problems due to vfs splitting create into two
946 pieces - need to set mode after file created not while it is
947 being created */
948
949 /* BB FIXME BB */
950/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
951 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700952
953 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700954 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700955 count += name_len;
956 pSMB->hdr.smb_buf_length += count;
957
958 pSMB->ByteCount = cpu_to_le16(count);
959 /* long_op set to 1 to allow for oplock break timeouts */
960 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
961 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
962 cifs_stats_inc(&tcon->num_opens);
963 if (rc) {
964 cFYI(1, ("Error in Open = %d", rc));
965 } else {
966 /* BB verify if wct == 15 */
967
968/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
969
970 *netfid = pSMBr->Fid; /* cifs fid stays in le */
971 /* Let caller know file was created so we can set the mode. */
972 /* Do we care about the CreateAction in any other cases? */
973 /* BB FIXME BB */
974/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
975 *pOplock |= CIFS_CREATE_ACTION; */
976 /* BB FIXME END */
977
978 if(pfile_info) {
979 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
980 pfile_info->LastAccessTime = 0; /* BB fixme */
981 pfile_info->LastWriteTime = 0; /* BB fixme */
982 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -0700983 pfile_info->Attributes =
984 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700985 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -0700986 pfile_info->AllocationSize =
987 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
988 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -0700989 pfile_info->NumberOfLinks = cpu_to_le32(1);
990 }
991 }
992
993 cifs_buf_release(pSMB);
994 if (rc == -EAGAIN)
995 goto OldOpenRetry;
996 return rc;
997}
998
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999int
1000CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1001 const char *fileName, const int openDisposition,
1002 const int access_flags, const int create_options, __u16 * netfid,
1003 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001004 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005{
1006 int rc = -EACCES;
1007 OPEN_REQ *pSMB = NULL;
1008 OPEN_RSP *pSMBr = NULL;
1009 int bytes_returned;
1010 int name_len;
1011 __u16 count;
1012
1013openRetry:
1014 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1015 (void **) &pSMBr);
1016 if (rc)
1017 return rc;
1018
1019 pSMB->AndXCommand = 0xFF; /* none */
1020
1021 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1022 count = 1; /* account for one byte pad to word boundary */
1023 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001024 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001025 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 name_len++; /* trailing null */
1027 name_len *= 2;
1028 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001029 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 count = 0; /* no pad */
1031 name_len = strnlen(fileName, PATH_MAX);
1032 name_len++; /* trailing null */
1033 pSMB->NameLength = cpu_to_le16(name_len);
1034 strncpy(pSMB->fileName, fileName, name_len);
1035 }
1036 if (*pOplock & REQ_OPLOCK)
1037 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1038 else if (*pOplock & REQ_BATCHOPLOCK) {
1039 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1040 }
1041 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1042 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001043 /* set file as system file if special file such
1044 as fifo and server expecting SFU style and
1045 no Unix extensions */
1046 if(create_options & CREATE_OPTION_SPECIAL)
1047 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1048 else
1049 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 /* XP does not handle ATTR_POSIX_SEMANTICS */
1051 /* but it helps speed up case sensitive checks for other
1052 servers such as Samba */
1053 if (tcon->ses->capabilities & CAP_UNIX)
1054 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1055
1056 /* if ((omode & S_IWUGO) == 0)
1057 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1058 /* Above line causes problems due to vfs splitting create into two
1059 pieces - need to set mode after file created not while it is
1060 being created */
1061 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1062 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001063 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001064 /* BB Expirement with various impersonation levels and verify */
1065 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 pSMB->SecurityFlags =
1067 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1068
1069 count += name_len;
1070 pSMB->hdr.smb_buf_length += count;
1071
1072 pSMB->ByteCount = cpu_to_le16(count);
1073 /* long_op set to 1 to allow for oplock break timeouts */
1074 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1075 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001076 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 if (rc) {
1078 cFYI(1, ("Error in Open = %d", rc));
1079 } else {
Steve French09d1db52005-04-28 22:41:08 -07001080 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1082 /* Let caller know file was created so we can set the mode. */
1083 /* Do we care about the CreateAction in any other cases? */
1084 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1085 *pOplock |= CIFS_CREATE_ACTION;
1086 if(pfile_info) {
1087 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1088 36 /* CreationTime to Attributes */);
1089 /* the file_info buf is endian converted by caller */
1090 pfile_info->AllocationSize = pSMBr->AllocationSize;
1091 pfile_info->EndOfFile = pSMBr->EndOfFile;
1092 pfile_info->NumberOfLinks = cpu_to_le32(1);
1093 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001095
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 cifs_buf_release(pSMB);
1097 if (rc == -EAGAIN)
1098 goto openRetry;
1099 return rc;
1100}
1101
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102int
1103CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001104 const int netfid, const unsigned int count,
1105 const __u64 lseek, unsigned int *nbytes, char **buf,
1106 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107{
1108 int rc = -EACCES;
1109 READ_REQ *pSMB = NULL;
1110 READ_RSP *pSMBr = NULL;
1111 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001112 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001113 int resp_buf_type = 0;
1114 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115
1116 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001117 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1118 wct = 12;
1119 else
1120 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121
1122 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001123 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 if (rc)
1125 return rc;
1126
1127 /* tcon and ses pointer are checked in smb_init */
1128 if (tcon->ses->server == NULL)
1129 return -ECONNABORTED;
1130
Steve Frenchec637e32005-12-12 20:53:18 -08001131 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 pSMB->Fid = netfid;
1133 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001134 if(wct == 12)
1135 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001136 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1137 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001138
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 pSMB->Remaining = 0;
1140 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1141 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001142 if(wct == 12)
1143 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1144 else {
1145 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001146 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001147 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001148 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001149 }
Steve Frenchec637e32005-12-12 20:53:18 -08001150
1151 iov[0].iov_base = (char *)pSMB;
1152 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1153 rc = SendReceive2(xid, tcon->ses, iov,
1154 1 /* num iovecs */,
1155 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001156 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001157 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 if (rc) {
1159 cERROR(1, ("Send error in read = %d", rc));
1160 } else {
1161 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1162 data_length = data_length << 16;
1163 data_length += le16_to_cpu(pSMBr->DataLength);
1164 *nbytes = data_length;
1165
1166 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001167 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 || (data_length > count)) {
1169 cFYI(1,("bad length %d for count %d",data_length,count));
1170 rc = -EIO;
1171 *nbytes = 0;
1172 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001173 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001175/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1176 cERROR(1,("Faulting on read rc = %d",rc));
1177 rc = -EFAULT;
1178 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001180 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181 }
1182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183
Steve French4b8f9302006-02-26 16:41:18 +00001184/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001185 if(*buf) {
1186 if(resp_buf_type == CIFS_SMALL_BUFFER)
1187 cifs_small_buf_release(iov[0].iov_base);
1188 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1189 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001190 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1191 /* return buffer to caller to free */
1192 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001193 if(resp_buf_type == CIFS_SMALL_BUFFER)
1194 *pbuf_type = CIFS_SMALL_BUFFER;
1195 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1196 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001197 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001198
1199 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 since file handle passed in no longer valid */
1201 return rc;
1202}
1203
Steve Frenchec637e32005-12-12 20:53:18 -08001204
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205int
1206CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1207 const int netfid, const unsigned int count,
1208 const __u64 offset, unsigned int *nbytes, const char *buf,
1209 const char __user * ubuf, const int long_op)
1210{
1211 int rc = -EACCES;
1212 WRITE_REQ *pSMB = NULL;
1213 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001214 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 __u32 bytes_sent;
1216 __u16 byte_count;
1217
1218 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001219 if(tcon->ses == NULL)
1220 return -ECONNABORTED;
1221
1222 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1223 wct = 14;
1224 else
1225 wct = 12;
1226
1227 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 (void **) &pSMBr);
1229 if (rc)
1230 return rc;
1231 /* tcon and ses pointer are checked in smb_init */
1232 if (tcon->ses->server == NULL)
1233 return -ECONNABORTED;
1234
1235 pSMB->AndXCommand = 0xFF; /* none */
1236 pSMB->Fid = netfid;
1237 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001238 if(wct == 14)
1239 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1240 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1241 return -EIO;
1242
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 pSMB->Reserved = 0xFFFFFFFF;
1244 pSMB->WriteMode = 0;
1245 pSMB->Remaining = 0;
1246
1247 /* Can increase buffer size if buffer is big enough in some cases - ie we
1248 can send more if LARGE_WRITE_X capability returned by the server and if
1249 our buffer is big enough or if we convert to iovecs on socket writes
1250 and eliminate the copy to the CIFS buffer */
1251 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1252 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1253 } else {
1254 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1255 & ~0xFF;
1256 }
1257
1258 if (bytes_sent > count)
1259 bytes_sent = count;
1260 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001261 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 if(buf)
1263 memcpy(pSMB->Data,buf,bytes_sent);
1264 else if(ubuf) {
1265 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1266 cifs_buf_release(pSMB);
1267 return -EFAULT;
1268 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001269 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 /* No buffer */
1271 cifs_buf_release(pSMB);
1272 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001273 } /* else setting file size with write of zero bytes */
1274 if(wct == 14)
1275 byte_count = bytes_sent + 1; /* pad */
1276 else /* wct == 12 */ {
1277 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1280 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001281 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001282
1283 if(wct == 14)
1284 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001285 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001286 struct smb_com_writex_req * pSMBW =
1287 (struct smb_com_writex_req *)pSMB;
1288 pSMBW->ByteCount = cpu_to_le16(byte_count);
1289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
1291 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1292 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001293 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 if (rc) {
1295 cFYI(1, ("Send error in write = %d", rc));
1296 *nbytes = 0;
1297 } else {
1298 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1299 *nbytes = (*nbytes) << 16;
1300 *nbytes += le16_to_cpu(pSMBr->Count);
1301 }
1302
1303 cifs_buf_release(pSMB);
1304
1305 /* Note: On -EAGAIN error only caller can retry on handle based calls
1306 since file handle passed in no longer valid */
1307
1308 return rc;
1309}
1310
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001311int
1312CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001314 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1315 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316{
1317 int rc = -EACCES;
1318 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001319 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001320 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001321 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322
Steve Frenchff7feac2005-11-15 16:45:16 -08001323 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1324
Steve French8cc64c62005-10-03 13:49:43 -07001325 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1326 wct = 14;
1327 else
1328 wct = 12;
1329 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 if (rc)
1331 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 /* tcon and ses pointer are checked in smb_init */
1333 if (tcon->ses->server == NULL)
1334 return -ECONNABORTED;
1335
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001336 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 pSMB->Fid = netfid;
1338 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001339 if(wct == 14)
1340 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1341 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1342 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 pSMB->Reserved = 0xFFFFFFFF;
1344 pSMB->WriteMode = 0;
1345 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001346
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 pSMB->DataOffset =
1348 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1349
Steve French3e844692005-10-03 13:37:24 -07001350 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1351 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001352 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001353 if(wct == 14)
1354 pSMB->hdr.smb_buf_length += count+1;
1355 else /* wct == 12 */
1356 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1357 if(wct == 14)
1358 pSMB->ByteCount = cpu_to_le16(count + 1);
1359 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1360 struct smb_com_writex_req * pSMBW =
1361 (struct smb_com_writex_req *)pSMB;
1362 pSMBW->ByteCount = cpu_to_le16(count + 5);
1363 }
Steve French3e844692005-10-03 13:37:24 -07001364 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001365 if(wct == 14)
1366 iov[0].iov_len = smb_hdr_len + 4;
1367 else /* wct == 12 pad bigger by four bytes */
1368 iov[0].iov_len = smb_hdr_len + 8;
1369
Steve French3e844692005-10-03 13:37:24 -07001370
Steve Frenchec637e32005-12-12 20:53:18 -08001371 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001372 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001373 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001375 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001377 } else if(resp_buf_type == 0) {
1378 /* presumably this can not happen, but best to be safe */
1379 rc = -EIO;
1380 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001381 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001382 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001383 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1384 *nbytes = (*nbytes) << 16;
1385 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001386 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
Steve French4b8f9302006-02-26 16:41:18 +00001388/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001389 if(resp_buf_type == CIFS_SMALL_BUFFER)
1390 cifs_small_buf_release(iov[0].iov_base);
1391 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1392 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
1394 /* Note: On -EAGAIN error only caller can retry on handle based calls
1395 since file handle passed in no longer valid */
1396
1397 return rc;
1398}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001399
1400
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401int
1402CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1403 const __u16 smb_file_id, const __u64 len,
1404 const __u64 offset, const __u32 numUnlock,
1405 const __u32 numLock, const __u8 lockType, const int waitFlag)
1406{
1407 int rc = 0;
1408 LOCK_REQ *pSMB = NULL;
1409 LOCK_RSP *pSMBr = NULL;
1410 int bytes_returned;
1411 int timeout = 0;
1412 __u16 count;
1413
1414 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001415 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1416
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 if (rc)
1418 return rc;
1419
Steve French46810cb2005-04-28 22:41:09 -07001420 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1421
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1423 timeout = -1; /* no response expected */
1424 pSMB->Timeout = 0;
1425 } else if (waitFlag == TRUE) {
1426 timeout = 3; /* blocking operation, no timeout */
1427 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1428 } else {
1429 pSMB->Timeout = 0;
1430 }
1431
1432 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1433 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1434 pSMB->LockType = lockType;
1435 pSMB->AndXCommand = 0xFF; /* none */
1436 pSMB->Fid = smb_file_id; /* netfid stays le */
1437
1438 if((numLock != 0) || (numUnlock != 0)) {
1439 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1440 /* BB where to store pid high? */
1441 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1442 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1443 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1444 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1445 count = sizeof(LOCKING_ANDX_RANGE);
1446 } else {
1447 /* oplock break */
1448 count = 0;
1449 }
1450 pSMB->hdr.smb_buf_length += count;
1451 pSMB->ByteCount = cpu_to_le16(count);
1452
1453 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1454 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha4544342005-08-24 13:59:35 -07001455 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 if (rc) {
1457 cFYI(1, ("Send error in Lock = %d", rc));
1458 }
Steve French46810cb2005-04-28 22:41:09 -07001459 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460
1461 /* Note: On -EAGAIN error only caller can retry on handle based calls
1462 since file handle passed in no longer valid */
1463 return rc;
1464}
1465
1466int
Steve French08547b02006-02-28 22:39:25 +00001467CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1468 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001469 struct file_lock *pLockData, const __u16 lock_type,
1470 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001471{
1472 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1473 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1474 char *data_offset;
1475 struct cifs_posix_lock *parm_data;
1476 int rc = 0;
1477 int bytes_returned = 0;
1478 __u16 params, param_offset, offset, byte_count, count;
1479
1480 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001481
1482 if(pLockData == NULL)
1483 return EINVAL;
1484
Steve French08547b02006-02-28 22:39:25 +00001485 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1486
1487 if (rc)
1488 return rc;
1489
1490 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1491
1492 params = 6;
1493 pSMB->MaxSetupCount = 0;
1494 pSMB->Reserved = 0;
1495 pSMB->Flags = 0;
1496 pSMB->Timeout = 0;
1497 pSMB->Reserved2 = 0;
1498 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1499 offset = param_offset + params;
1500
1501 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1502
1503 count = sizeof(struct cifs_posix_lock);
1504 pSMB->MaxParameterCount = cpu_to_le16(2);
1505 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1506 pSMB->SetupCount = 1;
1507 pSMB->Reserved3 = 0;
1508 if(get_flag)
1509 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1510 else
1511 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1512 byte_count = 3 /* pad */ + params + count;
1513 pSMB->DataCount = cpu_to_le16(count);
1514 pSMB->ParameterCount = cpu_to_le16(params);
1515 pSMB->TotalDataCount = pSMB->DataCount;
1516 pSMB->TotalParameterCount = pSMB->ParameterCount;
1517 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1518 parm_data = (struct cifs_posix_lock *)
1519 (((char *) &pSMB->hdr.Protocol) + offset);
1520
1521 parm_data->lock_type = cpu_to_le16(lock_type);
1522 if(waitFlag)
Steve Frenchcec6815a2006-05-30 18:07:17 +00001523 parm_data->lock_flags = cpu_to_le16(1);
Steve French08547b02006-02-28 22:39:25 +00001524 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001525 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001526 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001527
1528 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001529 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001530 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1531 pSMB->Reserved4 = 0;
1532 pSMB->hdr.smb_buf_length += byte_count;
1533 pSMB->ByteCount = cpu_to_le16(byte_count);
1534 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1535 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1536 if (rc) {
1537 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001538 } else if (get_flag) {
1539 /* lock structure can be returned on get */
1540 __u16 data_offset;
1541 __u16 data_count;
1542 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001543
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001544 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1545 rc = -EIO; /* bad smb */
1546 goto plk_err_exit;
1547 }
1548 if(pLockData == NULL) {
1549 rc = -EINVAL;
1550 goto plk_err_exit;
1551 }
1552 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1553 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1554 if(data_count < sizeof(struct cifs_posix_lock)) {
1555 rc = -EIO;
1556 goto plk_err_exit;
1557 }
1558 parm_data = (struct cifs_posix_lock *)
1559 ((char *)&pSMBr->hdr.Protocol + data_offset);
1560 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1561 pLockData->fl_type = F_UNLCK;
1562 }
1563
1564plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001565 if (pSMB)
1566 cifs_small_buf_release(pSMB);
1567
1568 /* Note: On -EAGAIN error only caller can retry on handle based calls
1569 since file handle passed in no longer valid */
1570
1571 return rc;
1572}
1573
1574
1575int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001576CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1577{
1578 int rc = 0;
1579 CLOSE_REQ *pSMB = NULL;
1580 CLOSE_RSP *pSMBr = NULL;
1581 int bytes_returned;
1582 cFYI(1, ("In CIFSSMBClose"));
1583
1584/* do not retry on dead session on close */
1585 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1586 if(rc == -EAGAIN)
1587 return 0;
1588 if (rc)
1589 return rc;
1590
1591 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1592
1593 pSMB->FileID = (__u16) smb_file_id;
1594 pSMB->LastWriteTime = 0;
1595 pSMB->ByteCount = 0;
1596 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1597 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001598 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001599 if (rc) {
1600 if(rc!=-EINTR) {
1601 /* EINTR is expected when user ctl-c to kill app */
1602 cERROR(1, ("Send error in Close = %d", rc));
1603 }
1604 }
1605
1606 cifs_small_buf_release(pSMB);
1607
1608 /* Since session is dead, file will be closed on server already */
1609 if(rc == -EAGAIN)
1610 rc = 0;
1611
1612 return rc;
1613}
1614
1615int
1616CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1617 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001618 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619{
1620 int rc = 0;
1621 RENAME_REQ *pSMB = NULL;
1622 RENAME_RSP *pSMBr = NULL;
1623 int bytes_returned;
1624 int name_len, name_len2;
1625 __u16 count;
1626
1627 cFYI(1, ("In CIFSSMBRename"));
1628renameRetry:
1629 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1630 (void **) &pSMBr);
1631 if (rc)
1632 return rc;
1633
1634 pSMB->BufferFormat = 0x04;
1635 pSMB->SearchAttributes =
1636 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1637 ATTR_DIRECTORY);
1638
1639 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1640 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001641 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001642 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 name_len++; /* trailing null */
1644 name_len *= 2;
1645 pSMB->OldFileName[name_len] = 0x04; /* pad */
1646 /* protocol requires ASCII signature byte on Unicode string */
1647 pSMB->OldFileName[name_len + 1] = 0x00;
1648 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001649 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001650 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1652 name_len2 *= 2; /* convert to bytes */
1653 } else { /* BB improve the check for buffer overruns BB */
1654 name_len = strnlen(fromName, PATH_MAX);
1655 name_len++; /* trailing null */
1656 strncpy(pSMB->OldFileName, fromName, name_len);
1657 name_len2 = strnlen(toName, PATH_MAX);
1658 name_len2++; /* trailing null */
1659 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1660 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1661 name_len2++; /* trailing null */
1662 name_len2++; /* signature byte */
1663 }
1664
1665 count = 1 /* 1st signature byte */ + name_len + name_len2;
1666 pSMB->hdr.smb_buf_length += count;
1667 pSMB->ByteCount = cpu_to_le16(count);
1668
1669 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1670 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001671 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 if (rc) {
1673 cFYI(1, ("Send error in rename = %d", rc));
1674 }
1675
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676 cifs_buf_release(pSMB);
1677
1678 if (rc == -EAGAIN)
1679 goto renameRetry;
1680
1681 return rc;
1682}
1683
1684int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001685 int netfid, char * target_name,
1686 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687{
1688 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1689 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1690 struct set_file_rename * rename_info;
1691 char *data_offset;
1692 char dummy_string[30];
1693 int rc = 0;
1694 int bytes_returned = 0;
1695 int len_of_str;
1696 __u16 params, param_offset, offset, count, byte_count;
1697
1698 cFYI(1, ("Rename to File by handle"));
1699 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1700 (void **) &pSMBr);
1701 if (rc)
1702 return rc;
1703
1704 params = 6;
1705 pSMB->MaxSetupCount = 0;
1706 pSMB->Reserved = 0;
1707 pSMB->Flags = 0;
1708 pSMB->Timeout = 0;
1709 pSMB->Reserved2 = 0;
1710 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1711 offset = param_offset + params;
1712
1713 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1714 rename_info = (struct set_file_rename *) data_offset;
1715 pSMB->MaxParameterCount = cpu_to_le16(2);
1716 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1717 pSMB->SetupCount = 1;
1718 pSMB->Reserved3 = 0;
1719 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1720 byte_count = 3 /* pad */ + params;
1721 pSMB->ParameterCount = cpu_to_le16(params);
1722 pSMB->TotalParameterCount = pSMB->ParameterCount;
1723 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1724 pSMB->DataOffset = cpu_to_le16(offset);
1725 /* construct random name ".cifs_tmp<inodenum><mid>" */
1726 rename_info->overwrite = cpu_to_le32(1);
1727 rename_info->root_fid = 0;
1728 /* unicode only call */
1729 if(target_name == NULL) {
1730 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001731 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001732 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001734 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001735 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 }
1737 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1738 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1739 byte_count += count;
1740 pSMB->DataCount = cpu_to_le16(count);
1741 pSMB->TotalDataCount = pSMB->DataCount;
1742 pSMB->Fid = netfid;
1743 pSMB->InformationLevel =
1744 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1745 pSMB->Reserved4 = 0;
1746 pSMB->hdr.smb_buf_length += byte_count;
1747 pSMB->ByteCount = cpu_to_le16(byte_count);
1748 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1749 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001750 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 if (rc) {
1752 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1753 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001754
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 cifs_buf_release(pSMB);
1756
1757 /* Note: On -EAGAIN error only caller can retry on handle based calls
1758 since file handle passed in no longer valid */
1759
1760 return rc;
1761}
1762
1763int
1764CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1765 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001766 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767{
1768 int rc = 0;
1769 COPY_REQ *pSMB = NULL;
1770 COPY_RSP *pSMBr = NULL;
1771 int bytes_returned;
1772 int name_len, name_len2;
1773 __u16 count;
1774
1775 cFYI(1, ("In CIFSSMBCopy"));
1776copyRetry:
1777 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1778 (void **) &pSMBr);
1779 if (rc)
1780 return rc;
1781
1782 pSMB->BufferFormat = 0x04;
1783 pSMB->Tid2 = target_tid;
1784
1785 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1786
1787 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001788 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001789 fromName, PATH_MAX, nls_codepage,
1790 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 name_len++; /* trailing null */
1792 name_len *= 2;
1793 pSMB->OldFileName[name_len] = 0x04; /* pad */
1794 /* protocol requires ASCII signature byte on Unicode string */
1795 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001796 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001797 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1799 name_len2 *= 2; /* convert to bytes */
1800 } else { /* BB improve the check for buffer overruns BB */
1801 name_len = strnlen(fromName, PATH_MAX);
1802 name_len++; /* trailing null */
1803 strncpy(pSMB->OldFileName, fromName, name_len);
1804 name_len2 = strnlen(toName, PATH_MAX);
1805 name_len2++; /* trailing null */
1806 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1807 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1808 name_len2++; /* trailing null */
1809 name_len2++; /* signature byte */
1810 }
1811
1812 count = 1 /* 1st signature byte */ + name_len + name_len2;
1813 pSMB->hdr.smb_buf_length += count;
1814 pSMB->ByteCount = cpu_to_le16(count);
1815
1816 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1817 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1818 if (rc) {
1819 cFYI(1, ("Send error in copy = %d with %d files copied",
1820 rc, le16_to_cpu(pSMBr->CopyCount)));
1821 }
1822 if (pSMB)
1823 cifs_buf_release(pSMB);
1824
1825 if (rc == -EAGAIN)
1826 goto copyRetry;
1827
1828 return rc;
1829}
1830
1831int
1832CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1833 const char *fromName, const char *toName,
1834 const struct nls_table *nls_codepage)
1835{
1836 TRANSACTION2_SPI_REQ *pSMB = NULL;
1837 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1838 char *data_offset;
1839 int name_len;
1840 int name_len_target;
1841 int rc = 0;
1842 int bytes_returned = 0;
1843 __u16 params, param_offset, offset, byte_count;
1844
1845 cFYI(1, ("In Symlink Unix style"));
1846createSymLinkRetry:
1847 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1848 (void **) &pSMBr);
1849 if (rc)
1850 return rc;
1851
1852 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1853 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001854 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 /* find define for this maxpathcomponent */
1856 , nls_codepage);
1857 name_len++; /* trailing null */
1858 name_len *= 2;
1859
1860 } else { /* BB improve the check for buffer overruns BB */
1861 name_len = strnlen(fromName, PATH_MAX);
1862 name_len++; /* trailing null */
1863 strncpy(pSMB->FileName, fromName, name_len);
1864 }
1865 params = 6 + name_len;
1866 pSMB->MaxSetupCount = 0;
1867 pSMB->Reserved = 0;
1868 pSMB->Flags = 0;
1869 pSMB->Timeout = 0;
1870 pSMB->Reserved2 = 0;
1871 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1872 InformationLevel) - 4;
1873 offset = param_offset + params;
1874
1875 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1876 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1877 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001878 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 /* find define for this maxpathcomponent */
1880 , nls_codepage);
1881 name_len_target++; /* trailing null */
1882 name_len_target *= 2;
1883 } else { /* BB improve the check for buffer overruns BB */
1884 name_len_target = strnlen(toName, PATH_MAX);
1885 name_len_target++; /* trailing null */
1886 strncpy(data_offset, toName, name_len_target);
1887 }
1888
1889 pSMB->MaxParameterCount = cpu_to_le16(2);
1890 /* BB find exact max on data count below from sess */
1891 pSMB->MaxDataCount = cpu_to_le16(1000);
1892 pSMB->SetupCount = 1;
1893 pSMB->Reserved3 = 0;
1894 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1895 byte_count = 3 /* pad */ + params + name_len_target;
1896 pSMB->DataCount = cpu_to_le16(name_len_target);
1897 pSMB->ParameterCount = cpu_to_le16(params);
1898 pSMB->TotalDataCount = pSMB->DataCount;
1899 pSMB->TotalParameterCount = pSMB->ParameterCount;
1900 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1901 pSMB->DataOffset = cpu_to_le16(offset);
1902 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1903 pSMB->Reserved4 = 0;
1904 pSMB->hdr.smb_buf_length += byte_count;
1905 pSMB->ByteCount = cpu_to_le16(byte_count);
1906 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1907 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001908 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 if (rc) {
1910 cFYI(1,
1911 ("Send error in SetPathInfo (create symlink) = %d",
1912 rc));
1913 }
1914
1915 if (pSMB)
1916 cifs_buf_release(pSMB);
1917
1918 if (rc == -EAGAIN)
1919 goto createSymLinkRetry;
1920
1921 return rc;
1922}
1923
1924int
1925CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1926 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001927 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928{
1929 TRANSACTION2_SPI_REQ *pSMB = NULL;
1930 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1931 char *data_offset;
1932 int name_len;
1933 int name_len_target;
1934 int rc = 0;
1935 int bytes_returned = 0;
1936 __u16 params, param_offset, offset, byte_count;
1937
1938 cFYI(1, ("In Create Hard link Unix style"));
1939createHardLinkRetry:
1940 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1941 (void **) &pSMBr);
1942 if (rc)
1943 return rc;
1944
1945 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001946 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001947 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 name_len++; /* trailing null */
1949 name_len *= 2;
1950
1951 } else { /* BB improve the check for buffer overruns BB */
1952 name_len = strnlen(toName, PATH_MAX);
1953 name_len++; /* trailing null */
1954 strncpy(pSMB->FileName, toName, name_len);
1955 }
1956 params = 6 + name_len;
1957 pSMB->MaxSetupCount = 0;
1958 pSMB->Reserved = 0;
1959 pSMB->Flags = 0;
1960 pSMB->Timeout = 0;
1961 pSMB->Reserved2 = 0;
1962 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1963 InformationLevel) - 4;
1964 offset = param_offset + params;
1965
1966 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1967 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1968 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001969 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001970 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 name_len_target++; /* trailing null */
1972 name_len_target *= 2;
1973 } else { /* BB improve the check for buffer overruns BB */
1974 name_len_target = strnlen(fromName, PATH_MAX);
1975 name_len_target++; /* trailing null */
1976 strncpy(data_offset, fromName, name_len_target);
1977 }
1978
1979 pSMB->MaxParameterCount = cpu_to_le16(2);
1980 /* BB find exact max on data count below from sess*/
1981 pSMB->MaxDataCount = cpu_to_le16(1000);
1982 pSMB->SetupCount = 1;
1983 pSMB->Reserved3 = 0;
1984 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1985 byte_count = 3 /* pad */ + params + name_len_target;
1986 pSMB->ParameterCount = cpu_to_le16(params);
1987 pSMB->TotalParameterCount = pSMB->ParameterCount;
1988 pSMB->DataCount = cpu_to_le16(name_len_target);
1989 pSMB->TotalDataCount = pSMB->DataCount;
1990 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1991 pSMB->DataOffset = cpu_to_le16(offset);
1992 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1993 pSMB->Reserved4 = 0;
1994 pSMB->hdr.smb_buf_length += byte_count;
1995 pSMB->ByteCount = cpu_to_le16(byte_count);
1996 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1997 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001998 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 if (rc) {
2000 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2001 }
2002
2003 cifs_buf_release(pSMB);
2004 if (rc == -EAGAIN)
2005 goto createHardLinkRetry;
2006
2007 return rc;
2008}
2009
2010int
2011CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2012 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002013 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014{
2015 int rc = 0;
2016 NT_RENAME_REQ *pSMB = NULL;
2017 RENAME_RSP *pSMBr = NULL;
2018 int bytes_returned;
2019 int name_len, name_len2;
2020 __u16 count;
2021
2022 cFYI(1, ("In CIFSCreateHardLink"));
2023winCreateHardLinkRetry:
2024
2025 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2026 (void **) &pSMBr);
2027 if (rc)
2028 return rc;
2029
2030 pSMB->SearchAttributes =
2031 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2032 ATTR_DIRECTORY);
2033 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2034 pSMB->ClusterCount = 0;
2035
2036 pSMB->BufferFormat = 0x04;
2037
2038 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2039 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002040 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002041 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 name_len++; /* trailing null */
2043 name_len *= 2;
2044 pSMB->OldFileName[name_len] = 0; /* pad */
2045 pSMB->OldFileName[name_len + 1] = 0x04;
2046 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002047 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002048 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2050 name_len2 *= 2; /* convert to bytes */
2051 } else { /* BB improve the check for buffer overruns BB */
2052 name_len = strnlen(fromName, PATH_MAX);
2053 name_len++; /* trailing null */
2054 strncpy(pSMB->OldFileName, fromName, name_len);
2055 name_len2 = strnlen(toName, PATH_MAX);
2056 name_len2++; /* trailing null */
2057 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2058 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2059 name_len2++; /* trailing null */
2060 name_len2++; /* signature byte */
2061 }
2062
2063 count = 1 /* string type byte */ + name_len + name_len2;
2064 pSMB->hdr.smb_buf_length += count;
2065 pSMB->ByteCount = cpu_to_le16(count);
2066
2067 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2068 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002069 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070 if (rc) {
2071 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2072 }
2073 cifs_buf_release(pSMB);
2074 if (rc == -EAGAIN)
2075 goto winCreateHardLinkRetry;
2076
2077 return rc;
2078}
2079
2080int
2081CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2082 const unsigned char *searchName,
2083 char *symlinkinfo, const int buflen,
2084 const struct nls_table *nls_codepage)
2085{
2086/* SMB_QUERY_FILE_UNIX_LINK */
2087 TRANSACTION2_QPI_REQ *pSMB = NULL;
2088 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2089 int rc = 0;
2090 int bytes_returned;
2091 int name_len;
2092 __u16 params, byte_count;
2093
2094 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2095
2096querySymLinkRetry:
2097 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2098 (void **) &pSMBr);
2099 if (rc)
2100 return rc;
2101
2102 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2103 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002104 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 /* find define for this maxpathcomponent */
2106 , nls_codepage);
2107 name_len++; /* trailing null */
2108 name_len *= 2;
2109 } else { /* BB improve the check for buffer overruns BB */
2110 name_len = strnlen(searchName, PATH_MAX);
2111 name_len++; /* trailing null */
2112 strncpy(pSMB->FileName, searchName, name_len);
2113 }
2114
2115 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2116 pSMB->TotalDataCount = 0;
2117 pSMB->MaxParameterCount = cpu_to_le16(2);
2118 /* BB find exact max data count below from sess structure BB */
2119 pSMB->MaxDataCount = cpu_to_le16(4000);
2120 pSMB->MaxSetupCount = 0;
2121 pSMB->Reserved = 0;
2122 pSMB->Flags = 0;
2123 pSMB->Timeout = 0;
2124 pSMB->Reserved2 = 0;
2125 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2126 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2127 pSMB->DataCount = 0;
2128 pSMB->DataOffset = 0;
2129 pSMB->SetupCount = 1;
2130 pSMB->Reserved3 = 0;
2131 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2132 byte_count = params + 1 /* pad */ ;
2133 pSMB->TotalParameterCount = cpu_to_le16(params);
2134 pSMB->ParameterCount = pSMB->TotalParameterCount;
2135 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2136 pSMB->Reserved4 = 0;
2137 pSMB->hdr.smb_buf_length += byte_count;
2138 pSMB->ByteCount = cpu_to_le16(byte_count);
2139
2140 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2141 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2142 if (rc) {
2143 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2144 } else {
2145 /* decode response */
2146
2147 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2148 if (rc || (pSMBr->ByteCount < 2))
2149 /* BB also check enough total bytes returned */
2150 rc = -EIO; /* bad smb */
2151 else {
2152 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2153 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2154
2155 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2156 name_len = UniStrnlen((wchar_t *) ((char *)
2157 &pSMBr->hdr.Protocol +data_offset),
2158 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002159 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002161 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 data_offset),
2163 name_len, nls_codepage);
2164 } else {
2165 strncpy(symlinkinfo,
2166 (char *) &pSMBr->hdr.Protocol +
2167 data_offset,
2168 min_t(const int, buflen, count));
2169 }
2170 symlinkinfo[buflen] = 0;
2171 /* just in case so calling code does not go off the end of buffer */
2172 }
2173 }
2174 cifs_buf_release(pSMB);
2175 if (rc == -EAGAIN)
2176 goto querySymLinkRetry;
2177 return rc;
2178}
2179
Steve French0a4b92c2006-01-12 15:44:21 -08002180/* Initialize NT TRANSACT SMB into small smb request buffer.
2181 This assumes that all NT TRANSACTS that we init here have
2182 total parm and data under about 400 bytes (to fit in small cifs
2183 buffer size), which is the case so far, it easily fits. NB:
2184 Setup words themselves and ByteCount
2185 MaxSetupCount (size of returned setup area) and
2186 MaxParameterCount (returned parms size) must be set by caller */
2187static int
2188smb_init_ntransact(const __u16 sub_command, const int setup_count,
2189 const int parm_len, struct cifsTconInfo *tcon,
2190 void ** ret_buf)
2191{
2192 int rc;
2193 __u32 temp_offset;
2194 struct smb_com_ntransact_req * pSMB;
2195
2196 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2197 (void **)&pSMB);
2198 if (rc)
2199 return rc;
2200 *ret_buf = (void *)pSMB;
2201 pSMB->Reserved = 0;
2202 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2203 pSMB->TotalDataCount = 0;
2204 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2205 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2206 pSMB->ParameterCount = pSMB->TotalParameterCount;
2207 pSMB->DataCount = pSMB->TotalDataCount;
2208 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2209 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2210 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2211 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2212 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2213 pSMB->SubCommand = cpu_to_le16(sub_command);
2214 return 0;
2215}
2216
2217static int
2218validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2219 int * pdatalen, int * pparmlen)
2220{
2221 char * end_of_smb;
2222 __u32 data_count, data_offset, parm_count, parm_offset;
2223 struct smb_com_ntransact_rsp * pSMBr;
2224
2225 if(buf == NULL)
2226 return -EINVAL;
2227
2228 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2229
2230 /* ByteCount was converted from little endian in SendReceive */
2231 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2232 (char *)&pSMBr->ByteCount;
2233
2234
2235 data_offset = le32_to_cpu(pSMBr->DataOffset);
2236 data_count = le32_to_cpu(pSMBr->DataCount);
2237 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2238 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2239
2240 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2241 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2242
2243 /* should we also check that parm and data areas do not overlap? */
2244 if(*ppparm > end_of_smb) {
2245 cFYI(1,("parms start after end of smb"));
2246 return -EINVAL;
2247 } else if(parm_count + *ppparm > end_of_smb) {
2248 cFYI(1,("parm end after end of smb"));
2249 return -EINVAL;
2250 } else if(*ppdata > end_of_smb) {
2251 cFYI(1,("data starts after end of smb"));
2252 return -EINVAL;
2253 } else if(data_count + *ppdata > end_of_smb) {
2254 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2255 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2256 return -EINVAL;
2257 } else if(parm_count + data_count > pSMBr->ByteCount) {
2258 cFYI(1,("parm count and data count larger than SMB"));
2259 return -EINVAL;
2260 }
2261 return 0;
2262}
2263
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264int
2265CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2266 const unsigned char *searchName,
2267 char *symlinkinfo, const int buflen,__u16 fid,
2268 const struct nls_table *nls_codepage)
2269{
2270 int rc = 0;
2271 int bytes_returned;
2272 int name_len;
2273 struct smb_com_transaction_ioctl_req * pSMB;
2274 struct smb_com_transaction_ioctl_rsp * pSMBr;
2275
2276 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2277 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2278 (void **) &pSMBr);
2279 if (rc)
2280 return rc;
2281
2282 pSMB->TotalParameterCount = 0 ;
2283 pSMB->TotalDataCount = 0;
2284 pSMB->MaxParameterCount = cpu_to_le32(2);
2285 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002286 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2287 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288 pSMB->MaxSetupCount = 4;
2289 pSMB->Reserved = 0;
2290 pSMB->ParameterOffset = 0;
2291 pSMB->DataCount = 0;
2292 pSMB->DataOffset = 0;
2293 pSMB->SetupCount = 4;
2294 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2295 pSMB->ParameterCount = pSMB->TotalParameterCount;
2296 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2297 pSMB->IsFsctl = 1; /* FSCTL */
2298 pSMB->IsRootFlag = 0;
2299 pSMB->Fid = fid; /* file handle always le */
2300 pSMB->ByteCount = 0;
2301
2302 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2303 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2304 if (rc) {
2305 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2306 } else { /* decode response */
2307 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2308 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2309 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2310 /* BB also check enough total bytes returned */
2311 rc = -EIO; /* bad smb */
2312 else {
2313 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002314 char * end_of_smb = 2 /* sizeof byte count */ +
2315 pSMBr->ByteCount +
2316 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317
2318 struct reparse_data * reparse_buf = (struct reparse_data *)
2319 ((char *)&pSMBr->hdr.Protocol + data_offset);
2320 if((char*)reparse_buf >= end_of_smb) {
2321 rc = -EIO;
2322 goto qreparse_out;
2323 }
2324 if((reparse_buf->LinkNamesBuf +
2325 reparse_buf->TargetNameOffset +
2326 reparse_buf->TargetNameLen) >
2327 end_of_smb) {
2328 cFYI(1,("reparse buf extended beyond SMB"));
2329 rc = -EIO;
2330 goto qreparse_out;
2331 }
2332
2333 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2334 name_len = UniStrnlen((wchar_t *)
2335 (reparse_buf->LinkNamesBuf +
2336 reparse_buf->TargetNameOffset),
2337 min(buflen/2, reparse_buf->TargetNameLen / 2));
2338 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002339 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340 reparse_buf->TargetNameOffset),
2341 name_len, nls_codepage);
2342 } else { /* ASCII names */
2343 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2344 reparse_buf->TargetNameOffset,
2345 min_t(const int, buflen, reparse_buf->TargetNameLen));
2346 }
2347 } else {
2348 rc = -EIO;
2349 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2350 }
2351 symlinkinfo[buflen] = 0; /* just in case so the caller
2352 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002353 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 }
2355 }
2356qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002357 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358
2359 /* Note: On -EAGAIN error only caller can retry on handle based calls
2360 since file handle passed in no longer valid */
2361
2362 return rc;
2363}
2364
2365#ifdef CONFIG_CIFS_POSIX
2366
2367/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2368static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2369{
2370 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002371 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2372 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2373 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2375
2376 return;
2377}
2378
2379/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002380static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2381 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382{
2383 int size = 0;
2384 int i;
2385 __u16 count;
2386 struct cifs_posix_ace * pACE;
2387 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2388 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2389
2390 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2391 return -EOPNOTSUPP;
2392
2393 if(acl_type & ACL_TYPE_ACCESS) {
2394 count = le16_to_cpu(cifs_acl->access_entry_count);
2395 pACE = &cifs_acl->ace_array[0];
2396 size = sizeof(struct cifs_posix_acl);
2397 size += sizeof(struct cifs_posix_ace) * count;
2398 /* check if we would go beyond end of SMB */
2399 if(size_of_data_area < size) {
2400 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2401 return -EINVAL;
2402 }
2403 } else if(acl_type & ACL_TYPE_DEFAULT) {
2404 count = le16_to_cpu(cifs_acl->access_entry_count);
2405 size = sizeof(struct cifs_posix_acl);
2406 size += sizeof(struct cifs_posix_ace) * count;
2407/* skip past access ACEs to get to default ACEs */
2408 pACE = &cifs_acl->ace_array[count];
2409 count = le16_to_cpu(cifs_acl->default_entry_count);
2410 size += sizeof(struct cifs_posix_ace) * count;
2411 /* check if we would go beyond end of SMB */
2412 if(size_of_data_area < size)
2413 return -EINVAL;
2414 } else {
2415 /* illegal type */
2416 return -EINVAL;
2417 }
2418
2419 size = posix_acl_xattr_size(count);
2420 if((buflen == 0) || (local_acl == NULL)) {
2421 /* used to query ACL EA size */
2422 } else if(size > buflen) {
2423 return -ERANGE;
2424 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002425 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426 for(i = 0;i < count ;i++) {
2427 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2428 pACE ++;
2429 }
2430 }
2431 return size;
2432}
2433
2434static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2435 const posix_acl_xattr_entry * local_ace)
2436{
2437 __u16 rc = 0; /* 0 = ACL converted ok */
2438
Steve Frenchff7feac2005-11-15 16:45:16 -08002439 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2440 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002442 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 /* Probably no need to le convert -1 on any arch but can not hurt */
2444 cifs_ace->cifs_uid = cpu_to_le64(-1);
2445 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002446 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2448 return rc;
2449}
2450
2451/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2452static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2453 const int acl_type)
2454{
2455 __u16 rc = 0;
2456 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2457 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2458 int count;
2459 int i;
2460
2461 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2462 return 0;
2463
2464 count = posix_acl_xattr_count((size_t)buflen);
2465 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002466 count, buflen, le32_to_cpu(local_acl->a_version)));
2467 if(le32_to_cpu(local_acl->a_version) != 2) {
2468 cFYI(1,("unknown POSIX ACL version %d",
2469 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 return 0;
2471 }
2472 cifs_acl->version = cpu_to_le16(1);
2473 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002474 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002476 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 else {
2478 cFYI(1,("unknown ACL type %d",acl_type));
2479 return 0;
2480 }
2481 for(i=0;i<count;i++) {
2482 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2483 &local_acl->a_entries[i]);
2484 if(rc != 0) {
2485 /* ACE not converted */
2486 break;
2487 }
2488 }
2489 if(rc == 0) {
2490 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2491 rc += sizeof(struct cifs_posix_acl);
2492 /* BB add check to make sure ACL does not overflow SMB */
2493 }
2494 return rc;
2495}
2496
2497int
2498CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2499 const unsigned char *searchName,
2500 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002501 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502{
2503/* SMB_QUERY_POSIX_ACL */
2504 TRANSACTION2_QPI_REQ *pSMB = NULL;
2505 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2506 int rc = 0;
2507 int bytes_returned;
2508 int name_len;
2509 __u16 params, byte_count;
2510
2511 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2512
2513queryAclRetry:
2514 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2515 (void **) &pSMBr);
2516 if (rc)
2517 return rc;
2518
2519 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2520 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002521 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002522 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 name_len++; /* trailing null */
2524 name_len *= 2;
2525 pSMB->FileName[name_len] = 0;
2526 pSMB->FileName[name_len+1] = 0;
2527 } else { /* BB improve the check for buffer overruns BB */
2528 name_len = strnlen(searchName, PATH_MAX);
2529 name_len++; /* trailing null */
2530 strncpy(pSMB->FileName, searchName, name_len);
2531 }
2532
2533 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2534 pSMB->TotalDataCount = 0;
2535 pSMB->MaxParameterCount = cpu_to_le16(2);
2536 /* BB find exact max data count below from sess structure BB */
2537 pSMB->MaxDataCount = cpu_to_le16(4000);
2538 pSMB->MaxSetupCount = 0;
2539 pSMB->Reserved = 0;
2540 pSMB->Flags = 0;
2541 pSMB->Timeout = 0;
2542 pSMB->Reserved2 = 0;
2543 pSMB->ParameterOffset = cpu_to_le16(
2544 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2545 pSMB->DataCount = 0;
2546 pSMB->DataOffset = 0;
2547 pSMB->SetupCount = 1;
2548 pSMB->Reserved3 = 0;
2549 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2550 byte_count = params + 1 /* pad */ ;
2551 pSMB->TotalParameterCount = cpu_to_le16(params);
2552 pSMB->ParameterCount = pSMB->TotalParameterCount;
2553 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2554 pSMB->Reserved4 = 0;
2555 pSMB->hdr.smb_buf_length += byte_count;
2556 pSMB->ByteCount = cpu_to_le16(byte_count);
2557
2558 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2559 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002560 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 if (rc) {
2562 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2563 } else {
2564 /* decode response */
2565
2566 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2567 if (rc || (pSMBr->ByteCount < 2))
2568 /* BB also check enough total bytes returned */
2569 rc = -EIO; /* bad smb */
2570 else {
2571 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2572 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2573 rc = cifs_copy_posix_acl(acl_inf,
2574 (char *)&pSMBr->hdr.Protocol+data_offset,
2575 buflen,acl_type,count);
2576 }
2577 }
2578 cifs_buf_release(pSMB);
2579 if (rc == -EAGAIN)
2580 goto queryAclRetry;
2581 return rc;
2582}
2583
2584int
2585CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2586 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002587 const char *local_acl, const int buflen,
2588 const int acl_type,
2589 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590{
2591 struct smb_com_transaction2_spi_req *pSMB = NULL;
2592 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2593 char *parm_data;
2594 int name_len;
2595 int rc = 0;
2596 int bytes_returned = 0;
2597 __u16 params, byte_count, data_count, param_offset, offset;
2598
2599 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2600setAclRetry:
2601 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2602 (void **) &pSMBr);
2603 if (rc)
2604 return rc;
2605 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2606 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002607 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002608 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609 name_len++; /* trailing null */
2610 name_len *= 2;
2611 } else { /* BB improve the check for buffer overruns BB */
2612 name_len = strnlen(fileName, PATH_MAX);
2613 name_len++; /* trailing null */
2614 strncpy(pSMB->FileName, fileName, name_len);
2615 }
2616 params = 6 + name_len;
2617 pSMB->MaxParameterCount = cpu_to_le16(2);
2618 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2619 pSMB->MaxSetupCount = 0;
2620 pSMB->Reserved = 0;
2621 pSMB->Flags = 0;
2622 pSMB->Timeout = 0;
2623 pSMB->Reserved2 = 0;
2624 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2625 InformationLevel) - 4;
2626 offset = param_offset + params;
2627 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2628 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2629
2630 /* convert to on the wire format for POSIX ACL */
2631 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2632
2633 if(data_count == 0) {
2634 rc = -EOPNOTSUPP;
2635 goto setACLerrorExit;
2636 }
2637 pSMB->DataOffset = cpu_to_le16(offset);
2638 pSMB->SetupCount = 1;
2639 pSMB->Reserved3 = 0;
2640 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2641 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2642 byte_count = 3 /* pad */ + params + data_count;
2643 pSMB->DataCount = cpu_to_le16(data_count);
2644 pSMB->TotalDataCount = pSMB->DataCount;
2645 pSMB->ParameterCount = cpu_to_le16(params);
2646 pSMB->TotalParameterCount = pSMB->ParameterCount;
2647 pSMB->Reserved4 = 0;
2648 pSMB->hdr.smb_buf_length += byte_count;
2649 pSMB->ByteCount = cpu_to_le16(byte_count);
2650 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2651 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2652 if (rc) {
2653 cFYI(1, ("Set POSIX ACL returned %d", rc));
2654 }
2655
2656setACLerrorExit:
2657 cifs_buf_release(pSMB);
2658 if (rc == -EAGAIN)
2659 goto setAclRetry;
2660 return rc;
2661}
2662
Steve Frenchf654bac2005-04-28 22:41:04 -07002663/* BB fix tabs in this function FIXME BB */
2664int
2665CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2666 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2667{
2668 int rc = 0;
2669 struct smb_t2_qfi_req *pSMB = NULL;
2670 struct smb_t2_qfi_rsp *pSMBr = NULL;
2671 int bytes_returned;
2672 __u16 params, byte_count;
2673
2674 cFYI(1,("In GetExtAttr"));
2675 if(tcon == NULL)
2676 return -ENODEV;
2677
2678GetExtAttrRetry:
2679 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2680 (void **) &pSMBr);
2681 if (rc)
2682 return rc;
2683
Steve Frenchc67593a2005-04-28 22:41:04 -07002684 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002685 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002686 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002687 /* BB find exact max data count below from sess structure BB */
2688 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2689 pSMB->t2.MaxSetupCount = 0;
2690 pSMB->t2.Reserved = 0;
2691 pSMB->t2.Flags = 0;
2692 pSMB->t2.Timeout = 0;
2693 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002694 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2695 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002696 pSMB->t2.DataCount = 0;
2697 pSMB->t2.DataOffset = 0;
2698 pSMB->t2.SetupCount = 1;
2699 pSMB->t2.Reserved3 = 0;
2700 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002701 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002702 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2703 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2704 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002705 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002706 pSMB->Fid = netfid;
2707 pSMB->hdr.smb_buf_length += byte_count;
2708 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2709
2710 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2711 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2712 if (rc) {
2713 cFYI(1, ("error %d in GetExtAttr", rc));
2714 } else {
2715 /* decode response */
2716 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2717 if (rc || (pSMBr->ByteCount < 2))
2718 /* BB also check enough total bytes returned */
2719 /* If rc should we check for EOPNOSUPP and
2720 disable the srvino flag? or in caller? */
2721 rc = -EIO; /* bad smb */
2722 else {
2723 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2724 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2725 struct file_chattr_info * pfinfo;
2726 /* BB Do we need a cast or hash here ? */
2727 if(count != 16) {
2728 cFYI(1, ("Illegal size ret in GetExtAttr"));
2729 rc = -EIO;
2730 goto GetExtAttrOut;
2731 }
2732 pfinfo = (struct file_chattr_info *)
2733 (data_offset + (char *) &pSMBr->hdr.Protocol);
2734 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2735 *pMask = le64_to_cpu(pfinfo->mask);
2736 }
2737 }
2738GetExtAttrOut:
2739 cifs_buf_release(pSMB);
2740 if (rc == -EAGAIN)
2741 goto GetExtAttrRetry;
2742 return rc;
2743}
2744
2745
2746#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747
Steve Frencheeac8042006-01-13 21:34:58 -08002748
2749/* security id for everyone */
2750const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2751/* group users */
2752const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2753
Steve French0a4b92c2006-01-12 15:44:21 -08002754/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002755static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002756{
Steve French0a4b92c2006-01-12 15:44:21 -08002757 return 0;
2758}
2759
2760/* Get Security Descriptor (by handle) from remote server for a file or dir */
2761int
2762CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2763 /* BB fix up return info */ char *acl_inf, const int buflen,
2764 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2765{
2766 int rc = 0;
2767 int buf_type = 0;
2768 QUERY_SEC_DESC_REQ * pSMB;
2769 struct kvec iov[1];
2770
2771 cFYI(1, ("GetCifsACL"));
2772
2773 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2774 8 /* parm len */, tcon, (void **) &pSMB);
2775 if (rc)
2776 return rc;
2777
2778 pSMB->MaxParameterCount = cpu_to_le32(4);
2779 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2780 pSMB->MaxSetupCount = 0;
2781 pSMB->Fid = fid; /* file handle always le */
2782 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2783 CIFS_ACL_DACL);
2784 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2785 pSMB->hdr.smb_buf_length += 11;
2786 iov[0].iov_base = (char *)pSMB;
2787 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2788
2789 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2790 cifs_stats_inc(&tcon->num_acl_get);
2791 if (rc) {
2792 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2793 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002794 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002795 __le32 * parm;
2796 int parm_len;
2797 int data_len;
2798 int acl_len;
2799 struct smb_com_ntransact_rsp * pSMBr;
2800
2801/* validate_nttransact */
2802 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2803 (char **)&psec_desc,
2804 &parm_len, &data_len);
2805
2806 if(rc)
2807 goto qsec_out;
2808 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2809
2810 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2811
2812 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2813 rc = -EIO; /* bad smb */
2814 goto qsec_out;
2815 }
2816
2817/* BB check that data area is minimum length and as big as acl_len */
2818
2819 acl_len = le32_to_cpu(*(__le32 *)parm);
2820 /* BB check if(acl_len > bufsize) */
2821
2822 parse_sec_desc(psec_desc, acl_len);
2823 }
2824qsec_out:
2825 if(buf_type == CIFS_SMALL_BUFFER)
2826 cifs_small_buf_release(iov[0].iov_base);
2827 else if(buf_type == CIFS_LARGE_BUFFER)
2828 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00002829/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08002830 return rc;
2831}
2832
2833
Steve French6b8edfe2005-08-23 20:26:03 -07002834/* Legacy Query Path Information call for lookup to old servers such
2835 as Win9x/WinME */
2836int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2837 const unsigned char *searchName,
2838 FILE_ALL_INFO * pFinfo,
2839 const struct nls_table *nls_codepage, int remap)
2840{
2841 QUERY_INFORMATION_REQ * pSMB;
2842 QUERY_INFORMATION_RSP * pSMBr;
2843 int rc = 0;
2844 int bytes_returned;
2845 int name_len;
2846
2847 cFYI(1, ("In SMBQPath path %s", searchName));
2848QInfRetry:
2849 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2850 (void **) &pSMBr);
2851 if (rc)
2852 return rc;
2853
2854 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2855 name_len =
2856 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2857 PATH_MAX, nls_codepage, remap);
2858 name_len++; /* trailing null */
2859 name_len *= 2;
2860 } else {
2861 name_len = strnlen(searchName, PATH_MAX);
2862 name_len++; /* trailing null */
2863 strncpy(pSMB->FileName, searchName, name_len);
2864 }
2865 pSMB->BufferFormat = 0x04;
2866 name_len++; /* account for buffer type byte */
2867 pSMB->hdr.smb_buf_length += (__u16) name_len;
2868 pSMB->ByteCount = cpu_to_le16(name_len);
2869
2870 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2871 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2872 if (rc) {
2873 cFYI(1, ("Send error in QueryInfo = %d", rc));
2874 } else if (pFinfo) { /* decode response */
2875 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002876 pFinfo->AllocationSize =
2877 cpu_to_le64(le32_to_cpu(pSMBr->size));
2878 pFinfo->EndOfFile = pFinfo->AllocationSize;
2879 pFinfo->Attributes =
2880 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002881 } else
2882 rc = -EIO; /* bad buffer passed in */
2883
2884 cifs_buf_release(pSMB);
2885
2886 if (rc == -EAGAIN)
2887 goto QInfRetry;
2888
2889 return rc;
2890}
2891
2892
2893
2894
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895int
2896CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2897 const unsigned char *searchName,
2898 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002899 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900{
2901/* level 263 SMB_QUERY_FILE_ALL_INFO */
2902 TRANSACTION2_QPI_REQ *pSMB = NULL;
2903 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2904 int rc = 0;
2905 int bytes_returned;
2906 int name_len;
2907 __u16 params, byte_count;
2908
2909/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2910QPathInfoRetry:
2911 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2912 (void **) &pSMBr);
2913 if (rc)
2914 return rc;
2915
2916 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2917 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002918 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002919 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 name_len++; /* trailing null */
2921 name_len *= 2;
2922 } else { /* BB improve the check for buffer overruns BB */
2923 name_len = strnlen(searchName, PATH_MAX);
2924 name_len++; /* trailing null */
2925 strncpy(pSMB->FileName, searchName, name_len);
2926 }
2927
2928 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2929 pSMB->TotalDataCount = 0;
2930 pSMB->MaxParameterCount = cpu_to_le16(2);
2931 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2932 pSMB->MaxSetupCount = 0;
2933 pSMB->Reserved = 0;
2934 pSMB->Flags = 0;
2935 pSMB->Timeout = 0;
2936 pSMB->Reserved2 = 0;
2937 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2938 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2939 pSMB->DataCount = 0;
2940 pSMB->DataOffset = 0;
2941 pSMB->SetupCount = 1;
2942 pSMB->Reserved3 = 0;
2943 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2944 byte_count = params + 1 /* pad */ ;
2945 pSMB->TotalParameterCount = cpu_to_le16(params);
2946 pSMB->ParameterCount = pSMB->TotalParameterCount;
2947 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2948 pSMB->Reserved4 = 0;
2949 pSMB->hdr.smb_buf_length += byte_count;
2950 pSMB->ByteCount = cpu_to_le16(byte_count);
2951
2952 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2953 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2954 if (rc) {
2955 cFYI(1, ("Send error in QPathInfo = %d", rc));
2956 } else { /* decode response */
2957 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2958
2959 if (rc || (pSMBr->ByteCount < 40))
2960 rc = -EIO; /* bad smb */
2961 else if (pFindData){
2962 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2963 memcpy((char *) pFindData,
2964 (char *) &pSMBr->hdr.Protocol +
2965 data_offset, sizeof (FILE_ALL_INFO));
2966 } else
2967 rc = -ENOMEM;
2968 }
2969 cifs_buf_release(pSMB);
2970 if (rc == -EAGAIN)
2971 goto QPathInfoRetry;
2972
2973 return rc;
2974}
2975
2976int
2977CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2978 const unsigned char *searchName,
2979 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002980 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981{
2982/* SMB_QUERY_FILE_UNIX_BASIC */
2983 TRANSACTION2_QPI_REQ *pSMB = NULL;
2984 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2985 int rc = 0;
2986 int bytes_returned = 0;
2987 int name_len;
2988 __u16 params, byte_count;
2989
2990 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2991UnixQPathInfoRetry:
2992 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2993 (void **) &pSMBr);
2994 if (rc)
2995 return rc;
2996
2997 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2998 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002999 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003000 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 name_len++; /* trailing null */
3002 name_len *= 2;
3003 } else { /* BB improve the check for buffer overruns BB */
3004 name_len = strnlen(searchName, PATH_MAX);
3005 name_len++; /* trailing null */
3006 strncpy(pSMB->FileName, searchName, name_len);
3007 }
3008
3009 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3010 pSMB->TotalDataCount = 0;
3011 pSMB->MaxParameterCount = cpu_to_le16(2);
3012 /* BB find exact max SMB PDU from sess structure BB */
3013 pSMB->MaxDataCount = cpu_to_le16(4000);
3014 pSMB->MaxSetupCount = 0;
3015 pSMB->Reserved = 0;
3016 pSMB->Flags = 0;
3017 pSMB->Timeout = 0;
3018 pSMB->Reserved2 = 0;
3019 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3020 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3021 pSMB->DataCount = 0;
3022 pSMB->DataOffset = 0;
3023 pSMB->SetupCount = 1;
3024 pSMB->Reserved3 = 0;
3025 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3026 byte_count = params + 1 /* pad */ ;
3027 pSMB->TotalParameterCount = cpu_to_le16(params);
3028 pSMB->ParameterCount = pSMB->TotalParameterCount;
3029 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3030 pSMB->Reserved4 = 0;
3031 pSMB->hdr.smb_buf_length += byte_count;
3032 pSMB->ByteCount = cpu_to_le16(byte_count);
3033
3034 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3035 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3036 if (rc) {
3037 cFYI(1, ("Send error in QPathInfo = %d", rc));
3038 } else { /* decode response */
3039 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3040
3041 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3042 rc = -EIO; /* bad smb */
3043 } else {
3044 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3045 memcpy((char *) pFindData,
3046 (char *) &pSMBr->hdr.Protocol +
3047 data_offset,
3048 sizeof (FILE_UNIX_BASIC_INFO));
3049 }
3050 }
3051 cifs_buf_release(pSMB);
3052 if (rc == -EAGAIN)
3053 goto UnixQPathInfoRetry;
3054
3055 return rc;
3056}
3057
3058#if 0 /* function unused at present */
3059int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3060 const char *searchName, FILE_ALL_INFO * findData,
3061 const struct nls_table *nls_codepage)
3062{
3063/* level 257 SMB_ */
3064 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3065 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3066 int rc = 0;
3067 int bytes_returned;
3068 int name_len;
3069 __u16 params, byte_count;
3070
3071 cFYI(1, ("In FindUnique"));
3072findUniqueRetry:
3073 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3074 (void **) &pSMBr);
3075 if (rc)
3076 return rc;
3077
3078 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3079 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003080 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003081 /* find define for this maxpathcomponent */
3082 , nls_codepage);
3083 name_len++; /* trailing null */
3084 name_len *= 2;
3085 } else { /* BB improve the check for buffer overruns BB */
3086 name_len = strnlen(searchName, PATH_MAX);
3087 name_len++; /* trailing null */
3088 strncpy(pSMB->FileName, searchName, name_len);
3089 }
3090
3091 params = 12 + name_len /* includes null */ ;
3092 pSMB->TotalDataCount = 0; /* no EAs */
3093 pSMB->MaxParameterCount = cpu_to_le16(2);
3094 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3095 pSMB->MaxSetupCount = 0;
3096 pSMB->Reserved = 0;
3097 pSMB->Flags = 0;
3098 pSMB->Timeout = 0;
3099 pSMB->Reserved2 = 0;
3100 pSMB->ParameterOffset = cpu_to_le16(
3101 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3102 pSMB->DataCount = 0;
3103 pSMB->DataOffset = 0;
3104 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3105 pSMB->Reserved3 = 0;
3106 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3107 byte_count = params + 1 /* pad */ ;
3108 pSMB->TotalParameterCount = cpu_to_le16(params);
3109 pSMB->ParameterCount = pSMB->TotalParameterCount;
3110 pSMB->SearchAttributes =
3111 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3112 ATTR_DIRECTORY);
3113 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3114 pSMB->SearchFlags = cpu_to_le16(1);
3115 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3116 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3117 pSMB->hdr.smb_buf_length += byte_count;
3118 pSMB->ByteCount = cpu_to_le16(byte_count);
3119
3120 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3121 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3122
3123 if (rc) {
3124 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3125 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003126 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003127 /* BB fill in */
3128 }
3129
3130 cifs_buf_release(pSMB);
3131 if (rc == -EAGAIN)
3132 goto findUniqueRetry;
3133
3134 return rc;
3135}
3136#endif /* end unused (temporarily) function */
3137
3138/* xid, tcon, searchName and codepage are input parms, rest are returned */
3139int
3140CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3141 const char *searchName,
3142 const struct nls_table *nls_codepage,
3143 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003144 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145{
3146/* level 257 SMB_ */
3147 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3148 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3149 T2_FFIRST_RSP_PARMS * parms;
3150 int rc = 0;
3151 int bytes_returned = 0;
3152 int name_len;
3153 __u16 params, byte_count;
3154
Steve French737b7582005-04-28 22:41:06 -07003155 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003156
3157findFirstRetry:
3158 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3159 (void **) &pSMBr);
3160 if (rc)
3161 return rc;
3162
3163 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3164 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003165 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003166 PATH_MAX, nls_codepage, remap);
3167 /* We can not add the asterik earlier in case
3168 it got remapped to 0xF03A as if it were part of the
3169 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003171 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003172 pSMB->FileName[name_len+1] = 0;
3173 pSMB->FileName[name_len+2] = '*';
3174 pSMB->FileName[name_len+3] = 0;
3175 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003176 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3177 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003178 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 } else { /* BB add check for overrun of SMB buf BB */
3180 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181/* BB fix here and in unicode clause above ie
3182 if(name_len > buffersize-header)
3183 free buffer exit; BB */
3184 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003185 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003186 pSMB->FileName[name_len+1] = '*';
3187 pSMB->FileName[name_len+2] = 0;
3188 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003189 }
3190
3191 params = 12 + name_len /* includes null */ ;
3192 pSMB->TotalDataCount = 0; /* no EAs */
3193 pSMB->MaxParameterCount = cpu_to_le16(10);
3194 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3195 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3196 pSMB->MaxSetupCount = 0;
3197 pSMB->Reserved = 0;
3198 pSMB->Flags = 0;
3199 pSMB->Timeout = 0;
3200 pSMB->Reserved2 = 0;
3201 byte_count = params + 1 /* pad */ ;
3202 pSMB->TotalParameterCount = cpu_to_le16(params);
3203 pSMB->ParameterCount = pSMB->TotalParameterCount;
3204 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003205 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3206 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 pSMB->DataCount = 0;
3208 pSMB->DataOffset = 0;
3209 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3210 pSMB->Reserved3 = 0;
3211 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3212 pSMB->SearchAttributes =
3213 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3214 ATTR_DIRECTORY);
3215 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3216 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3217 CIFS_SEARCH_RETURN_RESUME);
3218 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3219
3220 /* BB what should we set StorageType to? Does it matter? BB */
3221 pSMB->SearchStorageType = 0;
3222 pSMB->hdr.smb_buf_length += byte_count;
3223 pSMB->ByteCount = cpu_to_le16(byte_count);
3224
3225 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3226 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003227 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003228
Steve French88274812006-03-09 22:21:45 +00003229 if (rc) {/* BB add logic to retry regular search if Unix search
3230 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003231 /* BB Add code to handle unsupported level rc */
3232 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003233
Steve French88274812006-03-09 22:21:45 +00003234 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235
3236 /* BB eventually could optimize out free and realloc of buf */
3237 /* for this case */
3238 if (rc == -EAGAIN)
3239 goto findFirstRetry;
3240 } else { /* decode response */
3241 /* BB remember to free buffer if error BB */
3242 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3243 if(rc == 0) {
3244 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3245 psrch_inf->unicode = TRUE;
3246 else
3247 psrch_inf->unicode = FALSE;
3248
3249 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003250 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251 psrch_inf->srch_entries_start =
3252 (char *) &pSMBr->hdr.Protocol +
3253 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3255 le16_to_cpu(pSMBr->t2.ParameterOffset));
3256
3257 if(parms->EndofSearch)
3258 psrch_inf->endOfSearch = TRUE;
3259 else
3260 psrch_inf->endOfSearch = FALSE;
3261
3262 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003263 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003265 *pnetfid = parms->SearchHandle;
3266 } else {
3267 cifs_buf_release(pSMB);
3268 }
3269 }
3270
3271 return rc;
3272}
3273
3274int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3275 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3276{
3277 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3278 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3279 T2_FNEXT_RSP_PARMS * parms;
3280 char *response_data;
3281 int rc = 0;
3282 int bytes_returned, name_len;
3283 __u16 params, byte_count;
3284
3285 cFYI(1, ("In FindNext"));
3286
3287 if(psrch_inf->endOfSearch == TRUE)
3288 return -ENOENT;
3289
3290 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3291 (void **) &pSMBr);
3292 if (rc)
3293 return rc;
3294
3295 params = 14; /* includes 2 bytes of null string, converted to LE below */
3296 byte_count = 0;
3297 pSMB->TotalDataCount = 0; /* no EAs */
3298 pSMB->MaxParameterCount = cpu_to_le16(8);
3299 pSMB->MaxDataCount =
3300 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3301 pSMB->MaxSetupCount = 0;
3302 pSMB->Reserved = 0;
3303 pSMB->Flags = 0;
3304 pSMB->Timeout = 0;
3305 pSMB->Reserved2 = 0;
3306 pSMB->ParameterOffset = cpu_to_le16(
3307 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3308 pSMB->DataCount = 0;
3309 pSMB->DataOffset = 0;
3310 pSMB->SetupCount = 1;
3311 pSMB->Reserved3 = 0;
3312 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3313 pSMB->SearchHandle = searchHandle; /* always kept as le */
3314 pSMB->SearchCount =
3315 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3316 /* test for Unix extensions */
3317/* if (tcon->ses->capabilities & CAP_UNIX) {
3318 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3319 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3320 } else {
3321 pSMB->InformationLevel =
3322 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3323 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3324 } */
3325 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3326 pSMB->ResumeKey = psrch_inf->resume_key;
3327 pSMB->SearchFlags =
3328 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3329
3330 name_len = psrch_inf->resume_name_len;
3331 params += name_len;
3332 if(name_len < PATH_MAX) {
3333 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3334 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003335 /* 14 byte parm len above enough for 2 byte null terminator */
3336 pSMB->ResumeFileName[name_len] = 0;
3337 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338 } else {
3339 rc = -EINVAL;
3340 goto FNext2_err_exit;
3341 }
3342 byte_count = params + 1 /* pad */ ;
3343 pSMB->TotalParameterCount = cpu_to_le16(params);
3344 pSMB->ParameterCount = pSMB->TotalParameterCount;
3345 pSMB->hdr.smb_buf_length += byte_count;
3346 pSMB->ByteCount = cpu_to_le16(byte_count);
3347
3348 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3349 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003350 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003351 if (rc) {
3352 if (rc == -EBADF) {
3353 psrch_inf->endOfSearch = TRUE;
3354 rc = 0; /* search probably was closed at end of search above */
3355 } else
3356 cFYI(1, ("FindNext returned = %d", rc));
3357 } else { /* decode response */
3358 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3359
3360 if(rc == 0) {
3361 /* BB fixme add lock for file (srch_info) struct here */
3362 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3363 psrch_inf->unicode = TRUE;
3364 else
3365 psrch_inf->unicode = FALSE;
3366 response_data = (char *) &pSMBr->hdr.Protocol +
3367 le16_to_cpu(pSMBr->t2.ParameterOffset);
3368 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3369 response_data = (char *)&pSMBr->hdr.Protocol +
3370 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003371 if(psrch_inf->smallBuf)
3372 cifs_small_buf_release(
3373 psrch_inf->ntwrk_buf_start);
3374 else
3375 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 psrch_inf->srch_entries_start = response_data;
3377 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003378 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 if(parms->EndofSearch)
3380 psrch_inf->endOfSearch = TRUE;
3381 else
3382 psrch_inf->endOfSearch = FALSE;
3383
3384 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3385 psrch_inf->index_of_last_entry +=
3386 psrch_inf->entries_in_buffer;
3387/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3388
3389 /* BB fixme add unlock here */
3390 }
3391
3392 }
3393
3394 /* BB On error, should we leave previous search buf (and count and
3395 last entry fields) intact or free the previous one? */
3396
3397 /* Note: On -EAGAIN error only caller can retry on handle based calls
3398 since file handle passed in no longer valid */
3399FNext2_err_exit:
3400 if (rc != 0)
3401 cifs_buf_release(pSMB);
3402
3403 return rc;
3404}
3405
3406int
3407CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3408{
3409 int rc = 0;
3410 FINDCLOSE_REQ *pSMB = NULL;
3411 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3412 int bytes_returned;
3413
3414 cFYI(1, ("In CIFSSMBFindClose"));
3415 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3416
3417 /* no sense returning error if session restarted
3418 as file handle has been closed */
3419 if(rc == -EAGAIN)
3420 return 0;
3421 if (rc)
3422 return rc;
3423
3424 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3425 pSMB->FileID = searchHandle;
3426 pSMB->ByteCount = 0;
3427 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3428 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3429 if (rc) {
3430 cERROR(1, ("Send error in FindClose = %d", rc));
3431 }
Steve Frencha4544342005-08-24 13:59:35 -07003432 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 cifs_small_buf_release(pSMB);
3434
3435 /* Since session is dead, search handle closed on server already */
3436 if (rc == -EAGAIN)
3437 rc = 0;
3438
3439 return rc;
3440}
3441
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442int
3443CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3444 const unsigned char *searchName,
3445 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003446 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003447{
3448 int rc = 0;
3449 TRANSACTION2_QPI_REQ *pSMB = NULL;
3450 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3451 int name_len, bytes_returned;
3452 __u16 params, byte_count;
3453
3454 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3455 if(tcon == NULL)
3456 return -ENODEV;
3457
3458GetInodeNumberRetry:
3459 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3460 (void **) &pSMBr);
3461 if (rc)
3462 return rc;
3463
3464
3465 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3466 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003467 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003468 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 name_len++; /* trailing null */
3470 name_len *= 2;
3471 } else { /* BB improve the check for buffer overruns BB */
3472 name_len = strnlen(searchName, PATH_MAX);
3473 name_len++; /* trailing null */
3474 strncpy(pSMB->FileName, searchName, name_len);
3475 }
3476
3477 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3478 pSMB->TotalDataCount = 0;
3479 pSMB->MaxParameterCount = cpu_to_le16(2);
3480 /* BB find exact max data count below from sess structure BB */
3481 pSMB->MaxDataCount = cpu_to_le16(4000);
3482 pSMB->MaxSetupCount = 0;
3483 pSMB->Reserved = 0;
3484 pSMB->Flags = 0;
3485 pSMB->Timeout = 0;
3486 pSMB->Reserved2 = 0;
3487 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3488 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3489 pSMB->DataCount = 0;
3490 pSMB->DataOffset = 0;
3491 pSMB->SetupCount = 1;
3492 pSMB->Reserved3 = 0;
3493 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3494 byte_count = params + 1 /* pad */ ;
3495 pSMB->TotalParameterCount = cpu_to_le16(params);
3496 pSMB->ParameterCount = pSMB->TotalParameterCount;
3497 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3498 pSMB->Reserved4 = 0;
3499 pSMB->hdr.smb_buf_length += byte_count;
3500 pSMB->ByteCount = cpu_to_le16(byte_count);
3501
3502 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3503 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3504 if (rc) {
3505 cFYI(1, ("error %d in QueryInternalInfo", rc));
3506 } else {
3507 /* decode response */
3508 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3509 if (rc || (pSMBr->ByteCount < 2))
3510 /* BB also check enough total bytes returned */
3511 /* If rc should we check for EOPNOSUPP and
3512 disable the srvino flag? or in caller? */
3513 rc = -EIO; /* bad smb */
3514 else {
3515 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3516 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3517 struct file_internal_info * pfinfo;
3518 /* BB Do we need a cast or hash here ? */
3519 if(count < 8) {
3520 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3521 rc = -EIO;
3522 goto GetInodeNumOut;
3523 }
3524 pfinfo = (struct file_internal_info *)
3525 (data_offset + (char *) &pSMBr->hdr.Protocol);
3526 *inode_number = pfinfo->UniqueId;
3527 }
3528 }
3529GetInodeNumOut:
3530 cifs_buf_release(pSMB);
3531 if (rc == -EAGAIN)
3532 goto GetInodeNumberRetry;
3533 return rc;
3534}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535
3536int
3537CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3538 const unsigned char *searchName,
3539 unsigned char **targetUNCs,
3540 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003541 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542{
3543/* TRANS2_GET_DFS_REFERRAL */
3544 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3545 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3546 struct dfs_referral_level_3 * referrals = NULL;
3547 int rc = 0;
3548 int bytes_returned;
3549 int name_len;
3550 unsigned int i;
3551 char * temp;
3552 __u16 params, byte_count;
3553 *number_of_UNC_in_array = 0;
3554 *targetUNCs = NULL;
3555
3556 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3557 if (ses == NULL)
3558 return -ENODEV;
3559getDFSRetry:
3560 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3561 (void **) &pSMBr);
3562 if (rc)
3563 return rc;
Steve French1982c342005-08-17 12:38:22 -07003564
3565 /* server pointer checked in called function,
3566 but should never be null here anyway */
3567 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 pSMB->hdr.Tid = ses->ipc_tid;
3569 pSMB->hdr.Uid = ses->Suid;
3570 if (ses->capabilities & CAP_STATUS32) {
3571 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3572 }
3573 if (ses->capabilities & CAP_DFS) {
3574 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3575 }
3576
3577 if (ses->capabilities & CAP_UNICODE) {
3578 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3579 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003580 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003581 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003582 name_len++; /* trailing null */
3583 name_len *= 2;
3584 } else { /* BB improve the check for buffer overruns BB */
3585 name_len = strnlen(searchName, PATH_MAX);
3586 name_len++; /* trailing null */
3587 strncpy(pSMB->RequestFileName, searchName, name_len);
3588 }
3589
3590 params = 2 /* level */ + name_len /*includes null */ ;
3591 pSMB->TotalDataCount = 0;
3592 pSMB->DataCount = 0;
3593 pSMB->DataOffset = 0;
3594 pSMB->MaxParameterCount = 0;
3595 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3596 pSMB->MaxSetupCount = 0;
3597 pSMB->Reserved = 0;
3598 pSMB->Flags = 0;
3599 pSMB->Timeout = 0;
3600 pSMB->Reserved2 = 0;
3601 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3602 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3603 pSMB->SetupCount = 1;
3604 pSMB->Reserved3 = 0;
3605 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3606 byte_count = params + 3 /* pad */ ;
3607 pSMB->ParameterCount = cpu_to_le16(params);
3608 pSMB->TotalParameterCount = pSMB->ParameterCount;
3609 pSMB->MaxReferralLevel = cpu_to_le16(3);
3610 pSMB->hdr.smb_buf_length += byte_count;
3611 pSMB->ByteCount = cpu_to_le16(byte_count);
3612
3613 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3614 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3615 if (rc) {
3616 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3617 } else { /* decode response */
3618/* BB Add logic to parse referrals here */
3619 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3620
3621 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3622 rc = -EIO; /* bad smb */
3623 else {
3624 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3625 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3626
3627 cFYI(1,
3628 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3629 pSMBr->ByteCount, data_offset));
3630 referrals =
3631 (struct dfs_referral_level_3 *)
3632 (8 /* sizeof start of data block */ +
3633 data_offset +
3634 (char *) &pSMBr->hdr.Protocol);
3635 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",
3636 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)));
3637 /* BB This field is actually two bytes in from start of
3638 data block so we could do safety check that DataBlock
3639 begins at address of pSMBr->NumberOfReferrals */
3640 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3641
3642 /* BB Fix below so can return more than one referral */
3643 if(*number_of_UNC_in_array > 1)
3644 *number_of_UNC_in_array = 1;
3645
3646 /* get the length of the strings describing refs */
3647 name_len = 0;
3648 for(i=0;i<*number_of_UNC_in_array;i++) {
3649 /* make sure that DfsPathOffset not past end */
3650 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3651 if (offset > data_count) {
3652 /* if invalid referral, stop here and do
3653 not try to copy any more */
3654 *number_of_UNC_in_array = i;
3655 break;
3656 }
3657 temp = ((char *)referrals) + offset;
3658
3659 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3660 name_len += UniStrnlen((wchar_t *)temp,data_count);
3661 } else {
3662 name_len += strnlen(temp,data_count);
3663 }
3664 referrals++;
3665 /* BB add check that referral pointer does not fall off end PDU */
3666
3667 }
3668 /* BB add check for name_len bigger than bcc */
3669 *targetUNCs =
3670 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3671 if(*targetUNCs == NULL) {
3672 rc = -ENOMEM;
3673 goto GetDFSRefExit;
3674 }
3675 /* copy the ref strings */
3676 referrals =
3677 (struct dfs_referral_level_3 *)
3678 (8 /* sizeof data hdr */ +
3679 data_offset +
3680 (char *) &pSMBr->hdr.Protocol);
3681
3682 for(i=0;i<*number_of_UNC_in_array;i++) {
3683 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3684 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3685 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003686 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 } else {
3688 strncpy(*targetUNCs,temp,name_len);
3689 }
3690 /* BB update target_uncs pointers */
3691 referrals++;
3692 }
3693 temp = *targetUNCs;
3694 temp[name_len] = 0;
3695 }
3696
3697 }
3698GetDFSRefExit:
3699 if (pSMB)
3700 cifs_buf_release(pSMB);
3701
3702 if (rc == -EAGAIN)
3703 goto getDFSRetry;
3704
3705 return rc;
3706}
3707
Steve French20962432005-09-21 22:05:57 -07003708/* Query File System Info such as free space to old servers such as Win 9x */
3709int
3710SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3711{
3712/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3713 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3714 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3715 FILE_SYSTEM_ALLOC_INFO *response_data;
3716 int rc = 0;
3717 int bytes_returned = 0;
3718 __u16 params, byte_count;
3719
3720 cFYI(1, ("OldQFSInfo"));
3721oldQFSInfoRetry:
3722 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3723 (void **) &pSMBr);
3724 if (rc)
3725 return rc;
3726 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3727 (void **) &pSMBr);
3728 if (rc)
3729 return rc;
3730
3731 params = 2; /* level */
3732 pSMB->TotalDataCount = 0;
3733 pSMB->MaxParameterCount = cpu_to_le16(2);
3734 pSMB->MaxDataCount = cpu_to_le16(1000);
3735 pSMB->MaxSetupCount = 0;
3736 pSMB->Reserved = 0;
3737 pSMB->Flags = 0;
3738 pSMB->Timeout = 0;
3739 pSMB->Reserved2 = 0;
3740 byte_count = params + 1 /* pad */ ;
3741 pSMB->TotalParameterCount = cpu_to_le16(params);
3742 pSMB->ParameterCount = pSMB->TotalParameterCount;
3743 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3744 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3745 pSMB->DataCount = 0;
3746 pSMB->DataOffset = 0;
3747 pSMB->SetupCount = 1;
3748 pSMB->Reserved3 = 0;
3749 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3750 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3751 pSMB->hdr.smb_buf_length += byte_count;
3752 pSMB->ByteCount = cpu_to_le16(byte_count);
3753
3754 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3755 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3756 if (rc) {
3757 cFYI(1, ("Send error in QFSInfo = %d", rc));
3758 } else { /* decode response */
3759 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3760
3761 if (rc || (pSMBr->ByteCount < 18))
3762 rc = -EIO; /* bad smb */
3763 else {
3764 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3765 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3766 pSMBr->ByteCount, data_offset));
3767
3768 response_data =
3769 (FILE_SYSTEM_ALLOC_INFO *)
3770 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3771 FSData->f_bsize =
3772 le16_to_cpu(response_data->BytesPerSector) *
3773 le32_to_cpu(response_data->
3774 SectorsPerAllocationUnit);
3775 FSData->f_blocks =
3776 le32_to_cpu(response_data->TotalAllocationUnits);
3777 FSData->f_bfree = FSData->f_bavail =
3778 le32_to_cpu(response_data->FreeAllocationUnits);
3779 cFYI(1,
3780 ("Blocks: %lld Free: %lld Block size %ld",
3781 (unsigned long long)FSData->f_blocks,
3782 (unsigned long long)FSData->f_bfree,
3783 FSData->f_bsize));
3784 }
3785 }
3786 cifs_buf_release(pSMB);
3787
3788 if (rc == -EAGAIN)
3789 goto oldQFSInfoRetry;
3790
3791 return rc;
3792}
3793
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794int
Steve French737b7582005-04-28 22:41:06 -07003795CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796{
3797/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3798 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3799 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3800 FILE_SYSTEM_INFO *response_data;
3801 int rc = 0;
3802 int bytes_returned = 0;
3803 __u16 params, byte_count;
3804
3805 cFYI(1, ("In QFSInfo"));
3806QFSInfoRetry:
3807 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3808 (void **) &pSMBr);
3809 if (rc)
3810 return rc;
3811
3812 params = 2; /* level */
3813 pSMB->TotalDataCount = 0;
3814 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003815 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816 pSMB->MaxSetupCount = 0;
3817 pSMB->Reserved = 0;
3818 pSMB->Flags = 0;
3819 pSMB->Timeout = 0;
3820 pSMB->Reserved2 = 0;
3821 byte_count = params + 1 /* pad */ ;
3822 pSMB->TotalParameterCount = cpu_to_le16(params);
3823 pSMB->ParameterCount = pSMB->TotalParameterCount;
3824 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3825 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3826 pSMB->DataCount = 0;
3827 pSMB->DataOffset = 0;
3828 pSMB->SetupCount = 1;
3829 pSMB->Reserved3 = 0;
3830 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3831 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3832 pSMB->hdr.smb_buf_length += byte_count;
3833 pSMB->ByteCount = cpu_to_le16(byte_count);
3834
3835 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3836 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3837 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003838 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839 } else { /* decode response */
3840 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3841
Steve French20962432005-09-21 22:05:57 -07003842 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 rc = -EIO; /* bad smb */
3844 else {
3845 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846
3847 response_data =
3848 (FILE_SYSTEM_INFO
3849 *) (((char *) &pSMBr->hdr.Protocol) +
3850 data_offset);
3851 FSData->f_bsize =
3852 le32_to_cpu(response_data->BytesPerSector) *
3853 le32_to_cpu(response_data->
3854 SectorsPerAllocationUnit);
3855 FSData->f_blocks =
3856 le64_to_cpu(response_data->TotalAllocationUnits);
3857 FSData->f_bfree = FSData->f_bavail =
3858 le64_to_cpu(response_data->FreeAllocationUnits);
3859 cFYI(1,
3860 ("Blocks: %lld Free: %lld Block size %ld",
3861 (unsigned long long)FSData->f_blocks,
3862 (unsigned long long)FSData->f_bfree,
3863 FSData->f_bsize));
3864 }
3865 }
3866 cifs_buf_release(pSMB);
3867
3868 if (rc == -EAGAIN)
3869 goto QFSInfoRetry;
3870
3871 return rc;
3872}
3873
3874int
Steve French737b7582005-04-28 22:41:06 -07003875CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876{
3877/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3878 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3879 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3880 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3881 int rc = 0;
3882 int bytes_returned = 0;
3883 __u16 params, byte_count;
3884
3885 cFYI(1, ("In QFSAttributeInfo"));
3886QFSAttributeRetry:
3887 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3888 (void **) &pSMBr);
3889 if (rc)
3890 return rc;
3891
3892 params = 2; /* level */
3893 pSMB->TotalDataCount = 0;
3894 pSMB->MaxParameterCount = cpu_to_le16(2);
3895 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3896 pSMB->MaxSetupCount = 0;
3897 pSMB->Reserved = 0;
3898 pSMB->Flags = 0;
3899 pSMB->Timeout = 0;
3900 pSMB->Reserved2 = 0;
3901 byte_count = params + 1 /* pad */ ;
3902 pSMB->TotalParameterCount = cpu_to_le16(params);
3903 pSMB->ParameterCount = pSMB->TotalParameterCount;
3904 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3905 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3906 pSMB->DataCount = 0;
3907 pSMB->DataOffset = 0;
3908 pSMB->SetupCount = 1;
3909 pSMB->Reserved3 = 0;
3910 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3911 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3912 pSMB->hdr.smb_buf_length += byte_count;
3913 pSMB->ByteCount = cpu_to_le16(byte_count);
3914
3915 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3916 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3917 if (rc) {
3918 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3919 } else { /* decode response */
3920 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3921
3922 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3923 rc = -EIO; /* bad smb */
3924 } else {
3925 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3926 response_data =
3927 (FILE_SYSTEM_ATTRIBUTE_INFO
3928 *) (((char *) &pSMBr->hdr.Protocol) +
3929 data_offset);
3930 memcpy(&tcon->fsAttrInfo, response_data,
3931 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3932 }
3933 }
3934 cifs_buf_release(pSMB);
3935
3936 if (rc == -EAGAIN)
3937 goto QFSAttributeRetry;
3938
3939 return rc;
3940}
3941
3942int
Steve French737b7582005-04-28 22:41:06 -07003943CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944{
3945/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3946 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3947 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3948 FILE_SYSTEM_DEVICE_INFO *response_data;
3949 int rc = 0;
3950 int bytes_returned = 0;
3951 __u16 params, byte_count;
3952
3953 cFYI(1, ("In QFSDeviceInfo"));
3954QFSDeviceRetry:
3955 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3956 (void **) &pSMBr);
3957 if (rc)
3958 return rc;
3959
3960 params = 2; /* level */
3961 pSMB->TotalDataCount = 0;
3962 pSMB->MaxParameterCount = cpu_to_le16(2);
3963 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3964 pSMB->MaxSetupCount = 0;
3965 pSMB->Reserved = 0;
3966 pSMB->Flags = 0;
3967 pSMB->Timeout = 0;
3968 pSMB->Reserved2 = 0;
3969 byte_count = params + 1 /* pad */ ;
3970 pSMB->TotalParameterCount = cpu_to_le16(params);
3971 pSMB->ParameterCount = pSMB->TotalParameterCount;
3972 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3973 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3974
3975 pSMB->DataCount = 0;
3976 pSMB->DataOffset = 0;
3977 pSMB->SetupCount = 1;
3978 pSMB->Reserved3 = 0;
3979 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3980 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3981 pSMB->hdr.smb_buf_length += byte_count;
3982 pSMB->ByteCount = cpu_to_le16(byte_count);
3983
3984 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3985 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3986 if (rc) {
3987 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3988 } else { /* decode response */
3989 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3990
3991 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3992 rc = -EIO; /* bad smb */
3993 else {
3994 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3995 response_data =
Steve French737b7582005-04-28 22:41:06 -07003996 (FILE_SYSTEM_DEVICE_INFO *)
3997 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 data_offset);
3999 memcpy(&tcon->fsDevInfo, response_data,
4000 sizeof (FILE_SYSTEM_DEVICE_INFO));
4001 }
4002 }
4003 cifs_buf_release(pSMB);
4004
4005 if (rc == -EAGAIN)
4006 goto QFSDeviceRetry;
4007
4008 return rc;
4009}
4010
4011int
Steve French737b7582005-04-28 22:41:06 -07004012CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013{
4014/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4015 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4016 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4017 FILE_SYSTEM_UNIX_INFO *response_data;
4018 int rc = 0;
4019 int bytes_returned = 0;
4020 __u16 params, byte_count;
4021
4022 cFYI(1, ("In QFSUnixInfo"));
4023QFSUnixRetry:
4024 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4025 (void **) &pSMBr);
4026 if (rc)
4027 return rc;
4028
4029 params = 2; /* level */
4030 pSMB->TotalDataCount = 0;
4031 pSMB->DataCount = 0;
4032 pSMB->DataOffset = 0;
4033 pSMB->MaxParameterCount = cpu_to_le16(2);
4034 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4035 pSMB->MaxSetupCount = 0;
4036 pSMB->Reserved = 0;
4037 pSMB->Flags = 0;
4038 pSMB->Timeout = 0;
4039 pSMB->Reserved2 = 0;
4040 byte_count = params + 1 /* pad */ ;
4041 pSMB->ParameterCount = cpu_to_le16(params);
4042 pSMB->TotalParameterCount = pSMB->ParameterCount;
4043 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4044 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4045 pSMB->SetupCount = 1;
4046 pSMB->Reserved3 = 0;
4047 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4048 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4049 pSMB->hdr.smb_buf_length += byte_count;
4050 pSMB->ByteCount = cpu_to_le16(byte_count);
4051
4052 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4053 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4054 if (rc) {
4055 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4056 } else { /* decode response */
4057 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4058
4059 if (rc || (pSMBr->ByteCount < 13)) {
4060 rc = -EIO; /* bad smb */
4061 } else {
4062 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4063 response_data =
4064 (FILE_SYSTEM_UNIX_INFO
4065 *) (((char *) &pSMBr->hdr.Protocol) +
4066 data_offset);
4067 memcpy(&tcon->fsUnixInfo, response_data,
4068 sizeof (FILE_SYSTEM_UNIX_INFO));
4069 }
4070 }
4071 cifs_buf_release(pSMB);
4072
4073 if (rc == -EAGAIN)
4074 goto QFSUnixRetry;
4075
4076
4077 return rc;
4078}
4079
Jeremy Allisonac670552005-06-22 17:26:35 -07004080int
Steve French45abc6e2005-06-23 13:42:03 -05004081CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004082{
4083/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4084 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4085 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4086 int rc = 0;
4087 int bytes_returned = 0;
4088 __u16 params, param_offset, offset, byte_count;
4089
4090 cFYI(1, ("In SETFSUnixInfo"));
4091SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004092 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004093 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4094 (void **) &pSMBr);
4095 if (rc)
4096 return rc;
4097
4098 params = 4; /* 2 bytes zero followed by info level. */
4099 pSMB->MaxSetupCount = 0;
4100 pSMB->Reserved = 0;
4101 pSMB->Flags = 0;
4102 pSMB->Timeout = 0;
4103 pSMB->Reserved2 = 0;
4104 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4105 offset = param_offset + params;
4106
4107 pSMB->MaxParameterCount = cpu_to_le16(4);
4108 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4109 pSMB->SetupCount = 1;
4110 pSMB->Reserved3 = 0;
4111 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4112 byte_count = 1 /* pad */ + params + 12;
4113
4114 pSMB->DataCount = cpu_to_le16(12);
4115 pSMB->ParameterCount = cpu_to_le16(params);
4116 pSMB->TotalDataCount = pSMB->DataCount;
4117 pSMB->TotalParameterCount = pSMB->ParameterCount;
4118 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4119 pSMB->DataOffset = cpu_to_le16(offset);
4120
4121 /* Params. */
4122 pSMB->FileNum = 0;
4123 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4124
4125 /* Data. */
4126 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4127 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4128 pSMB->ClientUnixCap = cpu_to_le64(cap);
4129
4130 pSMB->hdr.smb_buf_length += byte_count;
4131 pSMB->ByteCount = cpu_to_le16(byte_count);
4132
4133 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4134 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4135 if (rc) {
4136 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4137 } else { /* decode response */
4138 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4139 if (rc) {
4140 rc = -EIO; /* bad smb */
4141 }
4142 }
4143 cifs_buf_release(pSMB);
4144
4145 if (rc == -EAGAIN)
4146 goto SETFSUnixRetry;
4147
4148 return rc;
4149}
4150
4151
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152
4153int
4154CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004155 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156{
4157/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4158 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4159 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4160 FILE_SYSTEM_POSIX_INFO *response_data;
4161 int rc = 0;
4162 int bytes_returned = 0;
4163 __u16 params, byte_count;
4164
4165 cFYI(1, ("In QFSPosixInfo"));
4166QFSPosixRetry:
4167 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4168 (void **) &pSMBr);
4169 if (rc)
4170 return rc;
4171
4172 params = 2; /* level */
4173 pSMB->TotalDataCount = 0;
4174 pSMB->DataCount = 0;
4175 pSMB->DataOffset = 0;
4176 pSMB->MaxParameterCount = cpu_to_le16(2);
4177 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4178 pSMB->MaxSetupCount = 0;
4179 pSMB->Reserved = 0;
4180 pSMB->Flags = 0;
4181 pSMB->Timeout = 0;
4182 pSMB->Reserved2 = 0;
4183 byte_count = params + 1 /* pad */ ;
4184 pSMB->ParameterCount = cpu_to_le16(params);
4185 pSMB->TotalParameterCount = pSMB->ParameterCount;
4186 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4187 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4188 pSMB->SetupCount = 1;
4189 pSMB->Reserved3 = 0;
4190 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4191 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4192 pSMB->hdr.smb_buf_length += byte_count;
4193 pSMB->ByteCount = cpu_to_le16(byte_count);
4194
4195 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4196 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4197 if (rc) {
4198 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4199 } else { /* decode response */
4200 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4201
4202 if (rc || (pSMBr->ByteCount < 13)) {
4203 rc = -EIO; /* bad smb */
4204 } else {
4205 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4206 response_data =
4207 (FILE_SYSTEM_POSIX_INFO
4208 *) (((char *) &pSMBr->hdr.Protocol) +
4209 data_offset);
4210 FSData->f_bsize =
4211 le32_to_cpu(response_data->BlockSize);
4212 FSData->f_blocks =
4213 le64_to_cpu(response_data->TotalBlocks);
4214 FSData->f_bfree =
4215 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004216 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 FSData->f_bavail = FSData->f_bfree;
4218 } else {
4219 FSData->f_bavail =
4220 le64_to_cpu(response_data->UserBlocksAvail);
4221 }
Steve French70ca7342005-09-22 16:32:06 -07004222 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 FSData->f_files =
4224 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004225 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 FSData->f_ffree =
4227 le64_to_cpu(response_data->FreeFileNodes);
4228 }
4229 }
4230 cifs_buf_release(pSMB);
4231
4232 if (rc == -EAGAIN)
4233 goto QFSPosixRetry;
4234
4235 return rc;
4236}
4237
4238
4239/* We can not use write of zero bytes trick to
4240 set file size due to need for large file support. Also note that
4241 this SetPathInfo is preferred to SetFileInfo based method in next
4242 routine which is only needed to work around a sharing violation bug
4243 in Samba which this routine can run into */
4244
4245int
4246CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004247 __u64 size, int SetAllocation,
4248 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249{
4250 struct smb_com_transaction2_spi_req *pSMB = NULL;
4251 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4252 struct file_end_of_file_info *parm_data;
4253 int name_len;
4254 int rc = 0;
4255 int bytes_returned = 0;
4256 __u16 params, byte_count, data_count, param_offset, offset;
4257
4258 cFYI(1, ("In SetEOF"));
4259SetEOFRetry:
4260 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4261 (void **) &pSMBr);
4262 if (rc)
4263 return rc;
4264
4265 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4266 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004267 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004268 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 name_len++; /* trailing null */
4270 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004271 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004272 name_len = strnlen(fileName, PATH_MAX);
4273 name_len++; /* trailing null */
4274 strncpy(pSMB->FileName, fileName, name_len);
4275 }
4276 params = 6 + name_len;
4277 data_count = sizeof (struct file_end_of_file_info);
4278 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004279 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280 pSMB->MaxSetupCount = 0;
4281 pSMB->Reserved = 0;
4282 pSMB->Flags = 0;
4283 pSMB->Timeout = 0;
4284 pSMB->Reserved2 = 0;
4285 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4286 InformationLevel) - 4;
4287 offset = param_offset + params;
4288 if(SetAllocation) {
4289 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4290 pSMB->InformationLevel =
4291 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4292 else
4293 pSMB->InformationLevel =
4294 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4295 } else /* Set File Size */ {
4296 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4297 pSMB->InformationLevel =
4298 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4299 else
4300 pSMB->InformationLevel =
4301 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4302 }
4303
4304 parm_data =
4305 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4306 offset);
4307 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4308 pSMB->DataOffset = cpu_to_le16(offset);
4309 pSMB->SetupCount = 1;
4310 pSMB->Reserved3 = 0;
4311 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4312 byte_count = 3 /* pad */ + params + data_count;
4313 pSMB->DataCount = cpu_to_le16(data_count);
4314 pSMB->TotalDataCount = pSMB->DataCount;
4315 pSMB->ParameterCount = cpu_to_le16(params);
4316 pSMB->TotalParameterCount = pSMB->ParameterCount;
4317 pSMB->Reserved4 = 0;
4318 pSMB->hdr.smb_buf_length += byte_count;
4319 parm_data->FileSize = cpu_to_le64(size);
4320 pSMB->ByteCount = cpu_to_le16(byte_count);
4321 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4322 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4323 if (rc) {
4324 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4325 }
4326
4327 cifs_buf_release(pSMB);
4328
4329 if (rc == -EAGAIN)
4330 goto SetEOFRetry;
4331
4332 return rc;
4333}
4334
4335int
4336CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4337 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4338{
4339 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4340 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4341 char *data_offset;
4342 struct file_end_of_file_info *parm_data;
4343 int rc = 0;
4344 int bytes_returned = 0;
4345 __u16 params, param_offset, offset, byte_count, count;
4346
4347 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4348 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004349 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4350
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351 if (rc)
4352 return rc;
4353
Steve Frenchcd634992005-04-28 22:41:10 -07004354 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4355
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4357 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4358
4359 params = 6;
4360 pSMB->MaxSetupCount = 0;
4361 pSMB->Reserved = 0;
4362 pSMB->Flags = 0;
4363 pSMB->Timeout = 0;
4364 pSMB->Reserved2 = 0;
4365 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4366 offset = param_offset + params;
4367
4368 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4369
4370 count = sizeof(struct file_end_of_file_info);
4371 pSMB->MaxParameterCount = cpu_to_le16(2);
4372 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4373 pSMB->SetupCount = 1;
4374 pSMB->Reserved3 = 0;
4375 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4376 byte_count = 3 /* pad */ + params + count;
4377 pSMB->DataCount = cpu_to_le16(count);
4378 pSMB->ParameterCount = cpu_to_le16(params);
4379 pSMB->TotalDataCount = pSMB->DataCount;
4380 pSMB->TotalParameterCount = pSMB->ParameterCount;
4381 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4382 parm_data =
4383 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4384 offset);
4385 pSMB->DataOffset = cpu_to_le16(offset);
4386 parm_data->FileSize = cpu_to_le64(size);
4387 pSMB->Fid = fid;
4388 if(SetAllocation) {
4389 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4390 pSMB->InformationLevel =
4391 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4392 else
4393 pSMB->InformationLevel =
4394 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4395 } else /* Set File Size */ {
4396 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4397 pSMB->InformationLevel =
4398 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4399 else
4400 pSMB->InformationLevel =
4401 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4402 }
4403 pSMB->Reserved4 = 0;
4404 pSMB->hdr.smb_buf_length += byte_count;
4405 pSMB->ByteCount = cpu_to_le16(byte_count);
4406 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4407 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4408 if (rc) {
4409 cFYI(1,
4410 ("Send error in SetFileInfo (SetFileSize) = %d",
4411 rc));
4412 }
4413
4414 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004415 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416
4417 /* Note: On -EAGAIN error only caller can retry on handle based calls
4418 since file handle passed in no longer valid */
4419
4420 return rc;
4421}
4422
4423/* Some legacy servers such as NT4 require that the file times be set on
4424 an open handle, rather than by pathname - this is awkward due to
4425 potential access conflicts on the open, but it is unavoidable for these
4426 old servers since the only other choice is to go from 100 nanosecond DCE
4427 time and resort to the original setpathinfo level which takes the ancient
4428 DOS time format with 2 second granularity */
4429int
4430CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4431 __u16 fid)
4432{
4433 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4434 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4435 char *data_offset;
4436 int rc = 0;
4437 int bytes_returned = 0;
4438 __u16 params, param_offset, offset, byte_count, count;
4439
4440 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004441 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4442
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443 if (rc)
4444 return rc;
4445
Steve Frenchcd634992005-04-28 22:41:10 -07004446 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4447
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 /* At this point there is no need to override the current pid
4449 with the pid of the opener, but that could change if we someday
4450 use an existing handle (rather than opening one on the fly) */
4451 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4452 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4453
4454 params = 6;
4455 pSMB->MaxSetupCount = 0;
4456 pSMB->Reserved = 0;
4457 pSMB->Flags = 0;
4458 pSMB->Timeout = 0;
4459 pSMB->Reserved2 = 0;
4460 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4461 offset = param_offset + params;
4462
4463 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4464
4465 count = sizeof (FILE_BASIC_INFO);
4466 pSMB->MaxParameterCount = cpu_to_le16(2);
4467 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4468 pSMB->SetupCount = 1;
4469 pSMB->Reserved3 = 0;
4470 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4471 byte_count = 3 /* pad */ + params + count;
4472 pSMB->DataCount = cpu_to_le16(count);
4473 pSMB->ParameterCount = cpu_to_le16(params);
4474 pSMB->TotalDataCount = pSMB->DataCount;
4475 pSMB->TotalParameterCount = pSMB->ParameterCount;
4476 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4477 pSMB->DataOffset = cpu_to_le16(offset);
4478 pSMB->Fid = fid;
4479 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4480 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4481 else
4482 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4483 pSMB->Reserved4 = 0;
4484 pSMB->hdr.smb_buf_length += byte_count;
4485 pSMB->ByteCount = cpu_to_le16(byte_count);
4486 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4487 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4488 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4489 if (rc) {
4490 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4491 }
4492
Steve Frenchcd634992005-04-28 22:41:10 -07004493 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494
4495 /* Note: On -EAGAIN error only caller can retry on handle based calls
4496 since file handle passed in no longer valid */
4497
4498 return rc;
4499}
4500
4501
4502int
4503CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4504 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004505 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004506{
4507 TRANSACTION2_SPI_REQ *pSMB = NULL;
4508 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4509 int name_len;
4510 int rc = 0;
4511 int bytes_returned = 0;
4512 char *data_offset;
4513 __u16 params, param_offset, offset, byte_count, count;
4514
4515 cFYI(1, ("In SetTimes"));
4516
4517SetTimesRetry:
4518 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4519 (void **) &pSMBr);
4520 if (rc)
4521 return rc;
4522
4523 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4524 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004525 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004526 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004527 name_len++; /* trailing null */
4528 name_len *= 2;
4529 } else { /* BB improve the check for buffer overruns BB */
4530 name_len = strnlen(fileName, PATH_MAX);
4531 name_len++; /* trailing null */
4532 strncpy(pSMB->FileName, fileName, name_len);
4533 }
4534
4535 params = 6 + name_len;
4536 count = sizeof (FILE_BASIC_INFO);
4537 pSMB->MaxParameterCount = cpu_to_le16(2);
4538 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4539 pSMB->MaxSetupCount = 0;
4540 pSMB->Reserved = 0;
4541 pSMB->Flags = 0;
4542 pSMB->Timeout = 0;
4543 pSMB->Reserved2 = 0;
4544 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4545 InformationLevel) - 4;
4546 offset = param_offset + params;
4547 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4548 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4549 pSMB->DataOffset = cpu_to_le16(offset);
4550 pSMB->SetupCount = 1;
4551 pSMB->Reserved3 = 0;
4552 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4553 byte_count = 3 /* pad */ + params + count;
4554
4555 pSMB->DataCount = cpu_to_le16(count);
4556 pSMB->ParameterCount = cpu_to_le16(params);
4557 pSMB->TotalDataCount = pSMB->DataCount;
4558 pSMB->TotalParameterCount = pSMB->ParameterCount;
4559 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4560 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4561 else
4562 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4563 pSMB->Reserved4 = 0;
4564 pSMB->hdr.smb_buf_length += byte_count;
4565 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4566 pSMB->ByteCount = cpu_to_le16(byte_count);
4567 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4568 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4569 if (rc) {
4570 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4571 }
4572
4573 cifs_buf_release(pSMB);
4574
4575 if (rc == -EAGAIN)
4576 goto SetTimesRetry;
4577
4578 return rc;
4579}
4580
4581/* Can not be used to set time stamps yet (due to old DOS time format) */
4582/* Can be used to set attributes */
4583#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4584 handling it anyway and NT4 was what we thought it would be needed for
4585 Do not delete it until we prove whether needed for Win9x though */
4586int
4587CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4588 __u16 dos_attrs, const struct nls_table *nls_codepage)
4589{
4590 SETATTR_REQ *pSMB = NULL;
4591 SETATTR_RSP *pSMBr = NULL;
4592 int rc = 0;
4593 int bytes_returned;
4594 int name_len;
4595
4596 cFYI(1, ("In SetAttrLegacy"));
4597
4598SetAttrLgcyRetry:
4599 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4600 (void **) &pSMBr);
4601 if (rc)
4602 return rc;
4603
4604 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4605 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004606 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 PATH_MAX, nls_codepage);
4608 name_len++; /* trailing null */
4609 name_len *= 2;
4610 } else { /* BB improve the check for buffer overruns BB */
4611 name_len = strnlen(fileName, PATH_MAX);
4612 name_len++; /* trailing null */
4613 strncpy(pSMB->fileName, fileName, name_len);
4614 }
4615 pSMB->attr = cpu_to_le16(dos_attrs);
4616 pSMB->BufferFormat = 0x04;
4617 pSMB->hdr.smb_buf_length += name_len + 1;
4618 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4619 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4620 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4621 if (rc) {
4622 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4623 }
4624
4625 cifs_buf_release(pSMB);
4626
4627 if (rc == -EAGAIN)
4628 goto SetAttrLgcyRetry;
4629
4630 return rc;
4631}
4632#endif /* temporarily unneeded SetAttr legacy function */
4633
4634int
4635CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004636 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4637 dev_t device, const struct nls_table *nls_codepage,
4638 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004639{
4640 TRANSACTION2_SPI_REQ *pSMB = NULL;
4641 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4642 int name_len;
4643 int rc = 0;
4644 int bytes_returned = 0;
4645 FILE_UNIX_BASIC_INFO *data_offset;
4646 __u16 params, param_offset, offset, count, byte_count;
4647
4648 cFYI(1, ("In SetUID/GID/Mode"));
4649setPermsRetry:
4650 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4651 (void **) &pSMBr);
4652 if (rc)
4653 return rc;
4654
4655 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4656 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004657 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004658 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004659 name_len++; /* trailing null */
4660 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004661 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004662 name_len = strnlen(fileName, PATH_MAX);
4663 name_len++; /* trailing null */
4664 strncpy(pSMB->FileName, fileName, name_len);
4665 }
4666
4667 params = 6 + name_len;
4668 count = sizeof (FILE_UNIX_BASIC_INFO);
4669 pSMB->MaxParameterCount = cpu_to_le16(2);
4670 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4671 pSMB->MaxSetupCount = 0;
4672 pSMB->Reserved = 0;
4673 pSMB->Flags = 0;
4674 pSMB->Timeout = 0;
4675 pSMB->Reserved2 = 0;
4676 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4677 InformationLevel) - 4;
4678 offset = param_offset + params;
4679 data_offset =
4680 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4681 offset);
4682 memset(data_offset, 0, count);
4683 pSMB->DataOffset = cpu_to_le16(offset);
4684 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4685 pSMB->SetupCount = 1;
4686 pSMB->Reserved3 = 0;
4687 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4688 byte_count = 3 /* pad */ + params + count;
4689 pSMB->ParameterCount = cpu_to_le16(params);
4690 pSMB->DataCount = cpu_to_le16(count);
4691 pSMB->TotalParameterCount = pSMB->ParameterCount;
4692 pSMB->TotalDataCount = pSMB->DataCount;
4693 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4694 pSMB->Reserved4 = 0;
4695 pSMB->hdr.smb_buf_length += byte_count;
4696 data_offset->Uid = cpu_to_le64(uid);
4697 data_offset->Gid = cpu_to_le64(gid);
4698 /* better to leave device as zero when it is */
4699 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4700 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4701 data_offset->Permissions = cpu_to_le64(mode);
4702
4703 if(S_ISREG(mode))
4704 data_offset->Type = cpu_to_le32(UNIX_FILE);
4705 else if(S_ISDIR(mode))
4706 data_offset->Type = cpu_to_le32(UNIX_DIR);
4707 else if(S_ISLNK(mode))
4708 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4709 else if(S_ISCHR(mode))
4710 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4711 else if(S_ISBLK(mode))
4712 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4713 else if(S_ISFIFO(mode))
4714 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4715 else if(S_ISSOCK(mode))
4716 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4717
4718
4719 pSMB->ByteCount = cpu_to_le16(byte_count);
4720 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4721 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4722 if (rc) {
4723 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4724 }
4725
4726 if (pSMB)
4727 cifs_buf_release(pSMB);
4728 if (rc == -EAGAIN)
4729 goto setPermsRetry;
4730 return rc;
4731}
4732
4733int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004734 const int notify_subdirs, const __u16 netfid,
4735 __u32 filter, struct file * pfile, int multishot,
4736 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737{
4738 int rc = 0;
4739 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004740 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004741 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 int bytes_returned;
4743
4744 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4745 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4746 (void **) &pSMBr);
4747 if (rc)
4748 return rc;
4749
4750 pSMB->TotalParameterCount = 0 ;
4751 pSMB->TotalDataCount = 0;
4752 pSMB->MaxParameterCount = cpu_to_le32(2);
4753 /* BB find exact data count max from sess structure BB */
4754 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004755/* BB VERIFY verify which is correct for above BB */
4756 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4757 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4758
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 pSMB->MaxSetupCount = 4;
4760 pSMB->Reserved = 0;
4761 pSMB->ParameterOffset = 0;
4762 pSMB->DataCount = 0;
4763 pSMB->DataOffset = 0;
4764 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4765 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4766 pSMB->ParameterCount = pSMB->TotalParameterCount;
4767 if(notify_subdirs)
4768 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4769 pSMB->Reserved2 = 0;
4770 pSMB->CompletionFilter = cpu_to_le32(filter);
4771 pSMB->Fid = netfid; /* file handle always le */
4772 pSMB->ByteCount = 0;
4773
4774 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4775 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4776 if (rc) {
4777 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004778 } else {
4779 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004780 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004781 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004782 sizeof(struct dir_notify_req),
4783 GFP_KERNEL);
4784 if(dnotify_req) {
4785 dnotify_req->Pid = pSMB->hdr.Pid;
4786 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4787 dnotify_req->Mid = pSMB->hdr.Mid;
4788 dnotify_req->Tid = pSMB->hdr.Tid;
4789 dnotify_req->Uid = pSMB->hdr.Uid;
4790 dnotify_req->netfid = netfid;
4791 dnotify_req->pfile = pfile;
4792 dnotify_req->filter = filter;
4793 dnotify_req->multishot = multishot;
4794 spin_lock(&GlobalMid_Lock);
4795 list_add_tail(&dnotify_req->lhead,
4796 &GlobalDnotifyReqList);
4797 spin_unlock(&GlobalMid_Lock);
4798 } else
4799 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 }
4801 cifs_buf_release(pSMB);
4802 return rc;
4803}
4804#ifdef CONFIG_CIFS_XATTR
4805ssize_t
4806CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4807 const unsigned char *searchName,
4808 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004809 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810{
4811 /* BB assumes one setup word */
4812 TRANSACTION2_QPI_REQ *pSMB = NULL;
4813 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4814 int rc = 0;
4815 int bytes_returned;
4816 int name_len;
4817 struct fea * temp_fea;
4818 char * temp_ptr;
4819 __u16 params, byte_count;
4820
4821 cFYI(1, ("In Query All EAs path %s", searchName));
4822QAllEAsRetry:
4823 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4824 (void **) &pSMBr);
4825 if (rc)
4826 return rc;
4827
4828 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4829 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004830 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004831 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 name_len++; /* trailing null */
4833 name_len *= 2;
4834 } else { /* BB improve the check for buffer overruns BB */
4835 name_len = strnlen(searchName, PATH_MAX);
4836 name_len++; /* trailing null */
4837 strncpy(pSMB->FileName, searchName, name_len);
4838 }
4839
4840 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4841 pSMB->TotalDataCount = 0;
4842 pSMB->MaxParameterCount = cpu_to_le16(2);
4843 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4844 pSMB->MaxSetupCount = 0;
4845 pSMB->Reserved = 0;
4846 pSMB->Flags = 0;
4847 pSMB->Timeout = 0;
4848 pSMB->Reserved2 = 0;
4849 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4850 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4851 pSMB->DataCount = 0;
4852 pSMB->DataOffset = 0;
4853 pSMB->SetupCount = 1;
4854 pSMB->Reserved3 = 0;
4855 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4856 byte_count = params + 1 /* pad */ ;
4857 pSMB->TotalParameterCount = cpu_to_le16(params);
4858 pSMB->ParameterCount = pSMB->TotalParameterCount;
4859 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4860 pSMB->Reserved4 = 0;
4861 pSMB->hdr.smb_buf_length += byte_count;
4862 pSMB->ByteCount = cpu_to_le16(byte_count);
4863
4864 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4865 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4866 if (rc) {
4867 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4868 } else { /* decode response */
4869 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4870
4871 /* BB also check enough total bytes returned */
4872 /* BB we need to improve the validity checking
4873 of these trans2 responses */
4874 if (rc || (pSMBr->ByteCount < 4))
4875 rc = -EIO; /* bad smb */
4876 /* else if (pFindData){
4877 memcpy((char *) pFindData,
4878 (char *) &pSMBr->hdr.Protocol +
4879 data_offset, kl);
4880 }*/ else {
4881 /* check that length of list is not more than bcc */
4882 /* check that each entry does not go beyond length
4883 of list */
4884 /* check that each element of each entry does not
4885 go beyond end of list */
4886 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4887 struct fealist * ea_response_data;
4888 rc = 0;
4889 /* validate_trans2_offsets() */
4890 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4891 ea_response_data = (struct fealist *)
4892 (((char *) &pSMBr->hdr.Protocol) +
4893 data_offset);
4894 name_len = le32_to_cpu(ea_response_data->list_len);
4895 cFYI(1,("ea length %d", name_len));
4896 if(name_len <= 8) {
4897 /* returned EA size zeroed at top of function */
4898 cFYI(1,("empty EA list returned from server"));
4899 } else {
4900 /* account for ea list len */
4901 name_len -= 4;
4902 temp_fea = ea_response_data->list;
4903 temp_ptr = (char *)temp_fea;
4904 while(name_len > 0) {
4905 __u16 value_len;
4906 name_len -= 4;
4907 temp_ptr += 4;
4908 rc += temp_fea->name_len;
4909 /* account for prefix user. and trailing null */
4910 rc = rc + 5 + 1;
4911 if(rc<(int)buf_size) {
4912 memcpy(EAData,"user.",5);
4913 EAData+=5;
4914 memcpy(EAData,temp_ptr,temp_fea->name_len);
4915 EAData+=temp_fea->name_len;
4916 /* null terminate name */
4917 *EAData = 0;
4918 EAData = EAData + 1;
4919 } else if(buf_size == 0) {
4920 /* skip copy - calc size only */
4921 } else {
4922 /* stop before overrun buffer */
4923 rc = -ERANGE;
4924 break;
4925 }
4926 name_len -= temp_fea->name_len;
4927 temp_ptr += temp_fea->name_len;
4928 /* account for trailing null */
4929 name_len--;
4930 temp_ptr++;
4931 value_len = le16_to_cpu(temp_fea->value_len);
4932 name_len -= value_len;
4933 temp_ptr += value_len;
4934 /* BB check that temp_ptr is still within smb BB*/
4935 /* no trailing null to account for in value len */
4936 /* go on to next EA */
4937 temp_fea = (struct fea *)temp_ptr;
4938 }
4939 }
4940 }
4941 }
4942 if (pSMB)
4943 cifs_buf_release(pSMB);
4944 if (rc == -EAGAIN)
4945 goto QAllEAsRetry;
4946
4947 return (ssize_t)rc;
4948}
4949
4950ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4951 const unsigned char * searchName,const unsigned char * ea_name,
4952 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004953 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004954{
4955 TRANSACTION2_QPI_REQ *pSMB = NULL;
4956 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4957 int rc = 0;
4958 int bytes_returned;
4959 int name_len;
4960 struct fea * temp_fea;
4961 char * temp_ptr;
4962 __u16 params, byte_count;
4963
4964 cFYI(1, ("In Query EA path %s", searchName));
4965QEARetry:
4966 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4967 (void **) &pSMBr);
4968 if (rc)
4969 return rc;
4970
4971 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4972 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004973 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004974 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975 name_len++; /* trailing null */
4976 name_len *= 2;
4977 } else { /* BB improve the check for buffer overruns BB */
4978 name_len = strnlen(searchName, PATH_MAX);
4979 name_len++; /* trailing null */
4980 strncpy(pSMB->FileName, searchName, name_len);
4981 }
4982
4983 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4984 pSMB->TotalDataCount = 0;
4985 pSMB->MaxParameterCount = cpu_to_le16(2);
4986 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4987 pSMB->MaxSetupCount = 0;
4988 pSMB->Reserved = 0;
4989 pSMB->Flags = 0;
4990 pSMB->Timeout = 0;
4991 pSMB->Reserved2 = 0;
4992 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4993 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4994 pSMB->DataCount = 0;
4995 pSMB->DataOffset = 0;
4996 pSMB->SetupCount = 1;
4997 pSMB->Reserved3 = 0;
4998 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4999 byte_count = params + 1 /* pad */ ;
5000 pSMB->TotalParameterCount = cpu_to_le16(params);
5001 pSMB->ParameterCount = pSMB->TotalParameterCount;
5002 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5003 pSMB->Reserved4 = 0;
5004 pSMB->hdr.smb_buf_length += byte_count;
5005 pSMB->ByteCount = cpu_to_le16(byte_count);
5006
5007 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5008 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5009 if (rc) {
5010 cFYI(1, ("Send error in Query EA = %d", rc));
5011 } else { /* decode response */
5012 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5013
5014 /* BB also check enough total bytes returned */
5015 /* BB we need to improve the validity checking
5016 of these trans2 responses */
5017 if (rc || (pSMBr->ByteCount < 4))
5018 rc = -EIO; /* bad smb */
5019 /* else if (pFindData){
5020 memcpy((char *) pFindData,
5021 (char *) &pSMBr->hdr.Protocol +
5022 data_offset, kl);
5023 }*/ else {
5024 /* check that length of list is not more than bcc */
5025 /* check that each entry does not go beyond length
5026 of list */
5027 /* check that each element of each entry does not
5028 go beyond end of list */
5029 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5030 struct fealist * ea_response_data;
5031 rc = -ENODATA;
5032 /* validate_trans2_offsets() */
5033 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5034 ea_response_data = (struct fealist *)
5035 (((char *) &pSMBr->hdr.Protocol) +
5036 data_offset);
5037 name_len = le32_to_cpu(ea_response_data->list_len);
5038 cFYI(1,("ea length %d", name_len));
5039 if(name_len <= 8) {
5040 /* returned EA size zeroed at top of function */
5041 cFYI(1,("empty EA list returned from server"));
5042 } else {
5043 /* account for ea list len */
5044 name_len -= 4;
5045 temp_fea = ea_response_data->list;
5046 temp_ptr = (char *)temp_fea;
5047 /* loop through checking if we have a matching
5048 name and then return the associated value */
5049 while(name_len > 0) {
5050 __u16 value_len;
5051 name_len -= 4;
5052 temp_ptr += 4;
5053 value_len = le16_to_cpu(temp_fea->value_len);
5054 /* BB validate that value_len falls within SMB,
5055 even though maximum for name_len is 255 */
5056 if(memcmp(temp_fea->name,ea_name,
5057 temp_fea->name_len) == 0) {
5058 /* found a match */
5059 rc = value_len;
5060 /* account for prefix user. and trailing null */
5061 if(rc<=(int)buf_size) {
5062 memcpy(ea_value,
5063 temp_fea->name+temp_fea->name_len+1,
5064 rc);
5065 /* ea values, unlike ea names,
5066 are not null terminated */
5067 } else if(buf_size == 0) {
5068 /* skip copy - calc size only */
5069 } else {
5070 /* stop before overrun buffer */
5071 rc = -ERANGE;
5072 }
5073 break;
5074 }
5075 name_len -= temp_fea->name_len;
5076 temp_ptr += temp_fea->name_len;
5077 /* account for trailing null */
5078 name_len--;
5079 temp_ptr++;
5080 name_len -= value_len;
5081 temp_ptr += value_len;
5082 /* no trailing null to account for in value len */
5083 /* go on to next EA */
5084 temp_fea = (struct fea *)temp_ptr;
5085 }
5086 }
5087 }
5088 }
5089 if (pSMB)
5090 cifs_buf_release(pSMB);
5091 if (rc == -EAGAIN)
5092 goto QEARetry;
5093
5094 return (ssize_t)rc;
5095}
5096
5097int
5098CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5099 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005100 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5101 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005102{
5103 struct smb_com_transaction2_spi_req *pSMB = NULL;
5104 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5105 struct fealist *parm_data;
5106 int name_len;
5107 int rc = 0;
5108 int bytes_returned = 0;
5109 __u16 params, param_offset, byte_count, offset, count;
5110
5111 cFYI(1, ("In SetEA"));
5112SetEARetry:
5113 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5114 (void **) &pSMBr);
5115 if (rc)
5116 return rc;
5117
5118 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5119 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005120 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005121 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122 name_len++; /* trailing null */
5123 name_len *= 2;
5124 } else { /* BB improve the check for buffer overruns BB */
5125 name_len = strnlen(fileName, PATH_MAX);
5126 name_len++; /* trailing null */
5127 strncpy(pSMB->FileName, fileName, name_len);
5128 }
5129
5130 params = 6 + name_len;
5131
5132 /* done calculating parms using name_len of file name,
5133 now use name_len to calculate length of ea name
5134 we are going to create in the inode xattrs */
5135 if(ea_name == NULL)
5136 name_len = 0;
5137 else
5138 name_len = strnlen(ea_name,255);
5139
5140 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5141 pSMB->MaxParameterCount = cpu_to_le16(2);
5142 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5143 pSMB->MaxSetupCount = 0;
5144 pSMB->Reserved = 0;
5145 pSMB->Flags = 0;
5146 pSMB->Timeout = 0;
5147 pSMB->Reserved2 = 0;
5148 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5149 InformationLevel) - 4;
5150 offset = param_offset + params;
5151 pSMB->InformationLevel =
5152 cpu_to_le16(SMB_SET_FILE_EA);
5153
5154 parm_data =
5155 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5156 offset);
5157 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5158 pSMB->DataOffset = cpu_to_le16(offset);
5159 pSMB->SetupCount = 1;
5160 pSMB->Reserved3 = 0;
5161 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5162 byte_count = 3 /* pad */ + params + count;
5163 pSMB->DataCount = cpu_to_le16(count);
5164 parm_data->list_len = cpu_to_le32(count);
5165 parm_data->list[0].EA_flags = 0;
5166 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005167 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005168 /* EA names are always ASCII */
5169 if(ea_name)
5170 strncpy(parm_data->list[0].name,ea_name,name_len);
5171 parm_data->list[0].name[name_len] = 0;
5172 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5173 /* caller ensures that ea_value_len is less than 64K but
5174 we need to ensure that it fits within the smb */
5175
5176 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5177 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5178 if(ea_value_len)
5179 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5180
5181 pSMB->TotalDataCount = pSMB->DataCount;
5182 pSMB->ParameterCount = cpu_to_le16(params);
5183 pSMB->TotalParameterCount = pSMB->ParameterCount;
5184 pSMB->Reserved4 = 0;
5185 pSMB->hdr.smb_buf_length += byte_count;
5186 pSMB->ByteCount = cpu_to_le16(byte_count);
5187 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5188 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5189 if (rc) {
5190 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5191 }
5192
5193 cifs_buf_release(pSMB);
5194
5195 if (rc == -EAGAIN)
5196 goto SetEARetry;
5197
5198 return rc;
5199}
5200
5201#endif