blob: 1620991cd4d280593301d99ab00e49d210a27798 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
4 * Copyright (C) International Business Machines Corp., 2002,2005
5 * 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"
40
41#ifdef CONFIG_CIFS_POSIX
42static struct {
43 int index;
44 char *name;
45} protocols[] = {
46 {CIFS_PROT, "\2NT LM 0.12"},
47 {CIFS_PROT, "\2POSIX 2"},
48 {BAD_PROT, "\2"}
49};
50#else
51static struct {
52 int index;
53 char *name;
54} protocols[] = {
55 {CIFS_PROT, "\2NT LM 0.12"},
56 {BAD_PROT, "\2"}
57};
58#endif
59
60
61/* Mark as invalid, all open files on tree connections since they
62 were closed when session to server was lost */
63static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
64{
65 struct cifsFileInfo *open_file = NULL;
66 struct list_head * tmp;
67 struct list_head * tmp1;
68
69/* list all files open on tree connection and mark them invalid */
70 write_lock(&GlobalSMBSeslock);
71 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
72 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
73 if(open_file) {
74 open_file->invalidHandle = TRUE;
75 }
76 }
77 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -070078 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
79 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -070080}
81
82/* If the return code is zero, this function must fill in request_buf pointer */
83static int
84small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
85 void **request_buf /* returned */)
86{
87 int rc = 0;
88
89 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
90 check for tcp and smb session status done differently
91 for those three - in the calling routine */
92 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -080093 if(tcon->tidStatus == CifsExiting) {
94 /* only tree disconnect, open, and write,
95 (and ulogoff which does not have tcon)
96 are allowed as we start force umount */
97 if((smb_command != SMB_COM_WRITE_ANDX) &&
98 (smb_command != SMB_COM_OPEN_ANDX) &&
99 (smb_command != SMB_COM_TREE_DISCONNECT)) {
100 cFYI(1,("can not send cmd %d while umounting",
101 smb_command));
102 return -ENODEV;
103 }
104 }
Steve French31ca3bc2005-04-28 22:41:11 -0700105 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
106 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 struct nls_table *nls_codepage;
108 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700109 reconnect, should be greater than cifs socket
110 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
112 wait_event_interruptible_timeout(tcon->ses->server->response_q,
113 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
114 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
115 /* on "soft" mounts we wait once */
116 if((tcon->retry == FALSE) ||
117 (tcon->ses->status == CifsExiting)) {
118 cFYI(1,("gave up waiting on reconnect in smb_init"));
119 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700120 } /* else "hard" mount - keep retrying
121 until process is killed or server
122 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 } else /* TCP session is reestablished now */
124 break;
125
126 }
127
128 nls_codepage = load_nls_default();
129 /* need to prevent multiple threads trying to
130 simultaneously reconnect the same SMB session */
131 down(&tcon->ses->sesSem);
132 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700133 rc = cifs_setup_session(0, tcon->ses,
134 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
136 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700137 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
138 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700140 /* BB FIXME add code to check if wsize needs
141 update due to negotiated smb buffer size
142 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 if(rc == 0)
144 atomic_inc(&tconInfoReconnectCount);
145
146 cFYI(1, ("reconnect tcon rc = %d", rc));
147 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700148 it is safer (and faster) to reopen files
149 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700152 know whether we can continue or not without
153 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 switch(smb_command) {
155 case SMB_COM_READ_ANDX:
156 case SMB_COM_WRITE_ANDX:
157 case SMB_COM_CLOSE:
158 case SMB_COM_FIND_CLOSE2:
159 case SMB_COM_LOCKING_ANDX: {
160 unload_nls(nls_codepage);
161 return -EAGAIN;
162 }
163 }
164 } else {
165 up(&tcon->ses->sesSem);
166 }
167 unload_nls(nls_codepage);
168
169 } else {
170 return -EIO;
171 }
172 }
173 if(rc)
174 return rc;
175
176 *request_buf = cifs_small_buf_get();
177 if (*request_buf == NULL) {
178 /* BB should we add a retry in here if not a writepage? */
179 return -ENOMEM;
180 }
181
182 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
183
Steve Frencha4544342005-08-24 13:59:35 -0700184 if(tcon != NULL)
185 cifs_stats_inc(&tcon->num_smbs_sent);
186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 return rc;
188}
189
190/* If the return code is zero, this function must fill in request_buf pointer */
191static int
192smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
193 void **request_buf /* returned */ ,
194 void **response_buf /* returned */ )
195{
196 int rc = 0;
197
198 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
199 check for tcp and smb session status done differently
200 for those three - in the calling routine */
201 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800202 if(tcon->tidStatus == CifsExiting) {
203 /* only tree disconnect, open, and write,
204 (and ulogoff which does not have tcon)
205 are allowed as we start force umount */
206 if((smb_command != SMB_COM_WRITE_ANDX) &&
207 (smb_command != SMB_COM_OPEN_ANDX) &&
208 (smb_command != SMB_COM_TREE_DISCONNECT)) {
209 cFYI(1,("can not send cmd %d while umounting",
210 smb_command));
211 return -ENODEV;
212 }
213 }
214
Steve French31ca3bc2005-04-28 22:41:11 -0700215 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
216 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700218 /* Give Demultiplex thread up to 10 seconds to
219 reconnect, should be greater than cifs socket
220 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
222 wait_event_interruptible_timeout(tcon->ses->server->response_q,
223 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
Steve French09d1db52005-04-28 22:41:08 -0700224 if(tcon->ses->server->tcpStatus ==
225 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 /* on "soft" mounts we wait once */
227 if((tcon->retry == FALSE) ||
228 (tcon->ses->status == CifsExiting)) {
229 cFYI(1,("gave up waiting on reconnect in smb_init"));
230 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700231 } /* else "hard" mount - keep retrying
232 until process is killed or server
233 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 } else /* TCP session is reestablished now */
235 break;
236
237 }
238
239 nls_codepage = load_nls_default();
240 /* need to prevent multiple threads trying to
241 simultaneously reconnect the same SMB session */
242 down(&tcon->ses->sesSem);
243 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700244 rc = cifs_setup_session(0, tcon->ses,
245 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
247 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700248 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
249 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700251 /* BB FIXME add code to check if wsize needs
252 update due to negotiated smb buffer size
253 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 if(rc == 0)
255 atomic_inc(&tconInfoReconnectCount);
256
257 cFYI(1, ("reconnect tcon rc = %d", rc));
258 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700259 it is safer (and faster) to reopen files
260 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
262 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700263 know whether we can continue or not without
264 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 switch(smb_command) {
266 case SMB_COM_READ_ANDX:
267 case SMB_COM_WRITE_ANDX:
268 case SMB_COM_CLOSE:
269 case SMB_COM_FIND_CLOSE2:
270 case SMB_COM_LOCKING_ANDX: {
271 unload_nls(nls_codepage);
272 return -EAGAIN;
273 }
274 }
275 } else {
276 up(&tcon->ses->sesSem);
277 }
278 unload_nls(nls_codepage);
279
280 } else {
281 return -EIO;
282 }
283 }
284 if(rc)
285 return rc;
286
287 *request_buf = cifs_buf_get();
288 if (*request_buf == NULL) {
289 /* BB should we add a retry in here if not a writepage? */
290 return -ENOMEM;
291 }
292 /* Although the original thought was we needed the response buf for */
293 /* potential retries of smb operations it turns out we can determine */
294 /* from the mid flags when the request buffer can be resent without */
295 /* having to use a second distinct buffer for the response */
296 *response_buf = *request_buf;
297
298 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
299 wct /*wct */ );
300
Steve Frencha4544342005-08-24 13:59:35 -0700301 if(tcon != NULL)
302 cifs_stats_inc(&tcon->num_smbs_sent);
303
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 return rc;
305}
306
307static int validate_t2(struct smb_t2_rsp * pSMB)
308{
309 int rc = -EINVAL;
310 int total_size;
311 char * pBCC;
312
313 /* check for plausible wct, bcc and t2 data and parm sizes */
314 /* check for parm and data offset going beyond end of smb */
315 if(pSMB->hdr.WordCount >= 10) {
316 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
317 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
318 /* check that bcc is at least as big as parms + data */
319 /* check that bcc is less than negotiated smb buffer */
320 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
321 if(total_size < 512) {
322 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
323 /* BCC le converted in SendReceive */
Steve French09d1db52005-04-28 22:41:08 -0700324 pBCC = (pSMB->hdr.WordCount * 2) +
325 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 (char *)pSMB;
327 if((total_size <= (*(u16 *)pBCC)) &&
328 (total_size <
329 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
330 return 0;
331 }
332
333 }
334 }
335 }
336 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
337 sizeof(struct smb_t2_rsp) + 16);
338 return rc;
339}
340int
341CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
342{
343 NEGOTIATE_REQ *pSMB;
344 NEGOTIATE_RSP *pSMBr;
345 int rc = 0;
346 int bytes_returned;
347 struct TCP_Server_Info * server;
348 u16 count;
349
350 if(ses->server)
351 server = ses->server;
352 else {
353 rc = -EIO;
354 return rc;
355 }
356 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
357 (void **) &pSMB, (void **) &pSMBr);
358 if (rc)
359 return rc;
Steve French1982c342005-08-17 12:38:22 -0700360 pSMB->hdr.Mid = GetNextMid(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
362 if (extended_security)
363 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
364
365 count = strlen(protocols[0].name) + 1;
366 strncpy(pSMB->DialectsArray, protocols[0].name, 30);
367 /* null guaranteed to be at end of source and target buffers anyway */
368
369 pSMB->hdr.smb_buf_length += count;
370 pSMB->ByteCount = cpu_to_le16(count);
371
372 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
373 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
374 if (rc == 0) {
375 server->secMode = pSMBr->SecurityMode;
Steve French09d1db52005-04-28 22:41:08 -0700376 server->secType = NTLM; /* BB override default for
377 NTLMv2 or kerberos v5 */
378 /* one byte - no need to convert this or EncryptionKeyLen
379 from little endian */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
381 /* probably no need to store and check maxvcs */
382 server->maxBuf =
383 min(le32_to_cpu(pSMBr->MaxBufferSize),
384 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
385 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
386 cFYI(0, ("Max buf = %d ", ses->server->maxBuf));
387 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
388 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
389 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
390 /* BB with UTC do we ever need to be using srvr timezone? */
391 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
392 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
393 CIFS_CRYPTO_KEY_SIZE);
394 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
395 && (pSMBr->EncryptionKeyLength == 0)) {
396 /* decode security blob */
397 } else
398 rc = -EIO;
399
400 /* BB might be helpful to save off the domain of server here */
401
402 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
403 (server->capabilities & CAP_EXTENDED_SECURITY)) {
404 count = pSMBr->ByteCount;
405 if (count < 16)
406 rc = -EIO;
407 else if (count == 16) {
408 server->secType = RawNTLMSSP;
409 if (server->socketUseCount.counter > 1) {
410 if (memcmp
411 (server->server_GUID,
412 pSMBr->u.extended_response.
413 GUID, 16) != 0) {
414 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700415 ("UID of server does not match previous connection to same ip address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 memcpy(server->
417 server_GUID,
418 pSMBr->u.
419 extended_response.
420 GUID, 16);
421 }
422 } else
423 memcpy(server->server_GUID,
424 pSMBr->u.extended_response.
425 GUID, 16);
426 } else {
427 rc = decode_negTokenInit(pSMBr->u.
428 extended_response.
429 SecurityBlob,
430 count - 16,
431 &server->secType);
432 if(rc == 1) {
433 /* BB Need to fill struct for sessetup here */
434 rc = -EOPNOTSUPP;
435 } else {
436 rc = -EINVAL;
437 }
438 }
439 } else
440 server->capabilities &= ~CAP_EXTENDED_SECURITY;
441 if(sign_CIFS_PDUs == FALSE) {
442 if(server->secMode & SECMODE_SIGN_REQUIRED)
443 cERROR(1,
444 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
Steve French1982c342005-08-17 12:38:22 -0700445 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 } else if(sign_CIFS_PDUs == 1) {
447 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French1982c342005-08-17 12:38:22 -0700448 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 }
450
451 }
Steve French1982c342005-08-17 12:38:22 -0700452
Steve French4a6d87f2005-08-13 08:15:54 -0700453 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 return rc;
455}
456
457int
458CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
459{
460 struct smb_hdr *smb_buffer;
461 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
462 int rc = 0;
463 int length;
464
465 cFYI(1, ("In tree disconnect"));
466 /*
467 * If last user of the connection and
468 * connection alive - disconnect it
469 * If this is the last connection on the server session disconnect it
470 * (and inside session disconnect we should check if tcp socket needs
471 * to be freed and kernel thread woken up).
472 */
473 if (tcon)
474 down(&tcon->tconSem);
475 else
476 return -EIO;
477
478 atomic_dec(&tcon->useCount);
479 if (atomic_read(&tcon->useCount) > 0) {
480 up(&tcon->tconSem);
481 return -EBUSY;
482 }
483
484 /* No need to return error on this operation if tid invalidated and
485 closed on server already e.g. due to tcp session crashing */
486 if(tcon->tidStatus == CifsNeedReconnect) {
487 up(&tcon->tconSem);
488 return 0;
489 }
490
491 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
492 up(&tcon->tconSem);
493 return -EIO;
494 }
Steve French09d1db52005-04-28 22:41:08 -0700495 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
496 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 if (rc) {
498 up(&tcon->tconSem);
499 return rc;
500 } else {
501 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700502 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
504 &length, 0);
505 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700506 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508 if (smb_buffer)
509 cifs_small_buf_release(smb_buffer);
510 up(&tcon->tconSem);
511
512 /* No need to return error on this operation if tid invalidated and
513 closed on server already e.g. due to tcp session crashing */
514 if (rc == -EAGAIN)
515 rc = 0;
516
517 return rc;
518}
519
520int
521CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
522{
523 struct smb_hdr *smb_buffer_response;
524 LOGOFF_ANDX_REQ *pSMB;
525 int rc = 0;
526 int length;
527
528 cFYI(1, ("In SMBLogoff for session disconnect"));
529 if (ses)
530 down(&ses->sesSem);
531 else
532 return -EIO;
533
534 atomic_dec(&ses->inUse);
535 if (atomic_read(&ses->inUse) > 0) {
536 up(&ses->sesSem);
537 return -EBUSY;
538 }
539 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
540 if (rc) {
541 up(&ses->sesSem);
542 return rc;
543 }
544
545 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
546
547 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700548 pSMB->hdr.Mid = GetNextMid(ses->server);
549
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 if(ses->server->secMode &
551 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
552 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
553 }
554
555 pSMB->hdr.Uid = ses->Suid;
556
557 pSMB->AndXCommand = 0xFF;
558 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
559 smb_buffer_response, &length, 0);
560 if (ses->server) {
561 atomic_dec(&ses->server->socketUseCount);
562 if (atomic_read(&ses->server->socketUseCount) == 0) {
563 spin_lock(&GlobalMid_Lock);
564 ses->server->tcpStatus = CifsExiting;
565 spin_unlock(&GlobalMid_Lock);
566 rc = -ESHUTDOWN;
567 }
568 }
Steve Frencha59c6582005-08-17 12:12:19 -0700569 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700570 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
572 /* if session dead then we do not need to do ulogoff,
573 since server closed smb session, no sense reporting
574 error */
575 if (rc == -EAGAIN)
576 rc = 0;
577 return rc;
578}
579
580int
Steve French737b7582005-04-28 22:41:06 -0700581CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
582 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583{
584 DELETE_FILE_REQ *pSMB = NULL;
585 DELETE_FILE_RSP *pSMBr = NULL;
586 int rc = 0;
587 int bytes_returned;
588 int name_len;
589
590DelFileRetry:
591 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
592 (void **) &pSMBr);
593 if (rc)
594 return rc;
595
596 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
597 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500598 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700599 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 name_len++; /* trailing null */
601 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700602 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 name_len = strnlen(fileName, PATH_MAX);
604 name_len++; /* trailing null */
605 strncpy(pSMB->fileName, fileName, name_len);
606 }
607 pSMB->SearchAttributes =
608 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
609 pSMB->BufferFormat = 0x04;
610 pSMB->hdr.smb_buf_length += name_len + 1;
611 pSMB->ByteCount = cpu_to_le16(name_len + 1);
612 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
613 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700614 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 if (rc) {
616 cFYI(1, ("Error in RMFile = %d", rc));
617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
619 cifs_buf_release(pSMB);
620 if (rc == -EAGAIN)
621 goto DelFileRetry;
622
623 return rc;
624}
625
626int
Steve French737b7582005-04-28 22:41:06 -0700627CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
628 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629{
630 DELETE_DIRECTORY_REQ *pSMB = NULL;
631 DELETE_DIRECTORY_RSP *pSMBr = NULL;
632 int rc = 0;
633 int bytes_returned;
634 int name_len;
635
636 cFYI(1, ("In CIFSSMBRmDir"));
637RmDirRetry:
638 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
639 (void **) &pSMBr);
640 if (rc)
641 return rc;
642
643 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700644 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
645 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 name_len++; /* trailing null */
647 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700648 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 name_len = strnlen(dirName, PATH_MAX);
650 name_len++; /* trailing null */
651 strncpy(pSMB->DirName, dirName, name_len);
652 }
653
654 pSMB->BufferFormat = 0x04;
655 pSMB->hdr.smb_buf_length += name_len + 1;
656 pSMB->ByteCount = cpu_to_le16(name_len + 1);
657 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
658 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700659 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 if (rc) {
661 cFYI(1, ("Error in RMDir = %d", rc));
662 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
664 cifs_buf_release(pSMB);
665 if (rc == -EAGAIN)
666 goto RmDirRetry;
667 return rc;
668}
669
670int
671CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700672 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673{
674 int rc = 0;
675 CREATE_DIRECTORY_REQ *pSMB = NULL;
676 CREATE_DIRECTORY_RSP *pSMBr = NULL;
677 int bytes_returned;
678 int name_len;
679
680 cFYI(1, ("In CIFSSMBMkDir"));
681MkDirRetry:
682 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
683 (void **) &pSMBr);
684 if (rc)
685 return rc;
686
687 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500688 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700689 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 name_len++; /* trailing null */
691 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700692 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 name_len = strnlen(name, PATH_MAX);
694 name_len++; /* trailing null */
695 strncpy(pSMB->DirName, name, name_len);
696 }
697
698 pSMB->BufferFormat = 0x04;
699 pSMB->hdr.smb_buf_length += name_len + 1;
700 pSMB->ByteCount = cpu_to_le16(name_len + 1);
701 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
702 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700703 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 if (rc) {
705 cFYI(1, ("Error in Mkdir = %d", rc));
706 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700707
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 cifs_buf_release(pSMB);
709 if (rc == -EAGAIN)
710 goto MkDirRetry;
711 return rc;
712}
713
Steve Frencha9d02ad2005-08-24 23:06:05 -0700714static __u16 convert_disposition(int disposition)
715{
716 __u16 ofun = 0;
717
718 switch (disposition) {
719 case FILE_SUPERSEDE:
720 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
721 break;
722 case FILE_OPEN:
723 ofun = SMBOPEN_OAPPEND;
724 break;
725 case FILE_CREATE:
726 ofun = SMBOPEN_OCREATE;
727 break;
728 case FILE_OPEN_IF:
729 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
730 break;
731 case FILE_OVERWRITE:
732 ofun = SMBOPEN_OTRUNC;
733 break;
734 case FILE_OVERWRITE_IF:
735 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
736 break;
737 default:
738 cFYI(1,("unknown disposition %d",disposition));
739 ofun = SMBOPEN_OAPPEND; /* regular open */
740 }
741 return ofun;
742}
743
744int
745SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
746 const char *fileName, const int openDisposition,
747 const int access_flags, const int create_options, __u16 * netfid,
748 int *pOplock, FILE_ALL_INFO * pfile_info,
749 const struct nls_table *nls_codepage, int remap)
750{
751 int rc = -EACCES;
752 OPENX_REQ *pSMB = NULL;
753 OPENX_RSP *pSMBr = NULL;
754 int bytes_returned;
755 int name_len;
756 __u16 count;
757
758OldOpenRetry:
759 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
760 (void **) &pSMBr);
761 if (rc)
762 return rc;
763
764 pSMB->AndXCommand = 0xFF; /* none */
765
766 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
767 count = 1; /* account for one byte pad to word boundary */
768 name_len =
769 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
770 fileName, PATH_MAX, nls_codepage, remap);
771 name_len++; /* trailing null */
772 name_len *= 2;
773 } else { /* BB improve check for buffer overruns BB */
774 count = 0; /* no pad */
775 name_len = strnlen(fileName, PATH_MAX);
776 name_len++; /* trailing null */
777 strncpy(pSMB->fileName, fileName, name_len);
778 }
779 if (*pOplock & REQ_OPLOCK)
780 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
781 else if (*pOplock & REQ_BATCHOPLOCK) {
782 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
783 }
784 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
785 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
786 /* 0 = read
787 1 = write
788 2 = rw
789 3 = execute
790 */
791 pSMB->Mode = cpu_to_le16(2);
792 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
793 /* set file as system file if special file such
794 as fifo and server expecting SFU style and
795 no Unix extensions */
796
797 if(create_options & CREATE_OPTION_SPECIAL)
798 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
799 else
Steve French3e87d802005-09-18 20:49:21 -0700800 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700801
802 /* if ((omode & S_IWUGO) == 0)
803 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
804 /* Above line causes problems due to vfs splitting create into two
805 pieces - need to set mode after file created not while it is
806 being created */
807
808 /* BB FIXME BB */
809/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
810 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700811
812 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700813 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700814 count += name_len;
815 pSMB->hdr.smb_buf_length += count;
816
817 pSMB->ByteCount = cpu_to_le16(count);
818 /* long_op set to 1 to allow for oplock break timeouts */
819 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
820 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
821 cifs_stats_inc(&tcon->num_opens);
822 if (rc) {
823 cFYI(1, ("Error in Open = %d", rc));
824 } else {
825 /* BB verify if wct == 15 */
826
827/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
828
829 *netfid = pSMBr->Fid; /* cifs fid stays in le */
830 /* Let caller know file was created so we can set the mode. */
831 /* Do we care about the CreateAction in any other cases? */
832 /* BB FIXME BB */
833/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
834 *pOplock |= CIFS_CREATE_ACTION; */
835 /* BB FIXME END */
836
837 if(pfile_info) {
838 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
839 pfile_info->LastAccessTime = 0; /* BB fixme */
840 pfile_info->LastWriteTime = 0; /* BB fixme */
841 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -0700842 pfile_info->Attributes =
843 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700844 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -0700845 pfile_info->AllocationSize =
846 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
847 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -0700848 pfile_info->NumberOfLinks = cpu_to_le32(1);
849 }
850 }
851
852 cifs_buf_release(pSMB);
853 if (rc == -EAGAIN)
854 goto OldOpenRetry;
855 return rc;
856}
857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858int
859CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
860 const char *fileName, const int openDisposition,
861 const int access_flags, const int create_options, __u16 * netfid,
862 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -0700863 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864{
865 int rc = -EACCES;
866 OPEN_REQ *pSMB = NULL;
867 OPEN_RSP *pSMBr = NULL;
868 int bytes_returned;
869 int name_len;
870 __u16 count;
871
872openRetry:
873 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
874 (void **) &pSMBr);
875 if (rc)
876 return rc;
877
878 pSMB->AndXCommand = 0xFF; /* none */
879
880 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
881 count = 1; /* account for one byte pad to word boundary */
882 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500883 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -0700884 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 name_len++; /* trailing null */
886 name_len *= 2;
887 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -0700888 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 count = 0; /* no pad */
890 name_len = strnlen(fileName, PATH_MAX);
891 name_len++; /* trailing null */
892 pSMB->NameLength = cpu_to_le16(name_len);
893 strncpy(pSMB->fileName, fileName, name_len);
894 }
895 if (*pOplock & REQ_OPLOCK)
896 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
897 else if (*pOplock & REQ_BATCHOPLOCK) {
898 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
899 }
900 pSMB->DesiredAccess = cpu_to_le32(access_flags);
901 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -0700902 /* set file as system file if special file such
903 as fifo and server expecting SFU style and
904 no Unix extensions */
905 if(create_options & CREATE_OPTION_SPECIAL)
906 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
907 else
908 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 /* XP does not handle ATTR_POSIX_SEMANTICS */
910 /* but it helps speed up case sensitive checks for other
911 servers such as Samba */
912 if (tcon->ses->capabilities & CAP_UNIX)
913 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
914
915 /* if ((omode & S_IWUGO) == 0)
916 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
917 /* Above line causes problems due to vfs splitting create into two
918 pieces - need to set mode after file created not while it is
919 being created */
920 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
921 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -0700922 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -0700923 /* BB Expirement with various impersonation levels and verify */
924 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 pSMB->SecurityFlags =
926 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
927
928 count += name_len;
929 pSMB->hdr.smb_buf_length += count;
930
931 pSMB->ByteCount = cpu_to_le16(count);
932 /* long_op set to 1 to allow for oplock break timeouts */
933 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
934 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -0700935 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 if (rc) {
937 cFYI(1, ("Error in Open = %d", rc));
938 } else {
Steve French09d1db52005-04-28 22:41:08 -0700939 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 *netfid = pSMBr->Fid; /* cifs fid stays in le */
941 /* Let caller know file was created so we can set the mode. */
942 /* Do we care about the CreateAction in any other cases? */
943 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
944 *pOplock |= CIFS_CREATE_ACTION;
945 if(pfile_info) {
946 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
947 36 /* CreationTime to Attributes */);
948 /* the file_info buf is endian converted by caller */
949 pfile_info->AllocationSize = pSMBr->AllocationSize;
950 pfile_info->EndOfFile = pSMBr->EndOfFile;
951 pfile_info->NumberOfLinks = cpu_to_le32(1);
952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700954
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 cifs_buf_release(pSMB);
956 if (rc == -EAGAIN)
957 goto openRetry;
958 return rc;
959}
960
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961int
962CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -0800963 const int netfid, const unsigned int count,
964 const __u64 lseek, unsigned int *nbytes, char **buf,
965 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966{
967 int rc = -EACCES;
968 READ_REQ *pSMB = NULL;
969 READ_RSP *pSMBr = NULL;
970 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -0700971 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -0800972 int resp_buf_type = 0;
973 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
975 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -0700976 if(tcon->ses->capabilities & CAP_LARGE_FILES)
977 wct = 12;
978 else
979 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
981 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -0800982 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 if (rc)
984 return rc;
985
986 /* tcon and ses pointer are checked in smb_init */
987 if (tcon->ses->server == NULL)
988 return -ECONNABORTED;
989
Steve Frenchec637e32005-12-12 20:53:18 -0800990 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 pSMB->Fid = netfid;
992 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -0700993 if(wct == 12)
994 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -0800995 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
996 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -0700997
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 pSMB->Remaining = 0;
999 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1000 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001001 if(wct == 12)
1002 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1003 else {
1004 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001005 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001006 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001007 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001008 }
Steve Frenchec637e32005-12-12 20:53:18 -08001009
1010 iov[0].iov_base = (char *)pSMB;
1011 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1012 rc = SendReceive2(xid, tcon->ses, iov,
1013 1 /* num iovecs */,
1014 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001015 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001016 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 if (rc) {
1018 cERROR(1, ("Send error in read = %d", rc));
1019 } else {
1020 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1021 data_length = data_length << 16;
1022 data_length += le16_to_cpu(pSMBr->DataLength);
1023 *nbytes = data_length;
1024
1025 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001026 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 || (data_length > count)) {
1028 cFYI(1,("bad length %d for count %d",data_length,count));
1029 rc = -EIO;
1030 *nbytes = 0;
1031 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001032 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001034/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1035 cERROR(1,("Faulting on read rc = %d",rc));
1036 rc = -EFAULT;
1037 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001039 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 }
1041 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
Steve Frenchec637e32005-12-12 20:53:18 -08001043 cifs_small_buf_release(pSMB);
1044 if(*buf) {
1045 if(resp_buf_type == CIFS_SMALL_BUFFER)
1046 cifs_small_buf_release(iov[0].iov_base);
1047 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1048 cifs_buf_release(iov[0].iov_base);
1049 } else /* return buffer to caller to free */ /* BB FIXME how do we tell caller if it is not a large buffer */ {
1050 *buf = iov[0].iov_base;
1051 if(resp_buf_type == CIFS_SMALL_BUFFER)
1052 *pbuf_type = CIFS_SMALL_BUFFER;
1053 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1054 *pbuf_type = CIFS_LARGE_BUFFER;
1055 }
1056
1057 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 since file handle passed in no longer valid */
1059 return rc;
1060}
1061
Steve Frenchec637e32005-12-12 20:53:18 -08001062
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063int
1064CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1065 const int netfid, const unsigned int count,
1066 const __u64 offset, unsigned int *nbytes, const char *buf,
1067 const char __user * ubuf, const int long_op)
1068{
1069 int rc = -EACCES;
1070 WRITE_REQ *pSMB = NULL;
1071 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001072 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 __u32 bytes_sent;
1074 __u16 byte_count;
1075
1076 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001077 if(tcon->ses == NULL)
1078 return -ECONNABORTED;
1079
1080 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1081 wct = 14;
1082 else
1083 wct = 12;
1084
1085 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 (void **) &pSMBr);
1087 if (rc)
1088 return rc;
1089 /* tcon and ses pointer are checked in smb_init */
1090 if (tcon->ses->server == NULL)
1091 return -ECONNABORTED;
1092
1093 pSMB->AndXCommand = 0xFF; /* none */
1094 pSMB->Fid = netfid;
1095 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001096 if(wct == 14)
1097 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1098 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1099 return -EIO;
1100
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 pSMB->Reserved = 0xFFFFFFFF;
1102 pSMB->WriteMode = 0;
1103 pSMB->Remaining = 0;
1104
1105 /* Can increase buffer size if buffer is big enough in some cases - ie we
1106 can send more if LARGE_WRITE_X capability returned by the server and if
1107 our buffer is big enough or if we convert to iovecs on socket writes
1108 and eliminate the copy to the CIFS buffer */
1109 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1110 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1111 } else {
1112 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1113 & ~0xFF;
1114 }
1115
1116 if (bytes_sent > count)
1117 bytes_sent = count;
1118 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001119 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 if(buf)
1121 memcpy(pSMB->Data,buf,bytes_sent);
1122 else if(ubuf) {
1123 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1124 cifs_buf_release(pSMB);
1125 return -EFAULT;
1126 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001127 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128 /* No buffer */
1129 cifs_buf_release(pSMB);
1130 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001131 } /* else setting file size with write of zero bytes */
1132 if(wct == 14)
1133 byte_count = bytes_sent + 1; /* pad */
1134 else /* wct == 12 */ {
1135 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1138 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001139 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001140
1141 if(wct == 14)
1142 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001143 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001144 struct smb_com_writex_req * pSMBW =
1145 (struct smb_com_writex_req *)pSMB;
1146 pSMBW->ByteCount = cpu_to_le16(byte_count);
1147 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
1149 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1150 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001151 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 if (rc) {
1153 cFYI(1, ("Send error in write = %d", rc));
1154 *nbytes = 0;
1155 } else {
1156 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1157 *nbytes = (*nbytes) << 16;
1158 *nbytes += le16_to_cpu(pSMBr->Count);
1159 }
1160
1161 cifs_buf_release(pSMB);
1162
1163 /* Note: On -EAGAIN error only caller can retry on handle based calls
1164 since file handle passed in no longer valid */
1165
1166 return rc;
1167}
1168
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001169int
1170CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001172 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1173 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174{
1175 int rc = -EACCES;
1176 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001177 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001178 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001179 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180
Steve Frenchff7feac2005-11-15 16:45:16 -08001181 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1182
Steve French8cc64c62005-10-03 13:49:43 -07001183 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1184 wct = 14;
1185 else
1186 wct = 12;
1187 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 if (rc)
1189 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 /* tcon and ses pointer are checked in smb_init */
1191 if (tcon->ses->server == NULL)
1192 return -ECONNABORTED;
1193
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001194 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 pSMB->Fid = netfid;
1196 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001197 if(wct == 14)
1198 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1199 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1200 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 pSMB->Reserved = 0xFFFFFFFF;
1202 pSMB->WriteMode = 0;
1203 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001204
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 pSMB->DataOffset =
1206 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1207
Steve French3e844692005-10-03 13:37:24 -07001208 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1209 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001210 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001211 if(wct == 14)
1212 pSMB->hdr.smb_buf_length += count+1;
1213 else /* wct == 12 */
1214 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1215 if(wct == 14)
1216 pSMB->ByteCount = cpu_to_le16(count + 1);
1217 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1218 struct smb_com_writex_req * pSMBW =
1219 (struct smb_com_writex_req *)pSMB;
1220 pSMBW->ByteCount = cpu_to_le16(count + 5);
1221 }
Steve French3e844692005-10-03 13:37:24 -07001222 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001223 if(wct == 14)
1224 iov[0].iov_len = smb_hdr_len + 4;
1225 else /* wct == 12 pad bigger by four bytes */
1226 iov[0].iov_len = smb_hdr_len + 8;
1227
Steve French3e844692005-10-03 13:37:24 -07001228
Steve Frenchec637e32005-12-12 20:53:18 -08001229 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001230 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001231 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001233 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001235 } else if(resp_buf_type == 0) {
1236 /* presumably this can not happen, but best to be safe */
1237 rc = -EIO;
1238 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001239 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001240 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001241 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1242 *nbytes = (*nbytes) << 16;
1243 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245
1246 cifs_small_buf_release(pSMB);
Steve Frenchec637e32005-12-12 20:53:18 -08001247 if(resp_buf_type == CIFS_SMALL_BUFFER)
1248 cifs_small_buf_release(iov[0].iov_base);
1249 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1250 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
1252 /* Note: On -EAGAIN error only caller can retry on handle based calls
1253 since file handle passed in no longer valid */
1254
1255 return rc;
1256}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001257
1258
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259int
1260CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1261 const __u16 smb_file_id, const __u64 len,
1262 const __u64 offset, const __u32 numUnlock,
1263 const __u32 numLock, const __u8 lockType, const int waitFlag)
1264{
1265 int rc = 0;
1266 LOCK_REQ *pSMB = NULL;
1267 LOCK_RSP *pSMBr = NULL;
1268 int bytes_returned;
1269 int timeout = 0;
1270 __u16 count;
1271
1272 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001273 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1274
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 if (rc)
1276 return rc;
1277
Steve French46810cb2005-04-28 22:41:09 -07001278 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1279
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1281 timeout = -1; /* no response expected */
1282 pSMB->Timeout = 0;
1283 } else if (waitFlag == TRUE) {
1284 timeout = 3; /* blocking operation, no timeout */
1285 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1286 } else {
1287 pSMB->Timeout = 0;
1288 }
1289
1290 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1291 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1292 pSMB->LockType = lockType;
1293 pSMB->AndXCommand = 0xFF; /* none */
1294 pSMB->Fid = smb_file_id; /* netfid stays le */
1295
1296 if((numLock != 0) || (numUnlock != 0)) {
1297 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1298 /* BB where to store pid high? */
1299 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1300 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1301 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1302 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1303 count = sizeof(LOCKING_ANDX_RANGE);
1304 } else {
1305 /* oplock break */
1306 count = 0;
1307 }
1308 pSMB->hdr.smb_buf_length += count;
1309 pSMB->ByteCount = cpu_to_le16(count);
1310
1311 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1312 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha4544342005-08-24 13:59:35 -07001313 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 if (rc) {
1315 cFYI(1, ("Send error in Lock = %d", rc));
1316 }
Steve French46810cb2005-04-28 22:41:09 -07001317 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318
1319 /* Note: On -EAGAIN error only caller can retry on handle based calls
1320 since file handle passed in no longer valid */
1321 return rc;
1322}
1323
1324int
1325CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1326{
1327 int rc = 0;
1328 CLOSE_REQ *pSMB = NULL;
1329 CLOSE_RSP *pSMBr = NULL;
1330 int bytes_returned;
1331 cFYI(1, ("In CIFSSMBClose"));
1332
1333/* do not retry on dead session on close */
1334 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1335 if(rc == -EAGAIN)
1336 return 0;
1337 if (rc)
1338 return rc;
1339
1340 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1341
1342 pSMB->FileID = (__u16) smb_file_id;
1343 pSMB->LastWriteTime = 0;
1344 pSMB->ByteCount = 0;
1345 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1346 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001347 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 if (rc) {
1349 if(rc!=-EINTR) {
1350 /* EINTR is expected when user ctl-c to kill app */
1351 cERROR(1, ("Send error in Close = %d", rc));
1352 }
1353 }
1354
1355 cifs_small_buf_release(pSMB);
1356
1357 /* Since session is dead, file will be closed on server already */
1358 if(rc == -EAGAIN)
1359 rc = 0;
1360
1361 return rc;
1362}
1363
1364int
1365CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1366 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001367 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368{
1369 int rc = 0;
1370 RENAME_REQ *pSMB = NULL;
1371 RENAME_RSP *pSMBr = NULL;
1372 int bytes_returned;
1373 int name_len, name_len2;
1374 __u16 count;
1375
1376 cFYI(1, ("In CIFSSMBRename"));
1377renameRetry:
1378 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1379 (void **) &pSMBr);
1380 if (rc)
1381 return rc;
1382
1383 pSMB->BufferFormat = 0x04;
1384 pSMB->SearchAttributes =
1385 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1386 ATTR_DIRECTORY);
1387
1388 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1389 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001390 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001391 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 name_len++; /* trailing null */
1393 name_len *= 2;
1394 pSMB->OldFileName[name_len] = 0x04; /* pad */
1395 /* protocol requires ASCII signature byte on Unicode string */
1396 pSMB->OldFileName[name_len + 1] = 0x00;
1397 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001398 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001399 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1401 name_len2 *= 2; /* convert to bytes */
1402 } else { /* BB improve the check for buffer overruns BB */
1403 name_len = strnlen(fromName, PATH_MAX);
1404 name_len++; /* trailing null */
1405 strncpy(pSMB->OldFileName, fromName, name_len);
1406 name_len2 = strnlen(toName, PATH_MAX);
1407 name_len2++; /* trailing null */
1408 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1409 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1410 name_len2++; /* trailing null */
1411 name_len2++; /* signature byte */
1412 }
1413
1414 count = 1 /* 1st signature byte */ + name_len + name_len2;
1415 pSMB->hdr.smb_buf_length += count;
1416 pSMB->ByteCount = cpu_to_le16(count);
1417
1418 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1419 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001420 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 if (rc) {
1422 cFYI(1, ("Send error in rename = %d", rc));
1423 }
1424
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 cifs_buf_release(pSMB);
1426
1427 if (rc == -EAGAIN)
1428 goto renameRetry;
1429
1430 return rc;
1431}
1432
1433int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001434 int netfid, char * target_name,
1435 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436{
1437 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1438 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1439 struct set_file_rename * rename_info;
1440 char *data_offset;
1441 char dummy_string[30];
1442 int rc = 0;
1443 int bytes_returned = 0;
1444 int len_of_str;
1445 __u16 params, param_offset, offset, count, byte_count;
1446
1447 cFYI(1, ("Rename to File by handle"));
1448 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1449 (void **) &pSMBr);
1450 if (rc)
1451 return rc;
1452
1453 params = 6;
1454 pSMB->MaxSetupCount = 0;
1455 pSMB->Reserved = 0;
1456 pSMB->Flags = 0;
1457 pSMB->Timeout = 0;
1458 pSMB->Reserved2 = 0;
1459 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1460 offset = param_offset + params;
1461
1462 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1463 rename_info = (struct set_file_rename *) data_offset;
1464 pSMB->MaxParameterCount = cpu_to_le16(2);
1465 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1466 pSMB->SetupCount = 1;
1467 pSMB->Reserved3 = 0;
1468 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1469 byte_count = 3 /* pad */ + params;
1470 pSMB->ParameterCount = cpu_to_le16(params);
1471 pSMB->TotalParameterCount = pSMB->ParameterCount;
1472 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1473 pSMB->DataOffset = cpu_to_le16(offset);
1474 /* construct random name ".cifs_tmp<inodenum><mid>" */
1475 rename_info->overwrite = cpu_to_le32(1);
1476 rename_info->root_fid = 0;
1477 /* unicode only call */
1478 if(target_name == NULL) {
1479 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001480 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001481 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001483 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001484 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 }
1486 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1487 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1488 byte_count += count;
1489 pSMB->DataCount = cpu_to_le16(count);
1490 pSMB->TotalDataCount = pSMB->DataCount;
1491 pSMB->Fid = netfid;
1492 pSMB->InformationLevel =
1493 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1494 pSMB->Reserved4 = 0;
1495 pSMB->hdr.smb_buf_length += byte_count;
1496 pSMB->ByteCount = cpu_to_le16(byte_count);
1497 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1498 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001499 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 if (rc) {
1501 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1502 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001503
Linus Torvalds1da177e2005-04-16 15:20:36 -07001504 cifs_buf_release(pSMB);
1505
1506 /* Note: On -EAGAIN error only caller can retry on handle based calls
1507 since file handle passed in no longer valid */
1508
1509 return rc;
1510}
1511
1512int
1513CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1514 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001515 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516{
1517 int rc = 0;
1518 COPY_REQ *pSMB = NULL;
1519 COPY_RSP *pSMBr = NULL;
1520 int bytes_returned;
1521 int name_len, name_len2;
1522 __u16 count;
1523
1524 cFYI(1, ("In CIFSSMBCopy"));
1525copyRetry:
1526 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1527 (void **) &pSMBr);
1528 if (rc)
1529 return rc;
1530
1531 pSMB->BufferFormat = 0x04;
1532 pSMB->Tid2 = target_tid;
1533
1534 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1535
1536 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001537 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001538 fromName, PATH_MAX, nls_codepage,
1539 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 name_len++; /* trailing null */
1541 name_len *= 2;
1542 pSMB->OldFileName[name_len] = 0x04; /* pad */
1543 /* protocol requires ASCII signature byte on Unicode string */
1544 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001545 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001546 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1548 name_len2 *= 2; /* convert to bytes */
1549 } else { /* BB improve the check for buffer overruns BB */
1550 name_len = strnlen(fromName, PATH_MAX);
1551 name_len++; /* trailing null */
1552 strncpy(pSMB->OldFileName, fromName, name_len);
1553 name_len2 = strnlen(toName, PATH_MAX);
1554 name_len2++; /* trailing null */
1555 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1556 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1557 name_len2++; /* trailing null */
1558 name_len2++; /* signature byte */
1559 }
1560
1561 count = 1 /* 1st signature byte */ + name_len + name_len2;
1562 pSMB->hdr.smb_buf_length += count;
1563 pSMB->ByteCount = cpu_to_le16(count);
1564
1565 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1566 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1567 if (rc) {
1568 cFYI(1, ("Send error in copy = %d with %d files copied",
1569 rc, le16_to_cpu(pSMBr->CopyCount)));
1570 }
1571 if (pSMB)
1572 cifs_buf_release(pSMB);
1573
1574 if (rc == -EAGAIN)
1575 goto copyRetry;
1576
1577 return rc;
1578}
1579
1580int
1581CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1582 const char *fromName, const char *toName,
1583 const struct nls_table *nls_codepage)
1584{
1585 TRANSACTION2_SPI_REQ *pSMB = NULL;
1586 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1587 char *data_offset;
1588 int name_len;
1589 int name_len_target;
1590 int rc = 0;
1591 int bytes_returned = 0;
1592 __u16 params, param_offset, offset, byte_count;
1593
1594 cFYI(1, ("In Symlink Unix style"));
1595createSymLinkRetry:
1596 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1597 (void **) &pSMBr);
1598 if (rc)
1599 return rc;
1600
1601 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1602 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001603 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 /* find define for this maxpathcomponent */
1605 , nls_codepage);
1606 name_len++; /* trailing null */
1607 name_len *= 2;
1608
1609 } else { /* BB improve the check for buffer overruns BB */
1610 name_len = strnlen(fromName, PATH_MAX);
1611 name_len++; /* trailing null */
1612 strncpy(pSMB->FileName, fromName, name_len);
1613 }
1614 params = 6 + name_len;
1615 pSMB->MaxSetupCount = 0;
1616 pSMB->Reserved = 0;
1617 pSMB->Flags = 0;
1618 pSMB->Timeout = 0;
1619 pSMB->Reserved2 = 0;
1620 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1621 InformationLevel) - 4;
1622 offset = param_offset + params;
1623
1624 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1625 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1626 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001627 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 /* find define for this maxpathcomponent */
1629 , nls_codepage);
1630 name_len_target++; /* trailing null */
1631 name_len_target *= 2;
1632 } else { /* BB improve the check for buffer overruns BB */
1633 name_len_target = strnlen(toName, PATH_MAX);
1634 name_len_target++; /* trailing null */
1635 strncpy(data_offset, toName, name_len_target);
1636 }
1637
1638 pSMB->MaxParameterCount = cpu_to_le16(2);
1639 /* BB find exact max on data count below from sess */
1640 pSMB->MaxDataCount = cpu_to_le16(1000);
1641 pSMB->SetupCount = 1;
1642 pSMB->Reserved3 = 0;
1643 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1644 byte_count = 3 /* pad */ + params + name_len_target;
1645 pSMB->DataCount = cpu_to_le16(name_len_target);
1646 pSMB->ParameterCount = cpu_to_le16(params);
1647 pSMB->TotalDataCount = pSMB->DataCount;
1648 pSMB->TotalParameterCount = pSMB->ParameterCount;
1649 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1650 pSMB->DataOffset = cpu_to_le16(offset);
1651 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1652 pSMB->Reserved4 = 0;
1653 pSMB->hdr.smb_buf_length += byte_count;
1654 pSMB->ByteCount = cpu_to_le16(byte_count);
1655 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1656 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001657 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 if (rc) {
1659 cFYI(1,
1660 ("Send error in SetPathInfo (create symlink) = %d",
1661 rc));
1662 }
1663
1664 if (pSMB)
1665 cifs_buf_release(pSMB);
1666
1667 if (rc == -EAGAIN)
1668 goto createSymLinkRetry;
1669
1670 return rc;
1671}
1672
1673int
1674CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1675 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001676 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677{
1678 TRANSACTION2_SPI_REQ *pSMB = NULL;
1679 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1680 char *data_offset;
1681 int name_len;
1682 int name_len_target;
1683 int rc = 0;
1684 int bytes_returned = 0;
1685 __u16 params, param_offset, offset, byte_count;
1686
1687 cFYI(1, ("In Create Hard link Unix style"));
1688createHardLinkRetry:
1689 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1690 (void **) &pSMBr);
1691 if (rc)
1692 return rc;
1693
1694 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001695 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001696 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697 name_len++; /* trailing null */
1698 name_len *= 2;
1699
1700 } else { /* BB improve the check for buffer overruns BB */
1701 name_len = strnlen(toName, PATH_MAX);
1702 name_len++; /* trailing null */
1703 strncpy(pSMB->FileName, toName, name_len);
1704 }
1705 params = 6 + name_len;
1706 pSMB->MaxSetupCount = 0;
1707 pSMB->Reserved = 0;
1708 pSMB->Flags = 0;
1709 pSMB->Timeout = 0;
1710 pSMB->Reserved2 = 0;
1711 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1712 InformationLevel) - 4;
1713 offset = param_offset + params;
1714
1715 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1716 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1717 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001718 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001719 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 name_len_target++; /* trailing null */
1721 name_len_target *= 2;
1722 } else { /* BB improve the check for buffer overruns BB */
1723 name_len_target = strnlen(fromName, PATH_MAX);
1724 name_len_target++; /* trailing null */
1725 strncpy(data_offset, fromName, name_len_target);
1726 }
1727
1728 pSMB->MaxParameterCount = cpu_to_le16(2);
1729 /* BB find exact max on data count below from sess*/
1730 pSMB->MaxDataCount = cpu_to_le16(1000);
1731 pSMB->SetupCount = 1;
1732 pSMB->Reserved3 = 0;
1733 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1734 byte_count = 3 /* pad */ + params + name_len_target;
1735 pSMB->ParameterCount = cpu_to_le16(params);
1736 pSMB->TotalParameterCount = pSMB->ParameterCount;
1737 pSMB->DataCount = cpu_to_le16(name_len_target);
1738 pSMB->TotalDataCount = pSMB->DataCount;
1739 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1740 pSMB->DataOffset = cpu_to_le16(offset);
1741 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1742 pSMB->Reserved4 = 0;
1743 pSMB->hdr.smb_buf_length += byte_count;
1744 pSMB->ByteCount = cpu_to_le16(byte_count);
1745 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1746 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001747 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 if (rc) {
1749 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1750 }
1751
1752 cifs_buf_release(pSMB);
1753 if (rc == -EAGAIN)
1754 goto createHardLinkRetry;
1755
1756 return rc;
1757}
1758
1759int
1760CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1761 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001762 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763{
1764 int rc = 0;
1765 NT_RENAME_REQ *pSMB = NULL;
1766 RENAME_RSP *pSMBr = NULL;
1767 int bytes_returned;
1768 int name_len, name_len2;
1769 __u16 count;
1770
1771 cFYI(1, ("In CIFSCreateHardLink"));
1772winCreateHardLinkRetry:
1773
1774 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1775 (void **) &pSMBr);
1776 if (rc)
1777 return rc;
1778
1779 pSMB->SearchAttributes =
1780 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1781 ATTR_DIRECTORY);
1782 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1783 pSMB->ClusterCount = 0;
1784
1785 pSMB->BufferFormat = 0x04;
1786
1787 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1788 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001789 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001790 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 name_len++; /* trailing null */
1792 name_len *= 2;
1793 pSMB->OldFileName[name_len] = 0; /* pad */
1794 pSMB->OldFileName[name_len + 1] = 0x04;
1795 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001796 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 /* string type 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);
Steve Frencha4544342005-08-24 13:59:35 -07001818 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 if (rc) {
1820 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1821 }
1822 cifs_buf_release(pSMB);
1823 if (rc == -EAGAIN)
1824 goto winCreateHardLinkRetry;
1825
1826 return rc;
1827}
1828
1829int
1830CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1831 const unsigned char *searchName,
1832 char *symlinkinfo, const int buflen,
1833 const struct nls_table *nls_codepage)
1834{
1835/* SMB_QUERY_FILE_UNIX_LINK */
1836 TRANSACTION2_QPI_REQ *pSMB = NULL;
1837 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1838 int rc = 0;
1839 int bytes_returned;
1840 int name_len;
1841 __u16 params, byte_count;
1842
1843 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1844
1845querySymLinkRetry:
1846 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1847 (void **) &pSMBr);
1848 if (rc)
1849 return rc;
1850
1851 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1852 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001853 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 /* find define for this maxpathcomponent */
1855 , nls_codepage);
1856 name_len++; /* trailing null */
1857 name_len *= 2;
1858 } else { /* BB improve the check for buffer overruns BB */
1859 name_len = strnlen(searchName, PATH_MAX);
1860 name_len++; /* trailing null */
1861 strncpy(pSMB->FileName, searchName, name_len);
1862 }
1863
1864 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1865 pSMB->TotalDataCount = 0;
1866 pSMB->MaxParameterCount = cpu_to_le16(2);
1867 /* BB find exact max data count below from sess structure BB */
1868 pSMB->MaxDataCount = cpu_to_le16(4000);
1869 pSMB->MaxSetupCount = 0;
1870 pSMB->Reserved = 0;
1871 pSMB->Flags = 0;
1872 pSMB->Timeout = 0;
1873 pSMB->Reserved2 = 0;
1874 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1875 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1876 pSMB->DataCount = 0;
1877 pSMB->DataOffset = 0;
1878 pSMB->SetupCount = 1;
1879 pSMB->Reserved3 = 0;
1880 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1881 byte_count = params + 1 /* pad */ ;
1882 pSMB->TotalParameterCount = cpu_to_le16(params);
1883 pSMB->ParameterCount = pSMB->TotalParameterCount;
1884 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1885 pSMB->Reserved4 = 0;
1886 pSMB->hdr.smb_buf_length += byte_count;
1887 pSMB->ByteCount = cpu_to_le16(byte_count);
1888
1889 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1890 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1891 if (rc) {
1892 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1893 } else {
1894 /* decode response */
1895
1896 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1897 if (rc || (pSMBr->ByteCount < 2))
1898 /* BB also check enough total bytes returned */
1899 rc = -EIO; /* bad smb */
1900 else {
1901 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1902 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1903
1904 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1905 name_len = UniStrnlen((wchar_t *) ((char *)
1906 &pSMBr->hdr.Protocol +data_offset),
1907 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07001908 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08001910 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 data_offset),
1912 name_len, nls_codepage);
1913 } else {
1914 strncpy(symlinkinfo,
1915 (char *) &pSMBr->hdr.Protocol +
1916 data_offset,
1917 min_t(const int, buflen, count));
1918 }
1919 symlinkinfo[buflen] = 0;
1920 /* just in case so calling code does not go off the end of buffer */
1921 }
1922 }
1923 cifs_buf_release(pSMB);
1924 if (rc == -EAGAIN)
1925 goto querySymLinkRetry;
1926 return rc;
1927}
1928
1929int
1930CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1931 const unsigned char *searchName,
1932 char *symlinkinfo, const int buflen,__u16 fid,
1933 const struct nls_table *nls_codepage)
1934{
1935 int rc = 0;
1936 int bytes_returned;
1937 int name_len;
1938 struct smb_com_transaction_ioctl_req * pSMB;
1939 struct smb_com_transaction_ioctl_rsp * pSMBr;
1940
1941 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1942 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1943 (void **) &pSMBr);
1944 if (rc)
1945 return rc;
1946
1947 pSMB->TotalParameterCount = 0 ;
1948 pSMB->TotalDataCount = 0;
1949 pSMB->MaxParameterCount = cpu_to_le32(2);
1950 /* BB find exact data count max from sess structure BB */
1951 pSMB->MaxDataCount = cpu_to_le32(4000);
1952 pSMB->MaxSetupCount = 4;
1953 pSMB->Reserved = 0;
1954 pSMB->ParameterOffset = 0;
1955 pSMB->DataCount = 0;
1956 pSMB->DataOffset = 0;
1957 pSMB->SetupCount = 4;
1958 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1959 pSMB->ParameterCount = pSMB->TotalParameterCount;
1960 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1961 pSMB->IsFsctl = 1; /* FSCTL */
1962 pSMB->IsRootFlag = 0;
1963 pSMB->Fid = fid; /* file handle always le */
1964 pSMB->ByteCount = 0;
1965
1966 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1967 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1968 if (rc) {
1969 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1970 } else { /* decode response */
1971 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1972 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1973 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1974 /* BB also check enough total bytes returned */
1975 rc = -EIO; /* bad smb */
1976 else {
1977 if(data_count && (data_count < 2048)) {
1978 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1979
1980 struct reparse_data * reparse_buf = (struct reparse_data *)
1981 ((char *)&pSMBr->hdr.Protocol + data_offset);
1982 if((char*)reparse_buf >= end_of_smb) {
1983 rc = -EIO;
1984 goto qreparse_out;
1985 }
1986 if((reparse_buf->LinkNamesBuf +
1987 reparse_buf->TargetNameOffset +
1988 reparse_buf->TargetNameLen) >
1989 end_of_smb) {
1990 cFYI(1,("reparse buf extended beyond SMB"));
1991 rc = -EIO;
1992 goto qreparse_out;
1993 }
1994
1995 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1996 name_len = UniStrnlen((wchar_t *)
1997 (reparse_buf->LinkNamesBuf +
1998 reparse_buf->TargetNameOffset),
1999 min(buflen/2, reparse_buf->TargetNameLen / 2));
2000 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002001 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 reparse_buf->TargetNameOffset),
2003 name_len, nls_codepage);
2004 } else { /* ASCII names */
2005 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2006 reparse_buf->TargetNameOffset,
2007 min_t(const int, buflen, reparse_buf->TargetNameLen));
2008 }
2009 } else {
2010 rc = -EIO;
2011 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2012 }
2013 symlinkinfo[buflen] = 0; /* just in case so the caller
2014 does not go off the end of the buffer */
2015 cFYI(1,("readlink result - %s ",symlinkinfo));
2016 }
2017 }
2018qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002019 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020
2021 /* Note: On -EAGAIN error only caller can retry on handle based calls
2022 since file handle passed in no longer valid */
2023
2024 return rc;
2025}
2026
2027#ifdef CONFIG_CIFS_POSIX
2028
2029/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2030static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2031{
2032 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002033 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2034 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2035 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2037
2038 return;
2039}
2040
2041/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002042static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2043 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044{
2045 int size = 0;
2046 int i;
2047 __u16 count;
2048 struct cifs_posix_ace * pACE;
2049 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2050 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2051
2052 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2053 return -EOPNOTSUPP;
2054
2055 if(acl_type & ACL_TYPE_ACCESS) {
2056 count = le16_to_cpu(cifs_acl->access_entry_count);
2057 pACE = &cifs_acl->ace_array[0];
2058 size = sizeof(struct cifs_posix_acl);
2059 size += sizeof(struct cifs_posix_ace) * count;
2060 /* check if we would go beyond end of SMB */
2061 if(size_of_data_area < size) {
2062 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2063 return -EINVAL;
2064 }
2065 } else if(acl_type & ACL_TYPE_DEFAULT) {
2066 count = le16_to_cpu(cifs_acl->access_entry_count);
2067 size = sizeof(struct cifs_posix_acl);
2068 size += sizeof(struct cifs_posix_ace) * count;
2069/* skip past access ACEs to get to default ACEs */
2070 pACE = &cifs_acl->ace_array[count];
2071 count = le16_to_cpu(cifs_acl->default_entry_count);
2072 size += sizeof(struct cifs_posix_ace) * count;
2073 /* check if we would go beyond end of SMB */
2074 if(size_of_data_area < size)
2075 return -EINVAL;
2076 } else {
2077 /* illegal type */
2078 return -EINVAL;
2079 }
2080
2081 size = posix_acl_xattr_size(count);
2082 if((buflen == 0) || (local_acl == NULL)) {
2083 /* used to query ACL EA size */
2084 } else if(size > buflen) {
2085 return -ERANGE;
2086 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002087 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 for(i = 0;i < count ;i++) {
2089 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2090 pACE ++;
2091 }
2092 }
2093 return size;
2094}
2095
2096static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2097 const posix_acl_xattr_entry * local_ace)
2098{
2099 __u16 rc = 0; /* 0 = ACL converted ok */
2100
Steve Frenchff7feac2005-11-15 16:45:16 -08002101 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2102 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002104 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 /* Probably no need to le convert -1 on any arch but can not hurt */
2106 cifs_ace->cifs_uid = cpu_to_le64(-1);
2107 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002108 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2110 return rc;
2111}
2112
2113/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2114static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2115 const int acl_type)
2116{
2117 __u16 rc = 0;
2118 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2119 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2120 int count;
2121 int i;
2122
2123 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2124 return 0;
2125
2126 count = posix_acl_xattr_count((size_t)buflen);
2127 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002128 count, buflen, le32_to_cpu(local_acl->a_version)));
2129 if(le32_to_cpu(local_acl->a_version) != 2) {
2130 cFYI(1,("unknown POSIX ACL version %d",
2131 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 return 0;
2133 }
2134 cifs_acl->version = cpu_to_le16(1);
2135 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002136 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002138 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 else {
2140 cFYI(1,("unknown ACL type %d",acl_type));
2141 return 0;
2142 }
2143 for(i=0;i<count;i++) {
2144 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2145 &local_acl->a_entries[i]);
2146 if(rc != 0) {
2147 /* ACE not converted */
2148 break;
2149 }
2150 }
2151 if(rc == 0) {
2152 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2153 rc += sizeof(struct cifs_posix_acl);
2154 /* BB add check to make sure ACL does not overflow SMB */
2155 }
2156 return rc;
2157}
2158
2159int
2160CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2161 const unsigned char *searchName,
2162 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002163 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164{
2165/* SMB_QUERY_POSIX_ACL */
2166 TRANSACTION2_QPI_REQ *pSMB = NULL;
2167 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2168 int rc = 0;
2169 int bytes_returned;
2170 int name_len;
2171 __u16 params, byte_count;
2172
2173 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2174
2175queryAclRetry:
2176 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2177 (void **) &pSMBr);
2178 if (rc)
2179 return rc;
2180
2181 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2182 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002183 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002184 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 name_len++; /* trailing null */
2186 name_len *= 2;
2187 pSMB->FileName[name_len] = 0;
2188 pSMB->FileName[name_len+1] = 0;
2189 } else { /* BB improve the check for buffer overruns BB */
2190 name_len = strnlen(searchName, PATH_MAX);
2191 name_len++; /* trailing null */
2192 strncpy(pSMB->FileName, searchName, name_len);
2193 }
2194
2195 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2196 pSMB->TotalDataCount = 0;
2197 pSMB->MaxParameterCount = cpu_to_le16(2);
2198 /* BB find exact max data count below from sess structure BB */
2199 pSMB->MaxDataCount = cpu_to_le16(4000);
2200 pSMB->MaxSetupCount = 0;
2201 pSMB->Reserved = 0;
2202 pSMB->Flags = 0;
2203 pSMB->Timeout = 0;
2204 pSMB->Reserved2 = 0;
2205 pSMB->ParameterOffset = cpu_to_le16(
2206 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2207 pSMB->DataCount = 0;
2208 pSMB->DataOffset = 0;
2209 pSMB->SetupCount = 1;
2210 pSMB->Reserved3 = 0;
2211 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2212 byte_count = params + 1 /* pad */ ;
2213 pSMB->TotalParameterCount = cpu_to_le16(params);
2214 pSMB->ParameterCount = pSMB->TotalParameterCount;
2215 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2216 pSMB->Reserved4 = 0;
2217 pSMB->hdr.smb_buf_length += byte_count;
2218 pSMB->ByteCount = cpu_to_le16(byte_count);
2219
2220 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2221 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2222 if (rc) {
2223 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2224 } else {
2225 /* decode response */
2226
2227 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2228 if (rc || (pSMBr->ByteCount < 2))
2229 /* BB also check enough total bytes returned */
2230 rc = -EIO; /* bad smb */
2231 else {
2232 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2233 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2234 rc = cifs_copy_posix_acl(acl_inf,
2235 (char *)&pSMBr->hdr.Protocol+data_offset,
2236 buflen,acl_type,count);
2237 }
2238 }
2239 cifs_buf_release(pSMB);
2240 if (rc == -EAGAIN)
2241 goto queryAclRetry;
2242 return rc;
2243}
2244
2245int
2246CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2247 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002248 const char *local_acl, const int buflen,
2249 const int acl_type,
2250 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251{
2252 struct smb_com_transaction2_spi_req *pSMB = NULL;
2253 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2254 char *parm_data;
2255 int name_len;
2256 int rc = 0;
2257 int bytes_returned = 0;
2258 __u16 params, byte_count, data_count, param_offset, offset;
2259
2260 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2261setAclRetry:
2262 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2263 (void **) &pSMBr);
2264 if (rc)
2265 return rc;
2266 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2267 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002268 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002269 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270 name_len++; /* trailing null */
2271 name_len *= 2;
2272 } else { /* BB improve the check for buffer overruns BB */
2273 name_len = strnlen(fileName, PATH_MAX);
2274 name_len++; /* trailing null */
2275 strncpy(pSMB->FileName, fileName, name_len);
2276 }
2277 params = 6 + name_len;
2278 pSMB->MaxParameterCount = cpu_to_le16(2);
2279 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2280 pSMB->MaxSetupCount = 0;
2281 pSMB->Reserved = 0;
2282 pSMB->Flags = 0;
2283 pSMB->Timeout = 0;
2284 pSMB->Reserved2 = 0;
2285 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2286 InformationLevel) - 4;
2287 offset = param_offset + params;
2288 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2289 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2290
2291 /* convert to on the wire format for POSIX ACL */
2292 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2293
2294 if(data_count == 0) {
2295 rc = -EOPNOTSUPP;
2296 goto setACLerrorExit;
2297 }
2298 pSMB->DataOffset = cpu_to_le16(offset);
2299 pSMB->SetupCount = 1;
2300 pSMB->Reserved3 = 0;
2301 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2302 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2303 byte_count = 3 /* pad */ + params + data_count;
2304 pSMB->DataCount = cpu_to_le16(data_count);
2305 pSMB->TotalDataCount = pSMB->DataCount;
2306 pSMB->ParameterCount = cpu_to_le16(params);
2307 pSMB->TotalParameterCount = pSMB->ParameterCount;
2308 pSMB->Reserved4 = 0;
2309 pSMB->hdr.smb_buf_length += byte_count;
2310 pSMB->ByteCount = cpu_to_le16(byte_count);
2311 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2312 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2313 if (rc) {
2314 cFYI(1, ("Set POSIX ACL returned %d", rc));
2315 }
2316
2317setACLerrorExit:
2318 cifs_buf_release(pSMB);
2319 if (rc == -EAGAIN)
2320 goto setAclRetry;
2321 return rc;
2322}
2323
Steve Frenchf654bac2005-04-28 22:41:04 -07002324/* BB fix tabs in this function FIXME BB */
2325int
2326CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2327 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2328{
2329 int rc = 0;
2330 struct smb_t2_qfi_req *pSMB = NULL;
2331 struct smb_t2_qfi_rsp *pSMBr = NULL;
2332 int bytes_returned;
2333 __u16 params, byte_count;
2334
2335 cFYI(1,("In GetExtAttr"));
2336 if(tcon == NULL)
2337 return -ENODEV;
2338
2339GetExtAttrRetry:
2340 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2341 (void **) &pSMBr);
2342 if (rc)
2343 return rc;
2344
Steve Frenchc67593a2005-04-28 22:41:04 -07002345 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002346 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002347 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002348 /* BB find exact max data count below from sess structure BB */
2349 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2350 pSMB->t2.MaxSetupCount = 0;
2351 pSMB->t2.Reserved = 0;
2352 pSMB->t2.Flags = 0;
2353 pSMB->t2.Timeout = 0;
2354 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002355 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2356 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002357 pSMB->t2.DataCount = 0;
2358 pSMB->t2.DataOffset = 0;
2359 pSMB->t2.SetupCount = 1;
2360 pSMB->t2.Reserved3 = 0;
2361 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002362 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002363 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2364 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2365 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002366 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002367 pSMB->Fid = netfid;
2368 pSMB->hdr.smb_buf_length += byte_count;
2369 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2370
2371 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2372 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2373 if (rc) {
2374 cFYI(1, ("error %d in GetExtAttr", rc));
2375 } else {
2376 /* decode response */
2377 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2378 if (rc || (pSMBr->ByteCount < 2))
2379 /* BB also check enough total bytes returned */
2380 /* If rc should we check for EOPNOSUPP and
2381 disable the srvino flag? or in caller? */
2382 rc = -EIO; /* bad smb */
2383 else {
2384 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2385 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2386 struct file_chattr_info * pfinfo;
2387 /* BB Do we need a cast or hash here ? */
2388 if(count != 16) {
2389 cFYI(1, ("Illegal size ret in GetExtAttr"));
2390 rc = -EIO;
2391 goto GetExtAttrOut;
2392 }
2393 pfinfo = (struct file_chattr_info *)
2394 (data_offset + (char *) &pSMBr->hdr.Protocol);
2395 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2396 *pMask = le64_to_cpu(pfinfo->mask);
2397 }
2398 }
2399GetExtAttrOut:
2400 cifs_buf_release(pSMB);
2401 if (rc == -EAGAIN)
2402 goto GetExtAttrRetry;
2403 return rc;
2404}
2405
2406
2407#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408
Steve French6b8edfe2005-08-23 20:26:03 -07002409/* Legacy Query Path Information call for lookup to old servers such
2410 as Win9x/WinME */
2411int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2412 const unsigned char *searchName,
2413 FILE_ALL_INFO * pFinfo,
2414 const struct nls_table *nls_codepage, int remap)
2415{
2416 QUERY_INFORMATION_REQ * pSMB;
2417 QUERY_INFORMATION_RSP * pSMBr;
2418 int rc = 0;
2419 int bytes_returned;
2420 int name_len;
2421
2422 cFYI(1, ("In SMBQPath path %s", searchName));
2423QInfRetry:
2424 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2425 (void **) &pSMBr);
2426 if (rc)
2427 return rc;
2428
2429 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2430 name_len =
2431 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2432 PATH_MAX, nls_codepage, remap);
2433 name_len++; /* trailing null */
2434 name_len *= 2;
2435 } else {
2436 name_len = strnlen(searchName, PATH_MAX);
2437 name_len++; /* trailing null */
2438 strncpy(pSMB->FileName, searchName, name_len);
2439 }
2440 pSMB->BufferFormat = 0x04;
2441 name_len++; /* account for buffer type byte */
2442 pSMB->hdr.smb_buf_length += (__u16) name_len;
2443 pSMB->ByteCount = cpu_to_le16(name_len);
2444
2445 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2446 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2447 if (rc) {
2448 cFYI(1, ("Send error in QueryInfo = %d", rc));
2449 } else if (pFinfo) { /* decode response */
2450 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002451 pFinfo->AllocationSize =
2452 cpu_to_le64(le32_to_cpu(pSMBr->size));
2453 pFinfo->EndOfFile = pFinfo->AllocationSize;
2454 pFinfo->Attributes =
2455 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002456 } else
2457 rc = -EIO; /* bad buffer passed in */
2458
2459 cifs_buf_release(pSMB);
2460
2461 if (rc == -EAGAIN)
2462 goto QInfRetry;
2463
2464 return rc;
2465}
2466
2467
2468
2469
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470int
2471CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2472 const unsigned char *searchName,
2473 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002474 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475{
2476/* level 263 SMB_QUERY_FILE_ALL_INFO */
2477 TRANSACTION2_QPI_REQ *pSMB = NULL;
2478 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2479 int rc = 0;
2480 int bytes_returned;
2481 int name_len;
2482 __u16 params, byte_count;
2483
2484/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2485QPathInfoRetry:
2486 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2487 (void **) &pSMBr);
2488 if (rc)
2489 return rc;
2490
2491 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2492 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002493 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002494 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 name_len++; /* trailing null */
2496 name_len *= 2;
2497 } else { /* BB improve the check for buffer overruns BB */
2498 name_len = strnlen(searchName, PATH_MAX);
2499 name_len++; /* trailing null */
2500 strncpy(pSMB->FileName, searchName, name_len);
2501 }
2502
2503 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2504 pSMB->TotalDataCount = 0;
2505 pSMB->MaxParameterCount = cpu_to_le16(2);
2506 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2507 pSMB->MaxSetupCount = 0;
2508 pSMB->Reserved = 0;
2509 pSMB->Flags = 0;
2510 pSMB->Timeout = 0;
2511 pSMB->Reserved2 = 0;
2512 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2513 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2514 pSMB->DataCount = 0;
2515 pSMB->DataOffset = 0;
2516 pSMB->SetupCount = 1;
2517 pSMB->Reserved3 = 0;
2518 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2519 byte_count = params + 1 /* pad */ ;
2520 pSMB->TotalParameterCount = cpu_to_le16(params);
2521 pSMB->ParameterCount = pSMB->TotalParameterCount;
2522 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2523 pSMB->Reserved4 = 0;
2524 pSMB->hdr.smb_buf_length += byte_count;
2525 pSMB->ByteCount = cpu_to_le16(byte_count);
2526
2527 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2528 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2529 if (rc) {
2530 cFYI(1, ("Send error in QPathInfo = %d", rc));
2531 } else { /* decode response */
2532 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2533
2534 if (rc || (pSMBr->ByteCount < 40))
2535 rc = -EIO; /* bad smb */
2536 else if (pFindData){
2537 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2538 memcpy((char *) pFindData,
2539 (char *) &pSMBr->hdr.Protocol +
2540 data_offset, sizeof (FILE_ALL_INFO));
2541 } else
2542 rc = -ENOMEM;
2543 }
2544 cifs_buf_release(pSMB);
2545 if (rc == -EAGAIN)
2546 goto QPathInfoRetry;
2547
2548 return rc;
2549}
2550
2551int
2552CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2553 const unsigned char *searchName,
2554 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002555 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556{
2557/* SMB_QUERY_FILE_UNIX_BASIC */
2558 TRANSACTION2_QPI_REQ *pSMB = NULL;
2559 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2560 int rc = 0;
2561 int bytes_returned = 0;
2562 int name_len;
2563 __u16 params, byte_count;
2564
2565 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2566UnixQPathInfoRetry:
2567 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2568 (void **) &pSMBr);
2569 if (rc)
2570 return rc;
2571
2572 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2573 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002574 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002575 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 name_len++; /* trailing null */
2577 name_len *= 2;
2578 } else { /* BB improve the check for buffer overruns BB */
2579 name_len = strnlen(searchName, PATH_MAX);
2580 name_len++; /* trailing null */
2581 strncpy(pSMB->FileName, searchName, name_len);
2582 }
2583
2584 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2585 pSMB->TotalDataCount = 0;
2586 pSMB->MaxParameterCount = cpu_to_le16(2);
2587 /* BB find exact max SMB PDU from sess structure BB */
2588 pSMB->MaxDataCount = cpu_to_le16(4000);
2589 pSMB->MaxSetupCount = 0;
2590 pSMB->Reserved = 0;
2591 pSMB->Flags = 0;
2592 pSMB->Timeout = 0;
2593 pSMB->Reserved2 = 0;
2594 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2595 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2596 pSMB->DataCount = 0;
2597 pSMB->DataOffset = 0;
2598 pSMB->SetupCount = 1;
2599 pSMB->Reserved3 = 0;
2600 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2601 byte_count = params + 1 /* pad */ ;
2602 pSMB->TotalParameterCount = cpu_to_le16(params);
2603 pSMB->ParameterCount = pSMB->TotalParameterCount;
2604 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2605 pSMB->Reserved4 = 0;
2606 pSMB->hdr.smb_buf_length += byte_count;
2607 pSMB->ByteCount = cpu_to_le16(byte_count);
2608
2609 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2610 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2611 if (rc) {
2612 cFYI(1, ("Send error in QPathInfo = %d", rc));
2613 } else { /* decode response */
2614 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2615
2616 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2617 rc = -EIO; /* bad smb */
2618 } else {
2619 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2620 memcpy((char *) pFindData,
2621 (char *) &pSMBr->hdr.Protocol +
2622 data_offset,
2623 sizeof (FILE_UNIX_BASIC_INFO));
2624 }
2625 }
2626 cifs_buf_release(pSMB);
2627 if (rc == -EAGAIN)
2628 goto UnixQPathInfoRetry;
2629
2630 return rc;
2631}
2632
2633#if 0 /* function unused at present */
2634int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2635 const char *searchName, FILE_ALL_INFO * findData,
2636 const struct nls_table *nls_codepage)
2637{
2638/* level 257 SMB_ */
2639 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2640 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2641 int rc = 0;
2642 int bytes_returned;
2643 int name_len;
2644 __u16 params, byte_count;
2645
2646 cFYI(1, ("In FindUnique"));
2647findUniqueRetry:
2648 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2649 (void **) &pSMBr);
2650 if (rc)
2651 return rc;
2652
2653 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2654 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002655 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 /* find define for this maxpathcomponent */
2657 , nls_codepage);
2658 name_len++; /* trailing null */
2659 name_len *= 2;
2660 } else { /* BB improve the check for buffer overruns BB */
2661 name_len = strnlen(searchName, PATH_MAX);
2662 name_len++; /* trailing null */
2663 strncpy(pSMB->FileName, searchName, name_len);
2664 }
2665
2666 params = 12 + name_len /* includes null */ ;
2667 pSMB->TotalDataCount = 0; /* no EAs */
2668 pSMB->MaxParameterCount = cpu_to_le16(2);
2669 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2670 pSMB->MaxSetupCount = 0;
2671 pSMB->Reserved = 0;
2672 pSMB->Flags = 0;
2673 pSMB->Timeout = 0;
2674 pSMB->Reserved2 = 0;
2675 pSMB->ParameterOffset = cpu_to_le16(
2676 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2677 pSMB->DataCount = 0;
2678 pSMB->DataOffset = 0;
2679 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2680 pSMB->Reserved3 = 0;
2681 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2682 byte_count = params + 1 /* pad */ ;
2683 pSMB->TotalParameterCount = cpu_to_le16(params);
2684 pSMB->ParameterCount = pSMB->TotalParameterCount;
2685 pSMB->SearchAttributes =
2686 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2687 ATTR_DIRECTORY);
2688 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2689 pSMB->SearchFlags = cpu_to_le16(1);
2690 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2691 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2692 pSMB->hdr.smb_buf_length += byte_count;
2693 pSMB->ByteCount = cpu_to_le16(byte_count);
2694
2695 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2696 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2697
2698 if (rc) {
2699 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2700 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07002701 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 /* BB fill in */
2703 }
2704
2705 cifs_buf_release(pSMB);
2706 if (rc == -EAGAIN)
2707 goto findUniqueRetry;
2708
2709 return rc;
2710}
2711#endif /* end unused (temporarily) function */
2712
2713/* xid, tcon, searchName and codepage are input parms, rest are returned */
2714int
2715CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2716 const char *searchName,
2717 const struct nls_table *nls_codepage,
2718 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07002719 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720{
2721/* level 257 SMB_ */
2722 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2723 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2724 T2_FFIRST_RSP_PARMS * parms;
2725 int rc = 0;
2726 int bytes_returned = 0;
2727 int name_len;
2728 __u16 params, byte_count;
2729
Steve French737b7582005-04-28 22:41:06 -07002730 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731
2732findFirstRetry:
2733 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2734 (void **) &pSMBr);
2735 if (rc)
2736 return rc;
2737
2738 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2739 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002740 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07002741 PATH_MAX, nls_codepage, remap);
2742 /* We can not add the asterik earlier in case
2743 it got remapped to 0xF03A as if it were part of the
2744 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07002746 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07002747 pSMB->FileName[name_len+1] = 0;
2748 pSMB->FileName[name_len+2] = '*';
2749 pSMB->FileName[name_len+3] = 0;
2750 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2752 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07002753 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 } else { /* BB add check for overrun of SMB buf BB */
2755 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756/* BB fix here and in unicode clause above ie
2757 if(name_len > buffersize-header)
2758 free buffer exit; BB */
2759 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07002760 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07002761 pSMB->FileName[name_len+1] = '*';
2762 pSMB->FileName[name_len+2] = 0;
2763 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 }
2765
2766 params = 12 + name_len /* includes null */ ;
2767 pSMB->TotalDataCount = 0; /* no EAs */
2768 pSMB->MaxParameterCount = cpu_to_le16(10);
2769 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2770 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2771 pSMB->MaxSetupCount = 0;
2772 pSMB->Reserved = 0;
2773 pSMB->Flags = 0;
2774 pSMB->Timeout = 0;
2775 pSMB->Reserved2 = 0;
2776 byte_count = params + 1 /* pad */ ;
2777 pSMB->TotalParameterCount = cpu_to_le16(params);
2778 pSMB->ParameterCount = pSMB->TotalParameterCount;
2779 pSMB->ParameterOffset = cpu_to_le16(
2780 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2781 pSMB->DataCount = 0;
2782 pSMB->DataOffset = 0;
2783 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2784 pSMB->Reserved3 = 0;
2785 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2786 pSMB->SearchAttributes =
2787 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2788 ATTR_DIRECTORY);
2789 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2790 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2791 CIFS_SEARCH_RETURN_RESUME);
2792 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2793
2794 /* BB what should we set StorageType to? Does it matter? BB */
2795 pSMB->SearchStorageType = 0;
2796 pSMB->hdr.smb_buf_length += byte_count;
2797 pSMB->ByteCount = cpu_to_le16(byte_count);
2798
2799 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2800 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002801 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802
Steve French1982c342005-08-17 12:38:22 -07002803 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 /* BB Add code to handle unsupported level rc */
2805 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07002806
2807 if (pSMB)
2808 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002809
2810 /* BB eventually could optimize out free and realloc of buf */
2811 /* for this case */
2812 if (rc == -EAGAIN)
2813 goto findFirstRetry;
2814 } else { /* decode response */
2815 /* BB remember to free buffer if error BB */
2816 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2817 if(rc == 0) {
2818 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2819 psrch_inf->unicode = TRUE;
2820 else
2821 psrch_inf->unicode = FALSE;
2822
2823 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2824 psrch_inf->srch_entries_start =
2825 (char *) &pSMBr->hdr.Protocol +
2826 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2828 le16_to_cpu(pSMBr->t2.ParameterOffset));
2829
2830 if(parms->EndofSearch)
2831 psrch_inf->endOfSearch = TRUE;
2832 else
2833 psrch_inf->endOfSearch = FALSE;
2834
2835 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2836 psrch_inf->index_of_last_entry =
2837 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 *pnetfid = parms->SearchHandle;
2839 } else {
2840 cifs_buf_release(pSMB);
2841 }
2842 }
2843
2844 return rc;
2845}
2846
2847int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2848 __u16 searchHandle, struct cifs_search_info * psrch_inf)
2849{
2850 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2851 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2852 T2_FNEXT_RSP_PARMS * parms;
2853 char *response_data;
2854 int rc = 0;
2855 int bytes_returned, name_len;
2856 __u16 params, byte_count;
2857
2858 cFYI(1, ("In FindNext"));
2859
2860 if(psrch_inf->endOfSearch == TRUE)
2861 return -ENOENT;
2862
2863 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2864 (void **) &pSMBr);
2865 if (rc)
2866 return rc;
2867
2868 params = 14; /* includes 2 bytes of null string, converted to LE below */
2869 byte_count = 0;
2870 pSMB->TotalDataCount = 0; /* no EAs */
2871 pSMB->MaxParameterCount = cpu_to_le16(8);
2872 pSMB->MaxDataCount =
2873 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2874 pSMB->MaxSetupCount = 0;
2875 pSMB->Reserved = 0;
2876 pSMB->Flags = 0;
2877 pSMB->Timeout = 0;
2878 pSMB->Reserved2 = 0;
2879 pSMB->ParameterOffset = cpu_to_le16(
2880 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2881 pSMB->DataCount = 0;
2882 pSMB->DataOffset = 0;
2883 pSMB->SetupCount = 1;
2884 pSMB->Reserved3 = 0;
2885 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2886 pSMB->SearchHandle = searchHandle; /* always kept as le */
2887 pSMB->SearchCount =
2888 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2889 /* test for Unix extensions */
2890/* if (tcon->ses->capabilities & CAP_UNIX) {
2891 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2892 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2893 } else {
2894 pSMB->InformationLevel =
2895 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2896 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2897 } */
2898 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2899 pSMB->ResumeKey = psrch_inf->resume_key;
2900 pSMB->SearchFlags =
2901 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2902
2903 name_len = psrch_inf->resume_name_len;
2904 params += name_len;
2905 if(name_len < PATH_MAX) {
2906 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2907 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07002908 /* 14 byte parm len above enough for 2 byte null terminator */
2909 pSMB->ResumeFileName[name_len] = 0;
2910 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 } else {
2912 rc = -EINVAL;
2913 goto FNext2_err_exit;
2914 }
2915 byte_count = params + 1 /* pad */ ;
2916 pSMB->TotalParameterCount = cpu_to_le16(params);
2917 pSMB->ParameterCount = pSMB->TotalParameterCount;
2918 pSMB->hdr.smb_buf_length += byte_count;
2919 pSMB->ByteCount = cpu_to_le16(byte_count);
2920
2921 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2922 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002923 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 if (rc) {
2925 if (rc == -EBADF) {
2926 psrch_inf->endOfSearch = TRUE;
2927 rc = 0; /* search probably was closed at end of search above */
2928 } else
2929 cFYI(1, ("FindNext returned = %d", rc));
2930 } else { /* decode response */
2931 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2932
2933 if(rc == 0) {
2934 /* BB fixme add lock for file (srch_info) struct here */
2935 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2936 psrch_inf->unicode = TRUE;
2937 else
2938 psrch_inf->unicode = FALSE;
2939 response_data = (char *) &pSMBr->hdr.Protocol +
2940 le16_to_cpu(pSMBr->t2.ParameterOffset);
2941 parms = (T2_FNEXT_RSP_PARMS *)response_data;
2942 response_data = (char *)&pSMBr->hdr.Protocol +
2943 le16_to_cpu(pSMBr->t2.DataOffset);
2944 cifs_buf_release(psrch_inf->ntwrk_buf_start);
2945 psrch_inf->srch_entries_start = response_data;
2946 psrch_inf->ntwrk_buf_start = (char *)pSMB;
2947 if(parms->EndofSearch)
2948 psrch_inf->endOfSearch = TRUE;
2949 else
2950 psrch_inf->endOfSearch = FALSE;
2951
2952 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2953 psrch_inf->index_of_last_entry +=
2954 psrch_inf->entries_in_buffer;
2955/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2956
2957 /* BB fixme add unlock here */
2958 }
2959
2960 }
2961
2962 /* BB On error, should we leave previous search buf (and count and
2963 last entry fields) intact or free the previous one? */
2964
2965 /* Note: On -EAGAIN error only caller can retry on handle based calls
2966 since file handle passed in no longer valid */
2967FNext2_err_exit:
2968 if (rc != 0)
2969 cifs_buf_release(pSMB);
2970
2971 return rc;
2972}
2973
2974int
2975CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2976{
2977 int rc = 0;
2978 FINDCLOSE_REQ *pSMB = NULL;
2979 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2980 int bytes_returned;
2981
2982 cFYI(1, ("In CIFSSMBFindClose"));
2983 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2984
2985 /* no sense returning error if session restarted
2986 as file handle has been closed */
2987 if(rc == -EAGAIN)
2988 return 0;
2989 if (rc)
2990 return rc;
2991
2992 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
2993 pSMB->FileID = searchHandle;
2994 pSMB->ByteCount = 0;
2995 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2996 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2997 if (rc) {
2998 cERROR(1, ("Send error in FindClose = %d", rc));
2999 }
Steve Frencha4544342005-08-24 13:59:35 -07003000 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 cifs_small_buf_release(pSMB);
3002
3003 /* Since session is dead, search handle closed on server already */
3004 if (rc == -EAGAIN)
3005 rc = 0;
3006
3007 return rc;
3008}
3009
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010int
3011CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3012 const unsigned char *searchName,
3013 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003014 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015{
3016 int rc = 0;
3017 TRANSACTION2_QPI_REQ *pSMB = NULL;
3018 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3019 int name_len, bytes_returned;
3020 __u16 params, byte_count;
3021
3022 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3023 if(tcon == NULL)
3024 return -ENODEV;
3025
3026GetInodeNumberRetry:
3027 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3028 (void **) &pSMBr);
3029 if (rc)
3030 return rc;
3031
3032
3033 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3034 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003035 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003036 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 name_len++; /* trailing null */
3038 name_len *= 2;
3039 } else { /* BB improve the check for buffer overruns BB */
3040 name_len = strnlen(searchName, PATH_MAX);
3041 name_len++; /* trailing null */
3042 strncpy(pSMB->FileName, searchName, name_len);
3043 }
3044
3045 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3046 pSMB->TotalDataCount = 0;
3047 pSMB->MaxParameterCount = cpu_to_le16(2);
3048 /* BB find exact max data count below from sess structure BB */
3049 pSMB->MaxDataCount = cpu_to_le16(4000);
3050 pSMB->MaxSetupCount = 0;
3051 pSMB->Reserved = 0;
3052 pSMB->Flags = 0;
3053 pSMB->Timeout = 0;
3054 pSMB->Reserved2 = 0;
3055 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3056 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3057 pSMB->DataCount = 0;
3058 pSMB->DataOffset = 0;
3059 pSMB->SetupCount = 1;
3060 pSMB->Reserved3 = 0;
3061 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3062 byte_count = params + 1 /* pad */ ;
3063 pSMB->TotalParameterCount = cpu_to_le16(params);
3064 pSMB->ParameterCount = pSMB->TotalParameterCount;
3065 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3066 pSMB->Reserved4 = 0;
3067 pSMB->hdr.smb_buf_length += byte_count;
3068 pSMB->ByteCount = cpu_to_le16(byte_count);
3069
3070 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3071 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3072 if (rc) {
3073 cFYI(1, ("error %d in QueryInternalInfo", rc));
3074 } else {
3075 /* decode response */
3076 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3077 if (rc || (pSMBr->ByteCount < 2))
3078 /* BB also check enough total bytes returned */
3079 /* If rc should we check for EOPNOSUPP and
3080 disable the srvino flag? or in caller? */
3081 rc = -EIO; /* bad smb */
3082 else {
3083 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3084 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3085 struct file_internal_info * pfinfo;
3086 /* BB Do we need a cast or hash here ? */
3087 if(count < 8) {
3088 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3089 rc = -EIO;
3090 goto GetInodeNumOut;
3091 }
3092 pfinfo = (struct file_internal_info *)
3093 (data_offset + (char *) &pSMBr->hdr.Protocol);
3094 *inode_number = pfinfo->UniqueId;
3095 }
3096 }
3097GetInodeNumOut:
3098 cifs_buf_release(pSMB);
3099 if (rc == -EAGAIN)
3100 goto GetInodeNumberRetry;
3101 return rc;
3102}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103
3104int
3105CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3106 const unsigned char *searchName,
3107 unsigned char **targetUNCs,
3108 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003109 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110{
3111/* TRANS2_GET_DFS_REFERRAL */
3112 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3113 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3114 struct dfs_referral_level_3 * referrals = NULL;
3115 int rc = 0;
3116 int bytes_returned;
3117 int name_len;
3118 unsigned int i;
3119 char * temp;
3120 __u16 params, byte_count;
3121 *number_of_UNC_in_array = 0;
3122 *targetUNCs = NULL;
3123
3124 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3125 if (ses == NULL)
3126 return -ENODEV;
3127getDFSRetry:
3128 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3129 (void **) &pSMBr);
3130 if (rc)
3131 return rc;
Steve French1982c342005-08-17 12:38:22 -07003132
3133 /* server pointer checked in called function,
3134 but should never be null here anyway */
3135 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 pSMB->hdr.Tid = ses->ipc_tid;
3137 pSMB->hdr.Uid = ses->Suid;
3138 if (ses->capabilities & CAP_STATUS32) {
3139 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3140 }
3141 if (ses->capabilities & CAP_DFS) {
3142 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3143 }
3144
3145 if (ses->capabilities & CAP_UNICODE) {
3146 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3147 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003148 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003149 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003150 name_len++; /* trailing null */
3151 name_len *= 2;
3152 } else { /* BB improve the check for buffer overruns BB */
3153 name_len = strnlen(searchName, PATH_MAX);
3154 name_len++; /* trailing null */
3155 strncpy(pSMB->RequestFileName, searchName, name_len);
3156 }
3157
3158 params = 2 /* level */ + name_len /*includes null */ ;
3159 pSMB->TotalDataCount = 0;
3160 pSMB->DataCount = 0;
3161 pSMB->DataOffset = 0;
3162 pSMB->MaxParameterCount = 0;
3163 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3164 pSMB->MaxSetupCount = 0;
3165 pSMB->Reserved = 0;
3166 pSMB->Flags = 0;
3167 pSMB->Timeout = 0;
3168 pSMB->Reserved2 = 0;
3169 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3170 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3171 pSMB->SetupCount = 1;
3172 pSMB->Reserved3 = 0;
3173 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3174 byte_count = params + 3 /* pad */ ;
3175 pSMB->ParameterCount = cpu_to_le16(params);
3176 pSMB->TotalParameterCount = pSMB->ParameterCount;
3177 pSMB->MaxReferralLevel = cpu_to_le16(3);
3178 pSMB->hdr.smb_buf_length += byte_count;
3179 pSMB->ByteCount = cpu_to_le16(byte_count);
3180
3181 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3182 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3183 if (rc) {
3184 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3185 } else { /* decode response */
3186/* BB Add logic to parse referrals here */
3187 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3188
3189 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3190 rc = -EIO; /* bad smb */
3191 else {
3192 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3193 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3194
3195 cFYI(1,
3196 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3197 pSMBr->ByteCount, data_offset));
3198 referrals =
3199 (struct dfs_referral_level_3 *)
3200 (8 /* sizeof start of data block */ +
3201 data_offset +
3202 (char *) &pSMBr->hdr.Protocol);
3203 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",
3204 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)));
3205 /* BB This field is actually two bytes in from start of
3206 data block so we could do safety check that DataBlock
3207 begins at address of pSMBr->NumberOfReferrals */
3208 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3209
3210 /* BB Fix below so can return more than one referral */
3211 if(*number_of_UNC_in_array > 1)
3212 *number_of_UNC_in_array = 1;
3213
3214 /* get the length of the strings describing refs */
3215 name_len = 0;
3216 for(i=0;i<*number_of_UNC_in_array;i++) {
3217 /* make sure that DfsPathOffset not past end */
3218 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3219 if (offset > data_count) {
3220 /* if invalid referral, stop here and do
3221 not try to copy any more */
3222 *number_of_UNC_in_array = i;
3223 break;
3224 }
3225 temp = ((char *)referrals) + offset;
3226
3227 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3228 name_len += UniStrnlen((wchar_t *)temp,data_count);
3229 } else {
3230 name_len += strnlen(temp,data_count);
3231 }
3232 referrals++;
3233 /* BB add check that referral pointer does not fall off end PDU */
3234
3235 }
3236 /* BB add check for name_len bigger than bcc */
3237 *targetUNCs =
3238 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3239 if(*targetUNCs == NULL) {
3240 rc = -ENOMEM;
3241 goto GetDFSRefExit;
3242 }
3243 /* copy the ref strings */
3244 referrals =
3245 (struct dfs_referral_level_3 *)
3246 (8 /* sizeof data hdr */ +
3247 data_offset +
3248 (char *) &pSMBr->hdr.Protocol);
3249
3250 for(i=0;i<*number_of_UNC_in_array;i++) {
3251 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3252 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3253 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003254 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003255 } else {
3256 strncpy(*targetUNCs,temp,name_len);
3257 }
3258 /* BB update target_uncs pointers */
3259 referrals++;
3260 }
3261 temp = *targetUNCs;
3262 temp[name_len] = 0;
3263 }
3264
3265 }
3266GetDFSRefExit:
3267 if (pSMB)
3268 cifs_buf_release(pSMB);
3269
3270 if (rc == -EAGAIN)
3271 goto getDFSRetry;
3272
3273 return rc;
3274}
3275
Steve French20962432005-09-21 22:05:57 -07003276/* Query File System Info such as free space to old servers such as Win 9x */
3277int
3278SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3279{
3280/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3281 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3282 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3283 FILE_SYSTEM_ALLOC_INFO *response_data;
3284 int rc = 0;
3285 int bytes_returned = 0;
3286 __u16 params, byte_count;
3287
3288 cFYI(1, ("OldQFSInfo"));
3289oldQFSInfoRetry:
3290 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3291 (void **) &pSMBr);
3292 if (rc)
3293 return rc;
3294 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3295 (void **) &pSMBr);
3296 if (rc)
3297 return rc;
3298
3299 params = 2; /* level */
3300 pSMB->TotalDataCount = 0;
3301 pSMB->MaxParameterCount = cpu_to_le16(2);
3302 pSMB->MaxDataCount = cpu_to_le16(1000);
3303 pSMB->MaxSetupCount = 0;
3304 pSMB->Reserved = 0;
3305 pSMB->Flags = 0;
3306 pSMB->Timeout = 0;
3307 pSMB->Reserved2 = 0;
3308 byte_count = params + 1 /* pad */ ;
3309 pSMB->TotalParameterCount = cpu_to_le16(params);
3310 pSMB->ParameterCount = pSMB->TotalParameterCount;
3311 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3312 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3313 pSMB->DataCount = 0;
3314 pSMB->DataOffset = 0;
3315 pSMB->SetupCount = 1;
3316 pSMB->Reserved3 = 0;
3317 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3318 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3319 pSMB->hdr.smb_buf_length += byte_count;
3320 pSMB->ByteCount = cpu_to_le16(byte_count);
3321
3322 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3323 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3324 if (rc) {
3325 cFYI(1, ("Send error in QFSInfo = %d", rc));
3326 } else { /* decode response */
3327 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3328
3329 if (rc || (pSMBr->ByteCount < 18))
3330 rc = -EIO; /* bad smb */
3331 else {
3332 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3333 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3334 pSMBr->ByteCount, data_offset));
3335
3336 response_data =
3337 (FILE_SYSTEM_ALLOC_INFO *)
3338 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3339 FSData->f_bsize =
3340 le16_to_cpu(response_data->BytesPerSector) *
3341 le32_to_cpu(response_data->
3342 SectorsPerAllocationUnit);
3343 FSData->f_blocks =
3344 le32_to_cpu(response_data->TotalAllocationUnits);
3345 FSData->f_bfree = FSData->f_bavail =
3346 le32_to_cpu(response_data->FreeAllocationUnits);
3347 cFYI(1,
3348 ("Blocks: %lld Free: %lld Block size %ld",
3349 (unsigned long long)FSData->f_blocks,
3350 (unsigned long long)FSData->f_bfree,
3351 FSData->f_bsize));
3352 }
3353 }
3354 cifs_buf_release(pSMB);
3355
3356 if (rc == -EAGAIN)
3357 goto oldQFSInfoRetry;
3358
3359 return rc;
3360}
3361
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362int
Steve French737b7582005-04-28 22:41:06 -07003363CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364{
3365/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3366 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3367 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3368 FILE_SYSTEM_INFO *response_data;
3369 int rc = 0;
3370 int bytes_returned = 0;
3371 __u16 params, byte_count;
3372
3373 cFYI(1, ("In QFSInfo"));
3374QFSInfoRetry:
3375 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3376 (void **) &pSMBr);
3377 if (rc)
3378 return rc;
3379
3380 params = 2; /* level */
3381 pSMB->TotalDataCount = 0;
3382 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003383 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 pSMB->MaxSetupCount = 0;
3385 pSMB->Reserved = 0;
3386 pSMB->Flags = 0;
3387 pSMB->Timeout = 0;
3388 pSMB->Reserved2 = 0;
3389 byte_count = params + 1 /* pad */ ;
3390 pSMB->TotalParameterCount = cpu_to_le16(params);
3391 pSMB->ParameterCount = pSMB->TotalParameterCount;
3392 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3393 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3394 pSMB->DataCount = 0;
3395 pSMB->DataOffset = 0;
3396 pSMB->SetupCount = 1;
3397 pSMB->Reserved3 = 0;
3398 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3399 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3400 pSMB->hdr.smb_buf_length += byte_count;
3401 pSMB->ByteCount = cpu_to_le16(byte_count);
3402
3403 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3404 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3405 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003406 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 } else { /* decode response */
3408 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3409
Steve French20962432005-09-21 22:05:57 -07003410 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003411 rc = -EIO; /* bad smb */
3412 else {
3413 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003414
3415 response_data =
3416 (FILE_SYSTEM_INFO
3417 *) (((char *) &pSMBr->hdr.Protocol) +
3418 data_offset);
3419 FSData->f_bsize =
3420 le32_to_cpu(response_data->BytesPerSector) *
3421 le32_to_cpu(response_data->
3422 SectorsPerAllocationUnit);
3423 FSData->f_blocks =
3424 le64_to_cpu(response_data->TotalAllocationUnits);
3425 FSData->f_bfree = FSData->f_bavail =
3426 le64_to_cpu(response_data->FreeAllocationUnits);
3427 cFYI(1,
3428 ("Blocks: %lld Free: %lld Block size %ld",
3429 (unsigned long long)FSData->f_blocks,
3430 (unsigned long long)FSData->f_bfree,
3431 FSData->f_bsize));
3432 }
3433 }
3434 cifs_buf_release(pSMB);
3435
3436 if (rc == -EAGAIN)
3437 goto QFSInfoRetry;
3438
3439 return rc;
3440}
3441
3442int
Steve French737b7582005-04-28 22:41:06 -07003443CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444{
3445/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3446 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3447 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3448 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3449 int rc = 0;
3450 int bytes_returned = 0;
3451 __u16 params, byte_count;
3452
3453 cFYI(1, ("In QFSAttributeInfo"));
3454QFSAttributeRetry:
3455 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3456 (void **) &pSMBr);
3457 if (rc)
3458 return rc;
3459
3460 params = 2; /* level */
3461 pSMB->TotalDataCount = 0;
3462 pSMB->MaxParameterCount = cpu_to_le16(2);
3463 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3464 pSMB->MaxSetupCount = 0;
3465 pSMB->Reserved = 0;
3466 pSMB->Flags = 0;
3467 pSMB->Timeout = 0;
3468 pSMB->Reserved2 = 0;
3469 byte_count = params + 1 /* pad */ ;
3470 pSMB->TotalParameterCount = cpu_to_le16(params);
3471 pSMB->ParameterCount = pSMB->TotalParameterCount;
3472 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3473 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3474 pSMB->DataCount = 0;
3475 pSMB->DataOffset = 0;
3476 pSMB->SetupCount = 1;
3477 pSMB->Reserved3 = 0;
3478 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3479 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3480 pSMB->hdr.smb_buf_length += byte_count;
3481 pSMB->ByteCount = cpu_to_le16(byte_count);
3482
3483 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3484 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3485 if (rc) {
3486 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3487 } else { /* decode response */
3488 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3489
3490 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3491 rc = -EIO; /* bad smb */
3492 } else {
3493 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3494 response_data =
3495 (FILE_SYSTEM_ATTRIBUTE_INFO
3496 *) (((char *) &pSMBr->hdr.Protocol) +
3497 data_offset);
3498 memcpy(&tcon->fsAttrInfo, response_data,
3499 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3500 }
3501 }
3502 cifs_buf_release(pSMB);
3503
3504 if (rc == -EAGAIN)
3505 goto QFSAttributeRetry;
3506
3507 return rc;
3508}
3509
3510int
Steve French737b7582005-04-28 22:41:06 -07003511CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512{
3513/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3514 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3515 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3516 FILE_SYSTEM_DEVICE_INFO *response_data;
3517 int rc = 0;
3518 int bytes_returned = 0;
3519 __u16 params, byte_count;
3520
3521 cFYI(1, ("In QFSDeviceInfo"));
3522QFSDeviceRetry:
3523 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3524 (void **) &pSMBr);
3525 if (rc)
3526 return rc;
3527
3528 params = 2; /* level */
3529 pSMB->TotalDataCount = 0;
3530 pSMB->MaxParameterCount = cpu_to_le16(2);
3531 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3532 pSMB->MaxSetupCount = 0;
3533 pSMB->Reserved = 0;
3534 pSMB->Flags = 0;
3535 pSMB->Timeout = 0;
3536 pSMB->Reserved2 = 0;
3537 byte_count = params + 1 /* pad */ ;
3538 pSMB->TotalParameterCount = cpu_to_le16(params);
3539 pSMB->ParameterCount = pSMB->TotalParameterCount;
3540 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3541 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3542
3543 pSMB->DataCount = 0;
3544 pSMB->DataOffset = 0;
3545 pSMB->SetupCount = 1;
3546 pSMB->Reserved3 = 0;
3547 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3548 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3549 pSMB->hdr.smb_buf_length += byte_count;
3550 pSMB->ByteCount = cpu_to_le16(byte_count);
3551
3552 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3553 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3554 if (rc) {
3555 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3556 } else { /* decode response */
3557 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3558
3559 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3560 rc = -EIO; /* bad smb */
3561 else {
3562 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3563 response_data =
Steve French737b7582005-04-28 22:41:06 -07003564 (FILE_SYSTEM_DEVICE_INFO *)
3565 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 data_offset);
3567 memcpy(&tcon->fsDevInfo, response_data,
3568 sizeof (FILE_SYSTEM_DEVICE_INFO));
3569 }
3570 }
3571 cifs_buf_release(pSMB);
3572
3573 if (rc == -EAGAIN)
3574 goto QFSDeviceRetry;
3575
3576 return rc;
3577}
3578
3579int
Steve French737b7582005-04-28 22:41:06 -07003580CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581{
3582/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3583 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3584 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3585 FILE_SYSTEM_UNIX_INFO *response_data;
3586 int rc = 0;
3587 int bytes_returned = 0;
3588 __u16 params, byte_count;
3589
3590 cFYI(1, ("In QFSUnixInfo"));
3591QFSUnixRetry:
3592 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3593 (void **) &pSMBr);
3594 if (rc)
3595 return rc;
3596
3597 params = 2; /* level */
3598 pSMB->TotalDataCount = 0;
3599 pSMB->DataCount = 0;
3600 pSMB->DataOffset = 0;
3601 pSMB->MaxParameterCount = cpu_to_le16(2);
3602 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3603 pSMB->MaxSetupCount = 0;
3604 pSMB->Reserved = 0;
3605 pSMB->Flags = 0;
3606 pSMB->Timeout = 0;
3607 pSMB->Reserved2 = 0;
3608 byte_count = params + 1 /* pad */ ;
3609 pSMB->ParameterCount = cpu_to_le16(params);
3610 pSMB->TotalParameterCount = pSMB->ParameterCount;
3611 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3612 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3613 pSMB->SetupCount = 1;
3614 pSMB->Reserved3 = 0;
3615 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3616 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3617 pSMB->hdr.smb_buf_length += byte_count;
3618 pSMB->ByteCount = cpu_to_le16(byte_count);
3619
3620 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3621 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3622 if (rc) {
3623 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3624 } else { /* decode response */
3625 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3626
3627 if (rc || (pSMBr->ByteCount < 13)) {
3628 rc = -EIO; /* bad smb */
3629 } else {
3630 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3631 response_data =
3632 (FILE_SYSTEM_UNIX_INFO
3633 *) (((char *) &pSMBr->hdr.Protocol) +
3634 data_offset);
3635 memcpy(&tcon->fsUnixInfo, response_data,
3636 sizeof (FILE_SYSTEM_UNIX_INFO));
3637 }
3638 }
3639 cifs_buf_release(pSMB);
3640
3641 if (rc == -EAGAIN)
3642 goto QFSUnixRetry;
3643
3644
3645 return rc;
3646}
3647
Jeremy Allisonac670552005-06-22 17:26:35 -07003648int
Steve French45abc6e2005-06-23 13:42:03 -05003649CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07003650{
3651/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3652 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3653 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3654 int rc = 0;
3655 int bytes_returned = 0;
3656 __u16 params, param_offset, offset, byte_count;
3657
3658 cFYI(1, ("In SETFSUnixInfo"));
3659SETFSUnixRetry:
3660 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3661 (void **) &pSMBr);
3662 if (rc)
3663 return rc;
3664
3665 params = 4; /* 2 bytes zero followed by info level. */
3666 pSMB->MaxSetupCount = 0;
3667 pSMB->Reserved = 0;
3668 pSMB->Flags = 0;
3669 pSMB->Timeout = 0;
3670 pSMB->Reserved2 = 0;
3671 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3672 offset = param_offset + params;
3673
3674 pSMB->MaxParameterCount = cpu_to_le16(4);
3675 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3676 pSMB->SetupCount = 1;
3677 pSMB->Reserved3 = 0;
3678 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3679 byte_count = 1 /* pad */ + params + 12;
3680
3681 pSMB->DataCount = cpu_to_le16(12);
3682 pSMB->ParameterCount = cpu_to_le16(params);
3683 pSMB->TotalDataCount = pSMB->DataCount;
3684 pSMB->TotalParameterCount = pSMB->ParameterCount;
3685 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3686 pSMB->DataOffset = cpu_to_le16(offset);
3687
3688 /* Params. */
3689 pSMB->FileNum = 0;
3690 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3691
3692 /* Data. */
3693 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3694 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3695 pSMB->ClientUnixCap = cpu_to_le64(cap);
3696
3697 pSMB->hdr.smb_buf_length += byte_count;
3698 pSMB->ByteCount = cpu_to_le16(byte_count);
3699
3700 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3701 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3702 if (rc) {
3703 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3704 } else { /* decode response */
3705 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3706 if (rc) {
3707 rc = -EIO; /* bad smb */
3708 }
3709 }
3710 cifs_buf_release(pSMB);
3711
3712 if (rc == -EAGAIN)
3713 goto SETFSUnixRetry;
3714
3715 return rc;
3716}
3717
3718
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719
3720int
3721CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003722 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723{
3724/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3725 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3726 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3727 FILE_SYSTEM_POSIX_INFO *response_data;
3728 int rc = 0;
3729 int bytes_returned = 0;
3730 __u16 params, byte_count;
3731
3732 cFYI(1, ("In QFSPosixInfo"));
3733QFSPosixRetry:
3734 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3735 (void **) &pSMBr);
3736 if (rc)
3737 return rc;
3738
3739 params = 2; /* level */
3740 pSMB->TotalDataCount = 0;
3741 pSMB->DataCount = 0;
3742 pSMB->DataOffset = 0;
3743 pSMB->MaxParameterCount = cpu_to_le16(2);
3744 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3745 pSMB->MaxSetupCount = 0;
3746 pSMB->Reserved = 0;
3747 pSMB->Flags = 0;
3748 pSMB->Timeout = 0;
3749 pSMB->Reserved2 = 0;
3750 byte_count = params + 1 /* pad */ ;
3751 pSMB->ParameterCount = cpu_to_le16(params);
3752 pSMB->TotalParameterCount = pSMB->ParameterCount;
3753 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3754 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3755 pSMB->SetupCount = 1;
3756 pSMB->Reserved3 = 0;
3757 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3758 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3759 pSMB->hdr.smb_buf_length += byte_count;
3760 pSMB->ByteCount = cpu_to_le16(byte_count);
3761
3762 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3763 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3764 if (rc) {
3765 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3766 } else { /* decode response */
3767 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3768
3769 if (rc || (pSMBr->ByteCount < 13)) {
3770 rc = -EIO; /* bad smb */
3771 } else {
3772 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3773 response_data =
3774 (FILE_SYSTEM_POSIX_INFO
3775 *) (((char *) &pSMBr->hdr.Protocol) +
3776 data_offset);
3777 FSData->f_bsize =
3778 le32_to_cpu(response_data->BlockSize);
3779 FSData->f_blocks =
3780 le64_to_cpu(response_data->TotalBlocks);
3781 FSData->f_bfree =
3782 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07003783 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 FSData->f_bavail = FSData->f_bfree;
3785 } else {
3786 FSData->f_bavail =
3787 le64_to_cpu(response_data->UserBlocksAvail);
3788 }
Steve French70ca7342005-09-22 16:32:06 -07003789 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 FSData->f_files =
3791 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07003792 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 FSData->f_ffree =
3794 le64_to_cpu(response_data->FreeFileNodes);
3795 }
3796 }
3797 cifs_buf_release(pSMB);
3798
3799 if (rc == -EAGAIN)
3800 goto QFSPosixRetry;
3801
3802 return rc;
3803}
3804
3805
3806/* We can not use write of zero bytes trick to
3807 set file size due to need for large file support. Also note that
3808 this SetPathInfo is preferred to SetFileInfo based method in next
3809 routine which is only needed to work around a sharing violation bug
3810 in Samba which this routine can run into */
3811
3812int
3813CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07003814 __u64 size, int SetAllocation,
3815 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816{
3817 struct smb_com_transaction2_spi_req *pSMB = NULL;
3818 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3819 struct file_end_of_file_info *parm_data;
3820 int name_len;
3821 int rc = 0;
3822 int bytes_returned = 0;
3823 __u16 params, byte_count, data_count, param_offset, offset;
3824
3825 cFYI(1, ("In SetEOF"));
3826SetEOFRetry:
3827 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3828 (void **) &pSMBr);
3829 if (rc)
3830 return rc;
3831
3832 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3833 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003834 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003835 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 name_len++; /* trailing null */
3837 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07003838 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839 name_len = strnlen(fileName, PATH_MAX);
3840 name_len++; /* trailing null */
3841 strncpy(pSMB->FileName, fileName, name_len);
3842 }
3843 params = 6 + name_len;
3844 data_count = sizeof (struct file_end_of_file_info);
3845 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07003846 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003847 pSMB->MaxSetupCount = 0;
3848 pSMB->Reserved = 0;
3849 pSMB->Flags = 0;
3850 pSMB->Timeout = 0;
3851 pSMB->Reserved2 = 0;
3852 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3853 InformationLevel) - 4;
3854 offset = param_offset + params;
3855 if(SetAllocation) {
3856 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3857 pSMB->InformationLevel =
3858 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3859 else
3860 pSMB->InformationLevel =
3861 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3862 } else /* Set File Size */ {
3863 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3864 pSMB->InformationLevel =
3865 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3866 else
3867 pSMB->InformationLevel =
3868 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3869 }
3870
3871 parm_data =
3872 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3873 offset);
3874 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3875 pSMB->DataOffset = cpu_to_le16(offset);
3876 pSMB->SetupCount = 1;
3877 pSMB->Reserved3 = 0;
3878 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3879 byte_count = 3 /* pad */ + params + data_count;
3880 pSMB->DataCount = cpu_to_le16(data_count);
3881 pSMB->TotalDataCount = pSMB->DataCount;
3882 pSMB->ParameterCount = cpu_to_le16(params);
3883 pSMB->TotalParameterCount = pSMB->ParameterCount;
3884 pSMB->Reserved4 = 0;
3885 pSMB->hdr.smb_buf_length += byte_count;
3886 parm_data->FileSize = cpu_to_le64(size);
3887 pSMB->ByteCount = cpu_to_le16(byte_count);
3888 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3889 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3890 if (rc) {
3891 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3892 }
3893
3894 cifs_buf_release(pSMB);
3895
3896 if (rc == -EAGAIN)
3897 goto SetEOFRetry;
3898
3899 return rc;
3900}
3901
3902int
3903CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
3904 __u16 fid, __u32 pid_of_opener, int SetAllocation)
3905{
3906 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3907 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3908 char *data_offset;
3909 struct file_end_of_file_info *parm_data;
3910 int rc = 0;
3911 int bytes_returned = 0;
3912 __u16 params, param_offset, offset, byte_count, count;
3913
3914 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3915 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07003916 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3917
Linus Torvalds1da177e2005-04-16 15:20:36 -07003918 if (rc)
3919 return rc;
3920
Steve Frenchcd634992005-04-28 22:41:10 -07003921 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3922
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3924 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3925
3926 params = 6;
3927 pSMB->MaxSetupCount = 0;
3928 pSMB->Reserved = 0;
3929 pSMB->Flags = 0;
3930 pSMB->Timeout = 0;
3931 pSMB->Reserved2 = 0;
3932 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3933 offset = param_offset + params;
3934
3935 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3936
3937 count = sizeof(struct file_end_of_file_info);
3938 pSMB->MaxParameterCount = cpu_to_le16(2);
3939 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3940 pSMB->SetupCount = 1;
3941 pSMB->Reserved3 = 0;
3942 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3943 byte_count = 3 /* pad */ + params + count;
3944 pSMB->DataCount = cpu_to_le16(count);
3945 pSMB->ParameterCount = cpu_to_le16(params);
3946 pSMB->TotalDataCount = pSMB->DataCount;
3947 pSMB->TotalParameterCount = pSMB->ParameterCount;
3948 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3949 parm_data =
3950 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3951 offset);
3952 pSMB->DataOffset = cpu_to_le16(offset);
3953 parm_data->FileSize = cpu_to_le64(size);
3954 pSMB->Fid = fid;
3955 if(SetAllocation) {
3956 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3957 pSMB->InformationLevel =
3958 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3959 else
3960 pSMB->InformationLevel =
3961 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3962 } else /* Set File Size */ {
3963 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3964 pSMB->InformationLevel =
3965 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3966 else
3967 pSMB->InformationLevel =
3968 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3969 }
3970 pSMB->Reserved4 = 0;
3971 pSMB->hdr.smb_buf_length += byte_count;
3972 pSMB->ByteCount = cpu_to_le16(byte_count);
3973 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3974 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3975 if (rc) {
3976 cFYI(1,
3977 ("Send error in SetFileInfo (SetFileSize) = %d",
3978 rc));
3979 }
3980
3981 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07003982 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983
3984 /* Note: On -EAGAIN error only caller can retry on handle based calls
3985 since file handle passed in no longer valid */
3986
3987 return rc;
3988}
3989
3990/* Some legacy servers such as NT4 require that the file times be set on
3991 an open handle, rather than by pathname - this is awkward due to
3992 potential access conflicts on the open, but it is unavoidable for these
3993 old servers since the only other choice is to go from 100 nanosecond DCE
3994 time and resort to the original setpathinfo level which takes the ancient
3995 DOS time format with 2 second granularity */
3996int
3997CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
3998 __u16 fid)
3999{
4000 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4001 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4002 char *data_offset;
4003 int rc = 0;
4004 int bytes_returned = 0;
4005 __u16 params, param_offset, offset, byte_count, count;
4006
4007 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004008 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4009
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 if (rc)
4011 return rc;
4012
Steve Frenchcd634992005-04-28 22:41:10 -07004013 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4014
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 /* At this point there is no need to override the current pid
4016 with the pid of the opener, but that could change if we someday
4017 use an existing handle (rather than opening one on the fly) */
4018 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4019 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4020
4021 params = 6;
4022 pSMB->MaxSetupCount = 0;
4023 pSMB->Reserved = 0;
4024 pSMB->Flags = 0;
4025 pSMB->Timeout = 0;
4026 pSMB->Reserved2 = 0;
4027 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4028 offset = param_offset + params;
4029
4030 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4031
4032 count = sizeof (FILE_BASIC_INFO);
4033 pSMB->MaxParameterCount = cpu_to_le16(2);
4034 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4035 pSMB->SetupCount = 1;
4036 pSMB->Reserved3 = 0;
4037 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4038 byte_count = 3 /* pad */ + params + count;
4039 pSMB->DataCount = cpu_to_le16(count);
4040 pSMB->ParameterCount = cpu_to_le16(params);
4041 pSMB->TotalDataCount = pSMB->DataCount;
4042 pSMB->TotalParameterCount = pSMB->ParameterCount;
4043 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4044 pSMB->DataOffset = cpu_to_le16(offset);
4045 pSMB->Fid = fid;
4046 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4047 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4048 else
4049 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4050 pSMB->Reserved4 = 0;
4051 pSMB->hdr.smb_buf_length += byte_count;
4052 pSMB->ByteCount = cpu_to_le16(byte_count);
4053 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4054 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4055 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4056 if (rc) {
4057 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4058 }
4059
Steve Frenchcd634992005-04-28 22:41:10 -07004060 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061
4062 /* Note: On -EAGAIN error only caller can retry on handle based calls
4063 since file handle passed in no longer valid */
4064
4065 return rc;
4066}
4067
4068
4069int
4070CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4071 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004072 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073{
4074 TRANSACTION2_SPI_REQ *pSMB = NULL;
4075 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4076 int name_len;
4077 int rc = 0;
4078 int bytes_returned = 0;
4079 char *data_offset;
4080 __u16 params, param_offset, offset, byte_count, count;
4081
4082 cFYI(1, ("In SetTimes"));
4083
4084SetTimesRetry:
4085 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4086 (void **) &pSMBr);
4087 if (rc)
4088 return rc;
4089
4090 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4091 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004092 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004093 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 name_len++; /* trailing null */
4095 name_len *= 2;
4096 } else { /* BB improve the check for buffer overruns BB */
4097 name_len = strnlen(fileName, PATH_MAX);
4098 name_len++; /* trailing null */
4099 strncpy(pSMB->FileName, fileName, name_len);
4100 }
4101
4102 params = 6 + name_len;
4103 count = sizeof (FILE_BASIC_INFO);
4104 pSMB->MaxParameterCount = cpu_to_le16(2);
4105 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4106 pSMB->MaxSetupCount = 0;
4107 pSMB->Reserved = 0;
4108 pSMB->Flags = 0;
4109 pSMB->Timeout = 0;
4110 pSMB->Reserved2 = 0;
4111 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4112 InformationLevel) - 4;
4113 offset = param_offset + params;
4114 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4115 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4116 pSMB->DataOffset = cpu_to_le16(offset);
4117 pSMB->SetupCount = 1;
4118 pSMB->Reserved3 = 0;
4119 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4120 byte_count = 3 /* pad */ + params + count;
4121
4122 pSMB->DataCount = cpu_to_le16(count);
4123 pSMB->ParameterCount = cpu_to_le16(params);
4124 pSMB->TotalDataCount = pSMB->DataCount;
4125 pSMB->TotalParameterCount = pSMB->ParameterCount;
4126 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4127 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4128 else
4129 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4130 pSMB->Reserved4 = 0;
4131 pSMB->hdr.smb_buf_length += byte_count;
4132 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4133 pSMB->ByteCount = cpu_to_le16(byte_count);
4134 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4135 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4136 if (rc) {
4137 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4138 }
4139
4140 cifs_buf_release(pSMB);
4141
4142 if (rc == -EAGAIN)
4143 goto SetTimesRetry;
4144
4145 return rc;
4146}
4147
4148/* Can not be used to set time stamps yet (due to old DOS time format) */
4149/* Can be used to set attributes */
4150#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4151 handling it anyway and NT4 was what we thought it would be needed for
4152 Do not delete it until we prove whether needed for Win9x though */
4153int
4154CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4155 __u16 dos_attrs, const struct nls_table *nls_codepage)
4156{
4157 SETATTR_REQ *pSMB = NULL;
4158 SETATTR_RSP *pSMBr = NULL;
4159 int rc = 0;
4160 int bytes_returned;
4161 int name_len;
4162
4163 cFYI(1, ("In SetAttrLegacy"));
4164
4165SetAttrLgcyRetry:
4166 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4167 (void **) &pSMBr);
4168 if (rc)
4169 return rc;
4170
4171 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4172 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004173 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 PATH_MAX, nls_codepage);
4175 name_len++; /* trailing null */
4176 name_len *= 2;
4177 } else { /* BB improve the check for buffer overruns BB */
4178 name_len = strnlen(fileName, PATH_MAX);
4179 name_len++; /* trailing null */
4180 strncpy(pSMB->fileName, fileName, name_len);
4181 }
4182 pSMB->attr = cpu_to_le16(dos_attrs);
4183 pSMB->BufferFormat = 0x04;
4184 pSMB->hdr.smb_buf_length += name_len + 1;
4185 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4186 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4187 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4188 if (rc) {
4189 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4190 }
4191
4192 cifs_buf_release(pSMB);
4193
4194 if (rc == -EAGAIN)
4195 goto SetAttrLgcyRetry;
4196
4197 return rc;
4198}
4199#endif /* temporarily unneeded SetAttr legacy function */
4200
4201int
4202CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004203 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4204 dev_t device, const struct nls_table *nls_codepage,
4205 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206{
4207 TRANSACTION2_SPI_REQ *pSMB = NULL;
4208 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4209 int name_len;
4210 int rc = 0;
4211 int bytes_returned = 0;
4212 FILE_UNIX_BASIC_INFO *data_offset;
4213 __u16 params, param_offset, offset, count, byte_count;
4214
4215 cFYI(1, ("In SetUID/GID/Mode"));
4216setPermsRetry:
4217 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4218 (void **) &pSMBr);
4219 if (rc)
4220 return rc;
4221
4222 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4223 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004224 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004225 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 name_len++; /* trailing null */
4227 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004228 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 name_len = strnlen(fileName, PATH_MAX);
4230 name_len++; /* trailing null */
4231 strncpy(pSMB->FileName, fileName, name_len);
4232 }
4233
4234 params = 6 + name_len;
4235 count = sizeof (FILE_UNIX_BASIC_INFO);
4236 pSMB->MaxParameterCount = cpu_to_le16(2);
4237 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4238 pSMB->MaxSetupCount = 0;
4239 pSMB->Reserved = 0;
4240 pSMB->Flags = 0;
4241 pSMB->Timeout = 0;
4242 pSMB->Reserved2 = 0;
4243 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4244 InformationLevel) - 4;
4245 offset = param_offset + params;
4246 data_offset =
4247 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4248 offset);
4249 memset(data_offset, 0, count);
4250 pSMB->DataOffset = cpu_to_le16(offset);
4251 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4252 pSMB->SetupCount = 1;
4253 pSMB->Reserved3 = 0;
4254 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4255 byte_count = 3 /* pad */ + params + count;
4256 pSMB->ParameterCount = cpu_to_le16(params);
4257 pSMB->DataCount = cpu_to_le16(count);
4258 pSMB->TotalParameterCount = pSMB->ParameterCount;
4259 pSMB->TotalDataCount = pSMB->DataCount;
4260 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4261 pSMB->Reserved4 = 0;
4262 pSMB->hdr.smb_buf_length += byte_count;
4263 data_offset->Uid = cpu_to_le64(uid);
4264 data_offset->Gid = cpu_to_le64(gid);
4265 /* better to leave device as zero when it is */
4266 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4267 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4268 data_offset->Permissions = cpu_to_le64(mode);
4269
4270 if(S_ISREG(mode))
4271 data_offset->Type = cpu_to_le32(UNIX_FILE);
4272 else if(S_ISDIR(mode))
4273 data_offset->Type = cpu_to_le32(UNIX_DIR);
4274 else if(S_ISLNK(mode))
4275 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4276 else if(S_ISCHR(mode))
4277 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4278 else if(S_ISBLK(mode))
4279 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4280 else if(S_ISFIFO(mode))
4281 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4282 else if(S_ISSOCK(mode))
4283 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4284
4285
4286 pSMB->ByteCount = cpu_to_le16(byte_count);
4287 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4288 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4289 if (rc) {
4290 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4291 }
4292
4293 if (pSMB)
4294 cifs_buf_release(pSMB);
4295 if (rc == -EAGAIN)
4296 goto setPermsRetry;
4297 return rc;
4298}
4299
4300int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004301 const int notify_subdirs, const __u16 netfid,
4302 __u32 filter, struct file * pfile, int multishot,
4303 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304{
4305 int rc = 0;
4306 struct smb_com_transaction_change_notify_req * pSMB = NULL;
4307 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004308 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 int bytes_returned;
4310
4311 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4312 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4313 (void **) &pSMBr);
4314 if (rc)
4315 return rc;
4316
4317 pSMB->TotalParameterCount = 0 ;
4318 pSMB->TotalDataCount = 0;
4319 pSMB->MaxParameterCount = cpu_to_le32(2);
4320 /* BB find exact data count max from sess structure BB */
4321 pSMB->MaxDataCount = 0; /* same in little endian or be */
4322 pSMB->MaxSetupCount = 4;
4323 pSMB->Reserved = 0;
4324 pSMB->ParameterOffset = 0;
4325 pSMB->DataCount = 0;
4326 pSMB->DataOffset = 0;
4327 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4328 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4329 pSMB->ParameterCount = pSMB->TotalParameterCount;
4330 if(notify_subdirs)
4331 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4332 pSMB->Reserved2 = 0;
4333 pSMB->CompletionFilter = cpu_to_le32(filter);
4334 pSMB->Fid = netfid; /* file handle always le */
4335 pSMB->ByteCount = 0;
4336
4337 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4338 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4339 if (rc) {
4340 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004341 } else {
4342 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004343 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004344 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004345 sizeof(struct dir_notify_req),
4346 GFP_KERNEL);
4347 if(dnotify_req) {
4348 dnotify_req->Pid = pSMB->hdr.Pid;
4349 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4350 dnotify_req->Mid = pSMB->hdr.Mid;
4351 dnotify_req->Tid = pSMB->hdr.Tid;
4352 dnotify_req->Uid = pSMB->hdr.Uid;
4353 dnotify_req->netfid = netfid;
4354 dnotify_req->pfile = pfile;
4355 dnotify_req->filter = filter;
4356 dnotify_req->multishot = multishot;
4357 spin_lock(&GlobalMid_Lock);
4358 list_add_tail(&dnotify_req->lhead,
4359 &GlobalDnotifyReqList);
4360 spin_unlock(&GlobalMid_Lock);
4361 } else
4362 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363 }
4364 cifs_buf_release(pSMB);
4365 return rc;
4366}
4367#ifdef CONFIG_CIFS_XATTR
4368ssize_t
4369CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4370 const unsigned char *searchName,
4371 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004372 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004373{
4374 /* BB assumes one setup word */
4375 TRANSACTION2_QPI_REQ *pSMB = NULL;
4376 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4377 int rc = 0;
4378 int bytes_returned;
4379 int name_len;
4380 struct fea * temp_fea;
4381 char * temp_ptr;
4382 __u16 params, byte_count;
4383
4384 cFYI(1, ("In Query All EAs path %s", searchName));
4385QAllEAsRetry:
4386 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4387 (void **) &pSMBr);
4388 if (rc)
4389 return rc;
4390
4391 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4392 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004393 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004394 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395 name_len++; /* trailing null */
4396 name_len *= 2;
4397 } else { /* BB improve the check for buffer overruns BB */
4398 name_len = strnlen(searchName, PATH_MAX);
4399 name_len++; /* trailing null */
4400 strncpy(pSMB->FileName, searchName, name_len);
4401 }
4402
4403 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4404 pSMB->TotalDataCount = 0;
4405 pSMB->MaxParameterCount = cpu_to_le16(2);
4406 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4407 pSMB->MaxSetupCount = 0;
4408 pSMB->Reserved = 0;
4409 pSMB->Flags = 0;
4410 pSMB->Timeout = 0;
4411 pSMB->Reserved2 = 0;
4412 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4413 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4414 pSMB->DataCount = 0;
4415 pSMB->DataOffset = 0;
4416 pSMB->SetupCount = 1;
4417 pSMB->Reserved3 = 0;
4418 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4419 byte_count = params + 1 /* pad */ ;
4420 pSMB->TotalParameterCount = cpu_to_le16(params);
4421 pSMB->ParameterCount = pSMB->TotalParameterCount;
4422 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4423 pSMB->Reserved4 = 0;
4424 pSMB->hdr.smb_buf_length += byte_count;
4425 pSMB->ByteCount = cpu_to_le16(byte_count);
4426
4427 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4428 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4429 if (rc) {
4430 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4431 } else { /* decode response */
4432 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4433
4434 /* BB also check enough total bytes returned */
4435 /* BB we need to improve the validity checking
4436 of these trans2 responses */
4437 if (rc || (pSMBr->ByteCount < 4))
4438 rc = -EIO; /* bad smb */
4439 /* else if (pFindData){
4440 memcpy((char *) pFindData,
4441 (char *) &pSMBr->hdr.Protocol +
4442 data_offset, kl);
4443 }*/ else {
4444 /* check that length of list is not more than bcc */
4445 /* check that each entry does not go beyond length
4446 of list */
4447 /* check that each element of each entry does not
4448 go beyond end of list */
4449 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4450 struct fealist * ea_response_data;
4451 rc = 0;
4452 /* validate_trans2_offsets() */
4453 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4454 ea_response_data = (struct fealist *)
4455 (((char *) &pSMBr->hdr.Protocol) +
4456 data_offset);
4457 name_len = le32_to_cpu(ea_response_data->list_len);
4458 cFYI(1,("ea length %d", name_len));
4459 if(name_len <= 8) {
4460 /* returned EA size zeroed at top of function */
4461 cFYI(1,("empty EA list returned from server"));
4462 } else {
4463 /* account for ea list len */
4464 name_len -= 4;
4465 temp_fea = ea_response_data->list;
4466 temp_ptr = (char *)temp_fea;
4467 while(name_len > 0) {
4468 __u16 value_len;
4469 name_len -= 4;
4470 temp_ptr += 4;
4471 rc += temp_fea->name_len;
4472 /* account for prefix user. and trailing null */
4473 rc = rc + 5 + 1;
4474 if(rc<(int)buf_size) {
4475 memcpy(EAData,"user.",5);
4476 EAData+=5;
4477 memcpy(EAData,temp_ptr,temp_fea->name_len);
4478 EAData+=temp_fea->name_len;
4479 /* null terminate name */
4480 *EAData = 0;
4481 EAData = EAData + 1;
4482 } else if(buf_size == 0) {
4483 /* skip copy - calc size only */
4484 } else {
4485 /* stop before overrun buffer */
4486 rc = -ERANGE;
4487 break;
4488 }
4489 name_len -= temp_fea->name_len;
4490 temp_ptr += temp_fea->name_len;
4491 /* account for trailing null */
4492 name_len--;
4493 temp_ptr++;
4494 value_len = le16_to_cpu(temp_fea->value_len);
4495 name_len -= value_len;
4496 temp_ptr += value_len;
4497 /* BB check that temp_ptr is still within smb BB*/
4498 /* no trailing null to account for in value len */
4499 /* go on to next EA */
4500 temp_fea = (struct fea *)temp_ptr;
4501 }
4502 }
4503 }
4504 }
4505 if (pSMB)
4506 cifs_buf_release(pSMB);
4507 if (rc == -EAGAIN)
4508 goto QAllEAsRetry;
4509
4510 return (ssize_t)rc;
4511}
4512
4513ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4514 const unsigned char * searchName,const unsigned char * ea_name,
4515 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004516 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517{
4518 TRANSACTION2_QPI_REQ *pSMB = NULL;
4519 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4520 int rc = 0;
4521 int bytes_returned;
4522 int name_len;
4523 struct fea * temp_fea;
4524 char * temp_ptr;
4525 __u16 params, byte_count;
4526
4527 cFYI(1, ("In Query EA path %s", searchName));
4528QEARetry:
4529 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4530 (void **) &pSMBr);
4531 if (rc)
4532 return rc;
4533
4534 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4535 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004536 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004537 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004538 name_len++; /* trailing null */
4539 name_len *= 2;
4540 } else { /* BB improve the check for buffer overruns BB */
4541 name_len = strnlen(searchName, PATH_MAX);
4542 name_len++; /* trailing null */
4543 strncpy(pSMB->FileName, searchName, name_len);
4544 }
4545
4546 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4547 pSMB->TotalDataCount = 0;
4548 pSMB->MaxParameterCount = cpu_to_le16(2);
4549 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4550 pSMB->MaxSetupCount = 0;
4551 pSMB->Reserved = 0;
4552 pSMB->Flags = 0;
4553 pSMB->Timeout = 0;
4554 pSMB->Reserved2 = 0;
4555 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4556 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4557 pSMB->DataCount = 0;
4558 pSMB->DataOffset = 0;
4559 pSMB->SetupCount = 1;
4560 pSMB->Reserved3 = 0;
4561 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4562 byte_count = params + 1 /* pad */ ;
4563 pSMB->TotalParameterCount = cpu_to_le16(params);
4564 pSMB->ParameterCount = pSMB->TotalParameterCount;
4565 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4566 pSMB->Reserved4 = 0;
4567 pSMB->hdr.smb_buf_length += byte_count;
4568 pSMB->ByteCount = cpu_to_le16(byte_count);
4569
4570 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4571 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4572 if (rc) {
4573 cFYI(1, ("Send error in Query EA = %d", rc));
4574 } else { /* decode response */
4575 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4576
4577 /* BB also check enough total bytes returned */
4578 /* BB we need to improve the validity checking
4579 of these trans2 responses */
4580 if (rc || (pSMBr->ByteCount < 4))
4581 rc = -EIO; /* bad smb */
4582 /* else if (pFindData){
4583 memcpy((char *) pFindData,
4584 (char *) &pSMBr->hdr.Protocol +
4585 data_offset, kl);
4586 }*/ else {
4587 /* check that length of list is not more than bcc */
4588 /* check that each entry does not go beyond length
4589 of list */
4590 /* check that each element of each entry does not
4591 go beyond end of list */
4592 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4593 struct fealist * ea_response_data;
4594 rc = -ENODATA;
4595 /* validate_trans2_offsets() */
4596 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4597 ea_response_data = (struct fealist *)
4598 (((char *) &pSMBr->hdr.Protocol) +
4599 data_offset);
4600 name_len = le32_to_cpu(ea_response_data->list_len);
4601 cFYI(1,("ea length %d", name_len));
4602 if(name_len <= 8) {
4603 /* returned EA size zeroed at top of function */
4604 cFYI(1,("empty EA list returned from server"));
4605 } else {
4606 /* account for ea list len */
4607 name_len -= 4;
4608 temp_fea = ea_response_data->list;
4609 temp_ptr = (char *)temp_fea;
4610 /* loop through checking if we have a matching
4611 name and then return the associated value */
4612 while(name_len > 0) {
4613 __u16 value_len;
4614 name_len -= 4;
4615 temp_ptr += 4;
4616 value_len = le16_to_cpu(temp_fea->value_len);
4617 /* BB validate that value_len falls within SMB,
4618 even though maximum for name_len is 255 */
4619 if(memcmp(temp_fea->name,ea_name,
4620 temp_fea->name_len) == 0) {
4621 /* found a match */
4622 rc = value_len;
4623 /* account for prefix user. and trailing null */
4624 if(rc<=(int)buf_size) {
4625 memcpy(ea_value,
4626 temp_fea->name+temp_fea->name_len+1,
4627 rc);
4628 /* ea values, unlike ea names,
4629 are not null terminated */
4630 } else if(buf_size == 0) {
4631 /* skip copy - calc size only */
4632 } else {
4633 /* stop before overrun buffer */
4634 rc = -ERANGE;
4635 }
4636 break;
4637 }
4638 name_len -= temp_fea->name_len;
4639 temp_ptr += temp_fea->name_len;
4640 /* account for trailing null */
4641 name_len--;
4642 temp_ptr++;
4643 name_len -= value_len;
4644 temp_ptr += value_len;
4645 /* no trailing null to account for in value len */
4646 /* go on to next EA */
4647 temp_fea = (struct fea *)temp_ptr;
4648 }
4649 }
4650 }
4651 }
4652 if (pSMB)
4653 cifs_buf_release(pSMB);
4654 if (rc == -EAGAIN)
4655 goto QEARetry;
4656
4657 return (ssize_t)rc;
4658}
4659
4660int
4661CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4662 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004663 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4664 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665{
4666 struct smb_com_transaction2_spi_req *pSMB = NULL;
4667 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4668 struct fealist *parm_data;
4669 int name_len;
4670 int rc = 0;
4671 int bytes_returned = 0;
4672 __u16 params, param_offset, byte_count, offset, count;
4673
4674 cFYI(1, ("In SetEA"));
4675SetEARetry:
4676 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4677 (void **) &pSMBr);
4678 if (rc)
4679 return rc;
4680
4681 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4682 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004683 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004684 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685 name_len++; /* trailing null */
4686 name_len *= 2;
4687 } else { /* BB improve the check for buffer overruns BB */
4688 name_len = strnlen(fileName, PATH_MAX);
4689 name_len++; /* trailing null */
4690 strncpy(pSMB->FileName, fileName, name_len);
4691 }
4692
4693 params = 6 + name_len;
4694
4695 /* done calculating parms using name_len of file name,
4696 now use name_len to calculate length of ea name
4697 we are going to create in the inode xattrs */
4698 if(ea_name == NULL)
4699 name_len = 0;
4700 else
4701 name_len = strnlen(ea_name,255);
4702
4703 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4704 pSMB->MaxParameterCount = cpu_to_le16(2);
4705 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4706 pSMB->MaxSetupCount = 0;
4707 pSMB->Reserved = 0;
4708 pSMB->Flags = 0;
4709 pSMB->Timeout = 0;
4710 pSMB->Reserved2 = 0;
4711 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4712 InformationLevel) - 4;
4713 offset = param_offset + params;
4714 pSMB->InformationLevel =
4715 cpu_to_le16(SMB_SET_FILE_EA);
4716
4717 parm_data =
4718 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4719 offset);
4720 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4721 pSMB->DataOffset = cpu_to_le16(offset);
4722 pSMB->SetupCount = 1;
4723 pSMB->Reserved3 = 0;
4724 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4725 byte_count = 3 /* pad */ + params + count;
4726 pSMB->DataCount = cpu_to_le16(count);
4727 parm_data->list_len = cpu_to_le32(count);
4728 parm_data->list[0].EA_flags = 0;
4729 /* we checked above that name len is less than 255 */
4730 parm_data->list[0].name_len = (__u8)name_len;;
4731 /* EA names are always ASCII */
4732 if(ea_name)
4733 strncpy(parm_data->list[0].name,ea_name,name_len);
4734 parm_data->list[0].name[name_len] = 0;
4735 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4736 /* caller ensures that ea_value_len is less than 64K but
4737 we need to ensure that it fits within the smb */
4738
4739 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4740 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4741 if(ea_value_len)
4742 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4743
4744 pSMB->TotalDataCount = pSMB->DataCount;
4745 pSMB->ParameterCount = cpu_to_le16(params);
4746 pSMB->TotalParameterCount = pSMB->ParameterCount;
4747 pSMB->Reserved4 = 0;
4748 pSMB->hdr.smb_buf_length += byte_count;
4749 pSMB->ByteCount = cpu_to_le16(byte_count);
4750 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4751 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4752 if (rc) {
4753 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4754 }
4755
4756 cifs_buf_release(pSMB);
4757
4758 if (rc == -EAGAIN)
4759 goto SetEARetry;
4760
4761 return rc;
4762}
4763
4764#endif