blob: 20300bc9ae7786adf14d3b8a008d8009c6193408 [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
Steve French0a4b92c2006-01-12 15:44:21 -08001929/* Initialize NT TRANSACT SMB into small smb request buffer.
1930 This assumes that all NT TRANSACTS that we init here have
1931 total parm and data under about 400 bytes (to fit in small cifs
1932 buffer size), which is the case so far, it easily fits. NB:
1933 Setup words themselves and ByteCount
1934 MaxSetupCount (size of returned setup area) and
1935 MaxParameterCount (returned parms size) must be set by caller */
1936static int
1937smb_init_ntransact(const __u16 sub_command, const int setup_count,
1938 const int parm_len, struct cifsTconInfo *tcon,
1939 void ** ret_buf)
1940{
1941 int rc;
1942 __u32 temp_offset;
1943 struct smb_com_ntransact_req * pSMB;
1944
1945 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
1946 (void **)&pSMB);
1947 if (rc)
1948 return rc;
1949 *ret_buf = (void *)pSMB;
1950 pSMB->Reserved = 0;
1951 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
1952 pSMB->TotalDataCount = 0;
1953 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
1954 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
1955 pSMB->ParameterCount = pSMB->TotalParameterCount;
1956 pSMB->DataCount = pSMB->TotalDataCount;
1957 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
1958 (setup_count * 2) - 4 /* for rfc1001 length itself */;
1959 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
1960 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
1961 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
1962 pSMB->SubCommand = cpu_to_le16(sub_command);
1963 return 0;
1964}
1965
1966static int
1967validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
1968 int * pdatalen, int * pparmlen)
1969{
1970 char * end_of_smb;
1971 __u32 data_count, data_offset, parm_count, parm_offset;
1972 struct smb_com_ntransact_rsp * pSMBr;
1973
1974 if(buf == NULL)
1975 return -EINVAL;
1976
1977 pSMBr = (struct smb_com_ntransact_rsp *)buf;
1978
1979 /* ByteCount was converted from little endian in SendReceive */
1980 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
1981 (char *)&pSMBr->ByteCount;
1982
1983
1984 data_offset = le32_to_cpu(pSMBr->DataOffset);
1985 data_count = le32_to_cpu(pSMBr->DataCount);
1986 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
1987 parm_count = le32_to_cpu(pSMBr->ParameterCount);
1988
1989 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
1990 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
1991
1992 /* should we also check that parm and data areas do not overlap? */
1993 if(*ppparm > end_of_smb) {
1994 cFYI(1,("parms start after end of smb"));
1995 return -EINVAL;
1996 } else if(parm_count + *ppparm > end_of_smb) {
1997 cFYI(1,("parm end after end of smb"));
1998 return -EINVAL;
1999 } else if(*ppdata > end_of_smb) {
2000 cFYI(1,("data starts after end of smb"));
2001 return -EINVAL;
2002 } else if(data_count + *ppdata > end_of_smb) {
2003 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2004 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2005 return -EINVAL;
2006 } else if(parm_count + data_count > pSMBr->ByteCount) {
2007 cFYI(1,("parm count and data count larger than SMB"));
2008 return -EINVAL;
2009 }
2010 return 0;
2011}
2012
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013int
2014CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2015 const unsigned char *searchName,
2016 char *symlinkinfo, const int buflen,__u16 fid,
2017 const struct nls_table *nls_codepage)
2018{
2019 int rc = 0;
2020 int bytes_returned;
2021 int name_len;
2022 struct smb_com_transaction_ioctl_req * pSMB;
2023 struct smb_com_transaction_ioctl_rsp * pSMBr;
2024
2025 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2026 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2027 (void **) &pSMBr);
2028 if (rc)
2029 return rc;
2030
2031 pSMB->TotalParameterCount = 0 ;
2032 pSMB->TotalDataCount = 0;
2033 pSMB->MaxParameterCount = cpu_to_le32(2);
2034 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002035 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2036 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 pSMB->MaxSetupCount = 4;
2038 pSMB->Reserved = 0;
2039 pSMB->ParameterOffset = 0;
2040 pSMB->DataCount = 0;
2041 pSMB->DataOffset = 0;
2042 pSMB->SetupCount = 4;
2043 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2044 pSMB->ParameterCount = pSMB->TotalParameterCount;
2045 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2046 pSMB->IsFsctl = 1; /* FSCTL */
2047 pSMB->IsRootFlag = 0;
2048 pSMB->Fid = fid; /* file handle always le */
2049 pSMB->ByteCount = 0;
2050
2051 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2052 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2053 if (rc) {
2054 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2055 } else { /* decode response */
2056 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2057 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2058 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2059 /* BB also check enough total bytes returned */
2060 rc = -EIO; /* bad smb */
2061 else {
2062 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002063 char * end_of_smb = 2 /* sizeof byte count */ +
2064 pSMBr->ByteCount +
2065 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066
2067 struct reparse_data * reparse_buf = (struct reparse_data *)
2068 ((char *)&pSMBr->hdr.Protocol + data_offset);
2069 if((char*)reparse_buf >= end_of_smb) {
2070 rc = -EIO;
2071 goto qreparse_out;
2072 }
2073 if((reparse_buf->LinkNamesBuf +
2074 reparse_buf->TargetNameOffset +
2075 reparse_buf->TargetNameLen) >
2076 end_of_smb) {
2077 cFYI(1,("reparse buf extended beyond SMB"));
2078 rc = -EIO;
2079 goto qreparse_out;
2080 }
2081
2082 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2083 name_len = UniStrnlen((wchar_t *)
2084 (reparse_buf->LinkNamesBuf +
2085 reparse_buf->TargetNameOffset),
2086 min(buflen/2, reparse_buf->TargetNameLen / 2));
2087 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002088 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 reparse_buf->TargetNameOffset),
2090 name_len, nls_codepage);
2091 } else { /* ASCII names */
2092 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2093 reparse_buf->TargetNameOffset,
2094 min_t(const int, buflen, reparse_buf->TargetNameLen));
2095 }
2096 } else {
2097 rc = -EIO;
2098 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2099 }
2100 symlinkinfo[buflen] = 0; /* just in case so the caller
2101 does not go off the end of the buffer */
2102 cFYI(1,("readlink result - %s ",symlinkinfo));
2103 }
2104 }
2105qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002106 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002107
2108 /* Note: On -EAGAIN error only caller can retry on handle based calls
2109 since file handle passed in no longer valid */
2110
2111 return rc;
2112}
2113
2114#ifdef CONFIG_CIFS_POSIX
2115
2116/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2117static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2118{
2119 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002120 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2121 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2122 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2124
2125 return;
2126}
2127
2128/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002129static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2130 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131{
2132 int size = 0;
2133 int i;
2134 __u16 count;
2135 struct cifs_posix_ace * pACE;
2136 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2137 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2138
2139 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2140 return -EOPNOTSUPP;
2141
2142 if(acl_type & ACL_TYPE_ACCESS) {
2143 count = le16_to_cpu(cifs_acl->access_entry_count);
2144 pACE = &cifs_acl->ace_array[0];
2145 size = sizeof(struct cifs_posix_acl);
2146 size += sizeof(struct cifs_posix_ace) * count;
2147 /* check if we would go beyond end of SMB */
2148 if(size_of_data_area < size) {
2149 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2150 return -EINVAL;
2151 }
2152 } else if(acl_type & ACL_TYPE_DEFAULT) {
2153 count = le16_to_cpu(cifs_acl->access_entry_count);
2154 size = sizeof(struct cifs_posix_acl);
2155 size += sizeof(struct cifs_posix_ace) * count;
2156/* skip past access ACEs to get to default ACEs */
2157 pACE = &cifs_acl->ace_array[count];
2158 count = le16_to_cpu(cifs_acl->default_entry_count);
2159 size += sizeof(struct cifs_posix_ace) * count;
2160 /* check if we would go beyond end of SMB */
2161 if(size_of_data_area < size)
2162 return -EINVAL;
2163 } else {
2164 /* illegal type */
2165 return -EINVAL;
2166 }
2167
2168 size = posix_acl_xattr_size(count);
2169 if((buflen == 0) || (local_acl == NULL)) {
2170 /* used to query ACL EA size */
2171 } else if(size > buflen) {
2172 return -ERANGE;
2173 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002174 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175 for(i = 0;i < count ;i++) {
2176 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2177 pACE ++;
2178 }
2179 }
2180 return size;
2181}
2182
2183static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2184 const posix_acl_xattr_entry * local_ace)
2185{
2186 __u16 rc = 0; /* 0 = ACL converted ok */
2187
Steve Frenchff7feac2005-11-15 16:45:16 -08002188 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2189 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002191 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 /* Probably no need to le convert -1 on any arch but can not hurt */
2193 cifs_ace->cifs_uid = cpu_to_le64(-1);
2194 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002195 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2197 return rc;
2198}
2199
2200/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2201static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2202 const int acl_type)
2203{
2204 __u16 rc = 0;
2205 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2206 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2207 int count;
2208 int i;
2209
2210 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2211 return 0;
2212
2213 count = posix_acl_xattr_count((size_t)buflen);
2214 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002215 count, buflen, le32_to_cpu(local_acl->a_version)));
2216 if(le32_to_cpu(local_acl->a_version) != 2) {
2217 cFYI(1,("unknown POSIX ACL version %d",
2218 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 return 0;
2220 }
2221 cifs_acl->version = cpu_to_le16(1);
2222 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002223 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002225 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 else {
2227 cFYI(1,("unknown ACL type %d",acl_type));
2228 return 0;
2229 }
2230 for(i=0;i<count;i++) {
2231 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2232 &local_acl->a_entries[i]);
2233 if(rc != 0) {
2234 /* ACE not converted */
2235 break;
2236 }
2237 }
2238 if(rc == 0) {
2239 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2240 rc += sizeof(struct cifs_posix_acl);
2241 /* BB add check to make sure ACL does not overflow SMB */
2242 }
2243 return rc;
2244}
2245
2246int
2247CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2248 const unsigned char *searchName,
2249 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002250 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251{
2252/* SMB_QUERY_POSIX_ACL */
2253 TRANSACTION2_QPI_REQ *pSMB = NULL;
2254 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2255 int rc = 0;
2256 int bytes_returned;
2257 int name_len;
2258 __u16 params, byte_count;
2259
2260 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2261
2262queryAclRetry:
2263 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2264 (void **) &pSMBr);
2265 if (rc)
2266 return rc;
2267
2268 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2269 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002270 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002271 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 name_len++; /* trailing null */
2273 name_len *= 2;
2274 pSMB->FileName[name_len] = 0;
2275 pSMB->FileName[name_len+1] = 0;
2276 } else { /* BB improve the check for buffer overruns BB */
2277 name_len = strnlen(searchName, PATH_MAX);
2278 name_len++; /* trailing null */
2279 strncpy(pSMB->FileName, searchName, name_len);
2280 }
2281
2282 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2283 pSMB->TotalDataCount = 0;
2284 pSMB->MaxParameterCount = cpu_to_le16(2);
2285 /* BB find exact max data count below from sess structure BB */
2286 pSMB->MaxDataCount = cpu_to_le16(4000);
2287 pSMB->MaxSetupCount = 0;
2288 pSMB->Reserved = 0;
2289 pSMB->Flags = 0;
2290 pSMB->Timeout = 0;
2291 pSMB->Reserved2 = 0;
2292 pSMB->ParameterOffset = cpu_to_le16(
2293 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2294 pSMB->DataCount = 0;
2295 pSMB->DataOffset = 0;
2296 pSMB->SetupCount = 1;
2297 pSMB->Reserved3 = 0;
2298 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2299 byte_count = params + 1 /* pad */ ;
2300 pSMB->TotalParameterCount = cpu_to_le16(params);
2301 pSMB->ParameterCount = pSMB->TotalParameterCount;
2302 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2303 pSMB->Reserved4 = 0;
2304 pSMB->hdr.smb_buf_length += byte_count;
2305 pSMB->ByteCount = cpu_to_le16(byte_count);
2306
2307 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2308 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002309 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 if (rc) {
2311 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2312 } else {
2313 /* decode response */
2314
2315 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2316 if (rc || (pSMBr->ByteCount < 2))
2317 /* BB also check enough total bytes returned */
2318 rc = -EIO; /* bad smb */
2319 else {
2320 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2321 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2322 rc = cifs_copy_posix_acl(acl_inf,
2323 (char *)&pSMBr->hdr.Protocol+data_offset,
2324 buflen,acl_type,count);
2325 }
2326 }
2327 cifs_buf_release(pSMB);
2328 if (rc == -EAGAIN)
2329 goto queryAclRetry;
2330 return rc;
2331}
2332
2333int
2334CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2335 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002336 const char *local_acl, const int buflen,
2337 const int acl_type,
2338 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339{
2340 struct smb_com_transaction2_spi_req *pSMB = NULL;
2341 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2342 char *parm_data;
2343 int name_len;
2344 int rc = 0;
2345 int bytes_returned = 0;
2346 __u16 params, byte_count, data_count, param_offset, offset;
2347
2348 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2349setAclRetry:
2350 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2351 (void **) &pSMBr);
2352 if (rc)
2353 return rc;
2354 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2355 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002356 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002357 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 name_len++; /* trailing null */
2359 name_len *= 2;
2360 } else { /* BB improve the check for buffer overruns BB */
2361 name_len = strnlen(fileName, PATH_MAX);
2362 name_len++; /* trailing null */
2363 strncpy(pSMB->FileName, fileName, name_len);
2364 }
2365 params = 6 + name_len;
2366 pSMB->MaxParameterCount = cpu_to_le16(2);
2367 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2368 pSMB->MaxSetupCount = 0;
2369 pSMB->Reserved = 0;
2370 pSMB->Flags = 0;
2371 pSMB->Timeout = 0;
2372 pSMB->Reserved2 = 0;
2373 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2374 InformationLevel) - 4;
2375 offset = param_offset + params;
2376 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2377 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2378
2379 /* convert to on the wire format for POSIX ACL */
2380 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2381
2382 if(data_count == 0) {
2383 rc = -EOPNOTSUPP;
2384 goto setACLerrorExit;
2385 }
2386 pSMB->DataOffset = cpu_to_le16(offset);
2387 pSMB->SetupCount = 1;
2388 pSMB->Reserved3 = 0;
2389 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2390 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2391 byte_count = 3 /* pad */ + params + data_count;
2392 pSMB->DataCount = cpu_to_le16(data_count);
2393 pSMB->TotalDataCount = pSMB->DataCount;
2394 pSMB->ParameterCount = cpu_to_le16(params);
2395 pSMB->TotalParameterCount = pSMB->ParameterCount;
2396 pSMB->Reserved4 = 0;
2397 pSMB->hdr.smb_buf_length += byte_count;
2398 pSMB->ByteCount = cpu_to_le16(byte_count);
2399 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2400 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2401 if (rc) {
2402 cFYI(1, ("Set POSIX ACL returned %d", rc));
2403 }
2404
2405setACLerrorExit:
2406 cifs_buf_release(pSMB);
2407 if (rc == -EAGAIN)
2408 goto setAclRetry;
2409 return rc;
2410}
2411
Steve Frenchf654bac2005-04-28 22:41:04 -07002412/* BB fix tabs in this function FIXME BB */
2413int
2414CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2415 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2416{
2417 int rc = 0;
2418 struct smb_t2_qfi_req *pSMB = NULL;
2419 struct smb_t2_qfi_rsp *pSMBr = NULL;
2420 int bytes_returned;
2421 __u16 params, byte_count;
2422
2423 cFYI(1,("In GetExtAttr"));
2424 if(tcon == NULL)
2425 return -ENODEV;
2426
2427GetExtAttrRetry:
2428 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2429 (void **) &pSMBr);
2430 if (rc)
2431 return rc;
2432
Steve Frenchc67593a2005-04-28 22:41:04 -07002433 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002434 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002435 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002436 /* BB find exact max data count below from sess structure BB */
2437 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2438 pSMB->t2.MaxSetupCount = 0;
2439 pSMB->t2.Reserved = 0;
2440 pSMB->t2.Flags = 0;
2441 pSMB->t2.Timeout = 0;
2442 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002443 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2444 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002445 pSMB->t2.DataCount = 0;
2446 pSMB->t2.DataOffset = 0;
2447 pSMB->t2.SetupCount = 1;
2448 pSMB->t2.Reserved3 = 0;
2449 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002450 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002451 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2452 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2453 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002454 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002455 pSMB->Fid = netfid;
2456 pSMB->hdr.smb_buf_length += byte_count;
2457 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2458
2459 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2460 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2461 if (rc) {
2462 cFYI(1, ("error %d in GetExtAttr", rc));
2463 } else {
2464 /* decode response */
2465 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2466 if (rc || (pSMBr->ByteCount < 2))
2467 /* BB also check enough total bytes returned */
2468 /* If rc should we check for EOPNOSUPP and
2469 disable the srvino flag? or in caller? */
2470 rc = -EIO; /* bad smb */
2471 else {
2472 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2473 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2474 struct file_chattr_info * pfinfo;
2475 /* BB Do we need a cast or hash here ? */
2476 if(count != 16) {
2477 cFYI(1, ("Illegal size ret in GetExtAttr"));
2478 rc = -EIO;
2479 goto GetExtAttrOut;
2480 }
2481 pfinfo = (struct file_chattr_info *)
2482 (data_offset + (char *) &pSMBr->hdr.Protocol);
2483 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2484 *pMask = le64_to_cpu(pfinfo->mask);
2485 }
2486 }
2487GetExtAttrOut:
2488 cifs_buf_release(pSMB);
2489 if (rc == -EAGAIN)
2490 goto GetExtAttrRetry;
2491 return rc;
2492}
2493
2494
2495#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002496
Steve French0a4b92c2006-01-12 15:44:21 -08002497/* Convert CIFS ACL to POSIX form */
2498static int parse_sec_desc(struct sec_desc * psec_desc, int acl_len)
2499{
2500 CHECK ON OTHER COMPUTER TO SEE IF FORMAT ENCODED IN CIFSPDU.H ALREADY
2501 return 0;
2502}
2503
2504/* Get Security Descriptor (by handle) from remote server for a file or dir */
2505int
2506CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2507 /* BB fix up return info */ char *acl_inf, const int buflen,
2508 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2509{
2510 int rc = 0;
2511 int buf_type = 0;
2512 QUERY_SEC_DESC_REQ * pSMB;
2513 struct kvec iov[1];
2514
2515 cFYI(1, ("GetCifsACL"));
2516
2517 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2518 8 /* parm len */, tcon, (void **) &pSMB);
2519 if (rc)
2520 return rc;
2521
2522 pSMB->MaxParameterCount = cpu_to_le32(4);
2523 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2524 pSMB->MaxSetupCount = 0;
2525 pSMB->Fid = fid; /* file handle always le */
2526 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2527 CIFS_ACL_DACL);
2528 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2529 pSMB->hdr.smb_buf_length += 11;
2530 iov[0].iov_base = (char *)pSMB;
2531 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2532
2533 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2534 cifs_stats_inc(&tcon->num_acl_get);
2535 if (rc) {
2536 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2537 } else { /* decode response */
2538 struct sec_desc * psec_desc;
2539 __le32 * parm;
2540 int parm_len;
2541 int data_len;
2542 int acl_len;
2543 struct smb_com_ntransact_rsp * pSMBr;
2544
2545/* validate_nttransact */
2546 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2547 (char **)&psec_desc,
2548 &parm_len, &data_len);
2549
2550 if(rc)
2551 goto qsec_out;
2552 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2553
2554 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2555
2556 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2557 rc = -EIO; /* bad smb */
2558 goto qsec_out;
2559 }
2560
2561/* BB check that data area is minimum length and as big as acl_len */
2562
2563 acl_len = le32_to_cpu(*(__le32 *)parm);
2564 /* BB check if(acl_len > bufsize) */
2565
2566 parse_sec_desc(psec_desc, acl_len);
2567 }
2568qsec_out:
2569 if(buf_type == CIFS_SMALL_BUFFER)
2570 cifs_small_buf_release(iov[0].iov_base);
2571 else if(buf_type == CIFS_LARGE_BUFFER)
2572 cifs_buf_release(iov[0].iov_base);
2573 cifs_small_buf_release(pSMB);
2574 return rc;
2575}
2576
2577
Steve French6b8edfe2005-08-23 20:26:03 -07002578/* Legacy Query Path Information call for lookup to old servers such
2579 as Win9x/WinME */
2580int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2581 const unsigned char *searchName,
2582 FILE_ALL_INFO * pFinfo,
2583 const struct nls_table *nls_codepage, int remap)
2584{
2585 QUERY_INFORMATION_REQ * pSMB;
2586 QUERY_INFORMATION_RSP * pSMBr;
2587 int rc = 0;
2588 int bytes_returned;
2589 int name_len;
2590
2591 cFYI(1, ("In SMBQPath path %s", searchName));
2592QInfRetry:
2593 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2594 (void **) &pSMBr);
2595 if (rc)
2596 return rc;
2597
2598 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2599 name_len =
2600 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2601 PATH_MAX, nls_codepage, remap);
2602 name_len++; /* trailing null */
2603 name_len *= 2;
2604 } else {
2605 name_len = strnlen(searchName, PATH_MAX);
2606 name_len++; /* trailing null */
2607 strncpy(pSMB->FileName, searchName, name_len);
2608 }
2609 pSMB->BufferFormat = 0x04;
2610 name_len++; /* account for buffer type byte */
2611 pSMB->hdr.smb_buf_length += (__u16) name_len;
2612 pSMB->ByteCount = cpu_to_le16(name_len);
2613
2614 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2615 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2616 if (rc) {
2617 cFYI(1, ("Send error in QueryInfo = %d", rc));
2618 } else if (pFinfo) { /* decode response */
2619 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002620 pFinfo->AllocationSize =
2621 cpu_to_le64(le32_to_cpu(pSMBr->size));
2622 pFinfo->EndOfFile = pFinfo->AllocationSize;
2623 pFinfo->Attributes =
2624 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002625 } else
2626 rc = -EIO; /* bad buffer passed in */
2627
2628 cifs_buf_release(pSMB);
2629
2630 if (rc == -EAGAIN)
2631 goto QInfRetry;
2632
2633 return rc;
2634}
2635
2636
2637
2638
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639int
2640CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2641 const unsigned char *searchName,
2642 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002643 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644{
2645/* level 263 SMB_QUERY_FILE_ALL_INFO */
2646 TRANSACTION2_QPI_REQ *pSMB = NULL;
2647 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2648 int rc = 0;
2649 int bytes_returned;
2650 int name_len;
2651 __u16 params, byte_count;
2652
2653/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2654QPathInfoRetry:
2655 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2656 (void **) &pSMBr);
2657 if (rc)
2658 return rc;
2659
2660 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2661 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002662 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002663 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 name_len++; /* trailing null */
2665 name_len *= 2;
2666 } else { /* BB improve the check for buffer overruns BB */
2667 name_len = strnlen(searchName, PATH_MAX);
2668 name_len++; /* trailing null */
2669 strncpy(pSMB->FileName, searchName, name_len);
2670 }
2671
2672 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2673 pSMB->TotalDataCount = 0;
2674 pSMB->MaxParameterCount = cpu_to_le16(2);
2675 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2676 pSMB->MaxSetupCount = 0;
2677 pSMB->Reserved = 0;
2678 pSMB->Flags = 0;
2679 pSMB->Timeout = 0;
2680 pSMB->Reserved2 = 0;
2681 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2682 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2683 pSMB->DataCount = 0;
2684 pSMB->DataOffset = 0;
2685 pSMB->SetupCount = 1;
2686 pSMB->Reserved3 = 0;
2687 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2688 byte_count = params + 1 /* pad */ ;
2689 pSMB->TotalParameterCount = cpu_to_le16(params);
2690 pSMB->ParameterCount = pSMB->TotalParameterCount;
2691 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2692 pSMB->Reserved4 = 0;
2693 pSMB->hdr.smb_buf_length += byte_count;
2694 pSMB->ByteCount = cpu_to_le16(byte_count);
2695
2696 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2697 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2698 if (rc) {
2699 cFYI(1, ("Send error in QPathInfo = %d", rc));
2700 } else { /* decode response */
2701 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2702
2703 if (rc || (pSMBr->ByteCount < 40))
2704 rc = -EIO; /* bad smb */
2705 else if (pFindData){
2706 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2707 memcpy((char *) pFindData,
2708 (char *) &pSMBr->hdr.Protocol +
2709 data_offset, sizeof (FILE_ALL_INFO));
2710 } else
2711 rc = -ENOMEM;
2712 }
2713 cifs_buf_release(pSMB);
2714 if (rc == -EAGAIN)
2715 goto QPathInfoRetry;
2716
2717 return rc;
2718}
2719
2720int
2721CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2722 const unsigned char *searchName,
2723 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002724 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725{
2726/* SMB_QUERY_FILE_UNIX_BASIC */
2727 TRANSACTION2_QPI_REQ *pSMB = NULL;
2728 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2729 int rc = 0;
2730 int bytes_returned = 0;
2731 int name_len;
2732 __u16 params, byte_count;
2733
2734 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2735UnixQPathInfoRetry:
2736 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2737 (void **) &pSMBr);
2738 if (rc)
2739 return rc;
2740
2741 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2742 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002743 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002744 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 name_len++; /* trailing null */
2746 name_len *= 2;
2747 } else { /* BB improve the check for buffer overruns BB */
2748 name_len = strnlen(searchName, PATH_MAX);
2749 name_len++; /* trailing null */
2750 strncpy(pSMB->FileName, searchName, name_len);
2751 }
2752
2753 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2754 pSMB->TotalDataCount = 0;
2755 pSMB->MaxParameterCount = cpu_to_le16(2);
2756 /* BB find exact max SMB PDU from sess structure BB */
2757 pSMB->MaxDataCount = cpu_to_le16(4000);
2758 pSMB->MaxSetupCount = 0;
2759 pSMB->Reserved = 0;
2760 pSMB->Flags = 0;
2761 pSMB->Timeout = 0;
2762 pSMB->Reserved2 = 0;
2763 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2764 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2765 pSMB->DataCount = 0;
2766 pSMB->DataOffset = 0;
2767 pSMB->SetupCount = 1;
2768 pSMB->Reserved3 = 0;
2769 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2770 byte_count = params + 1 /* pad */ ;
2771 pSMB->TotalParameterCount = cpu_to_le16(params);
2772 pSMB->ParameterCount = pSMB->TotalParameterCount;
2773 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2774 pSMB->Reserved4 = 0;
2775 pSMB->hdr.smb_buf_length += byte_count;
2776 pSMB->ByteCount = cpu_to_le16(byte_count);
2777
2778 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2779 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2780 if (rc) {
2781 cFYI(1, ("Send error in QPathInfo = %d", rc));
2782 } else { /* decode response */
2783 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2784
2785 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2786 rc = -EIO; /* bad smb */
2787 } else {
2788 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2789 memcpy((char *) pFindData,
2790 (char *) &pSMBr->hdr.Protocol +
2791 data_offset,
2792 sizeof (FILE_UNIX_BASIC_INFO));
2793 }
2794 }
2795 cifs_buf_release(pSMB);
2796 if (rc == -EAGAIN)
2797 goto UnixQPathInfoRetry;
2798
2799 return rc;
2800}
2801
2802#if 0 /* function unused at present */
2803int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2804 const char *searchName, FILE_ALL_INFO * findData,
2805 const struct nls_table *nls_codepage)
2806{
2807/* level 257 SMB_ */
2808 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2809 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2810 int rc = 0;
2811 int bytes_returned;
2812 int name_len;
2813 __u16 params, byte_count;
2814
2815 cFYI(1, ("In FindUnique"));
2816findUniqueRetry:
2817 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2818 (void **) &pSMBr);
2819 if (rc)
2820 return rc;
2821
2822 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2823 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002824 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002825 /* find define for this maxpathcomponent */
2826 , nls_codepage);
2827 name_len++; /* trailing null */
2828 name_len *= 2;
2829 } else { /* BB improve the check for buffer overruns BB */
2830 name_len = strnlen(searchName, PATH_MAX);
2831 name_len++; /* trailing null */
2832 strncpy(pSMB->FileName, searchName, name_len);
2833 }
2834
2835 params = 12 + name_len /* includes null */ ;
2836 pSMB->TotalDataCount = 0; /* no EAs */
2837 pSMB->MaxParameterCount = cpu_to_le16(2);
2838 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2839 pSMB->MaxSetupCount = 0;
2840 pSMB->Reserved = 0;
2841 pSMB->Flags = 0;
2842 pSMB->Timeout = 0;
2843 pSMB->Reserved2 = 0;
2844 pSMB->ParameterOffset = cpu_to_le16(
2845 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2846 pSMB->DataCount = 0;
2847 pSMB->DataOffset = 0;
2848 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2849 pSMB->Reserved3 = 0;
2850 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2851 byte_count = params + 1 /* pad */ ;
2852 pSMB->TotalParameterCount = cpu_to_le16(params);
2853 pSMB->ParameterCount = pSMB->TotalParameterCount;
2854 pSMB->SearchAttributes =
2855 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2856 ATTR_DIRECTORY);
2857 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2858 pSMB->SearchFlags = cpu_to_le16(1);
2859 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2860 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2861 pSMB->hdr.smb_buf_length += byte_count;
2862 pSMB->ByteCount = cpu_to_le16(byte_count);
2863
2864 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2865 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2866
2867 if (rc) {
2868 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2869 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07002870 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 /* BB fill in */
2872 }
2873
2874 cifs_buf_release(pSMB);
2875 if (rc == -EAGAIN)
2876 goto findUniqueRetry;
2877
2878 return rc;
2879}
2880#endif /* end unused (temporarily) function */
2881
2882/* xid, tcon, searchName and codepage are input parms, rest are returned */
2883int
2884CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2885 const char *searchName,
2886 const struct nls_table *nls_codepage,
2887 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07002888 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889{
2890/* level 257 SMB_ */
2891 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2892 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2893 T2_FFIRST_RSP_PARMS * parms;
2894 int rc = 0;
2895 int bytes_returned = 0;
2896 int name_len;
2897 __u16 params, byte_count;
2898
Steve French737b7582005-04-28 22:41:06 -07002899 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900
2901findFirstRetry:
2902 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2903 (void **) &pSMBr);
2904 if (rc)
2905 return rc;
2906
2907 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2908 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002909 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07002910 PATH_MAX, nls_codepage, remap);
2911 /* We can not add the asterik earlier in case
2912 it got remapped to 0xF03A as if it were part of the
2913 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07002915 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07002916 pSMB->FileName[name_len+1] = 0;
2917 pSMB->FileName[name_len+2] = '*';
2918 pSMB->FileName[name_len+3] = 0;
2919 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2921 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07002922 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 } else { /* BB add check for overrun of SMB buf BB */
2924 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925/* BB fix here and in unicode clause above ie
2926 if(name_len > buffersize-header)
2927 free buffer exit; BB */
2928 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07002929 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07002930 pSMB->FileName[name_len+1] = '*';
2931 pSMB->FileName[name_len+2] = 0;
2932 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 }
2934
2935 params = 12 + name_len /* includes null */ ;
2936 pSMB->TotalDataCount = 0; /* no EAs */
2937 pSMB->MaxParameterCount = cpu_to_le16(10);
2938 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2939 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2940 pSMB->MaxSetupCount = 0;
2941 pSMB->Reserved = 0;
2942 pSMB->Flags = 0;
2943 pSMB->Timeout = 0;
2944 pSMB->Reserved2 = 0;
2945 byte_count = params + 1 /* pad */ ;
2946 pSMB->TotalParameterCount = cpu_to_le16(params);
2947 pSMB->ParameterCount = pSMB->TotalParameterCount;
2948 pSMB->ParameterOffset = cpu_to_le16(
2949 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2950 pSMB->DataCount = 0;
2951 pSMB->DataOffset = 0;
2952 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2953 pSMB->Reserved3 = 0;
2954 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2955 pSMB->SearchAttributes =
2956 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2957 ATTR_DIRECTORY);
2958 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2959 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2960 CIFS_SEARCH_RETURN_RESUME);
2961 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2962
2963 /* BB what should we set StorageType to? Does it matter? BB */
2964 pSMB->SearchStorageType = 0;
2965 pSMB->hdr.smb_buf_length += byte_count;
2966 pSMB->ByteCount = cpu_to_le16(byte_count);
2967
2968 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2969 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002970 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971
Steve French1982c342005-08-17 12:38:22 -07002972 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 /* BB Add code to handle unsupported level rc */
2974 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07002975
2976 if (pSMB)
2977 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978
2979 /* BB eventually could optimize out free and realloc of buf */
2980 /* for this case */
2981 if (rc == -EAGAIN)
2982 goto findFirstRetry;
2983 } else { /* decode response */
2984 /* BB remember to free buffer if error BB */
2985 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2986 if(rc == 0) {
2987 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2988 psrch_inf->unicode = TRUE;
2989 else
2990 psrch_inf->unicode = FALSE;
2991
2992 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2993 psrch_inf->srch_entries_start =
2994 (char *) &pSMBr->hdr.Protocol +
2995 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002996 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2997 le16_to_cpu(pSMBr->t2.ParameterOffset));
2998
2999 if(parms->EndofSearch)
3000 psrch_inf->endOfSearch = TRUE;
3001 else
3002 psrch_inf->endOfSearch = FALSE;
3003
3004 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3005 psrch_inf->index_of_last_entry =
3006 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 *pnetfid = parms->SearchHandle;
3008 } else {
3009 cifs_buf_release(pSMB);
3010 }
3011 }
3012
3013 return rc;
3014}
3015
3016int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3017 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3018{
3019 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3020 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3021 T2_FNEXT_RSP_PARMS * parms;
3022 char *response_data;
3023 int rc = 0;
3024 int bytes_returned, name_len;
3025 __u16 params, byte_count;
3026
3027 cFYI(1, ("In FindNext"));
3028
3029 if(psrch_inf->endOfSearch == TRUE)
3030 return -ENOENT;
3031
3032 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3033 (void **) &pSMBr);
3034 if (rc)
3035 return rc;
3036
3037 params = 14; /* includes 2 bytes of null string, converted to LE below */
3038 byte_count = 0;
3039 pSMB->TotalDataCount = 0; /* no EAs */
3040 pSMB->MaxParameterCount = cpu_to_le16(8);
3041 pSMB->MaxDataCount =
3042 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3043 pSMB->MaxSetupCount = 0;
3044 pSMB->Reserved = 0;
3045 pSMB->Flags = 0;
3046 pSMB->Timeout = 0;
3047 pSMB->Reserved2 = 0;
3048 pSMB->ParameterOffset = cpu_to_le16(
3049 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3050 pSMB->DataCount = 0;
3051 pSMB->DataOffset = 0;
3052 pSMB->SetupCount = 1;
3053 pSMB->Reserved3 = 0;
3054 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3055 pSMB->SearchHandle = searchHandle; /* always kept as le */
3056 pSMB->SearchCount =
3057 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3058 /* test for Unix extensions */
3059/* if (tcon->ses->capabilities & CAP_UNIX) {
3060 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3061 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3062 } else {
3063 pSMB->InformationLevel =
3064 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3065 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3066 } */
3067 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3068 pSMB->ResumeKey = psrch_inf->resume_key;
3069 pSMB->SearchFlags =
3070 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3071
3072 name_len = psrch_inf->resume_name_len;
3073 params += name_len;
3074 if(name_len < PATH_MAX) {
3075 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3076 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003077 /* 14 byte parm len above enough for 2 byte null terminator */
3078 pSMB->ResumeFileName[name_len] = 0;
3079 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080 } else {
3081 rc = -EINVAL;
3082 goto FNext2_err_exit;
3083 }
3084 byte_count = params + 1 /* pad */ ;
3085 pSMB->TotalParameterCount = cpu_to_le16(params);
3086 pSMB->ParameterCount = pSMB->TotalParameterCount;
3087 pSMB->hdr.smb_buf_length += byte_count;
3088 pSMB->ByteCount = cpu_to_le16(byte_count);
3089
3090 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3091 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003092 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093 if (rc) {
3094 if (rc == -EBADF) {
3095 psrch_inf->endOfSearch = TRUE;
3096 rc = 0; /* search probably was closed at end of search above */
3097 } else
3098 cFYI(1, ("FindNext returned = %d", rc));
3099 } else { /* decode response */
3100 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3101
3102 if(rc == 0) {
3103 /* BB fixme add lock for file (srch_info) struct here */
3104 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3105 psrch_inf->unicode = TRUE;
3106 else
3107 psrch_inf->unicode = FALSE;
3108 response_data = (char *) &pSMBr->hdr.Protocol +
3109 le16_to_cpu(pSMBr->t2.ParameterOffset);
3110 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3111 response_data = (char *)&pSMBr->hdr.Protocol +
3112 le16_to_cpu(pSMBr->t2.DataOffset);
3113 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3114 psrch_inf->srch_entries_start = response_data;
3115 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3116 if(parms->EndofSearch)
3117 psrch_inf->endOfSearch = TRUE;
3118 else
3119 psrch_inf->endOfSearch = FALSE;
3120
3121 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3122 psrch_inf->index_of_last_entry +=
3123 psrch_inf->entries_in_buffer;
3124/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3125
3126 /* BB fixme add unlock here */
3127 }
3128
3129 }
3130
3131 /* BB On error, should we leave previous search buf (and count and
3132 last entry fields) intact or free the previous one? */
3133
3134 /* Note: On -EAGAIN error only caller can retry on handle based calls
3135 since file handle passed in no longer valid */
3136FNext2_err_exit:
3137 if (rc != 0)
3138 cifs_buf_release(pSMB);
3139
3140 return rc;
3141}
3142
3143int
3144CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3145{
3146 int rc = 0;
3147 FINDCLOSE_REQ *pSMB = NULL;
3148 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3149 int bytes_returned;
3150
3151 cFYI(1, ("In CIFSSMBFindClose"));
3152 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3153
3154 /* no sense returning error if session restarted
3155 as file handle has been closed */
3156 if(rc == -EAGAIN)
3157 return 0;
3158 if (rc)
3159 return rc;
3160
3161 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3162 pSMB->FileID = searchHandle;
3163 pSMB->ByteCount = 0;
3164 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3165 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3166 if (rc) {
3167 cERROR(1, ("Send error in FindClose = %d", rc));
3168 }
Steve Frencha4544342005-08-24 13:59:35 -07003169 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 cifs_small_buf_release(pSMB);
3171
3172 /* Since session is dead, search handle closed on server already */
3173 if (rc == -EAGAIN)
3174 rc = 0;
3175
3176 return rc;
3177}
3178
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179int
3180CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3181 const unsigned char *searchName,
3182 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003183 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184{
3185 int rc = 0;
3186 TRANSACTION2_QPI_REQ *pSMB = NULL;
3187 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3188 int name_len, bytes_returned;
3189 __u16 params, byte_count;
3190
3191 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3192 if(tcon == NULL)
3193 return -ENODEV;
3194
3195GetInodeNumberRetry:
3196 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3197 (void **) &pSMBr);
3198 if (rc)
3199 return rc;
3200
3201
3202 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3203 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003204 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003205 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 name_len++; /* trailing null */
3207 name_len *= 2;
3208 } else { /* BB improve the check for buffer overruns BB */
3209 name_len = strnlen(searchName, PATH_MAX);
3210 name_len++; /* trailing null */
3211 strncpy(pSMB->FileName, searchName, name_len);
3212 }
3213
3214 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3215 pSMB->TotalDataCount = 0;
3216 pSMB->MaxParameterCount = cpu_to_le16(2);
3217 /* BB find exact max data count below from sess structure BB */
3218 pSMB->MaxDataCount = cpu_to_le16(4000);
3219 pSMB->MaxSetupCount = 0;
3220 pSMB->Reserved = 0;
3221 pSMB->Flags = 0;
3222 pSMB->Timeout = 0;
3223 pSMB->Reserved2 = 0;
3224 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3225 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3226 pSMB->DataCount = 0;
3227 pSMB->DataOffset = 0;
3228 pSMB->SetupCount = 1;
3229 pSMB->Reserved3 = 0;
3230 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3231 byte_count = params + 1 /* pad */ ;
3232 pSMB->TotalParameterCount = cpu_to_le16(params);
3233 pSMB->ParameterCount = pSMB->TotalParameterCount;
3234 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3235 pSMB->Reserved4 = 0;
3236 pSMB->hdr.smb_buf_length += byte_count;
3237 pSMB->ByteCount = cpu_to_le16(byte_count);
3238
3239 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3240 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3241 if (rc) {
3242 cFYI(1, ("error %d in QueryInternalInfo", rc));
3243 } else {
3244 /* decode response */
3245 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3246 if (rc || (pSMBr->ByteCount < 2))
3247 /* BB also check enough total bytes returned */
3248 /* If rc should we check for EOPNOSUPP and
3249 disable the srvino flag? or in caller? */
3250 rc = -EIO; /* bad smb */
3251 else {
3252 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3253 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3254 struct file_internal_info * pfinfo;
3255 /* BB Do we need a cast or hash here ? */
3256 if(count < 8) {
3257 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3258 rc = -EIO;
3259 goto GetInodeNumOut;
3260 }
3261 pfinfo = (struct file_internal_info *)
3262 (data_offset + (char *) &pSMBr->hdr.Protocol);
3263 *inode_number = pfinfo->UniqueId;
3264 }
3265 }
3266GetInodeNumOut:
3267 cifs_buf_release(pSMB);
3268 if (rc == -EAGAIN)
3269 goto GetInodeNumberRetry;
3270 return rc;
3271}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272
3273int
3274CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3275 const unsigned char *searchName,
3276 unsigned char **targetUNCs,
3277 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003278 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279{
3280/* TRANS2_GET_DFS_REFERRAL */
3281 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3282 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3283 struct dfs_referral_level_3 * referrals = NULL;
3284 int rc = 0;
3285 int bytes_returned;
3286 int name_len;
3287 unsigned int i;
3288 char * temp;
3289 __u16 params, byte_count;
3290 *number_of_UNC_in_array = 0;
3291 *targetUNCs = NULL;
3292
3293 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3294 if (ses == NULL)
3295 return -ENODEV;
3296getDFSRetry:
3297 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3298 (void **) &pSMBr);
3299 if (rc)
3300 return rc;
Steve French1982c342005-08-17 12:38:22 -07003301
3302 /* server pointer checked in called function,
3303 but should never be null here anyway */
3304 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 pSMB->hdr.Tid = ses->ipc_tid;
3306 pSMB->hdr.Uid = ses->Suid;
3307 if (ses->capabilities & CAP_STATUS32) {
3308 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3309 }
3310 if (ses->capabilities & CAP_DFS) {
3311 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3312 }
3313
3314 if (ses->capabilities & CAP_UNICODE) {
3315 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3316 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003317 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003318 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 name_len++; /* trailing null */
3320 name_len *= 2;
3321 } else { /* BB improve the check for buffer overruns BB */
3322 name_len = strnlen(searchName, PATH_MAX);
3323 name_len++; /* trailing null */
3324 strncpy(pSMB->RequestFileName, searchName, name_len);
3325 }
3326
3327 params = 2 /* level */ + name_len /*includes null */ ;
3328 pSMB->TotalDataCount = 0;
3329 pSMB->DataCount = 0;
3330 pSMB->DataOffset = 0;
3331 pSMB->MaxParameterCount = 0;
3332 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3333 pSMB->MaxSetupCount = 0;
3334 pSMB->Reserved = 0;
3335 pSMB->Flags = 0;
3336 pSMB->Timeout = 0;
3337 pSMB->Reserved2 = 0;
3338 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3339 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3340 pSMB->SetupCount = 1;
3341 pSMB->Reserved3 = 0;
3342 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3343 byte_count = params + 3 /* pad */ ;
3344 pSMB->ParameterCount = cpu_to_le16(params);
3345 pSMB->TotalParameterCount = pSMB->ParameterCount;
3346 pSMB->MaxReferralLevel = cpu_to_le16(3);
3347 pSMB->hdr.smb_buf_length += byte_count;
3348 pSMB->ByteCount = cpu_to_le16(byte_count);
3349
3350 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3351 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3352 if (rc) {
3353 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3354 } else { /* decode response */
3355/* BB Add logic to parse referrals here */
3356 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3357
3358 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3359 rc = -EIO; /* bad smb */
3360 else {
3361 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3362 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3363
3364 cFYI(1,
3365 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3366 pSMBr->ByteCount, data_offset));
3367 referrals =
3368 (struct dfs_referral_level_3 *)
3369 (8 /* sizeof start of data block */ +
3370 data_offset +
3371 (char *) &pSMBr->hdr.Protocol);
3372 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",
3373 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)));
3374 /* BB This field is actually two bytes in from start of
3375 data block so we could do safety check that DataBlock
3376 begins at address of pSMBr->NumberOfReferrals */
3377 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3378
3379 /* BB Fix below so can return more than one referral */
3380 if(*number_of_UNC_in_array > 1)
3381 *number_of_UNC_in_array = 1;
3382
3383 /* get the length of the strings describing refs */
3384 name_len = 0;
3385 for(i=0;i<*number_of_UNC_in_array;i++) {
3386 /* make sure that DfsPathOffset not past end */
3387 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3388 if (offset > data_count) {
3389 /* if invalid referral, stop here and do
3390 not try to copy any more */
3391 *number_of_UNC_in_array = i;
3392 break;
3393 }
3394 temp = ((char *)referrals) + offset;
3395
3396 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3397 name_len += UniStrnlen((wchar_t *)temp,data_count);
3398 } else {
3399 name_len += strnlen(temp,data_count);
3400 }
3401 referrals++;
3402 /* BB add check that referral pointer does not fall off end PDU */
3403
3404 }
3405 /* BB add check for name_len bigger than bcc */
3406 *targetUNCs =
3407 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3408 if(*targetUNCs == NULL) {
3409 rc = -ENOMEM;
3410 goto GetDFSRefExit;
3411 }
3412 /* copy the ref strings */
3413 referrals =
3414 (struct dfs_referral_level_3 *)
3415 (8 /* sizeof data hdr */ +
3416 data_offset +
3417 (char *) &pSMBr->hdr.Protocol);
3418
3419 for(i=0;i<*number_of_UNC_in_array;i++) {
3420 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3421 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3422 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003423 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424 } else {
3425 strncpy(*targetUNCs,temp,name_len);
3426 }
3427 /* BB update target_uncs pointers */
3428 referrals++;
3429 }
3430 temp = *targetUNCs;
3431 temp[name_len] = 0;
3432 }
3433
3434 }
3435GetDFSRefExit:
3436 if (pSMB)
3437 cifs_buf_release(pSMB);
3438
3439 if (rc == -EAGAIN)
3440 goto getDFSRetry;
3441
3442 return rc;
3443}
3444
Steve French20962432005-09-21 22:05:57 -07003445/* Query File System Info such as free space to old servers such as Win 9x */
3446int
3447SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3448{
3449/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3450 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3451 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3452 FILE_SYSTEM_ALLOC_INFO *response_data;
3453 int rc = 0;
3454 int bytes_returned = 0;
3455 __u16 params, byte_count;
3456
3457 cFYI(1, ("OldQFSInfo"));
3458oldQFSInfoRetry:
3459 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3460 (void **) &pSMBr);
3461 if (rc)
3462 return rc;
3463 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3464 (void **) &pSMBr);
3465 if (rc)
3466 return rc;
3467
3468 params = 2; /* level */
3469 pSMB->TotalDataCount = 0;
3470 pSMB->MaxParameterCount = cpu_to_le16(2);
3471 pSMB->MaxDataCount = cpu_to_le16(1000);
3472 pSMB->MaxSetupCount = 0;
3473 pSMB->Reserved = 0;
3474 pSMB->Flags = 0;
3475 pSMB->Timeout = 0;
3476 pSMB->Reserved2 = 0;
3477 byte_count = params + 1 /* pad */ ;
3478 pSMB->TotalParameterCount = cpu_to_le16(params);
3479 pSMB->ParameterCount = pSMB->TotalParameterCount;
3480 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3481 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3482 pSMB->DataCount = 0;
3483 pSMB->DataOffset = 0;
3484 pSMB->SetupCount = 1;
3485 pSMB->Reserved3 = 0;
3486 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3487 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3488 pSMB->hdr.smb_buf_length += byte_count;
3489 pSMB->ByteCount = cpu_to_le16(byte_count);
3490
3491 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3492 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3493 if (rc) {
3494 cFYI(1, ("Send error in QFSInfo = %d", rc));
3495 } else { /* decode response */
3496 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3497
3498 if (rc || (pSMBr->ByteCount < 18))
3499 rc = -EIO; /* bad smb */
3500 else {
3501 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3502 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3503 pSMBr->ByteCount, data_offset));
3504
3505 response_data =
3506 (FILE_SYSTEM_ALLOC_INFO *)
3507 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3508 FSData->f_bsize =
3509 le16_to_cpu(response_data->BytesPerSector) *
3510 le32_to_cpu(response_data->
3511 SectorsPerAllocationUnit);
3512 FSData->f_blocks =
3513 le32_to_cpu(response_data->TotalAllocationUnits);
3514 FSData->f_bfree = FSData->f_bavail =
3515 le32_to_cpu(response_data->FreeAllocationUnits);
3516 cFYI(1,
3517 ("Blocks: %lld Free: %lld Block size %ld",
3518 (unsigned long long)FSData->f_blocks,
3519 (unsigned long long)FSData->f_bfree,
3520 FSData->f_bsize));
3521 }
3522 }
3523 cifs_buf_release(pSMB);
3524
3525 if (rc == -EAGAIN)
3526 goto oldQFSInfoRetry;
3527
3528 return rc;
3529}
3530
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531int
Steve French737b7582005-04-28 22:41:06 -07003532CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533{
3534/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3535 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3536 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3537 FILE_SYSTEM_INFO *response_data;
3538 int rc = 0;
3539 int bytes_returned = 0;
3540 __u16 params, byte_count;
3541
3542 cFYI(1, ("In QFSInfo"));
3543QFSInfoRetry:
3544 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3545 (void **) &pSMBr);
3546 if (rc)
3547 return rc;
3548
3549 params = 2; /* level */
3550 pSMB->TotalDataCount = 0;
3551 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003552 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 pSMB->MaxSetupCount = 0;
3554 pSMB->Reserved = 0;
3555 pSMB->Flags = 0;
3556 pSMB->Timeout = 0;
3557 pSMB->Reserved2 = 0;
3558 byte_count = params + 1 /* pad */ ;
3559 pSMB->TotalParameterCount = cpu_to_le16(params);
3560 pSMB->ParameterCount = pSMB->TotalParameterCount;
3561 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3562 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3563 pSMB->DataCount = 0;
3564 pSMB->DataOffset = 0;
3565 pSMB->SetupCount = 1;
3566 pSMB->Reserved3 = 0;
3567 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3568 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3569 pSMB->hdr.smb_buf_length += byte_count;
3570 pSMB->ByteCount = cpu_to_le16(byte_count);
3571
3572 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3573 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3574 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003575 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576 } else { /* decode response */
3577 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3578
Steve French20962432005-09-21 22:05:57 -07003579 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 rc = -EIO; /* bad smb */
3581 else {
3582 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583
3584 response_data =
3585 (FILE_SYSTEM_INFO
3586 *) (((char *) &pSMBr->hdr.Protocol) +
3587 data_offset);
3588 FSData->f_bsize =
3589 le32_to_cpu(response_data->BytesPerSector) *
3590 le32_to_cpu(response_data->
3591 SectorsPerAllocationUnit);
3592 FSData->f_blocks =
3593 le64_to_cpu(response_data->TotalAllocationUnits);
3594 FSData->f_bfree = FSData->f_bavail =
3595 le64_to_cpu(response_data->FreeAllocationUnits);
3596 cFYI(1,
3597 ("Blocks: %lld Free: %lld Block size %ld",
3598 (unsigned long long)FSData->f_blocks,
3599 (unsigned long long)FSData->f_bfree,
3600 FSData->f_bsize));
3601 }
3602 }
3603 cifs_buf_release(pSMB);
3604
3605 if (rc == -EAGAIN)
3606 goto QFSInfoRetry;
3607
3608 return rc;
3609}
3610
3611int
Steve French737b7582005-04-28 22:41:06 -07003612CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613{
3614/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3615 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3616 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3617 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3618 int rc = 0;
3619 int bytes_returned = 0;
3620 __u16 params, byte_count;
3621
3622 cFYI(1, ("In QFSAttributeInfo"));
3623QFSAttributeRetry:
3624 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3625 (void **) &pSMBr);
3626 if (rc)
3627 return rc;
3628
3629 params = 2; /* level */
3630 pSMB->TotalDataCount = 0;
3631 pSMB->MaxParameterCount = cpu_to_le16(2);
3632 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3633 pSMB->MaxSetupCount = 0;
3634 pSMB->Reserved = 0;
3635 pSMB->Flags = 0;
3636 pSMB->Timeout = 0;
3637 pSMB->Reserved2 = 0;
3638 byte_count = params + 1 /* pad */ ;
3639 pSMB->TotalParameterCount = cpu_to_le16(params);
3640 pSMB->ParameterCount = pSMB->TotalParameterCount;
3641 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3642 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3643 pSMB->DataCount = 0;
3644 pSMB->DataOffset = 0;
3645 pSMB->SetupCount = 1;
3646 pSMB->Reserved3 = 0;
3647 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3648 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3649 pSMB->hdr.smb_buf_length += byte_count;
3650 pSMB->ByteCount = cpu_to_le16(byte_count);
3651
3652 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3653 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3654 if (rc) {
3655 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3656 } else { /* decode response */
3657 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3658
3659 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3660 rc = -EIO; /* bad smb */
3661 } else {
3662 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3663 response_data =
3664 (FILE_SYSTEM_ATTRIBUTE_INFO
3665 *) (((char *) &pSMBr->hdr.Protocol) +
3666 data_offset);
3667 memcpy(&tcon->fsAttrInfo, response_data,
3668 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3669 }
3670 }
3671 cifs_buf_release(pSMB);
3672
3673 if (rc == -EAGAIN)
3674 goto QFSAttributeRetry;
3675
3676 return rc;
3677}
3678
3679int
Steve French737b7582005-04-28 22:41:06 -07003680CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681{
3682/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3683 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3684 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3685 FILE_SYSTEM_DEVICE_INFO *response_data;
3686 int rc = 0;
3687 int bytes_returned = 0;
3688 __u16 params, byte_count;
3689
3690 cFYI(1, ("In QFSDeviceInfo"));
3691QFSDeviceRetry:
3692 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3693 (void **) &pSMBr);
3694 if (rc)
3695 return rc;
3696
3697 params = 2; /* level */
3698 pSMB->TotalDataCount = 0;
3699 pSMB->MaxParameterCount = cpu_to_le16(2);
3700 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3701 pSMB->MaxSetupCount = 0;
3702 pSMB->Reserved = 0;
3703 pSMB->Flags = 0;
3704 pSMB->Timeout = 0;
3705 pSMB->Reserved2 = 0;
3706 byte_count = params + 1 /* pad */ ;
3707 pSMB->TotalParameterCount = cpu_to_le16(params);
3708 pSMB->ParameterCount = pSMB->TotalParameterCount;
3709 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3710 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3711
3712 pSMB->DataCount = 0;
3713 pSMB->DataOffset = 0;
3714 pSMB->SetupCount = 1;
3715 pSMB->Reserved3 = 0;
3716 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3717 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3718 pSMB->hdr.smb_buf_length += byte_count;
3719 pSMB->ByteCount = cpu_to_le16(byte_count);
3720
3721 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3722 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3723 if (rc) {
3724 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3725 } else { /* decode response */
3726 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3727
3728 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3729 rc = -EIO; /* bad smb */
3730 else {
3731 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3732 response_data =
Steve French737b7582005-04-28 22:41:06 -07003733 (FILE_SYSTEM_DEVICE_INFO *)
3734 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735 data_offset);
3736 memcpy(&tcon->fsDevInfo, response_data,
3737 sizeof (FILE_SYSTEM_DEVICE_INFO));
3738 }
3739 }
3740 cifs_buf_release(pSMB);
3741
3742 if (rc == -EAGAIN)
3743 goto QFSDeviceRetry;
3744
3745 return rc;
3746}
3747
3748int
Steve French737b7582005-04-28 22:41:06 -07003749CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750{
3751/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3752 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3753 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3754 FILE_SYSTEM_UNIX_INFO *response_data;
3755 int rc = 0;
3756 int bytes_returned = 0;
3757 __u16 params, byte_count;
3758
3759 cFYI(1, ("In QFSUnixInfo"));
3760QFSUnixRetry:
3761 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3762 (void **) &pSMBr);
3763 if (rc)
3764 return rc;
3765
3766 params = 2; /* level */
3767 pSMB->TotalDataCount = 0;
3768 pSMB->DataCount = 0;
3769 pSMB->DataOffset = 0;
3770 pSMB->MaxParameterCount = cpu_to_le16(2);
3771 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3772 pSMB->MaxSetupCount = 0;
3773 pSMB->Reserved = 0;
3774 pSMB->Flags = 0;
3775 pSMB->Timeout = 0;
3776 pSMB->Reserved2 = 0;
3777 byte_count = params + 1 /* pad */ ;
3778 pSMB->ParameterCount = cpu_to_le16(params);
3779 pSMB->TotalParameterCount = pSMB->ParameterCount;
3780 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3781 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3782 pSMB->SetupCount = 1;
3783 pSMB->Reserved3 = 0;
3784 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3785 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3786 pSMB->hdr.smb_buf_length += byte_count;
3787 pSMB->ByteCount = cpu_to_le16(byte_count);
3788
3789 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3790 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3791 if (rc) {
3792 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3793 } else { /* decode response */
3794 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3795
3796 if (rc || (pSMBr->ByteCount < 13)) {
3797 rc = -EIO; /* bad smb */
3798 } else {
3799 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3800 response_data =
3801 (FILE_SYSTEM_UNIX_INFO
3802 *) (((char *) &pSMBr->hdr.Protocol) +
3803 data_offset);
3804 memcpy(&tcon->fsUnixInfo, response_data,
3805 sizeof (FILE_SYSTEM_UNIX_INFO));
3806 }
3807 }
3808 cifs_buf_release(pSMB);
3809
3810 if (rc == -EAGAIN)
3811 goto QFSUnixRetry;
3812
3813
3814 return rc;
3815}
3816
Jeremy Allisonac670552005-06-22 17:26:35 -07003817int
Steve French45abc6e2005-06-23 13:42:03 -05003818CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07003819{
3820/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3821 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3822 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3823 int rc = 0;
3824 int bytes_returned = 0;
3825 __u16 params, param_offset, offset, byte_count;
3826
3827 cFYI(1, ("In SETFSUnixInfo"));
3828SETFSUnixRetry:
3829 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3830 (void **) &pSMBr);
3831 if (rc)
3832 return rc;
3833
3834 params = 4; /* 2 bytes zero followed by info level. */
3835 pSMB->MaxSetupCount = 0;
3836 pSMB->Reserved = 0;
3837 pSMB->Flags = 0;
3838 pSMB->Timeout = 0;
3839 pSMB->Reserved2 = 0;
3840 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3841 offset = param_offset + params;
3842
3843 pSMB->MaxParameterCount = cpu_to_le16(4);
3844 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3845 pSMB->SetupCount = 1;
3846 pSMB->Reserved3 = 0;
3847 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3848 byte_count = 1 /* pad */ + params + 12;
3849
3850 pSMB->DataCount = cpu_to_le16(12);
3851 pSMB->ParameterCount = cpu_to_le16(params);
3852 pSMB->TotalDataCount = pSMB->DataCount;
3853 pSMB->TotalParameterCount = pSMB->ParameterCount;
3854 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3855 pSMB->DataOffset = cpu_to_le16(offset);
3856
3857 /* Params. */
3858 pSMB->FileNum = 0;
3859 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3860
3861 /* Data. */
3862 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3863 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3864 pSMB->ClientUnixCap = cpu_to_le64(cap);
3865
3866 pSMB->hdr.smb_buf_length += byte_count;
3867 pSMB->ByteCount = cpu_to_le16(byte_count);
3868
3869 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3870 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3871 if (rc) {
3872 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3873 } else { /* decode response */
3874 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3875 if (rc) {
3876 rc = -EIO; /* bad smb */
3877 }
3878 }
3879 cifs_buf_release(pSMB);
3880
3881 if (rc == -EAGAIN)
3882 goto SETFSUnixRetry;
3883
3884 return rc;
3885}
3886
3887
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888
3889int
3890CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003891 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003892{
3893/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3894 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3895 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3896 FILE_SYSTEM_POSIX_INFO *response_data;
3897 int rc = 0;
3898 int bytes_returned = 0;
3899 __u16 params, byte_count;
3900
3901 cFYI(1, ("In QFSPosixInfo"));
3902QFSPosixRetry:
3903 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3904 (void **) &pSMBr);
3905 if (rc)
3906 return rc;
3907
3908 params = 2; /* level */
3909 pSMB->TotalDataCount = 0;
3910 pSMB->DataCount = 0;
3911 pSMB->DataOffset = 0;
3912 pSMB->MaxParameterCount = cpu_to_le16(2);
3913 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3914 pSMB->MaxSetupCount = 0;
3915 pSMB->Reserved = 0;
3916 pSMB->Flags = 0;
3917 pSMB->Timeout = 0;
3918 pSMB->Reserved2 = 0;
3919 byte_count = params + 1 /* pad */ ;
3920 pSMB->ParameterCount = cpu_to_le16(params);
3921 pSMB->TotalParameterCount = pSMB->ParameterCount;
3922 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3923 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3924 pSMB->SetupCount = 1;
3925 pSMB->Reserved3 = 0;
3926 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3927 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3928 pSMB->hdr.smb_buf_length += byte_count;
3929 pSMB->ByteCount = cpu_to_le16(byte_count);
3930
3931 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3932 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3933 if (rc) {
3934 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3935 } else { /* decode response */
3936 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3937
3938 if (rc || (pSMBr->ByteCount < 13)) {
3939 rc = -EIO; /* bad smb */
3940 } else {
3941 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3942 response_data =
3943 (FILE_SYSTEM_POSIX_INFO
3944 *) (((char *) &pSMBr->hdr.Protocol) +
3945 data_offset);
3946 FSData->f_bsize =
3947 le32_to_cpu(response_data->BlockSize);
3948 FSData->f_blocks =
3949 le64_to_cpu(response_data->TotalBlocks);
3950 FSData->f_bfree =
3951 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07003952 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003953 FSData->f_bavail = FSData->f_bfree;
3954 } else {
3955 FSData->f_bavail =
3956 le64_to_cpu(response_data->UserBlocksAvail);
3957 }
Steve French70ca7342005-09-22 16:32:06 -07003958 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 FSData->f_files =
3960 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07003961 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 FSData->f_ffree =
3963 le64_to_cpu(response_data->FreeFileNodes);
3964 }
3965 }
3966 cifs_buf_release(pSMB);
3967
3968 if (rc == -EAGAIN)
3969 goto QFSPosixRetry;
3970
3971 return rc;
3972}
3973
3974
3975/* We can not use write of zero bytes trick to
3976 set file size due to need for large file support. Also note that
3977 this SetPathInfo is preferred to SetFileInfo based method in next
3978 routine which is only needed to work around a sharing violation bug
3979 in Samba which this routine can run into */
3980
3981int
3982CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07003983 __u64 size, int SetAllocation,
3984 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985{
3986 struct smb_com_transaction2_spi_req *pSMB = NULL;
3987 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3988 struct file_end_of_file_info *parm_data;
3989 int name_len;
3990 int rc = 0;
3991 int bytes_returned = 0;
3992 __u16 params, byte_count, data_count, param_offset, offset;
3993
3994 cFYI(1, ("In SetEOF"));
3995SetEOFRetry:
3996 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3997 (void **) &pSMBr);
3998 if (rc)
3999 return rc;
4000
4001 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4002 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004003 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004004 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004005 name_len++; /* trailing null */
4006 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004007 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 name_len = strnlen(fileName, PATH_MAX);
4009 name_len++; /* trailing null */
4010 strncpy(pSMB->FileName, fileName, name_len);
4011 }
4012 params = 6 + name_len;
4013 data_count = sizeof (struct file_end_of_file_info);
4014 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004015 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 pSMB->MaxSetupCount = 0;
4017 pSMB->Reserved = 0;
4018 pSMB->Flags = 0;
4019 pSMB->Timeout = 0;
4020 pSMB->Reserved2 = 0;
4021 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4022 InformationLevel) - 4;
4023 offset = param_offset + params;
4024 if(SetAllocation) {
4025 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4026 pSMB->InformationLevel =
4027 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4028 else
4029 pSMB->InformationLevel =
4030 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4031 } else /* Set File Size */ {
4032 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4033 pSMB->InformationLevel =
4034 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4035 else
4036 pSMB->InformationLevel =
4037 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4038 }
4039
4040 parm_data =
4041 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4042 offset);
4043 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4044 pSMB->DataOffset = cpu_to_le16(offset);
4045 pSMB->SetupCount = 1;
4046 pSMB->Reserved3 = 0;
4047 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4048 byte_count = 3 /* pad */ + params + data_count;
4049 pSMB->DataCount = cpu_to_le16(data_count);
4050 pSMB->TotalDataCount = pSMB->DataCount;
4051 pSMB->ParameterCount = cpu_to_le16(params);
4052 pSMB->TotalParameterCount = pSMB->ParameterCount;
4053 pSMB->Reserved4 = 0;
4054 pSMB->hdr.smb_buf_length += byte_count;
4055 parm_data->FileSize = cpu_to_le64(size);
4056 pSMB->ByteCount = cpu_to_le16(byte_count);
4057 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4058 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4059 if (rc) {
4060 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4061 }
4062
4063 cifs_buf_release(pSMB);
4064
4065 if (rc == -EAGAIN)
4066 goto SetEOFRetry;
4067
4068 return rc;
4069}
4070
4071int
4072CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4073 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4074{
4075 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4076 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4077 char *data_offset;
4078 struct file_end_of_file_info *parm_data;
4079 int rc = 0;
4080 int bytes_returned = 0;
4081 __u16 params, param_offset, offset, byte_count, count;
4082
4083 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4084 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004085 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4086
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087 if (rc)
4088 return rc;
4089
Steve Frenchcd634992005-04-28 22:41:10 -07004090 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4091
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4093 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4094
4095 params = 6;
4096 pSMB->MaxSetupCount = 0;
4097 pSMB->Reserved = 0;
4098 pSMB->Flags = 0;
4099 pSMB->Timeout = 0;
4100 pSMB->Reserved2 = 0;
4101 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4102 offset = param_offset + params;
4103
4104 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4105
4106 count = sizeof(struct file_end_of_file_info);
4107 pSMB->MaxParameterCount = cpu_to_le16(2);
4108 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4109 pSMB->SetupCount = 1;
4110 pSMB->Reserved3 = 0;
4111 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4112 byte_count = 3 /* pad */ + params + count;
4113 pSMB->DataCount = cpu_to_le16(count);
4114 pSMB->ParameterCount = cpu_to_le16(params);
4115 pSMB->TotalDataCount = pSMB->DataCount;
4116 pSMB->TotalParameterCount = pSMB->ParameterCount;
4117 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4118 parm_data =
4119 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4120 offset);
4121 pSMB->DataOffset = cpu_to_le16(offset);
4122 parm_data->FileSize = cpu_to_le64(size);
4123 pSMB->Fid = fid;
4124 if(SetAllocation) {
4125 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4126 pSMB->InformationLevel =
4127 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4128 else
4129 pSMB->InformationLevel =
4130 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4131 } else /* Set File Size */ {
4132 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4133 pSMB->InformationLevel =
4134 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4135 else
4136 pSMB->InformationLevel =
4137 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4138 }
4139 pSMB->Reserved4 = 0;
4140 pSMB->hdr.smb_buf_length += byte_count;
4141 pSMB->ByteCount = cpu_to_le16(byte_count);
4142 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4143 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4144 if (rc) {
4145 cFYI(1,
4146 ("Send error in SetFileInfo (SetFileSize) = %d",
4147 rc));
4148 }
4149
4150 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004151 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152
4153 /* Note: On -EAGAIN error only caller can retry on handle based calls
4154 since file handle passed in no longer valid */
4155
4156 return rc;
4157}
4158
4159/* Some legacy servers such as NT4 require that the file times be set on
4160 an open handle, rather than by pathname - this is awkward due to
4161 potential access conflicts on the open, but it is unavoidable for these
4162 old servers since the only other choice is to go from 100 nanosecond DCE
4163 time and resort to the original setpathinfo level which takes the ancient
4164 DOS time format with 2 second granularity */
4165int
4166CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4167 __u16 fid)
4168{
4169 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4170 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4171 char *data_offset;
4172 int rc = 0;
4173 int bytes_returned = 0;
4174 __u16 params, param_offset, offset, byte_count, count;
4175
4176 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004177 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4178
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179 if (rc)
4180 return rc;
4181
Steve Frenchcd634992005-04-28 22:41:10 -07004182 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4183
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 /* At this point there is no need to override the current pid
4185 with the pid of the opener, but that could change if we someday
4186 use an existing handle (rather than opening one on the fly) */
4187 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4188 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4189
4190 params = 6;
4191 pSMB->MaxSetupCount = 0;
4192 pSMB->Reserved = 0;
4193 pSMB->Flags = 0;
4194 pSMB->Timeout = 0;
4195 pSMB->Reserved2 = 0;
4196 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4197 offset = param_offset + params;
4198
4199 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4200
4201 count = sizeof (FILE_BASIC_INFO);
4202 pSMB->MaxParameterCount = cpu_to_le16(2);
4203 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4204 pSMB->SetupCount = 1;
4205 pSMB->Reserved3 = 0;
4206 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4207 byte_count = 3 /* pad */ + params + count;
4208 pSMB->DataCount = cpu_to_le16(count);
4209 pSMB->ParameterCount = cpu_to_le16(params);
4210 pSMB->TotalDataCount = pSMB->DataCount;
4211 pSMB->TotalParameterCount = pSMB->ParameterCount;
4212 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4213 pSMB->DataOffset = cpu_to_le16(offset);
4214 pSMB->Fid = fid;
4215 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4216 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4217 else
4218 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4219 pSMB->Reserved4 = 0;
4220 pSMB->hdr.smb_buf_length += byte_count;
4221 pSMB->ByteCount = cpu_to_le16(byte_count);
4222 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4223 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4224 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4225 if (rc) {
4226 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4227 }
4228
Steve Frenchcd634992005-04-28 22:41:10 -07004229 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230
4231 /* Note: On -EAGAIN error only caller can retry on handle based calls
4232 since file handle passed in no longer valid */
4233
4234 return rc;
4235}
4236
4237
4238int
4239CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4240 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004241 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004242{
4243 TRANSACTION2_SPI_REQ *pSMB = NULL;
4244 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4245 int name_len;
4246 int rc = 0;
4247 int bytes_returned = 0;
4248 char *data_offset;
4249 __u16 params, param_offset, offset, byte_count, count;
4250
4251 cFYI(1, ("In SetTimes"));
4252
4253SetTimesRetry:
4254 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4255 (void **) &pSMBr);
4256 if (rc)
4257 return rc;
4258
4259 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4260 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004261 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004262 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263 name_len++; /* trailing null */
4264 name_len *= 2;
4265 } else { /* BB improve the check for buffer overruns BB */
4266 name_len = strnlen(fileName, PATH_MAX);
4267 name_len++; /* trailing null */
4268 strncpy(pSMB->FileName, fileName, name_len);
4269 }
4270
4271 params = 6 + name_len;
4272 count = sizeof (FILE_BASIC_INFO);
4273 pSMB->MaxParameterCount = cpu_to_le16(2);
4274 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4275 pSMB->MaxSetupCount = 0;
4276 pSMB->Reserved = 0;
4277 pSMB->Flags = 0;
4278 pSMB->Timeout = 0;
4279 pSMB->Reserved2 = 0;
4280 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4281 InformationLevel) - 4;
4282 offset = param_offset + params;
4283 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4284 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4285 pSMB->DataOffset = cpu_to_le16(offset);
4286 pSMB->SetupCount = 1;
4287 pSMB->Reserved3 = 0;
4288 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4289 byte_count = 3 /* pad */ + params + count;
4290
4291 pSMB->DataCount = cpu_to_le16(count);
4292 pSMB->ParameterCount = cpu_to_le16(params);
4293 pSMB->TotalDataCount = pSMB->DataCount;
4294 pSMB->TotalParameterCount = pSMB->ParameterCount;
4295 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4296 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4297 else
4298 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4299 pSMB->Reserved4 = 0;
4300 pSMB->hdr.smb_buf_length += byte_count;
4301 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4302 pSMB->ByteCount = cpu_to_le16(byte_count);
4303 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4304 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4305 if (rc) {
4306 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4307 }
4308
4309 cifs_buf_release(pSMB);
4310
4311 if (rc == -EAGAIN)
4312 goto SetTimesRetry;
4313
4314 return rc;
4315}
4316
4317/* Can not be used to set time stamps yet (due to old DOS time format) */
4318/* Can be used to set attributes */
4319#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4320 handling it anyway and NT4 was what we thought it would be needed for
4321 Do not delete it until we prove whether needed for Win9x though */
4322int
4323CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4324 __u16 dos_attrs, const struct nls_table *nls_codepage)
4325{
4326 SETATTR_REQ *pSMB = NULL;
4327 SETATTR_RSP *pSMBr = NULL;
4328 int rc = 0;
4329 int bytes_returned;
4330 int name_len;
4331
4332 cFYI(1, ("In SetAttrLegacy"));
4333
4334SetAttrLgcyRetry:
4335 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4336 (void **) &pSMBr);
4337 if (rc)
4338 return rc;
4339
4340 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4341 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004342 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 PATH_MAX, nls_codepage);
4344 name_len++; /* trailing null */
4345 name_len *= 2;
4346 } else { /* BB improve the check for buffer overruns BB */
4347 name_len = strnlen(fileName, PATH_MAX);
4348 name_len++; /* trailing null */
4349 strncpy(pSMB->fileName, fileName, name_len);
4350 }
4351 pSMB->attr = cpu_to_le16(dos_attrs);
4352 pSMB->BufferFormat = 0x04;
4353 pSMB->hdr.smb_buf_length += name_len + 1;
4354 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4355 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4356 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4357 if (rc) {
4358 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4359 }
4360
4361 cifs_buf_release(pSMB);
4362
4363 if (rc == -EAGAIN)
4364 goto SetAttrLgcyRetry;
4365
4366 return rc;
4367}
4368#endif /* temporarily unneeded SetAttr legacy function */
4369
4370int
4371CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004372 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4373 dev_t device, const struct nls_table *nls_codepage,
4374 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375{
4376 TRANSACTION2_SPI_REQ *pSMB = NULL;
4377 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4378 int name_len;
4379 int rc = 0;
4380 int bytes_returned = 0;
4381 FILE_UNIX_BASIC_INFO *data_offset;
4382 __u16 params, param_offset, offset, count, byte_count;
4383
4384 cFYI(1, ("In SetUID/GID/Mode"));
4385setPermsRetry:
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, fileName,
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;
Steve French3e87d802005-09-18 20:49:21 -07004397 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398 name_len = strnlen(fileName, PATH_MAX);
4399 name_len++; /* trailing null */
4400 strncpy(pSMB->FileName, fileName, name_len);
4401 }
4402
4403 params = 6 + name_len;
4404 count = sizeof (FILE_UNIX_BASIC_INFO);
4405 pSMB->MaxParameterCount = cpu_to_le16(2);
4406 pSMB->MaxDataCount = cpu_to_le16(1000); /* 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 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4413 InformationLevel) - 4;
4414 offset = param_offset + params;
4415 data_offset =
4416 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4417 offset);
4418 memset(data_offset, 0, count);
4419 pSMB->DataOffset = cpu_to_le16(offset);
4420 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4421 pSMB->SetupCount = 1;
4422 pSMB->Reserved3 = 0;
4423 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4424 byte_count = 3 /* pad */ + params + count;
4425 pSMB->ParameterCount = cpu_to_le16(params);
4426 pSMB->DataCount = cpu_to_le16(count);
4427 pSMB->TotalParameterCount = pSMB->ParameterCount;
4428 pSMB->TotalDataCount = pSMB->DataCount;
4429 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4430 pSMB->Reserved4 = 0;
4431 pSMB->hdr.smb_buf_length += byte_count;
4432 data_offset->Uid = cpu_to_le64(uid);
4433 data_offset->Gid = cpu_to_le64(gid);
4434 /* better to leave device as zero when it is */
4435 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4436 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4437 data_offset->Permissions = cpu_to_le64(mode);
4438
4439 if(S_ISREG(mode))
4440 data_offset->Type = cpu_to_le32(UNIX_FILE);
4441 else if(S_ISDIR(mode))
4442 data_offset->Type = cpu_to_le32(UNIX_DIR);
4443 else if(S_ISLNK(mode))
4444 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4445 else if(S_ISCHR(mode))
4446 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4447 else if(S_ISBLK(mode))
4448 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4449 else if(S_ISFIFO(mode))
4450 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4451 else if(S_ISSOCK(mode))
4452 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4453
4454
4455 pSMB->ByteCount = cpu_to_le16(byte_count);
4456 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4457 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4458 if (rc) {
4459 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4460 }
4461
4462 if (pSMB)
4463 cifs_buf_release(pSMB);
4464 if (rc == -EAGAIN)
4465 goto setPermsRetry;
4466 return rc;
4467}
4468
4469int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004470 const int notify_subdirs, const __u16 netfid,
4471 __u32 filter, struct file * pfile, int multishot,
4472 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473{
4474 int rc = 0;
4475 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004476 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004477 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 int bytes_returned;
4479
4480 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4481 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4482 (void **) &pSMBr);
4483 if (rc)
4484 return rc;
4485
4486 pSMB->TotalParameterCount = 0 ;
4487 pSMB->TotalDataCount = 0;
4488 pSMB->MaxParameterCount = cpu_to_le32(2);
4489 /* BB find exact data count max from sess structure BB */
4490 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004491/* BB VERIFY verify which is correct for above BB */
4492 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4493 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4494
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495 pSMB->MaxSetupCount = 4;
4496 pSMB->Reserved = 0;
4497 pSMB->ParameterOffset = 0;
4498 pSMB->DataCount = 0;
4499 pSMB->DataOffset = 0;
4500 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4501 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4502 pSMB->ParameterCount = pSMB->TotalParameterCount;
4503 if(notify_subdirs)
4504 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4505 pSMB->Reserved2 = 0;
4506 pSMB->CompletionFilter = cpu_to_le32(filter);
4507 pSMB->Fid = netfid; /* file handle always le */
4508 pSMB->ByteCount = 0;
4509
4510 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4511 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4512 if (rc) {
4513 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004514 } else {
4515 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004516 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004517 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004518 sizeof(struct dir_notify_req),
4519 GFP_KERNEL);
4520 if(dnotify_req) {
4521 dnotify_req->Pid = pSMB->hdr.Pid;
4522 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4523 dnotify_req->Mid = pSMB->hdr.Mid;
4524 dnotify_req->Tid = pSMB->hdr.Tid;
4525 dnotify_req->Uid = pSMB->hdr.Uid;
4526 dnotify_req->netfid = netfid;
4527 dnotify_req->pfile = pfile;
4528 dnotify_req->filter = filter;
4529 dnotify_req->multishot = multishot;
4530 spin_lock(&GlobalMid_Lock);
4531 list_add_tail(&dnotify_req->lhead,
4532 &GlobalDnotifyReqList);
4533 spin_unlock(&GlobalMid_Lock);
4534 } else
4535 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536 }
4537 cifs_buf_release(pSMB);
4538 return rc;
4539}
4540#ifdef CONFIG_CIFS_XATTR
4541ssize_t
4542CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4543 const unsigned char *searchName,
4544 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004545 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546{
4547 /* BB assumes one setup word */
4548 TRANSACTION2_QPI_REQ *pSMB = NULL;
4549 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4550 int rc = 0;
4551 int bytes_returned;
4552 int name_len;
4553 struct fea * temp_fea;
4554 char * temp_ptr;
4555 __u16 params, byte_count;
4556
4557 cFYI(1, ("In Query All EAs path %s", searchName));
4558QAllEAsRetry:
4559 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4560 (void **) &pSMBr);
4561 if (rc)
4562 return rc;
4563
4564 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4565 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004566 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004567 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 name_len++; /* trailing null */
4569 name_len *= 2;
4570 } else { /* BB improve the check for buffer overruns BB */
4571 name_len = strnlen(searchName, PATH_MAX);
4572 name_len++; /* trailing null */
4573 strncpy(pSMB->FileName, searchName, name_len);
4574 }
4575
4576 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4577 pSMB->TotalDataCount = 0;
4578 pSMB->MaxParameterCount = cpu_to_le16(2);
4579 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4580 pSMB->MaxSetupCount = 0;
4581 pSMB->Reserved = 0;
4582 pSMB->Flags = 0;
4583 pSMB->Timeout = 0;
4584 pSMB->Reserved2 = 0;
4585 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4586 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4587 pSMB->DataCount = 0;
4588 pSMB->DataOffset = 0;
4589 pSMB->SetupCount = 1;
4590 pSMB->Reserved3 = 0;
4591 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4592 byte_count = params + 1 /* pad */ ;
4593 pSMB->TotalParameterCount = cpu_to_le16(params);
4594 pSMB->ParameterCount = pSMB->TotalParameterCount;
4595 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4596 pSMB->Reserved4 = 0;
4597 pSMB->hdr.smb_buf_length += byte_count;
4598 pSMB->ByteCount = cpu_to_le16(byte_count);
4599
4600 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4601 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4602 if (rc) {
4603 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4604 } else { /* decode response */
4605 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4606
4607 /* BB also check enough total bytes returned */
4608 /* BB we need to improve the validity checking
4609 of these trans2 responses */
4610 if (rc || (pSMBr->ByteCount < 4))
4611 rc = -EIO; /* bad smb */
4612 /* else if (pFindData){
4613 memcpy((char *) pFindData,
4614 (char *) &pSMBr->hdr.Protocol +
4615 data_offset, kl);
4616 }*/ else {
4617 /* check that length of list is not more than bcc */
4618 /* check that each entry does not go beyond length
4619 of list */
4620 /* check that each element of each entry does not
4621 go beyond end of list */
4622 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4623 struct fealist * ea_response_data;
4624 rc = 0;
4625 /* validate_trans2_offsets() */
4626 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4627 ea_response_data = (struct fealist *)
4628 (((char *) &pSMBr->hdr.Protocol) +
4629 data_offset);
4630 name_len = le32_to_cpu(ea_response_data->list_len);
4631 cFYI(1,("ea length %d", name_len));
4632 if(name_len <= 8) {
4633 /* returned EA size zeroed at top of function */
4634 cFYI(1,("empty EA list returned from server"));
4635 } else {
4636 /* account for ea list len */
4637 name_len -= 4;
4638 temp_fea = ea_response_data->list;
4639 temp_ptr = (char *)temp_fea;
4640 while(name_len > 0) {
4641 __u16 value_len;
4642 name_len -= 4;
4643 temp_ptr += 4;
4644 rc += temp_fea->name_len;
4645 /* account for prefix user. and trailing null */
4646 rc = rc + 5 + 1;
4647 if(rc<(int)buf_size) {
4648 memcpy(EAData,"user.",5);
4649 EAData+=5;
4650 memcpy(EAData,temp_ptr,temp_fea->name_len);
4651 EAData+=temp_fea->name_len;
4652 /* null terminate name */
4653 *EAData = 0;
4654 EAData = EAData + 1;
4655 } else if(buf_size == 0) {
4656 /* skip copy - calc size only */
4657 } else {
4658 /* stop before overrun buffer */
4659 rc = -ERANGE;
4660 break;
4661 }
4662 name_len -= temp_fea->name_len;
4663 temp_ptr += temp_fea->name_len;
4664 /* account for trailing null */
4665 name_len--;
4666 temp_ptr++;
4667 value_len = le16_to_cpu(temp_fea->value_len);
4668 name_len -= value_len;
4669 temp_ptr += value_len;
4670 /* BB check that temp_ptr is still within smb BB*/
4671 /* no trailing null to account for in value len */
4672 /* go on to next EA */
4673 temp_fea = (struct fea *)temp_ptr;
4674 }
4675 }
4676 }
4677 }
4678 if (pSMB)
4679 cifs_buf_release(pSMB);
4680 if (rc == -EAGAIN)
4681 goto QAllEAsRetry;
4682
4683 return (ssize_t)rc;
4684}
4685
4686ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4687 const unsigned char * searchName,const unsigned char * ea_name,
4688 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004689 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690{
4691 TRANSACTION2_QPI_REQ *pSMB = NULL;
4692 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4693 int rc = 0;
4694 int bytes_returned;
4695 int name_len;
4696 struct fea * temp_fea;
4697 char * temp_ptr;
4698 __u16 params, byte_count;
4699
4700 cFYI(1, ("In Query EA path %s", searchName));
4701QEARetry:
4702 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4703 (void **) &pSMBr);
4704 if (rc)
4705 return rc;
4706
4707 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4708 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004709 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004710 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711 name_len++; /* trailing null */
4712 name_len *= 2;
4713 } else { /* BB improve the check for buffer overruns BB */
4714 name_len = strnlen(searchName, PATH_MAX);
4715 name_len++; /* trailing null */
4716 strncpy(pSMB->FileName, searchName, name_len);
4717 }
4718
4719 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4720 pSMB->TotalDataCount = 0;
4721 pSMB->MaxParameterCount = cpu_to_le16(2);
4722 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4723 pSMB->MaxSetupCount = 0;
4724 pSMB->Reserved = 0;
4725 pSMB->Flags = 0;
4726 pSMB->Timeout = 0;
4727 pSMB->Reserved2 = 0;
4728 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4729 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4730 pSMB->DataCount = 0;
4731 pSMB->DataOffset = 0;
4732 pSMB->SetupCount = 1;
4733 pSMB->Reserved3 = 0;
4734 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4735 byte_count = params + 1 /* pad */ ;
4736 pSMB->TotalParameterCount = cpu_to_le16(params);
4737 pSMB->ParameterCount = pSMB->TotalParameterCount;
4738 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4739 pSMB->Reserved4 = 0;
4740 pSMB->hdr.smb_buf_length += byte_count;
4741 pSMB->ByteCount = cpu_to_le16(byte_count);
4742
4743 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4744 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4745 if (rc) {
4746 cFYI(1, ("Send error in Query EA = %d", rc));
4747 } else { /* decode response */
4748 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4749
4750 /* BB also check enough total bytes returned */
4751 /* BB we need to improve the validity checking
4752 of these trans2 responses */
4753 if (rc || (pSMBr->ByteCount < 4))
4754 rc = -EIO; /* bad smb */
4755 /* else if (pFindData){
4756 memcpy((char *) pFindData,
4757 (char *) &pSMBr->hdr.Protocol +
4758 data_offset, kl);
4759 }*/ else {
4760 /* check that length of list is not more than bcc */
4761 /* check that each entry does not go beyond length
4762 of list */
4763 /* check that each element of each entry does not
4764 go beyond end of list */
4765 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4766 struct fealist * ea_response_data;
4767 rc = -ENODATA;
4768 /* validate_trans2_offsets() */
4769 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4770 ea_response_data = (struct fealist *)
4771 (((char *) &pSMBr->hdr.Protocol) +
4772 data_offset);
4773 name_len = le32_to_cpu(ea_response_data->list_len);
4774 cFYI(1,("ea length %d", name_len));
4775 if(name_len <= 8) {
4776 /* returned EA size zeroed at top of function */
4777 cFYI(1,("empty EA list returned from server"));
4778 } else {
4779 /* account for ea list len */
4780 name_len -= 4;
4781 temp_fea = ea_response_data->list;
4782 temp_ptr = (char *)temp_fea;
4783 /* loop through checking if we have a matching
4784 name and then return the associated value */
4785 while(name_len > 0) {
4786 __u16 value_len;
4787 name_len -= 4;
4788 temp_ptr += 4;
4789 value_len = le16_to_cpu(temp_fea->value_len);
4790 /* BB validate that value_len falls within SMB,
4791 even though maximum for name_len is 255 */
4792 if(memcmp(temp_fea->name,ea_name,
4793 temp_fea->name_len) == 0) {
4794 /* found a match */
4795 rc = value_len;
4796 /* account for prefix user. and trailing null */
4797 if(rc<=(int)buf_size) {
4798 memcpy(ea_value,
4799 temp_fea->name+temp_fea->name_len+1,
4800 rc);
4801 /* ea values, unlike ea names,
4802 are not null terminated */
4803 } else if(buf_size == 0) {
4804 /* skip copy - calc size only */
4805 } else {
4806 /* stop before overrun buffer */
4807 rc = -ERANGE;
4808 }
4809 break;
4810 }
4811 name_len -= temp_fea->name_len;
4812 temp_ptr += temp_fea->name_len;
4813 /* account for trailing null */
4814 name_len--;
4815 temp_ptr++;
4816 name_len -= value_len;
4817 temp_ptr += value_len;
4818 /* no trailing null to account for in value len */
4819 /* go on to next EA */
4820 temp_fea = (struct fea *)temp_ptr;
4821 }
4822 }
4823 }
4824 }
4825 if (pSMB)
4826 cifs_buf_release(pSMB);
4827 if (rc == -EAGAIN)
4828 goto QEARetry;
4829
4830 return (ssize_t)rc;
4831}
4832
4833int
4834CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4835 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004836 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4837 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838{
4839 struct smb_com_transaction2_spi_req *pSMB = NULL;
4840 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4841 struct fealist *parm_data;
4842 int name_len;
4843 int rc = 0;
4844 int bytes_returned = 0;
4845 __u16 params, param_offset, byte_count, offset, count;
4846
4847 cFYI(1, ("In SetEA"));
4848SetEARetry:
4849 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4850 (void **) &pSMBr);
4851 if (rc)
4852 return rc;
4853
4854 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4855 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004856 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004857 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004858 name_len++; /* trailing null */
4859 name_len *= 2;
4860 } else { /* BB improve the check for buffer overruns BB */
4861 name_len = strnlen(fileName, PATH_MAX);
4862 name_len++; /* trailing null */
4863 strncpy(pSMB->FileName, fileName, name_len);
4864 }
4865
4866 params = 6 + name_len;
4867
4868 /* done calculating parms using name_len of file name,
4869 now use name_len to calculate length of ea name
4870 we are going to create in the inode xattrs */
4871 if(ea_name == NULL)
4872 name_len = 0;
4873 else
4874 name_len = strnlen(ea_name,255);
4875
4876 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4877 pSMB->MaxParameterCount = cpu_to_le16(2);
4878 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4879 pSMB->MaxSetupCount = 0;
4880 pSMB->Reserved = 0;
4881 pSMB->Flags = 0;
4882 pSMB->Timeout = 0;
4883 pSMB->Reserved2 = 0;
4884 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4885 InformationLevel) - 4;
4886 offset = param_offset + params;
4887 pSMB->InformationLevel =
4888 cpu_to_le16(SMB_SET_FILE_EA);
4889
4890 parm_data =
4891 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4892 offset);
4893 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4894 pSMB->DataOffset = cpu_to_le16(offset);
4895 pSMB->SetupCount = 1;
4896 pSMB->Reserved3 = 0;
4897 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4898 byte_count = 3 /* pad */ + params + count;
4899 pSMB->DataCount = cpu_to_le16(count);
4900 parm_data->list_len = cpu_to_le32(count);
4901 parm_data->list[0].EA_flags = 0;
4902 /* we checked above that name len is less than 255 */
4903 parm_data->list[0].name_len = (__u8)name_len;;
4904 /* EA names are always ASCII */
4905 if(ea_name)
4906 strncpy(parm_data->list[0].name,ea_name,name_len);
4907 parm_data->list[0].name[name_len] = 0;
4908 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4909 /* caller ensures that ea_value_len is less than 64K but
4910 we need to ensure that it fits within the smb */
4911
4912 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4913 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4914 if(ea_value_len)
4915 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4916
4917 pSMB->TotalDataCount = pSMB->DataCount;
4918 pSMB->ParameterCount = cpu_to_le16(params);
4919 pSMB->TotalParameterCount = pSMB->ParameterCount;
4920 pSMB->Reserved4 = 0;
4921 pSMB->hdr.smb_buf_length += byte_count;
4922 pSMB->ByteCount = cpu_to_le16(byte_count);
4923 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4924 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4925 if (rc) {
4926 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4927 }
4928
4929 cifs_buf_release(pSMB);
4930
4931 if (rc == -EAGAIN)
4932 goto SetEARetry;
4933
4934 return rc;
4935}
4936
4937#endif