blob: 217323b0c8966ae62db2683038adcda6d53dce3b [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"
Steve Frencheeac8042006-01-13 21:34:58 -080040#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#ifdef CONFIG_CIFS_POSIX
43static struct {
44 int index;
45 char *name;
46} protocols[] = {
47 {CIFS_PROT, "\2NT LM 0.12"},
48 {CIFS_PROT, "\2POSIX 2"},
49 {BAD_PROT, "\2"}
50};
51#else
52static struct {
53 int index;
54 char *name;
55} protocols[] = {
56 {CIFS_PROT, "\2NT LM 0.12"},
57 {BAD_PROT, "\2"}
58};
59#endif
60
61
62/* Mark as invalid, all open files on tree connections since they
63 were closed when session to server was lost */
64static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
65{
66 struct cifsFileInfo *open_file = NULL;
67 struct list_head * tmp;
68 struct list_head * tmp1;
69
70/* list all files open on tree connection and mark them invalid */
71 write_lock(&GlobalSMBSeslock);
72 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
73 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
74 if(open_file) {
75 open_file->invalidHandle = TRUE;
76 }
77 }
78 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -070079 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
80 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -070081}
82
83/* If the return code is zero, this function must fill in request_buf pointer */
84static int
85small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
86 void **request_buf /* returned */)
87{
88 int rc = 0;
89
90 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
91 check for tcp and smb session status done differently
92 for those three - in the calling routine */
93 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -080094 if(tcon->tidStatus == CifsExiting) {
95 /* only tree disconnect, open, and write,
96 (and ulogoff which does not have tcon)
97 are allowed as we start force umount */
98 if((smb_command != SMB_COM_WRITE_ANDX) &&
99 (smb_command != SMB_COM_OPEN_ANDX) &&
100 (smb_command != SMB_COM_TREE_DISCONNECT)) {
101 cFYI(1,("can not send cmd %d while umounting",
102 smb_command));
103 return -ENODEV;
104 }
105 }
Steve French31ca3bc2005-04-28 22:41:11 -0700106 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
107 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 struct nls_table *nls_codepage;
109 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700110 reconnect, should be greater than cifs socket
111 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
113 wait_event_interruptible_timeout(tcon->ses->server->response_q,
114 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
115 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
116 /* on "soft" mounts we wait once */
117 if((tcon->retry == FALSE) ||
118 (tcon->ses->status == CifsExiting)) {
119 cFYI(1,("gave up waiting on reconnect in smb_init"));
120 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700121 } /* else "hard" mount - keep retrying
122 until process is killed or server
123 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 } else /* TCP session is reestablished now */
125 break;
126
127 }
128
129 nls_codepage = load_nls_default();
130 /* need to prevent multiple threads trying to
131 simultaneously reconnect the same SMB session */
132 down(&tcon->ses->sesSem);
133 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700134 rc = cifs_setup_session(0, tcon->ses,
135 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
137 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700138 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
139 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700141 /* BB FIXME add code to check if wsize needs
142 update due to negotiated smb buffer size
143 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 if(rc == 0)
145 atomic_inc(&tconInfoReconnectCount);
146
147 cFYI(1, ("reconnect tcon rc = %d", rc));
148 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700149 it is safer (and faster) to reopen files
150 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
152 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700153 know whether we can continue or not without
154 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 switch(smb_command) {
156 case SMB_COM_READ_ANDX:
157 case SMB_COM_WRITE_ANDX:
158 case SMB_COM_CLOSE:
159 case SMB_COM_FIND_CLOSE2:
160 case SMB_COM_LOCKING_ANDX: {
161 unload_nls(nls_codepage);
162 return -EAGAIN;
163 }
164 }
165 } else {
166 up(&tcon->ses->sesSem);
167 }
168 unload_nls(nls_codepage);
169
170 } else {
171 return -EIO;
172 }
173 }
174 if(rc)
175 return rc;
176
177 *request_buf = cifs_small_buf_get();
178 if (*request_buf == NULL) {
179 /* BB should we add a retry in here if not a writepage? */
180 return -ENOMEM;
181 }
182
183 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
184
Steve Frencha4544342005-08-24 13:59:35 -0700185 if(tcon != NULL)
186 cifs_stats_inc(&tcon->num_smbs_sent);
187
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 return rc;
189}
190
191/* If the return code is zero, this function must fill in request_buf pointer */
192static int
193smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
194 void **request_buf /* returned */ ,
195 void **response_buf /* returned */ )
196{
197 int rc = 0;
198
199 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
200 check for tcp and smb session status done differently
201 for those three - in the calling routine */
202 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800203 if(tcon->tidStatus == CifsExiting) {
204 /* only tree disconnect, open, and write,
205 (and ulogoff which does not have tcon)
206 are allowed as we start force umount */
207 if((smb_command != SMB_COM_WRITE_ANDX) &&
208 (smb_command != SMB_COM_OPEN_ANDX) &&
209 (smb_command != SMB_COM_TREE_DISCONNECT)) {
210 cFYI(1,("can not send cmd %d while umounting",
211 smb_command));
212 return -ENODEV;
213 }
214 }
215
Steve French31ca3bc2005-04-28 22:41:11 -0700216 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
217 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700219 /* Give Demultiplex thread up to 10 seconds to
220 reconnect, should be greater than cifs socket
221 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
223 wait_event_interruptible_timeout(tcon->ses->server->response_q,
224 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
Steve French09d1db52005-04-28 22:41:08 -0700225 if(tcon->ses->server->tcpStatus ==
226 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 /* on "soft" mounts we wait once */
228 if((tcon->retry == FALSE) ||
229 (tcon->ses->status == CifsExiting)) {
230 cFYI(1,("gave up waiting on reconnect in smb_init"));
231 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700232 } /* else "hard" mount - keep retrying
233 until process is killed or server
234 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 } else /* TCP session is reestablished now */
236 break;
237
238 }
239
240 nls_codepage = load_nls_default();
241 /* need to prevent multiple threads trying to
242 simultaneously reconnect the same SMB session */
243 down(&tcon->ses->sesSem);
244 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700245 rc = cifs_setup_session(0, tcon->ses,
246 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
248 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700249 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
250 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700252 /* BB FIXME add code to check if wsize needs
253 update due to negotiated smb buffer size
254 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 if(rc == 0)
256 atomic_inc(&tconInfoReconnectCount);
257
258 cFYI(1, ("reconnect tcon rc = %d", rc));
259 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700260 it is safer (and faster) to reopen files
261 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
263 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700264 know whether we can continue or not without
265 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 switch(smb_command) {
267 case SMB_COM_READ_ANDX:
268 case SMB_COM_WRITE_ANDX:
269 case SMB_COM_CLOSE:
270 case SMB_COM_FIND_CLOSE2:
271 case SMB_COM_LOCKING_ANDX: {
272 unload_nls(nls_codepage);
273 return -EAGAIN;
274 }
275 }
276 } else {
277 up(&tcon->ses->sesSem);
278 }
279 unload_nls(nls_codepage);
280
281 } else {
282 return -EIO;
283 }
284 }
285 if(rc)
286 return rc;
287
288 *request_buf = cifs_buf_get();
289 if (*request_buf == NULL) {
290 /* BB should we add a retry in here if not a writepage? */
291 return -ENOMEM;
292 }
293 /* Although the original thought was we needed the response buf for */
294 /* potential retries of smb operations it turns out we can determine */
295 /* from the mid flags when the request buffer can be resent without */
296 /* having to use a second distinct buffer for the response */
297 *response_buf = *request_buf;
298
299 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
300 wct /*wct */ );
301
Steve Frencha4544342005-08-24 13:59:35 -0700302 if(tcon != NULL)
303 cifs_stats_inc(&tcon->num_smbs_sent);
304
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305 return rc;
306}
307
308static int validate_t2(struct smb_t2_rsp * pSMB)
309{
310 int rc = -EINVAL;
311 int total_size;
312 char * pBCC;
313
314 /* check for plausible wct, bcc and t2 data and parm sizes */
315 /* check for parm and data offset going beyond end of smb */
316 if(pSMB->hdr.WordCount >= 10) {
317 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
318 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
319 /* check that bcc is at least as big as parms + data */
320 /* check that bcc is less than negotiated smb buffer */
321 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
322 if(total_size < 512) {
323 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
324 /* BCC le converted in SendReceive */
Steve French09d1db52005-04-28 22:41:08 -0700325 pBCC = (pSMB->hdr.WordCount * 2) +
326 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 (char *)pSMB;
328 if((total_size <= (*(u16 *)pBCC)) &&
329 (total_size <
330 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
331 return 0;
332 }
333
334 }
335 }
336 }
337 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
338 sizeof(struct smb_t2_rsp) + 16);
339 return rc;
340}
341int
342CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
343{
344 NEGOTIATE_REQ *pSMB;
345 NEGOTIATE_RSP *pSMBr;
346 int rc = 0;
347 int bytes_returned;
348 struct TCP_Server_Info * server;
349 u16 count;
350
351 if(ses->server)
352 server = ses->server;
353 else {
354 rc = -EIO;
355 return rc;
356 }
357 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
358 (void **) &pSMB, (void **) &pSMBr);
359 if (rc)
360 return rc;
Steve French1982c342005-08-17 12:38:22 -0700361 pSMB->hdr.Mid = GetNextMid(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
363 if (extended_security)
364 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
365
366 count = strlen(protocols[0].name) + 1;
367 strncpy(pSMB->DialectsArray, protocols[0].name, 30);
368 /* null guaranteed to be at end of source and target buffers anyway */
369
370 pSMB->hdr.smb_buf_length += count;
371 pSMB->ByteCount = cpu_to_le16(count);
372
373 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
374 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
375 if (rc == 0) {
Steve Frencheeac8042006-01-13 21:34:58 -0800376 server->secMode = pSMBr->SecurityMode;
377 if((server->secMode & SECMODE_USER) == 0)
378 cFYI(1,("share mode security"));
379 server->secType = NTLM; /* BB override default for
Steve French09d1db52005-04-28 22:41:08 -0700380 NTLMv2 or kerberos v5 */
381 /* one byte - no need to convert this or EncryptionKeyLen
382 from little endian */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
384 /* probably no need to store and check maxvcs */
385 server->maxBuf =
386 min(le32_to_cpu(pSMBr->MaxBufferSize),
387 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
388 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
Steve Frencheeac8042006-01-13 21:34:58 -0800389 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
391 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
392 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
393 /* BB with UTC do we ever need to be using srvr timezone? */
394 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
395 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
396 CIFS_CRYPTO_KEY_SIZE);
397 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
398 && (pSMBr->EncryptionKeyLength == 0)) {
399 /* decode security blob */
400 } else
401 rc = -EIO;
402
403 /* BB might be helpful to save off the domain of server here */
404
405 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
406 (server->capabilities & CAP_EXTENDED_SECURITY)) {
407 count = pSMBr->ByteCount;
408 if (count < 16)
409 rc = -EIO;
410 else if (count == 16) {
411 server->secType = RawNTLMSSP;
412 if (server->socketUseCount.counter > 1) {
413 if (memcmp
414 (server->server_GUID,
415 pSMBr->u.extended_response.
416 GUID, 16) != 0) {
Steve Frencheeac8042006-01-13 21:34:58 -0800417 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 memcpy(server->
419 server_GUID,
420 pSMBr->u.
421 extended_response.
422 GUID, 16);
423 }
424 } else
425 memcpy(server->server_GUID,
426 pSMBr->u.extended_response.
427 GUID, 16);
428 } else {
429 rc = decode_negTokenInit(pSMBr->u.
430 extended_response.
431 SecurityBlob,
432 count - 16,
433 &server->secType);
434 if(rc == 1) {
435 /* BB Need to fill struct for sessetup here */
436 rc = -EOPNOTSUPP;
437 } else {
438 rc = -EINVAL;
439 }
440 }
441 } else
442 server->capabilities &= ~CAP_EXTENDED_SECURITY;
443 if(sign_CIFS_PDUs == FALSE) {
444 if(server->secMode & SECMODE_SIGN_REQUIRED)
445 cERROR(1,
446 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
Steve French1982c342005-08-17 12:38:22 -0700447 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 } else if(sign_CIFS_PDUs == 1) {
449 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French1982c342005-08-17 12:38:22 -0700450 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 }
452
453 }
Steve French1982c342005-08-17 12:38:22 -0700454
Steve French4a6d87f2005-08-13 08:15:54 -0700455 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 return rc;
457}
458
459int
460CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
461{
462 struct smb_hdr *smb_buffer;
463 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
464 int rc = 0;
465 int length;
466
467 cFYI(1, ("In tree disconnect"));
468 /*
469 * If last user of the connection and
470 * connection alive - disconnect it
471 * If this is the last connection on the server session disconnect it
472 * (and inside session disconnect we should check if tcp socket needs
473 * to be freed and kernel thread woken up).
474 */
475 if (tcon)
476 down(&tcon->tconSem);
477 else
478 return -EIO;
479
480 atomic_dec(&tcon->useCount);
481 if (atomic_read(&tcon->useCount) > 0) {
482 up(&tcon->tconSem);
483 return -EBUSY;
484 }
485
486 /* No need to return error on this operation if tid invalidated and
487 closed on server already e.g. due to tcp session crashing */
488 if(tcon->tidStatus == CifsNeedReconnect) {
489 up(&tcon->tconSem);
490 return 0;
491 }
492
493 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
494 up(&tcon->tconSem);
495 return -EIO;
496 }
Steve French09d1db52005-04-28 22:41:08 -0700497 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
498 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 if (rc) {
500 up(&tcon->tconSem);
501 return rc;
502 } else {
503 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700504 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
506 &length, 0);
507 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700508 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510 if (smb_buffer)
511 cifs_small_buf_release(smb_buffer);
512 up(&tcon->tconSem);
513
514 /* No need to return error on this operation if tid invalidated and
515 closed on server already e.g. due to tcp session crashing */
516 if (rc == -EAGAIN)
517 rc = 0;
518
519 return rc;
520}
521
522int
523CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
524{
525 struct smb_hdr *smb_buffer_response;
526 LOGOFF_ANDX_REQ *pSMB;
527 int rc = 0;
528 int length;
529
530 cFYI(1, ("In SMBLogoff for session disconnect"));
531 if (ses)
532 down(&ses->sesSem);
533 else
534 return -EIO;
535
536 atomic_dec(&ses->inUse);
537 if (atomic_read(&ses->inUse) > 0) {
538 up(&ses->sesSem);
539 return -EBUSY;
540 }
541 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
542 if (rc) {
543 up(&ses->sesSem);
544 return rc;
545 }
546
547 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
548
549 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700550 pSMB->hdr.Mid = GetNextMid(ses->server);
551
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 if(ses->server->secMode &
553 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
554 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
555 }
556
557 pSMB->hdr.Uid = ses->Suid;
558
559 pSMB->AndXCommand = 0xFF;
560 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
561 smb_buffer_response, &length, 0);
562 if (ses->server) {
563 atomic_dec(&ses->server->socketUseCount);
564 if (atomic_read(&ses->server->socketUseCount) == 0) {
565 spin_lock(&GlobalMid_Lock);
566 ses->server->tcpStatus = CifsExiting;
567 spin_unlock(&GlobalMid_Lock);
568 rc = -ESHUTDOWN;
569 }
570 }
Steve Frencha59c6582005-08-17 12:12:19 -0700571 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700572 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573
574 /* if session dead then we do not need to do ulogoff,
575 since server closed smb session, no sense reporting
576 error */
577 if (rc == -EAGAIN)
578 rc = 0;
579 return rc;
580}
581
582int
Steve French737b7582005-04-28 22:41:06 -0700583CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
584 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{
586 DELETE_FILE_REQ *pSMB = NULL;
587 DELETE_FILE_RSP *pSMBr = NULL;
588 int rc = 0;
589 int bytes_returned;
590 int name_len;
591
592DelFileRetry:
593 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
594 (void **) &pSMBr);
595 if (rc)
596 return rc;
597
598 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
599 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500600 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700601 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 name_len++; /* trailing null */
603 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700604 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 name_len = strnlen(fileName, PATH_MAX);
606 name_len++; /* trailing null */
607 strncpy(pSMB->fileName, fileName, name_len);
608 }
609 pSMB->SearchAttributes =
610 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
611 pSMB->BufferFormat = 0x04;
612 pSMB->hdr.smb_buf_length += name_len + 1;
613 pSMB->ByteCount = cpu_to_le16(name_len + 1);
614 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
615 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700616 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 if (rc) {
618 cFYI(1, ("Error in RMFile = %d", rc));
619 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
621 cifs_buf_release(pSMB);
622 if (rc == -EAGAIN)
623 goto DelFileRetry;
624
625 return rc;
626}
627
628int
Steve French737b7582005-04-28 22:41:06 -0700629CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
630 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631{
632 DELETE_DIRECTORY_REQ *pSMB = NULL;
633 DELETE_DIRECTORY_RSP *pSMBr = NULL;
634 int rc = 0;
635 int bytes_returned;
636 int name_len;
637
638 cFYI(1, ("In CIFSSMBRmDir"));
639RmDirRetry:
640 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
641 (void **) &pSMBr);
642 if (rc)
643 return rc;
644
645 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700646 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
647 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 name_len++; /* trailing null */
649 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700650 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 name_len = strnlen(dirName, PATH_MAX);
652 name_len++; /* trailing null */
653 strncpy(pSMB->DirName, dirName, name_len);
654 }
655
656 pSMB->BufferFormat = 0x04;
657 pSMB->hdr.smb_buf_length += name_len + 1;
658 pSMB->ByteCount = cpu_to_le16(name_len + 1);
659 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
660 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700661 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 if (rc) {
663 cFYI(1, ("Error in RMDir = %d", rc));
664 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
666 cifs_buf_release(pSMB);
667 if (rc == -EAGAIN)
668 goto RmDirRetry;
669 return rc;
670}
671
672int
673CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700674 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675{
676 int rc = 0;
677 CREATE_DIRECTORY_REQ *pSMB = NULL;
678 CREATE_DIRECTORY_RSP *pSMBr = NULL;
679 int bytes_returned;
680 int name_len;
681
682 cFYI(1, ("In CIFSSMBMkDir"));
683MkDirRetry:
684 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
685 (void **) &pSMBr);
686 if (rc)
687 return rc;
688
689 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500690 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700691 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 name_len++; /* trailing null */
693 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700694 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 name_len = strnlen(name, PATH_MAX);
696 name_len++; /* trailing null */
697 strncpy(pSMB->DirName, name, name_len);
698 }
699
700 pSMB->BufferFormat = 0x04;
701 pSMB->hdr.smb_buf_length += name_len + 1;
702 pSMB->ByteCount = cpu_to_le16(name_len + 1);
703 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
704 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700705 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 if (rc) {
707 cFYI(1, ("Error in Mkdir = %d", rc));
708 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700709
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 cifs_buf_release(pSMB);
711 if (rc == -EAGAIN)
712 goto MkDirRetry;
713 return rc;
714}
715
Steve Frencha9d02ad2005-08-24 23:06:05 -0700716static __u16 convert_disposition(int disposition)
717{
718 __u16 ofun = 0;
719
720 switch (disposition) {
721 case FILE_SUPERSEDE:
722 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
723 break;
724 case FILE_OPEN:
725 ofun = SMBOPEN_OAPPEND;
726 break;
727 case FILE_CREATE:
728 ofun = SMBOPEN_OCREATE;
729 break;
730 case FILE_OPEN_IF:
731 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
732 break;
733 case FILE_OVERWRITE:
734 ofun = SMBOPEN_OTRUNC;
735 break;
736 case FILE_OVERWRITE_IF:
737 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
738 break;
739 default:
740 cFYI(1,("unknown disposition %d",disposition));
741 ofun = SMBOPEN_OAPPEND; /* regular open */
742 }
743 return ofun;
744}
745
746int
747SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
748 const char *fileName, const int openDisposition,
749 const int access_flags, const int create_options, __u16 * netfid,
750 int *pOplock, FILE_ALL_INFO * pfile_info,
751 const struct nls_table *nls_codepage, int remap)
752{
753 int rc = -EACCES;
754 OPENX_REQ *pSMB = NULL;
755 OPENX_RSP *pSMBr = NULL;
756 int bytes_returned;
757 int name_len;
758 __u16 count;
759
760OldOpenRetry:
761 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
762 (void **) &pSMBr);
763 if (rc)
764 return rc;
765
766 pSMB->AndXCommand = 0xFF; /* none */
767
768 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
769 count = 1; /* account for one byte pad to word boundary */
770 name_len =
771 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
772 fileName, PATH_MAX, nls_codepage, remap);
773 name_len++; /* trailing null */
774 name_len *= 2;
775 } else { /* BB improve check for buffer overruns BB */
776 count = 0; /* no pad */
777 name_len = strnlen(fileName, PATH_MAX);
778 name_len++; /* trailing null */
779 strncpy(pSMB->fileName, fileName, name_len);
780 }
781 if (*pOplock & REQ_OPLOCK)
782 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
783 else if (*pOplock & REQ_BATCHOPLOCK) {
784 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
785 }
786 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
787 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
788 /* 0 = read
789 1 = write
790 2 = rw
791 3 = execute
792 */
793 pSMB->Mode = cpu_to_le16(2);
794 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
795 /* set file as system file if special file such
796 as fifo and server expecting SFU style and
797 no Unix extensions */
798
799 if(create_options & CREATE_OPTION_SPECIAL)
800 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
801 else
Steve French3e87d802005-09-18 20:49:21 -0700802 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700803
804 /* if ((omode & S_IWUGO) == 0)
805 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
806 /* Above line causes problems due to vfs splitting create into two
807 pieces - need to set mode after file created not while it is
808 being created */
809
810 /* BB FIXME BB */
811/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
812 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700813
814 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700815 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700816 count += name_len;
817 pSMB->hdr.smb_buf_length += count;
818
819 pSMB->ByteCount = cpu_to_le16(count);
820 /* long_op set to 1 to allow for oplock break timeouts */
821 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
822 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
823 cifs_stats_inc(&tcon->num_opens);
824 if (rc) {
825 cFYI(1, ("Error in Open = %d", rc));
826 } else {
827 /* BB verify if wct == 15 */
828
829/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
830
831 *netfid = pSMBr->Fid; /* cifs fid stays in le */
832 /* Let caller know file was created so we can set the mode. */
833 /* Do we care about the CreateAction in any other cases? */
834 /* BB FIXME BB */
835/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
836 *pOplock |= CIFS_CREATE_ACTION; */
837 /* BB FIXME END */
838
839 if(pfile_info) {
840 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
841 pfile_info->LastAccessTime = 0; /* BB fixme */
842 pfile_info->LastWriteTime = 0; /* BB fixme */
843 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -0700844 pfile_info->Attributes =
845 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700846 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -0700847 pfile_info->AllocationSize =
848 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
849 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -0700850 pfile_info->NumberOfLinks = cpu_to_le32(1);
851 }
852 }
853
854 cifs_buf_release(pSMB);
855 if (rc == -EAGAIN)
856 goto OldOpenRetry;
857 return rc;
858}
859
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860int
861CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
862 const char *fileName, const int openDisposition,
863 const int access_flags, const int create_options, __u16 * netfid,
864 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -0700865 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866{
867 int rc = -EACCES;
868 OPEN_REQ *pSMB = NULL;
869 OPEN_RSP *pSMBr = NULL;
870 int bytes_returned;
871 int name_len;
872 __u16 count;
873
874openRetry:
875 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
876 (void **) &pSMBr);
877 if (rc)
878 return rc;
879
880 pSMB->AndXCommand = 0xFF; /* none */
881
882 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
883 count = 1; /* account for one byte pad to word boundary */
884 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500885 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -0700886 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 name_len++; /* trailing null */
888 name_len *= 2;
889 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -0700890 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891 count = 0; /* no pad */
892 name_len = strnlen(fileName, PATH_MAX);
893 name_len++; /* trailing null */
894 pSMB->NameLength = cpu_to_le16(name_len);
895 strncpy(pSMB->fileName, fileName, name_len);
896 }
897 if (*pOplock & REQ_OPLOCK)
898 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
899 else if (*pOplock & REQ_BATCHOPLOCK) {
900 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
901 }
902 pSMB->DesiredAccess = cpu_to_le32(access_flags);
903 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -0700904 /* set file as system file if special file such
905 as fifo and server expecting SFU style and
906 no Unix extensions */
907 if(create_options & CREATE_OPTION_SPECIAL)
908 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
909 else
910 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 /* XP does not handle ATTR_POSIX_SEMANTICS */
912 /* but it helps speed up case sensitive checks for other
913 servers such as Samba */
914 if (tcon->ses->capabilities & CAP_UNIX)
915 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
916
917 /* if ((omode & S_IWUGO) == 0)
918 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
919 /* Above line causes problems due to vfs splitting create into two
920 pieces - need to set mode after file created not while it is
921 being created */
922 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
923 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -0700924 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -0700925 /* BB Expirement with various impersonation levels and verify */
926 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 pSMB->SecurityFlags =
928 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
929
930 count += name_len;
931 pSMB->hdr.smb_buf_length += count;
932
933 pSMB->ByteCount = cpu_to_le16(count);
934 /* long_op set to 1 to allow for oplock break timeouts */
935 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
936 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -0700937 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 if (rc) {
939 cFYI(1, ("Error in Open = %d", rc));
940 } else {
Steve French09d1db52005-04-28 22:41:08 -0700941 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 *netfid = pSMBr->Fid; /* cifs fid stays in le */
943 /* Let caller know file was created so we can set the mode. */
944 /* Do we care about the CreateAction in any other cases? */
945 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
946 *pOplock |= CIFS_CREATE_ACTION;
947 if(pfile_info) {
948 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
949 36 /* CreationTime to Attributes */);
950 /* the file_info buf is endian converted by caller */
951 pfile_info->AllocationSize = pSMBr->AllocationSize;
952 pfile_info->EndOfFile = pSMBr->EndOfFile;
953 pfile_info->NumberOfLinks = cpu_to_le32(1);
954 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700956
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 cifs_buf_release(pSMB);
958 if (rc == -EAGAIN)
959 goto openRetry;
960 return rc;
961}
962
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963int
964CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -0800965 const int netfid, const unsigned int count,
966 const __u64 lseek, unsigned int *nbytes, char **buf,
967 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968{
969 int rc = -EACCES;
970 READ_REQ *pSMB = NULL;
971 READ_RSP *pSMBr = NULL;
972 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -0700973 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -0800974 int resp_buf_type = 0;
975 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
977 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -0700978 if(tcon->ses->capabilities & CAP_LARGE_FILES)
979 wct = 12;
980 else
981 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
983 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -0800984 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 if (rc)
986 return rc;
987
988 /* tcon and ses pointer are checked in smb_init */
989 if (tcon->ses->server == NULL)
990 return -ECONNABORTED;
991
Steve Frenchec637e32005-12-12 20:53:18 -0800992 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 pSMB->Fid = netfid;
994 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -0700995 if(wct == 12)
996 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -0800997 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
998 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -0700999
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 pSMB->Remaining = 0;
1001 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1002 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001003 if(wct == 12)
1004 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1005 else {
1006 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001007 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001008 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001009 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001010 }
Steve Frenchec637e32005-12-12 20:53:18 -08001011
1012 iov[0].iov_base = (char *)pSMB;
1013 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1014 rc = SendReceive2(xid, tcon->ses, iov,
1015 1 /* num iovecs */,
1016 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001017 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001018 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 if (rc) {
1020 cERROR(1, ("Send error in read = %d", rc));
1021 } else {
1022 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1023 data_length = data_length << 16;
1024 data_length += le16_to_cpu(pSMBr->DataLength);
1025 *nbytes = data_length;
1026
1027 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001028 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 || (data_length > count)) {
1030 cFYI(1,("bad length %d for count %d",data_length,count));
1031 rc = -EIO;
1032 *nbytes = 0;
1033 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001034 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001036/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1037 cERROR(1,("Faulting on read rc = %d",rc));
1038 rc = -EFAULT;
1039 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001041 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 }
1043 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
Steve Frenchec637e32005-12-12 20:53:18 -08001045 cifs_small_buf_release(pSMB);
1046 if(*buf) {
1047 if(resp_buf_type == CIFS_SMALL_BUFFER)
1048 cifs_small_buf_release(iov[0].iov_base);
1049 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1050 cifs_buf_release(iov[0].iov_base);
1051 } else /* return buffer to caller to free */ /* BB FIXME how do we tell caller if it is not a large buffer */ {
1052 *buf = iov[0].iov_base;
1053 if(resp_buf_type == CIFS_SMALL_BUFFER)
1054 *pbuf_type = CIFS_SMALL_BUFFER;
1055 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1056 *pbuf_type = CIFS_LARGE_BUFFER;
1057 }
1058
1059 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 since file handle passed in no longer valid */
1061 return rc;
1062}
1063
Steve Frenchec637e32005-12-12 20:53:18 -08001064
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065int
1066CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1067 const int netfid, const unsigned int count,
1068 const __u64 offset, unsigned int *nbytes, const char *buf,
1069 const char __user * ubuf, const int long_op)
1070{
1071 int rc = -EACCES;
1072 WRITE_REQ *pSMB = NULL;
1073 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001074 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 __u32 bytes_sent;
1076 __u16 byte_count;
1077
1078 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001079 if(tcon->ses == NULL)
1080 return -ECONNABORTED;
1081
1082 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1083 wct = 14;
1084 else
1085 wct = 12;
1086
1087 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 (void **) &pSMBr);
1089 if (rc)
1090 return rc;
1091 /* tcon and ses pointer are checked in smb_init */
1092 if (tcon->ses->server == NULL)
1093 return -ECONNABORTED;
1094
1095 pSMB->AndXCommand = 0xFF; /* none */
1096 pSMB->Fid = netfid;
1097 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001098 if(wct == 14)
1099 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1100 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1101 return -EIO;
1102
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 pSMB->Reserved = 0xFFFFFFFF;
1104 pSMB->WriteMode = 0;
1105 pSMB->Remaining = 0;
1106
1107 /* Can increase buffer size if buffer is big enough in some cases - ie we
1108 can send more if LARGE_WRITE_X capability returned by the server and if
1109 our buffer is big enough or if we convert to iovecs on socket writes
1110 and eliminate the copy to the CIFS buffer */
1111 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1112 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1113 } else {
1114 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1115 & ~0xFF;
1116 }
1117
1118 if (bytes_sent > count)
1119 bytes_sent = count;
1120 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001121 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 if(buf)
1123 memcpy(pSMB->Data,buf,bytes_sent);
1124 else if(ubuf) {
1125 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1126 cifs_buf_release(pSMB);
1127 return -EFAULT;
1128 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001129 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 /* No buffer */
1131 cifs_buf_release(pSMB);
1132 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001133 } /* else setting file size with write of zero bytes */
1134 if(wct == 14)
1135 byte_count = bytes_sent + 1; /* pad */
1136 else /* wct == 12 */ {
1137 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1140 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001141 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001142
1143 if(wct == 14)
1144 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001145 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001146 struct smb_com_writex_req * pSMBW =
1147 (struct smb_com_writex_req *)pSMB;
1148 pSMBW->ByteCount = cpu_to_le16(byte_count);
1149 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
1151 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1152 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001153 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 if (rc) {
1155 cFYI(1, ("Send error in write = %d", rc));
1156 *nbytes = 0;
1157 } else {
1158 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1159 *nbytes = (*nbytes) << 16;
1160 *nbytes += le16_to_cpu(pSMBr->Count);
1161 }
1162
1163 cifs_buf_release(pSMB);
1164
1165 /* Note: On -EAGAIN error only caller can retry on handle based calls
1166 since file handle passed in no longer valid */
1167
1168 return rc;
1169}
1170
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001171int
1172CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001174 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1175 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176{
1177 int rc = -EACCES;
1178 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001179 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001180 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001181 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182
Steve Frenchff7feac2005-11-15 16:45:16 -08001183 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1184
Steve French8cc64c62005-10-03 13:49:43 -07001185 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1186 wct = 14;
1187 else
1188 wct = 12;
1189 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 if (rc)
1191 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 /* tcon and ses pointer are checked in smb_init */
1193 if (tcon->ses->server == NULL)
1194 return -ECONNABORTED;
1195
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001196 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 pSMB->Fid = netfid;
1198 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001199 if(wct == 14)
1200 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1201 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1202 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 pSMB->Reserved = 0xFFFFFFFF;
1204 pSMB->WriteMode = 0;
1205 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001206
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 pSMB->DataOffset =
1208 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1209
Steve French3e844692005-10-03 13:37:24 -07001210 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1211 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001212 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001213 if(wct == 14)
1214 pSMB->hdr.smb_buf_length += count+1;
1215 else /* wct == 12 */
1216 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1217 if(wct == 14)
1218 pSMB->ByteCount = cpu_to_le16(count + 1);
1219 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1220 struct smb_com_writex_req * pSMBW =
1221 (struct smb_com_writex_req *)pSMB;
1222 pSMBW->ByteCount = cpu_to_le16(count + 5);
1223 }
Steve French3e844692005-10-03 13:37:24 -07001224 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001225 if(wct == 14)
1226 iov[0].iov_len = smb_hdr_len + 4;
1227 else /* wct == 12 pad bigger by four bytes */
1228 iov[0].iov_len = smb_hdr_len + 8;
1229
Steve French3e844692005-10-03 13:37:24 -07001230
Steve Frenchec637e32005-12-12 20:53:18 -08001231 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001232 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001233 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001235 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001237 } else if(resp_buf_type == 0) {
1238 /* presumably this can not happen, but best to be safe */
1239 rc = -EIO;
1240 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001241 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001242 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001243 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1244 *nbytes = (*nbytes) << 16;
1245 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001246 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247
1248 cifs_small_buf_release(pSMB);
Steve Frenchec637e32005-12-12 20:53:18 -08001249 if(resp_buf_type == CIFS_SMALL_BUFFER)
1250 cifs_small_buf_release(iov[0].iov_base);
1251 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1252 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
1254 /* Note: On -EAGAIN error only caller can retry on handle based calls
1255 since file handle passed in no longer valid */
1256
1257 return rc;
1258}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001259
1260
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261int
1262CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1263 const __u16 smb_file_id, const __u64 len,
1264 const __u64 offset, const __u32 numUnlock,
1265 const __u32 numLock, const __u8 lockType, const int waitFlag)
1266{
1267 int rc = 0;
1268 LOCK_REQ *pSMB = NULL;
1269 LOCK_RSP *pSMBr = NULL;
1270 int bytes_returned;
1271 int timeout = 0;
1272 __u16 count;
1273
1274 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001275 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1276
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 if (rc)
1278 return rc;
1279
Steve French46810cb2005-04-28 22:41:09 -07001280 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1281
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1283 timeout = -1; /* no response expected */
1284 pSMB->Timeout = 0;
1285 } else if (waitFlag == TRUE) {
1286 timeout = 3; /* blocking operation, no timeout */
1287 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1288 } else {
1289 pSMB->Timeout = 0;
1290 }
1291
1292 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1293 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1294 pSMB->LockType = lockType;
1295 pSMB->AndXCommand = 0xFF; /* none */
1296 pSMB->Fid = smb_file_id; /* netfid stays le */
1297
1298 if((numLock != 0) || (numUnlock != 0)) {
1299 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1300 /* BB where to store pid high? */
1301 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1302 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1303 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1304 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1305 count = sizeof(LOCKING_ANDX_RANGE);
1306 } else {
1307 /* oplock break */
1308 count = 0;
1309 }
1310 pSMB->hdr.smb_buf_length += count;
1311 pSMB->ByteCount = cpu_to_le16(count);
1312
1313 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1314 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha4544342005-08-24 13:59:35 -07001315 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 if (rc) {
1317 cFYI(1, ("Send error in Lock = %d", rc));
1318 }
Steve French46810cb2005-04-28 22:41:09 -07001319 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320
1321 /* Note: On -EAGAIN error only caller can retry on handle based calls
1322 since file handle passed in no longer valid */
1323 return rc;
1324}
1325
1326int
1327CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1328{
1329 int rc = 0;
1330 CLOSE_REQ *pSMB = NULL;
1331 CLOSE_RSP *pSMBr = NULL;
1332 int bytes_returned;
1333 cFYI(1, ("In CIFSSMBClose"));
1334
1335/* do not retry on dead session on close */
1336 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1337 if(rc == -EAGAIN)
1338 return 0;
1339 if (rc)
1340 return rc;
1341
1342 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1343
1344 pSMB->FileID = (__u16) smb_file_id;
1345 pSMB->LastWriteTime = 0;
1346 pSMB->ByteCount = 0;
1347 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1348 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001349 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 if (rc) {
1351 if(rc!=-EINTR) {
1352 /* EINTR is expected when user ctl-c to kill app */
1353 cERROR(1, ("Send error in Close = %d", rc));
1354 }
1355 }
1356
1357 cifs_small_buf_release(pSMB);
1358
1359 /* Since session is dead, file will be closed on server already */
1360 if(rc == -EAGAIN)
1361 rc = 0;
1362
1363 return rc;
1364}
1365
1366int
1367CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1368 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001369 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370{
1371 int rc = 0;
1372 RENAME_REQ *pSMB = NULL;
1373 RENAME_RSP *pSMBr = NULL;
1374 int bytes_returned;
1375 int name_len, name_len2;
1376 __u16 count;
1377
1378 cFYI(1, ("In CIFSSMBRename"));
1379renameRetry:
1380 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1381 (void **) &pSMBr);
1382 if (rc)
1383 return rc;
1384
1385 pSMB->BufferFormat = 0x04;
1386 pSMB->SearchAttributes =
1387 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1388 ATTR_DIRECTORY);
1389
1390 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1391 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001392 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001393 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 name_len++; /* trailing null */
1395 name_len *= 2;
1396 pSMB->OldFileName[name_len] = 0x04; /* pad */
1397 /* protocol requires ASCII signature byte on Unicode string */
1398 pSMB->OldFileName[name_len + 1] = 0x00;
1399 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001400 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001401 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001402 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1403 name_len2 *= 2; /* convert to bytes */
1404 } else { /* BB improve the check for buffer overruns BB */
1405 name_len = strnlen(fromName, PATH_MAX);
1406 name_len++; /* trailing null */
1407 strncpy(pSMB->OldFileName, fromName, name_len);
1408 name_len2 = strnlen(toName, PATH_MAX);
1409 name_len2++; /* trailing null */
1410 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1411 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1412 name_len2++; /* trailing null */
1413 name_len2++; /* signature byte */
1414 }
1415
1416 count = 1 /* 1st signature byte */ + name_len + name_len2;
1417 pSMB->hdr.smb_buf_length += count;
1418 pSMB->ByteCount = cpu_to_le16(count);
1419
1420 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1421 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001422 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 if (rc) {
1424 cFYI(1, ("Send error in rename = %d", rc));
1425 }
1426
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 cifs_buf_release(pSMB);
1428
1429 if (rc == -EAGAIN)
1430 goto renameRetry;
1431
1432 return rc;
1433}
1434
1435int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001436 int netfid, char * target_name,
1437 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438{
1439 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1440 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1441 struct set_file_rename * rename_info;
1442 char *data_offset;
1443 char dummy_string[30];
1444 int rc = 0;
1445 int bytes_returned = 0;
1446 int len_of_str;
1447 __u16 params, param_offset, offset, count, byte_count;
1448
1449 cFYI(1, ("Rename to File by handle"));
1450 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1451 (void **) &pSMBr);
1452 if (rc)
1453 return rc;
1454
1455 params = 6;
1456 pSMB->MaxSetupCount = 0;
1457 pSMB->Reserved = 0;
1458 pSMB->Flags = 0;
1459 pSMB->Timeout = 0;
1460 pSMB->Reserved2 = 0;
1461 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1462 offset = param_offset + params;
1463
1464 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1465 rename_info = (struct set_file_rename *) data_offset;
1466 pSMB->MaxParameterCount = cpu_to_le16(2);
1467 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1468 pSMB->SetupCount = 1;
1469 pSMB->Reserved3 = 0;
1470 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1471 byte_count = 3 /* pad */ + params;
1472 pSMB->ParameterCount = cpu_to_le16(params);
1473 pSMB->TotalParameterCount = pSMB->ParameterCount;
1474 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1475 pSMB->DataOffset = cpu_to_le16(offset);
1476 /* construct random name ".cifs_tmp<inodenum><mid>" */
1477 rename_info->overwrite = cpu_to_le32(1);
1478 rename_info->root_fid = 0;
1479 /* unicode only call */
1480 if(target_name == NULL) {
1481 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001482 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001483 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001485 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001486 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 }
1488 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1489 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1490 byte_count += count;
1491 pSMB->DataCount = cpu_to_le16(count);
1492 pSMB->TotalDataCount = pSMB->DataCount;
1493 pSMB->Fid = netfid;
1494 pSMB->InformationLevel =
1495 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1496 pSMB->Reserved4 = 0;
1497 pSMB->hdr.smb_buf_length += byte_count;
1498 pSMB->ByteCount = cpu_to_le16(byte_count);
1499 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1500 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001501 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 if (rc) {
1503 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1504 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001505
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 cifs_buf_release(pSMB);
1507
1508 /* Note: On -EAGAIN error only caller can retry on handle based calls
1509 since file handle passed in no longer valid */
1510
1511 return rc;
1512}
1513
1514int
1515CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1516 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001517 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518{
1519 int rc = 0;
1520 COPY_REQ *pSMB = NULL;
1521 COPY_RSP *pSMBr = NULL;
1522 int bytes_returned;
1523 int name_len, name_len2;
1524 __u16 count;
1525
1526 cFYI(1, ("In CIFSSMBCopy"));
1527copyRetry:
1528 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1529 (void **) &pSMBr);
1530 if (rc)
1531 return rc;
1532
1533 pSMB->BufferFormat = 0x04;
1534 pSMB->Tid2 = target_tid;
1535
1536 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1537
1538 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001539 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001540 fromName, PATH_MAX, nls_codepage,
1541 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 name_len++; /* trailing null */
1543 name_len *= 2;
1544 pSMB->OldFileName[name_len] = 0x04; /* pad */
1545 /* protocol requires ASCII signature byte on Unicode string */
1546 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001547 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001548 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1550 name_len2 *= 2; /* convert to bytes */
1551 } else { /* BB improve the check for buffer overruns BB */
1552 name_len = strnlen(fromName, PATH_MAX);
1553 name_len++; /* trailing null */
1554 strncpy(pSMB->OldFileName, fromName, name_len);
1555 name_len2 = strnlen(toName, PATH_MAX);
1556 name_len2++; /* trailing null */
1557 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1558 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1559 name_len2++; /* trailing null */
1560 name_len2++; /* signature byte */
1561 }
1562
1563 count = 1 /* 1st signature byte */ + name_len + name_len2;
1564 pSMB->hdr.smb_buf_length += count;
1565 pSMB->ByteCount = cpu_to_le16(count);
1566
1567 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1568 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1569 if (rc) {
1570 cFYI(1, ("Send error in copy = %d with %d files copied",
1571 rc, le16_to_cpu(pSMBr->CopyCount)));
1572 }
1573 if (pSMB)
1574 cifs_buf_release(pSMB);
1575
1576 if (rc == -EAGAIN)
1577 goto copyRetry;
1578
1579 return rc;
1580}
1581
1582int
1583CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1584 const char *fromName, const char *toName,
1585 const struct nls_table *nls_codepage)
1586{
1587 TRANSACTION2_SPI_REQ *pSMB = NULL;
1588 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1589 char *data_offset;
1590 int name_len;
1591 int name_len_target;
1592 int rc = 0;
1593 int bytes_returned = 0;
1594 __u16 params, param_offset, offset, byte_count;
1595
1596 cFYI(1, ("In Symlink Unix style"));
1597createSymLinkRetry:
1598 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1599 (void **) &pSMBr);
1600 if (rc)
1601 return rc;
1602
1603 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1604 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001605 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 /* find define for this maxpathcomponent */
1607 , nls_codepage);
1608 name_len++; /* trailing null */
1609 name_len *= 2;
1610
1611 } else { /* BB improve the check for buffer overruns BB */
1612 name_len = strnlen(fromName, PATH_MAX);
1613 name_len++; /* trailing null */
1614 strncpy(pSMB->FileName, fromName, name_len);
1615 }
1616 params = 6 + name_len;
1617 pSMB->MaxSetupCount = 0;
1618 pSMB->Reserved = 0;
1619 pSMB->Flags = 0;
1620 pSMB->Timeout = 0;
1621 pSMB->Reserved2 = 0;
1622 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1623 InformationLevel) - 4;
1624 offset = param_offset + params;
1625
1626 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1627 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1628 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001629 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 /* find define for this maxpathcomponent */
1631 , nls_codepage);
1632 name_len_target++; /* trailing null */
1633 name_len_target *= 2;
1634 } else { /* BB improve the check for buffer overruns BB */
1635 name_len_target = strnlen(toName, PATH_MAX);
1636 name_len_target++; /* trailing null */
1637 strncpy(data_offset, toName, name_len_target);
1638 }
1639
1640 pSMB->MaxParameterCount = cpu_to_le16(2);
1641 /* BB find exact max on data count below from sess */
1642 pSMB->MaxDataCount = cpu_to_le16(1000);
1643 pSMB->SetupCount = 1;
1644 pSMB->Reserved3 = 0;
1645 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1646 byte_count = 3 /* pad */ + params + name_len_target;
1647 pSMB->DataCount = cpu_to_le16(name_len_target);
1648 pSMB->ParameterCount = cpu_to_le16(params);
1649 pSMB->TotalDataCount = pSMB->DataCount;
1650 pSMB->TotalParameterCount = pSMB->ParameterCount;
1651 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1652 pSMB->DataOffset = cpu_to_le16(offset);
1653 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1654 pSMB->Reserved4 = 0;
1655 pSMB->hdr.smb_buf_length += byte_count;
1656 pSMB->ByteCount = cpu_to_le16(byte_count);
1657 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1658 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001659 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 if (rc) {
1661 cFYI(1,
1662 ("Send error in SetPathInfo (create symlink) = %d",
1663 rc));
1664 }
1665
1666 if (pSMB)
1667 cifs_buf_release(pSMB);
1668
1669 if (rc == -EAGAIN)
1670 goto createSymLinkRetry;
1671
1672 return rc;
1673}
1674
1675int
1676CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1677 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001678 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679{
1680 TRANSACTION2_SPI_REQ *pSMB = NULL;
1681 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1682 char *data_offset;
1683 int name_len;
1684 int name_len_target;
1685 int rc = 0;
1686 int bytes_returned = 0;
1687 __u16 params, param_offset, offset, byte_count;
1688
1689 cFYI(1, ("In Create Hard link Unix style"));
1690createHardLinkRetry:
1691 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1692 (void **) &pSMBr);
1693 if (rc)
1694 return rc;
1695
1696 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001697 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001698 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 name_len++; /* trailing null */
1700 name_len *= 2;
1701
1702 } else { /* BB improve the check for buffer overruns BB */
1703 name_len = strnlen(toName, PATH_MAX);
1704 name_len++; /* trailing null */
1705 strncpy(pSMB->FileName, toName, name_len);
1706 }
1707 params = 6 + name_len;
1708 pSMB->MaxSetupCount = 0;
1709 pSMB->Reserved = 0;
1710 pSMB->Flags = 0;
1711 pSMB->Timeout = 0;
1712 pSMB->Reserved2 = 0;
1713 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1714 InformationLevel) - 4;
1715 offset = param_offset + params;
1716
1717 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1718 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1719 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001720 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001721 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722 name_len_target++; /* trailing null */
1723 name_len_target *= 2;
1724 } else { /* BB improve the check for buffer overruns BB */
1725 name_len_target = strnlen(fromName, PATH_MAX);
1726 name_len_target++; /* trailing null */
1727 strncpy(data_offset, fromName, name_len_target);
1728 }
1729
1730 pSMB->MaxParameterCount = cpu_to_le16(2);
1731 /* BB find exact max on data count below from sess*/
1732 pSMB->MaxDataCount = cpu_to_le16(1000);
1733 pSMB->SetupCount = 1;
1734 pSMB->Reserved3 = 0;
1735 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1736 byte_count = 3 /* pad */ + params + name_len_target;
1737 pSMB->ParameterCount = cpu_to_le16(params);
1738 pSMB->TotalParameterCount = pSMB->ParameterCount;
1739 pSMB->DataCount = cpu_to_le16(name_len_target);
1740 pSMB->TotalDataCount = pSMB->DataCount;
1741 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1742 pSMB->DataOffset = cpu_to_le16(offset);
1743 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1744 pSMB->Reserved4 = 0;
1745 pSMB->hdr.smb_buf_length += byte_count;
1746 pSMB->ByteCount = cpu_to_le16(byte_count);
1747 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1748 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001749 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 if (rc) {
1751 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1752 }
1753
1754 cifs_buf_release(pSMB);
1755 if (rc == -EAGAIN)
1756 goto createHardLinkRetry;
1757
1758 return rc;
1759}
1760
1761int
1762CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1763 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001764 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765{
1766 int rc = 0;
1767 NT_RENAME_REQ *pSMB = NULL;
1768 RENAME_RSP *pSMBr = NULL;
1769 int bytes_returned;
1770 int name_len, name_len2;
1771 __u16 count;
1772
1773 cFYI(1, ("In CIFSCreateHardLink"));
1774winCreateHardLinkRetry:
1775
1776 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1777 (void **) &pSMBr);
1778 if (rc)
1779 return rc;
1780
1781 pSMB->SearchAttributes =
1782 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1783 ATTR_DIRECTORY);
1784 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1785 pSMB->ClusterCount = 0;
1786
1787 pSMB->BufferFormat = 0x04;
1788
1789 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1790 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001791 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001792 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 name_len++; /* trailing null */
1794 name_len *= 2;
1795 pSMB->OldFileName[name_len] = 0; /* pad */
1796 pSMB->OldFileName[name_len + 1] = 0x04;
1797 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001798 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001799 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1801 name_len2 *= 2; /* convert to bytes */
1802 } else { /* BB improve the check for buffer overruns BB */
1803 name_len = strnlen(fromName, PATH_MAX);
1804 name_len++; /* trailing null */
1805 strncpy(pSMB->OldFileName, fromName, name_len);
1806 name_len2 = strnlen(toName, PATH_MAX);
1807 name_len2++; /* trailing null */
1808 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1809 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1810 name_len2++; /* trailing null */
1811 name_len2++; /* signature byte */
1812 }
1813
1814 count = 1 /* string type byte */ + name_len + name_len2;
1815 pSMB->hdr.smb_buf_length += count;
1816 pSMB->ByteCount = cpu_to_le16(count);
1817
1818 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1819 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001820 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 if (rc) {
1822 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1823 }
1824 cifs_buf_release(pSMB);
1825 if (rc == -EAGAIN)
1826 goto winCreateHardLinkRetry;
1827
1828 return rc;
1829}
1830
1831int
1832CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1833 const unsigned char *searchName,
1834 char *symlinkinfo, const int buflen,
1835 const struct nls_table *nls_codepage)
1836{
1837/* SMB_QUERY_FILE_UNIX_LINK */
1838 TRANSACTION2_QPI_REQ *pSMB = NULL;
1839 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1840 int rc = 0;
1841 int bytes_returned;
1842 int name_len;
1843 __u16 params, byte_count;
1844
1845 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1846
1847querySymLinkRetry:
1848 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1849 (void **) &pSMBr);
1850 if (rc)
1851 return rc;
1852
1853 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1854 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001855 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 /* find define for this maxpathcomponent */
1857 , nls_codepage);
1858 name_len++; /* trailing null */
1859 name_len *= 2;
1860 } else { /* BB improve the check for buffer overruns BB */
1861 name_len = strnlen(searchName, PATH_MAX);
1862 name_len++; /* trailing null */
1863 strncpy(pSMB->FileName, searchName, name_len);
1864 }
1865
1866 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1867 pSMB->TotalDataCount = 0;
1868 pSMB->MaxParameterCount = cpu_to_le16(2);
1869 /* BB find exact max data count below from sess structure BB */
1870 pSMB->MaxDataCount = cpu_to_le16(4000);
1871 pSMB->MaxSetupCount = 0;
1872 pSMB->Reserved = 0;
1873 pSMB->Flags = 0;
1874 pSMB->Timeout = 0;
1875 pSMB->Reserved2 = 0;
1876 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1877 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1878 pSMB->DataCount = 0;
1879 pSMB->DataOffset = 0;
1880 pSMB->SetupCount = 1;
1881 pSMB->Reserved3 = 0;
1882 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1883 byte_count = params + 1 /* pad */ ;
1884 pSMB->TotalParameterCount = cpu_to_le16(params);
1885 pSMB->ParameterCount = pSMB->TotalParameterCount;
1886 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1887 pSMB->Reserved4 = 0;
1888 pSMB->hdr.smb_buf_length += byte_count;
1889 pSMB->ByteCount = cpu_to_le16(byte_count);
1890
1891 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1892 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1893 if (rc) {
1894 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1895 } else {
1896 /* decode response */
1897
1898 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1899 if (rc || (pSMBr->ByteCount < 2))
1900 /* BB also check enough total bytes returned */
1901 rc = -EIO; /* bad smb */
1902 else {
1903 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1904 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1905
1906 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1907 name_len = UniStrnlen((wchar_t *) ((char *)
1908 &pSMBr->hdr.Protocol +data_offset),
1909 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07001910 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08001912 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 data_offset),
1914 name_len, nls_codepage);
1915 } else {
1916 strncpy(symlinkinfo,
1917 (char *) &pSMBr->hdr.Protocol +
1918 data_offset,
1919 min_t(const int, buflen, count));
1920 }
1921 symlinkinfo[buflen] = 0;
1922 /* just in case so calling code does not go off the end of buffer */
1923 }
1924 }
1925 cifs_buf_release(pSMB);
1926 if (rc == -EAGAIN)
1927 goto querySymLinkRetry;
1928 return rc;
1929}
1930
Steve French0a4b92c2006-01-12 15:44:21 -08001931/* Initialize NT TRANSACT SMB into small smb request buffer.
1932 This assumes that all NT TRANSACTS that we init here have
1933 total parm and data under about 400 bytes (to fit in small cifs
1934 buffer size), which is the case so far, it easily fits. NB:
1935 Setup words themselves and ByteCount
1936 MaxSetupCount (size of returned setup area) and
1937 MaxParameterCount (returned parms size) must be set by caller */
1938static int
1939smb_init_ntransact(const __u16 sub_command, const int setup_count,
1940 const int parm_len, struct cifsTconInfo *tcon,
1941 void ** ret_buf)
1942{
1943 int rc;
1944 __u32 temp_offset;
1945 struct smb_com_ntransact_req * pSMB;
1946
1947 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
1948 (void **)&pSMB);
1949 if (rc)
1950 return rc;
1951 *ret_buf = (void *)pSMB;
1952 pSMB->Reserved = 0;
1953 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
1954 pSMB->TotalDataCount = 0;
1955 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
1956 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
1957 pSMB->ParameterCount = pSMB->TotalParameterCount;
1958 pSMB->DataCount = pSMB->TotalDataCount;
1959 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
1960 (setup_count * 2) - 4 /* for rfc1001 length itself */;
1961 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
1962 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
1963 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
1964 pSMB->SubCommand = cpu_to_le16(sub_command);
1965 return 0;
1966}
1967
1968static int
1969validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
1970 int * pdatalen, int * pparmlen)
1971{
1972 char * end_of_smb;
1973 __u32 data_count, data_offset, parm_count, parm_offset;
1974 struct smb_com_ntransact_rsp * pSMBr;
1975
1976 if(buf == NULL)
1977 return -EINVAL;
1978
1979 pSMBr = (struct smb_com_ntransact_rsp *)buf;
1980
1981 /* ByteCount was converted from little endian in SendReceive */
1982 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
1983 (char *)&pSMBr->ByteCount;
1984
1985
1986 data_offset = le32_to_cpu(pSMBr->DataOffset);
1987 data_count = le32_to_cpu(pSMBr->DataCount);
1988 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
1989 parm_count = le32_to_cpu(pSMBr->ParameterCount);
1990
1991 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
1992 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
1993
1994 /* should we also check that parm and data areas do not overlap? */
1995 if(*ppparm > end_of_smb) {
1996 cFYI(1,("parms start after end of smb"));
1997 return -EINVAL;
1998 } else if(parm_count + *ppparm > end_of_smb) {
1999 cFYI(1,("parm end after end of smb"));
2000 return -EINVAL;
2001 } else if(*ppdata > end_of_smb) {
2002 cFYI(1,("data starts after end of smb"));
2003 return -EINVAL;
2004 } else if(data_count + *ppdata > end_of_smb) {
2005 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2006 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2007 return -EINVAL;
2008 } else if(parm_count + data_count > pSMBr->ByteCount) {
2009 cFYI(1,("parm count and data count larger than SMB"));
2010 return -EINVAL;
2011 }
2012 return 0;
2013}
2014
Linus Torvalds1da177e2005-04-16 15:20:36 -07002015int
2016CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2017 const unsigned char *searchName,
2018 char *symlinkinfo, const int buflen,__u16 fid,
2019 const struct nls_table *nls_codepage)
2020{
2021 int rc = 0;
2022 int bytes_returned;
2023 int name_len;
2024 struct smb_com_transaction_ioctl_req * pSMB;
2025 struct smb_com_transaction_ioctl_rsp * pSMBr;
2026
2027 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2028 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2029 (void **) &pSMBr);
2030 if (rc)
2031 return rc;
2032
2033 pSMB->TotalParameterCount = 0 ;
2034 pSMB->TotalDataCount = 0;
2035 pSMB->MaxParameterCount = cpu_to_le32(2);
2036 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002037 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2038 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002039 pSMB->MaxSetupCount = 4;
2040 pSMB->Reserved = 0;
2041 pSMB->ParameterOffset = 0;
2042 pSMB->DataCount = 0;
2043 pSMB->DataOffset = 0;
2044 pSMB->SetupCount = 4;
2045 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2046 pSMB->ParameterCount = pSMB->TotalParameterCount;
2047 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2048 pSMB->IsFsctl = 1; /* FSCTL */
2049 pSMB->IsRootFlag = 0;
2050 pSMB->Fid = fid; /* file handle always le */
2051 pSMB->ByteCount = 0;
2052
2053 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2054 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2055 if (rc) {
2056 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2057 } else { /* decode response */
2058 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2059 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2060 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2061 /* BB also check enough total bytes returned */
2062 rc = -EIO; /* bad smb */
2063 else {
2064 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002065 char * end_of_smb = 2 /* sizeof byte count */ +
2066 pSMBr->ByteCount +
2067 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068
2069 struct reparse_data * reparse_buf = (struct reparse_data *)
2070 ((char *)&pSMBr->hdr.Protocol + data_offset);
2071 if((char*)reparse_buf >= end_of_smb) {
2072 rc = -EIO;
2073 goto qreparse_out;
2074 }
2075 if((reparse_buf->LinkNamesBuf +
2076 reparse_buf->TargetNameOffset +
2077 reparse_buf->TargetNameLen) >
2078 end_of_smb) {
2079 cFYI(1,("reparse buf extended beyond SMB"));
2080 rc = -EIO;
2081 goto qreparse_out;
2082 }
2083
2084 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2085 name_len = UniStrnlen((wchar_t *)
2086 (reparse_buf->LinkNamesBuf +
2087 reparse_buf->TargetNameOffset),
2088 min(buflen/2, reparse_buf->TargetNameLen / 2));
2089 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002090 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 reparse_buf->TargetNameOffset),
2092 name_len, nls_codepage);
2093 } else { /* ASCII names */
2094 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2095 reparse_buf->TargetNameOffset,
2096 min_t(const int, buflen, reparse_buf->TargetNameLen));
2097 }
2098 } else {
2099 rc = -EIO;
2100 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2101 }
2102 symlinkinfo[buflen] = 0; /* just in case so the caller
2103 does not go off the end of the buffer */
2104 cFYI(1,("readlink result - %s ",symlinkinfo));
2105 }
2106 }
2107qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002108 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109
2110 /* Note: On -EAGAIN error only caller can retry on handle based calls
2111 since file handle passed in no longer valid */
2112
2113 return rc;
2114}
2115
2116#ifdef CONFIG_CIFS_POSIX
2117
2118/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2119static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2120{
2121 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002122 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2123 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2124 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2126
2127 return;
2128}
2129
2130/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002131static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2132 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002133{
2134 int size = 0;
2135 int i;
2136 __u16 count;
2137 struct cifs_posix_ace * pACE;
2138 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2139 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2140
2141 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2142 return -EOPNOTSUPP;
2143
2144 if(acl_type & ACL_TYPE_ACCESS) {
2145 count = le16_to_cpu(cifs_acl->access_entry_count);
2146 pACE = &cifs_acl->ace_array[0];
2147 size = sizeof(struct cifs_posix_acl);
2148 size += sizeof(struct cifs_posix_ace) * count;
2149 /* check if we would go beyond end of SMB */
2150 if(size_of_data_area < size) {
2151 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2152 return -EINVAL;
2153 }
2154 } else if(acl_type & ACL_TYPE_DEFAULT) {
2155 count = le16_to_cpu(cifs_acl->access_entry_count);
2156 size = sizeof(struct cifs_posix_acl);
2157 size += sizeof(struct cifs_posix_ace) * count;
2158/* skip past access ACEs to get to default ACEs */
2159 pACE = &cifs_acl->ace_array[count];
2160 count = le16_to_cpu(cifs_acl->default_entry_count);
2161 size += sizeof(struct cifs_posix_ace) * count;
2162 /* check if we would go beyond end of SMB */
2163 if(size_of_data_area < size)
2164 return -EINVAL;
2165 } else {
2166 /* illegal type */
2167 return -EINVAL;
2168 }
2169
2170 size = posix_acl_xattr_size(count);
2171 if((buflen == 0) || (local_acl == NULL)) {
2172 /* used to query ACL EA size */
2173 } else if(size > buflen) {
2174 return -ERANGE;
2175 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002176 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 for(i = 0;i < count ;i++) {
2178 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2179 pACE ++;
2180 }
2181 }
2182 return size;
2183}
2184
2185static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2186 const posix_acl_xattr_entry * local_ace)
2187{
2188 __u16 rc = 0; /* 0 = ACL converted ok */
2189
Steve Frenchff7feac2005-11-15 16:45:16 -08002190 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2191 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002193 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 /* Probably no need to le convert -1 on any arch but can not hurt */
2195 cifs_ace->cifs_uid = cpu_to_le64(-1);
2196 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002197 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2199 return rc;
2200}
2201
2202/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2203static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2204 const int acl_type)
2205{
2206 __u16 rc = 0;
2207 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2208 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2209 int count;
2210 int i;
2211
2212 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2213 return 0;
2214
2215 count = posix_acl_xattr_count((size_t)buflen);
2216 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002217 count, buflen, le32_to_cpu(local_acl->a_version)));
2218 if(le32_to_cpu(local_acl->a_version) != 2) {
2219 cFYI(1,("unknown POSIX ACL version %d",
2220 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 return 0;
2222 }
2223 cifs_acl->version = cpu_to_le16(1);
2224 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002225 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002227 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 else {
2229 cFYI(1,("unknown ACL type %d",acl_type));
2230 return 0;
2231 }
2232 for(i=0;i<count;i++) {
2233 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2234 &local_acl->a_entries[i]);
2235 if(rc != 0) {
2236 /* ACE not converted */
2237 break;
2238 }
2239 }
2240 if(rc == 0) {
2241 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2242 rc += sizeof(struct cifs_posix_acl);
2243 /* BB add check to make sure ACL does not overflow SMB */
2244 }
2245 return rc;
2246}
2247
2248int
2249CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2250 const unsigned char *searchName,
2251 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002252 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253{
2254/* SMB_QUERY_POSIX_ACL */
2255 TRANSACTION2_QPI_REQ *pSMB = NULL;
2256 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2257 int rc = 0;
2258 int bytes_returned;
2259 int name_len;
2260 __u16 params, byte_count;
2261
2262 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2263
2264queryAclRetry:
2265 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2266 (void **) &pSMBr);
2267 if (rc)
2268 return rc;
2269
2270 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2271 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002272 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002273 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 name_len++; /* trailing null */
2275 name_len *= 2;
2276 pSMB->FileName[name_len] = 0;
2277 pSMB->FileName[name_len+1] = 0;
2278 } else { /* BB improve the check for buffer overruns BB */
2279 name_len = strnlen(searchName, PATH_MAX);
2280 name_len++; /* trailing null */
2281 strncpy(pSMB->FileName, searchName, name_len);
2282 }
2283
2284 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2285 pSMB->TotalDataCount = 0;
2286 pSMB->MaxParameterCount = cpu_to_le16(2);
2287 /* BB find exact max data count below from sess structure BB */
2288 pSMB->MaxDataCount = cpu_to_le16(4000);
2289 pSMB->MaxSetupCount = 0;
2290 pSMB->Reserved = 0;
2291 pSMB->Flags = 0;
2292 pSMB->Timeout = 0;
2293 pSMB->Reserved2 = 0;
2294 pSMB->ParameterOffset = cpu_to_le16(
2295 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2296 pSMB->DataCount = 0;
2297 pSMB->DataOffset = 0;
2298 pSMB->SetupCount = 1;
2299 pSMB->Reserved3 = 0;
2300 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2301 byte_count = params + 1 /* pad */ ;
2302 pSMB->TotalParameterCount = cpu_to_le16(params);
2303 pSMB->ParameterCount = pSMB->TotalParameterCount;
2304 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2305 pSMB->Reserved4 = 0;
2306 pSMB->hdr.smb_buf_length += byte_count;
2307 pSMB->ByteCount = cpu_to_le16(byte_count);
2308
2309 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2310 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002311 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 if (rc) {
2313 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2314 } else {
2315 /* decode response */
2316
2317 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2318 if (rc || (pSMBr->ByteCount < 2))
2319 /* BB also check enough total bytes returned */
2320 rc = -EIO; /* bad smb */
2321 else {
2322 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2323 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2324 rc = cifs_copy_posix_acl(acl_inf,
2325 (char *)&pSMBr->hdr.Protocol+data_offset,
2326 buflen,acl_type,count);
2327 }
2328 }
2329 cifs_buf_release(pSMB);
2330 if (rc == -EAGAIN)
2331 goto queryAclRetry;
2332 return rc;
2333}
2334
2335int
2336CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2337 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002338 const char *local_acl, const int buflen,
2339 const int acl_type,
2340 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341{
2342 struct smb_com_transaction2_spi_req *pSMB = NULL;
2343 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2344 char *parm_data;
2345 int name_len;
2346 int rc = 0;
2347 int bytes_returned = 0;
2348 __u16 params, byte_count, data_count, param_offset, offset;
2349
2350 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2351setAclRetry:
2352 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2353 (void **) &pSMBr);
2354 if (rc)
2355 return rc;
2356 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2357 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002358 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002359 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 name_len++; /* trailing null */
2361 name_len *= 2;
2362 } else { /* BB improve the check for buffer overruns BB */
2363 name_len = strnlen(fileName, PATH_MAX);
2364 name_len++; /* trailing null */
2365 strncpy(pSMB->FileName, fileName, name_len);
2366 }
2367 params = 6 + name_len;
2368 pSMB->MaxParameterCount = cpu_to_le16(2);
2369 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2370 pSMB->MaxSetupCount = 0;
2371 pSMB->Reserved = 0;
2372 pSMB->Flags = 0;
2373 pSMB->Timeout = 0;
2374 pSMB->Reserved2 = 0;
2375 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2376 InformationLevel) - 4;
2377 offset = param_offset + params;
2378 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2379 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2380
2381 /* convert to on the wire format for POSIX ACL */
2382 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2383
2384 if(data_count == 0) {
2385 rc = -EOPNOTSUPP;
2386 goto setACLerrorExit;
2387 }
2388 pSMB->DataOffset = cpu_to_le16(offset);
2389 pSMB->SetupCount = 1;
2390 pSMB->Reserved3 = 0;
2391 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2392 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2393 byte_count = 3 /* pad */ + params + data_count;
2394 pSMB->DataCount = cpu_to_le16(data_count);
2395 pSMB->TotalDataCount = pSMB->DataCount;
2396 pSMB->ParameterCount = cpu_to_le16(params);
2397 pSMB->TotalParameterCount = pSMB->ParameterCount;
2398 pSMB->Reserved4 = 0;
2399 pSMB->hdr.smb_buf_length += byte_count;
2400 pSMB->ByteCount = cpu_to_le16(byte_count);
2401 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2402 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2403 if (rc) {
2404 cFYI(1, ("Set POSIX ACL returned %d", rc));
2405 }
2406
2407setACLerrorExit:
2408 cifs_buf_release(pSMB);
2409 if (rc == -EAGAIN)
2410 goto setAclRetry;
2411 return rc;
2412}
2413
Steve Frenchf654bac2005-04-28 22:41:04 -07002414/* BB fix tabs in this function FIXME BB */
2415int
2416CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2417 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2418{
2419 int rc = 0;
2420 struct smb_t2_qfi_req *pSMB = NULL;
2421 struct smb_t2_qfi_rsp *pSMBr = NULL;
2422 int bytes_returned;
2423 __u16 params, byte_count;
2424
2425 cFYI(1,("In GetExtAttr"));
2426 if(tcon == NULL)
2427 return -ENODEV;
2428
2429GetExtAttrRetry:
2430 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2431 (void **) &pSMBr);
2432 if (rc)
2433 return rc;
2434
Steve Frenchc67593a2005-04-28 22:41:04 -07002435 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002436 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002437 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002438 /* BB find exact max data count below from sess structure BB */
2439 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2440 pSMB->t2.MaxSetupCount = 0;
2441 pSMB->t2.Reserved = 0;
2442 pSMB->t2.Flags = 0;
2443 pSMB->t2.Timeout = 0;
2444 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002445 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2446 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002447 pSMB->t2.DataCount = 0;
2448 pSMB->t2.DataOffset = 0;
2449 pSMB->t2.SetupCount = 1;
2450 pSMB->t2.Reserved3 = 0;
2451 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002452 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002453 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2454 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2455 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002456 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002457 pSMB->Fid = netfid;
2458 pSMB->hdr.smb_buf_length += byte_count;
2459 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2460
2461 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2462 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2463 if (rc) {
2464 cFYI(1, ("error %d in GetExtAttr", rc));
2465 } else {
2466 /* decode response */
2467 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2468 if (rc || (pSMBr->ByteCount < 2))
2469 /* BB also check enough total bytes returned */
2470 /* If rc should we check for EOPNOSUPP and
2471 disable the srvino flag? or in caller? */
2472 rc = -EIO; /* bad smb */
2473 else {
2474 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2475 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2476 struct file_chattr_info * pfinfo;
2477 /* BB Do we need a cast or hash here ? */
2478 if(count != 16) {
2479 cFYI(1, ("Illegal size ret in GetExtAttr"));
2480 rc = -EIO;
2481 goto GetExtAttrOut;
2482 }
2483 pfinfo = (struct file_chattr_info *)
2484 (data_offset + (char *) &pSMBr->hdr.Protocol);
2485 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2486 *pMask = le64_to_cpu(pfinfo->mask);
2487 }
2488 }
2489GetExtAttrOut:
2490 cifs_buf_release(pSMB);
2491 if (rc == -EAGAIN)
2492 goto GetExtAttrRetry;
2493 return rc;
2494}
2495
2496
2497#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498
Steve Frencheeac8042006-01-13 21:34:58 -08002499
2500/* security id for everyone */
2501const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2502/* group users */
2503const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2504
Steve French0a4b92c2006-01-12 15:44:21 -08002505/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002506static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002507{
Steve French0a4b92c2006-01-12 15:44:21 -08002508 return 0;
2509}
2510
2511/* Get Security Descriptor (by handle) from remote server for a file or dir */
2512int
2513CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2514 /* BB fix up return info */ char *acl_inf, const int buflen,
2515 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2516{
2517 int rc = 0;
2518 int buf_type = 0;
2519 QUERY_SEC_DESC_REQ * pSMB;
2520 struct kvec iov[1];
2521
2522 cFYI(1, ("GetCifsACL"));
2523
2524 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2525 8 /* parm len */, tcon, (void **) &pSMB);
2526 if (rc)
2527 return rc;
2528
2529 pSMB->MaxParameterCount = cpu_to_le32(4);
2530 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2531 pSMB->MaxSetupCount = 0;
2532 pSMB->Fid = fid; /* file handle always le */
2533 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2534 CIFS_ACL_DACL);
2535 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2536 pSMB->hdr.smb_buf_length += 11;
2537 iov[0].iov_base = (char *)pSMB;
2538 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2539
2540 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2541 cifs_stats_inc(&tcon->num_acl_get);
2542 if (rc) {
2543 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2544 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002545 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002546 __le32 * parm;
2547 int parm_len;
2548 int data_len;
2549 int acl_len;
2550 struct smb_com_ntransact_rsp * pSMBr;
2551
2552/* validate_nttransact */
2553 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2554 (char **)&psec_desc,
2555 &parm_len, &data_len);
2556
2557 if(rc)
2558 goto qsec_out;
2559 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2560
2561 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2562
2563 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2564 rc = -EIO; /* bad smb */
2565 goto qsec_out;
2566 }
2567
2568/* BB check that data area is minimum length and as big as acl_len */
2569
2570 acl_len = le32_to_cpu(*(__le32 *)parm);
2571 /* BB check if(acl_len > bufsize) */
2572
2573 parse_sec_desc(psec_desc, acl_len);
2574 }
2575qsec_out:
2576 if(buf_type == CIFS_SMALL_BUFFER)
2577 cifs_small_buf_release(iov[0].iov_base);
2578 else if(buf_type == CIFS_LARGE_BUFFER)
2579 cifs_buf_release(iov[0].iov_base);
2580 cifs_small_buf_release(pSMB);
2581 return rc;
2582}
2583
2584
Steve French6b8edfe2005-08-23 20:26:03 -07002585/* Legacy Query Path Information call for lookup to old servers such
2586 as Win9x/WinME */
2587int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2588 const unsigned char *searchName,
2589 FILE_ALL_INFO * pFinfo,
2590 const struct nls_table *nls_codepage, int remap)
2591{
2592 QUERY_INFORMATION_REQ * pSMB;
2593 QUERY_INFORMATION_RSP * pSMBr;
2594 int rc = 0;
2595 int bytes_returned;
2596 int name_len;
2597
2598 cFYI(1, ("In SMBQPath path %s", searchName));
2599QInfRetry:
2600 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2601 (void **) &pSMBr);
2602 if (rc)
2603 return rc;
2604
2605 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2606 name_len =
2607 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2608 PATH_MAX, nls_codepage, remap);
2609 name_len++; /* trailing null */
2610 name_len *= 2;
2611 } else {
2612 name_len = strnlen(searchName, PATH_MAX);
2613 name_len++; /* trailing null */
2614 strncpy(pSMB->FileName, searchName, name_len);
2615 }
2616 pSMB->BufferFormat = 0x04;
2617 name_len++; /* account for buffer type byte */
2618 pSMB->hdr.smb_buf_length += (__u16) name_len;
2619 pSMB->ByteCount = cpu_to_le16(name_len);
2620
2621 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2622 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2623 if (rc) {
2624 cFYI(1, ("Send error in QueryInfo = %d", rc));
2625 } else if (pFinfo) { /* decode response */
2626 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002627 pFinfo->AllocationSize =
2628 cpu_to_le64(le32_to_cpu(pSMBr->size));
2629 pFinfo->EndOfFile = pFinfo->AllocationSize;
2630 pFinfo->Attributes =
2631 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002632 } else
2633 rc = -EIO; /* bad buffer passed in */
2634
2635 cifs_buf_release(pSMB);
2636
2637 if (rc == -EAGAIN)
2638 goto QInfRetry;
2639
2640 return rc;
2641}
2642
2643
2644
2645
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646int
2647CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2648 const unsigned char *searchName,
2649 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002650 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651{
2652/* level 263 SMB_QUERY_FILE_ALL_INFO */
2653 TRANSACTION2_QPI_REQ *pSMB = NULL;
2654 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2655 int rc = 0;
2656 int bytes_returned;
2657 int name_len;
2658 __u16 params, byte_count;
2659
2660/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2661QPathInfoRetry:
2662 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2663 (void **) &pSMBr);
2664 if (rc)
2665 return rc;
2666
2667 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2668 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002669 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002670 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 name_len++; /* trailing null */
2672 name_len *= 2;
2673 } else { /* BB improve the check for buffer overruns BB */
2674 name_len = strnlen(searchName, PATH_MAX);
2675 name_len++; /* trailing null */
2676 strncpy(pSMB->FileName, searchName, name_len);
2677 }
2678
2679 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2680 pSMB->TotalDataCount = 0;
2681 pSMB->MaxParameterCount = cpu_to_le16(2);
2682 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2683 pSMB->MaxSetupCount = 0;
2684 pSMB->Reserved = 0;
2685 pSMB->Flags = 0;
2686 pSMB->Timeout = 0;
2687 pSMB->Reserved2 = 0;
2688 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2689 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2690 pSMB->DataCount = 0;
2691 pSMB->DataOffset = 0;
2692 pSMB->SetupCount = 1;
2693 pSMB->Reserved3 = 0;
2694 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2695 byte_count = params + 1 /* pad */ ;
2696 pSMB->TotalParameterCount = cpu_to_le16(params);
2697 pSMB->ParameterCount = pSMB->TotalParameterCount;
2698 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2699 pSMB->Reserved4 = 0;
2700 pSMB->hdr.smb_buf_length += byte_count;
2701 pSMB->ByteCount = cpu_to_le16(byte_count);
2702
2703 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2704 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2705 if (rc) {
2706 cFYI(1, ("Send error in QPathInfo = %d", rc));
2707 } else { /* decode response */
2708 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2709
2710 if (rc || (pSMBr->ByteCount < 40))
2711 rc = -EIO; /* bad smb */
2712 else if (pFindData){
2713 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2714 memcpy((char *) pFindData,
2715 (char *) &pSMBr->hdr.Protocol +
2716 data_offset, sizeof (FILE_ALL_INFO));
2717 } else
2718 rc = -ENOMEM;
2719 }
2720 cifs_buf_release(pSMB);
2721 if (rc == -EAGAIN)
2722 goto QPathInfoRetry;
2723
2724 return rc;
2725}
2726
2727int
2728CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2729 const unsigned char *searchName,
2730 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002731 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732{
2733/* SMB_QUERY_FILE_UNIX_BASIC */
2734 TRANSACTION2_QPI_REQ *pSMB = NULL;
2735 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2736 int rc = 0;
2737 int bytes_returned = 0;
2738 int name_len;
2739 __u16 params, byte_count;
2740
2741 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2742UnixQPathInfoRetry:
2743 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2744 (void **) &pSMBr);
2745 if (rc)
2746 return rc;
2747
2748 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2749 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002750 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002751 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 name_len++; /* trailing null */
2753 name_len *= 2;
2754 } else { /* BB improve the check for buffer overruns BB */
2755 name_len = strnlen(searchName, PATH_MAX);
2756 name_len++; /* trailing null */
2757 strncpy(pSMB->FileName, searchName, name_len);
2758 }
2759
2760 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2761 pSMB->TotalDataCount = 0;
2762 pSMB->MaxParameterCount = cpu_to_le16(2);
2763 /* BB find exact max SMB PDU from sess structure BB */
2764 pSMB->MaxDataCount = cpu_to_le16(4000);
2765 pSMB->MaxSetupCount = 0;
2766 pSMB->Reserved = 0;
2767 pSMB->Flags = 0;
2768 pSMB->Timeout = 0;
2769 pSMB->Reserved2 = 0;
2770 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2771 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2772 pSMB->DataCount = 0;
2773 pSMB->DataOffset = 0;
2774 pSMB->SetupCount = 1;
2775 pSMB->Reserved3 = 0;
2776 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2777 byte_count = params + 1 /* pad */ ;
2778 pSMB->TotalParameterCount = cpu_to_le16(params);
2779 pSMB->ParameterCount = pSMB->TotalParameterCount;
2780 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2781 pSMB->Reserved4 = 0;
2782 pSMB->hdr.smb_buf_length += byte_count;
2783 pSMB->ByteCount = cpu_to_le16(byte_count);
2784
2785 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2786 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2787 if (rc) {
2788 cFYI(1, ("Send error in QPathInfo = %d", rc));
2789 } else { /* decode response */
2790 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2791
2792 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2793 rc = -EIO; /* bad smb */
2794 } else {
2795 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2796 memcpy((char *) pFindData,
2797 (char *) &pSMBr->hdr.Protocol +
2798 data_offset,
2799 sizeof (FILE_UNIX_BASIC_INFO));
2800 }
2801 }
2802 cifs_buf_release(pSMB);
2803 if (rc == -EAGAIN)
2804 goto UnixQPathInfoRetry;
2805
2806 return rc;
2807}
2808
2809#if 0 /* function unused at present */
2810int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2811 const char *searchName, FILE_ALL_INFO * findData,
2812 const struct nls_table *nls_codepage)
2813{
2814/* level 257 SMB_ */
2815 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2816 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2817 int rc = 0;
2818 int bytes_returned;
2819 int name_len;
2820 __u16 params, byte_count;
2821
2822 cFYI(1, ("In FindUnique"));
2823findUniqueRetry:
2824 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2825 (void **) &pSMBr);
2826 if (rc)
2827 return rc;
2828
2829 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2830 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002831 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 /* find define for this maxpathcomponent */
2833 , nls_codepage);
2834 name_len++; /* trailing null */
2835 name_len *= 2;
2836 } else { /* BB improve the check for buffer overruns BB */
2837 name_len = strnlen(searchName, PATH_MAX);
2838 name_len++; /* trailing null */
2839 strncpy(pSMB->FileName, searchName, name_len);
2840 }
2841
2842 params = 12 + name_len /* includes null */ ;
2843 pSMB->TotalDataCount = 0; /* no EAs */
2844 pSMB->MaxParameterCount = cpu_to_le16(2);
2845 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2846 pSMB->MaxSetupCount = 0;
2847 pSMB->Reserved = 0;
2848 pSMB->Flags = 0;
2849 pSMB->Timeout = 0;
2850 pSMB->Reserved2 = 0;
2851 pSMB->ParameterOffset = cpu_to_le16(
2852 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2853 pSMB->DataCount = 0;
2854 pSMB->DataOffset = 0;
2855 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2856 pSMB->Reserved3 = 0;
2857 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2858 byte_count = params + 1 /* pad */ ;
2859 pSMB->TotalParameterCount = cpu_to_le16(params);
2860 pSMB->ParameterCount = pSMB->TotalParameterCount;
2861 pSMB->SearchAttributes =
2862 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2863 ATTR_DIRECTORY);
2864 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2865 pSMB->SearchFlags = cpu_to_le16(1);
2866 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2867 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2868 pSMB->hdr.smb_buf_length += byte_count;
2869 pSMB->ByteCount = cpu_to_le16(byte_count);
2870
2871 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2872 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2873
2874 if (rc) {
2875 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2876 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07002877 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 /* BB fill in */
2879 }
2880
2881 cifs_buf_release(pSMB);
2882 if (rc == -EAGAIN)
2883 goto findUniqueRetry;
2884
2885 return rc;
2886}
2887#endif /* end unused (temporarily) function */
2888
2889/* xid, tcon, searchName and codepage are input parms, rest are returned */
2890int
2891CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2892 const char *searchName,
2893 const struct nls_table *nls_codepage,
2894 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07002895 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896{
2897/* level 257 SMB_ */
2898 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2899 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2900 T2_FFIRST_RSP_PARMS * parms;
2901 int rc = 0;
2902 int bytes_returned = 0;
2903 int name_len;
2904 __u16 params, byte_count;
2905
Steve French737b7582005-04-28 22:41:06 -07002906 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907
2908findFirstRetry:
2909 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2910 (void **) &pSMBr);
2911 if (rc)
2912 return rc;
2913
2914 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2915 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002916 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07002917 PATH_MAX, nls_codepage, remap);
2918 /* We can not add the asterik earlier in case
2919 it got remapped to 0xF03A as if it were part of the
2920 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07002922 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07002923 pSMB->FileName[name_len+1] = 0;
2924 pSMB->FileName[name_len+2] = '*';
2925 pSMB->FileName[name_len+3] = 0;
2926 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2928 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07002929 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 } else { /* BB add check for overrun of SMB buf BB */
2931 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002932/* BB fix here and in unicode clause above ie
2933 if(name_len > buffersize-header)
2934 free buffer exit; BB */
2935 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07002936 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07002937 pSMB->FileName[name_len+1] = '*';
2938 pSMB->FileName[name_len+2] = 0;
2939 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 }
2941
2942 params = 12 + name_len /* includes null */ ;
2943 pSMB->TotalDataCount = 0; /* no EAs */
2944 pSMB->MaxParameterCount = cpu_to_le16(10);
2945 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2946 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2947 pSMB->MaxSetupCount = 0;
2948 pSMB->Reserved = 0;
2949 pSMB->Flags = 0;
2950 pSMB->Timeout = 0;
2951 pSMB->Reserved2 = 0;
2952 byte_count = params + 1 /* pad */ ;
2953 pSMB->TotalParameterCount = cpu_to_le16(params);
2954 pSMB->ParameterCount = pSMB->TotalParameterCount;
2955 pSMB->ParameterOffset = cpu_to_le16(
2956 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2957 pSMB->DataCount = 0;
2958 pSMB->DataOffset = 0;
2959 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2960 pSMB->Reserved3 = 0;
2961 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2962 pSMB->SearchAttributes =
2963 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2964 ATTR_DIRECTORY);
2965 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2966 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2967 CIFS_SEARCH_RETURN_RESUME);
2968 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2969
2970 /* BB what should we set StorageType to? Does it matter? BB */
2971 pSMB->SearchStorageType = 0;
2972 pSMB->hdr.smb_buf_length += byte_count;
2973 pSMB->ByteCount = cpu_to_le16(byte_count);
2974
2975 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2976 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002977 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978
Steve French1982c342005-08-17 12:38:22 -07002979 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 /* BB Add code to handle unsupported level rc */
2981 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07002982
2983 if (pSMB)
2984 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985
2986 /* BB eventually could optimize out free and realloc of buf */
2987 /* for this case */
2988 if (rc == -EAGAIN)
2989 goto findFirstRetry;
2990 } else { /* decode response */
2991 /* BB remember to free buffer if error BB */
2992 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2993 if(rc == 0) {
2994 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2995 psrch_inf->unicode = TRUE;
2996 else
2997 psrch_inf->unicode = FALSE;
2998
2999 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3000 psrch_inf->srch_entries_start =
3001 (char *) &pSMBr->hdr.Protocol +
3002 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3004 le16_to_cpu(pSMBr->t2.ParameterOffset));
3005
3006 if(parms->EndofSearch)
3007 psrch_inf->endOfSearch = TRUE;
3008 else
3009 psrch_inf->endOfSearch = FALSE;
3010
3011 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3012 psrch_inf->index_of_last_entry =
3013 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 *pnetfid = parms->SearchHandle;
3015 } else {
3016 cifs_buf_release(pSMB);
3017 }
3018 }
3019
3020 return rc;
3021}
3022
3023int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3024 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3025{
3026 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3027 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3028 T2_FNEXT_RSP_PARMS * parms;
3029 char *response_data;
3030 int rc = 0;
3031 int bytes_returned, name_len;
3032 __u16 params, byte_count;
3033
3034 cFYI(1, ("In FindNext"));
3035
3036 if(psrch_inf->endOfSearch == TRUE)
3037 return -ENOENT;
3038
3039 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3040 (void **) &pSMBr);
3041 if (rc)
3042 return rc;
3043
3044 params = 14; /* includes 2 bytes of null string, converted to LE below */
3045 byte_count = 0;
3046 pSMB->TotalDataCount = 0; /* no EAs */
3047 pSMB->MaxParameterCount = cpu_to_le16(8);
3048 pSMB->MaxDataCount =
3049 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3050 pSMB->MaxSetupCount = 0;
3051 pSMB->Reserved = 0;
3052 pSMB->Flags = 0;
3053 pSMB->Timeout = 0;
3054 pSMB->Reserved2 = 0;
3055 pSMB->ParameterOffset = cpu_to_le16(
3056 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3057 pSMB->DataCount = 0;
3058 pSMB->DataOffset = 0;
3059 pSMB->SetupCount = 1;
3060 pSMB->Reserved3 = 0;
3061 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3062 pSMB->SearchHandle = searchHandle; /* always kept as le */
3063 pSMB->SearchCount =
3064 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3065 /* test for Unix extensions */
3066/* if (tcon->ses->capabilities & CAP_UNIX) {
3067 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3068 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3069 } else {
3070 pSMB->InformationLevel =
3071 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3072 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3073 } */
3074 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3075 pSMB->ResumeKey = psrch_inf->resume_key;
3076 pSMB->SearchFlags =
3077 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3078
3079 name_len = psrch_inf->resume_name_len;
3080 params += name_len;
3081 if(name_len < PATH_MAX) {
3082 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3083 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003084 /* 14 byte parm len above enough for 2 byte null terminator */
3085 pSMB->ResumeFileName[name_len] = 0;
3086 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 } else {
3088 rc = -EINVAL;
3089 goto FNext2_err_exit;
3090 }
3091 byte_count = params + 1 /* pad */ ;
3092 pSMB->TotalParameterCount = cpu_to_le16(params);
3093 pSMB->ParameterCount = pSMB->TotalParameterCount;
3094 pSMB->hdr.smb_buf_length += byte_count;
3095 pSMB->ByteCount = cpu_to_le16(byte_count);
3096
3097 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3098 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003099 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003100 if (rc) {
3101 if (rc == -EBADF) {
3102 psrch_inf->endOfSearch = TRUE;
3103 rc = 0; /* search probably was closed at end of search above */
3104 } else
3105 cFYI(1, ("FindNext returned = %d", rc));
3106 } else { /* decode response */
3107 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3108
3109 if(rc == 0) {
3110 /* BB fixme add lock for file (srch_info) struct here */
3111 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3112 psrch_inf->unicode = TRUE;
3113 else
3114 psrch_inf->unicode = FALSE;
3115 response_data = (char *) &pSMBr->hdr.Protocol +
3116 le16_to_cpu(pSMBr->t2.ParameterOffset);
3117 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3118 response_data = (char *)&pSMBr->hdr.Protocol +
3119 le16_to_cpu(pSMBr->t2.DataOffset);
3120 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3121 psrch_inf->srch_entries_start = response_data;
3122 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3123 if(parms->EndofSearch)
3124 psrch_inf->endOfSearch = TRUE;
3125 else
3126 psrch_inf->endOfSearch = FALSE;
3127
3128 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3129 psrch_inf->index_of_last_entry +=
3130 psrch_inf->entries_in_buffer;
3131/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3132
3133 /* BB fixme add unlock here */
3134 }
3135
3136 }
3137
3138 /* BB On error, should we leave previous search buf (and count and
3139 last entry fields) intact or free the previous one? */
3140
3141 /* Note: On -EAGAIN error only caller can retry on handle based calls
3142 since file handle passed in no longer valid */
3143FNext2_err_exit:
3144 if (rc != 0)
3145 cifs_buf_release(pSMB);
3146
3147 return rc;
3148}
3149
3150int
3151CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3152{
3153 int rc = 0;
3154 FINDCLOSE_REQ *pSMB = NULL;
3155 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3156 int bytes_returned;
3157
3158 cFYI(1, ("In CIFSSMBFindClose"));
3159 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3160
3161 /* no sense returning error if session restarted
3162 as file handle has been closed */
3163 if(rc == -EAGAIN)
3164 return 0;
3165 if (rc)
3166 return rc;
3167
3168 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3169 pSMB->FileID = searchHandle;
3170 pSMB->ByteCount = 0;
3171 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3172 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3173 if (rc) {
3174 cERROR(1, ("Send error in FindClose = %d", rc));
3175 }
Steve Frencha4544342005-08-24 13:59:35 -07003176 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 cifs_small_buf_release(pSMB);
3178
3179 /* Since session is dead, search handle closed on server already */
3180 if (rc == -EAGAIN)
3181 rc = 0;
3182
3183 return rc;
3184}
3185
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186int
3187CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3188 const unsigned char *searchName,
3189 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003190 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191{
3192 int rc = 0;
3193 TRANSACTION2_QPI_REQ *pSMB = NULL;
3194 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3195 int name_len, bytes_returned;
3196 __u16 params, byte_count;
3197
3198 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3199 if(tcon == NULL)
3200 return -ENODEV;
3201
3202GetInodeNumberRetry:
3203 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3204 (void **) &pSMBr);
3205 if (rc)
3206 return rc;
3207
3208
3209 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3210 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003211 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003212 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 name_len++; /* trailing null */
3214 name_len *= 2;
3215 } else { /* BB improve the check for buffer overruns BB */
3216 name_len = strnlen(searchName, PATH_MAX);
3217 name_len++; /* trailing null */
3218 strncpy(pSMB->FileName, searchName, name_len);
3219 }
3220
3221 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3222 pSMB->TotalDataCount = 0;
3223 pSMB->MaxParameterCount = cpu_to_le16(2);
3224 /* BB find exact max data count below from sess structure BB */
3225 pSMB->MaxDataCount = cpu_to_le16(4000);
3226 pSMB->MaxSetupCount = 0;
3227 pSMB->Reserved = 0;
3228 pSMB->Flags = 0;
3229 pSMB->Timeout = 0;
3230 pSMB->Reserved2 = 0;
3231 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3232 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3233 pSMB->DataCount = 0;
3234 pSMB->DataOffset = 0;
3235 pSMB->SetupCount = 1;
3236 pSMB->Reserved3 = 0;
3237 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3238 byte_count = params + 1 /* pad */ ;
3239 pSMB->TotalParameterCount = cpu_to_le16(params);
3240 pSMB->ParameterCount = pSMB->TotalParameterCount;
3241 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3242 pSMB->Reserved4 = 0;
3243 pSMB->hdr.smb_buf_length += byte_count;
3244 pSMB->ByteCount = cpu_to_le16(byte_count);
3245
3246 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3247 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3248 if (rc) {
3249 cFYI(1, ("error %d in QueryInternalInfo", rc));
3250 } else {
3251 /* decode response */
3252 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3253 if (rc || (pSMBr->ByteCount < 2))
3254 /* BB also check enough total bytes returned */
3255 /* If rc should we check for EOPNOSUPP and
3256 disable the srvino flag? or in caller? */
3257 rc = -EIO; /* bad smb */
3258 else {
3259 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3260 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3261 struct file_internal_info * pfinfo;
3262 /* BB Do we need a cast or hash here ? */
3263 if(count < 8) {
3264 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3265 rc = -EIO;
3266 goto GetInodeNumOut;
3267 }
3268 pfinfo = (struct file_internal_info *)
3269 (data_offset + (char *) &pSMBr->hdr.Protocol);
3270 *inode_number = pfinfo->UniqueId;
3271 }
3272 }
3273GetInodeNumOut:
3274 cifs_buf_release(pSMB);
3275 if (rc == -EAGAIN)
3276 goto GetInodeNumberRetry;
3277 return rc;
3278}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279
3280int
3281CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3282 const unsigned char *searchName,
3283 unsigned char **targetUNCs,
3284 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003285 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286{
3287/* TRANS2_GET_DFS_REFERRAL */
3288 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3289 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3290 struct dfs_referral_level_3 * referrals = NULL;
3291 int rc = 0;
3292 int bytes_returned;
3293 int name_len;
3294 unsigned int i;
3295 char * temp;
3296 __u16 params, byte_count;
3297 *number_of_UNC_in_array = 0;
3298 *targetUNCs = NULL;
3299
3300 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3301 if (ses == NULL)
3302 return -ENODEV;
3303getDFSRetry:
3304 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3305 (void **) &pSMBr);
3306 if (rc)
3307 return rc;
Steve French1982c342005-08-17 12:38:22 -07003308
3309 /* server pointer checked in called function,
3310 but should never be null here anyway */
3311 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312 pSMB->hdr.Tid = ses->ipc_tid;
3313 pSMB->hdr.Uid = ses->Suid;
3314 if (ses->capabilities & CAP_STATUS32) {
3315 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3316 }
3317 if (ses->capabilities & CAP_DFS) {
3318 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3319 }
3320
3321 if (ses->capabilities & CAP_UNICODE) {
3322 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3323 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003324 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003325 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 name_len++; /* trailing null */
3327 name_len *= 2;
3328 } else { /* BB improve the check for buffer overruns BB */
3329 name_len = strnlen(searchName, PATH_MAX);
3330 name_len++; /* trailing null */
3331 strncpy(pSMB->RequestFileName, searchName, name_len);
3332 }
3333
3334 params = 2 /* level */ + name_len /*includes null */ ;
3335 pSMB->TotalDataCount = 0;
3336 pSMB->DataCount = 0;
3337 pSMB->DataOffset = 0;
3338 pSMB->MaxParameterCount = 0;
3339 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3340 pSMB->MaxSetupCount = 0;
3341 pSMB->Reserved = 0;
3342 pSMB->Flags = 0;
3343 pSMB->Timeout = 0;
3344 pSMB->Reserved2 = 0;
3345 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3346 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3347 pSMB->SetupCount = 1;
3348 pSMB->Reserved3 = 0;
3349 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3350 byte_count = params + 3 /* pad */ ;
3351 pSMB->ParameterCount = cpu_to_le16(params);
3352 pSMB->TotalParameterCount = pSMB->ParameterCount;
3353 pSMB->MaxReferralLevel = cpu_to_le16(3);
3354 pSMB->hdr.smb_buf_length += byte_count;
3355 pSMB->ByteCount = cpu_to_le16(byte_count);
3356
3357 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3358 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3359 if (rc) {
3360 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3361 } else { /* decode response */
3362/* BB Add logic to parse referrals here */
3363 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3364
3365 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3366 rc = -EIO; /* bad smb */
3367 else {
3368 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3369 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3370
3371 cFYI(1,
3372 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3373 pSMBr->ByteCount, data_offset));
3374 referrals =
3375 (struct dfs_referral_level_3 *)
3376 (8 /* sizeof start of data block */ +
3377 data_offset +
3378 (char *) &pSMBr->hdr.Protocol);
3379 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",
3380 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)));
3381 /* BB This field is actually two bytes in from start of
3382 data block so we could do safety check that DataBlock
3383 begins at address of pSMBr->NumberOfReferrals */
3384 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3385
3386 /* BB Fix below so can return more than one referral */
3387 if(*number_of_UNC_in_array > 1)
3388 *number_of_UNC_in_array = 1;
3389
3390 /* get the length of the strings describing refs */
3391 name_len = 0;
3392 for(i=0;i<*number_of_UNC_in_array;i++) {
3393 /* make sure that DfsPathOffset not past end */
3394 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3395 if (offset > data_count) {
3396 /* if invalid referral, stop here and do
3397 not try to copy any more */
3398 *number_of_UNC_in_array = i;
3399 break;
3400 }
3401 temp = ((char *)referrals) + offset;
3402
3403 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3404 name_len += UniStrnlen((wchar_t *)temp,data_count);
3405 } else {
3406 name_len += strnlen(temp,data_count);
3407 }
3408 referrals++;
3409 /* BB add check that referral pointer does not fall off end PDU */
3410
3411 }
3412 /* BB add check for name_len bigger than bcc */
3413 *targetUNCs =
3414 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3415 if(*targetUNCs == NULL) {
3416 rc = -ENOMEM;
3417 goto GetDFSRefExit;
3418 }
3419 /* copy the ref strings */
3420 referrals =
3421 (struct dfs_referral_level_3 *)
3422 (8 /* sizeof data hdr */ +
3423 data_offset +
3424 (char *) &pSMBr->hdr.Protocol);
3425
3426 for(i=0;i<*number_of_UNC_in_array;i++) {
3427 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3428 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3429 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003430 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 } else {
3432 strncpy(*targetUNCs,temp,name_len);
3433 }
3434 /* BB update target_uncs pointers */
3435 referrals++;
3436 }
3437 temp = *targetUNCs;
3438 temp[name_len] = 0;
3439 }
3440
3441 }
3442GetDFSRefExit:
3443 if (pSMB)
3444 cifs_buf_release(pSMB);
3445
3446 if (rc == -EAGAIN)
3447 goto getDFSRetry;
3448
3449 return rc;
3450}
3451
Steve French20962432005-09-21 22:05:57 -07003452/* Query File System Info such as free space to old servers such as Win 9x */
3453int
3454SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3455{
3456/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3457 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3458 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3459 FILE_SYSTEM_ALLOC_INFO *response_data;
3460 int rc = 0;
3461 int bytes_returned = 0;
3462 __u16 params, byte_count;
3463
3464 cFYI(1, ("OldQFSInfo"));
3465oldQFSInfoRetry:
3466 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3467 (void **) &pSMBr);
3468 if (rc)
3469 return rc;
3470 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3471 (void **) &pSMBr);
3472 if (rc)
3473 return rc;
3474
3475 params = 2; /* level */
3476 pSMB->TotalDataCount = 0;
3477 pSMB->MaxParameterCount = cpu_to_le16(2);
3478 pSMB->MaxDataCount = cpu_to_le16(1000);
3479 pSMB->MaxSetupCount = 0;
3480 pSMB->Reserved = 0;
3481 pSMB->Flags = 0;
3482 pSMB->Timeout = 0;
3483 pSMB->Reserved2 = 0;
3484 byte_count = params + 1 /* pad */ ;
3485 pSMB->TotalParameterCount = cpu_to_le16(params);
3486 pSMB->ParameterCount = pSMB->TotalParameterCount;
3487 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3488 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3489 pSMB->DataCount = 0;
3490 pSMB->DataOffset = 0;
3491 pSMB->SetupCount = 1;
3492 pSMB->Reserved3 = 0;
3493 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3494 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3495 pSMB->hdr.smb_buf_length += byte_count;
3496 pSMB->ByteCount = cpu_to_le16(byte_count);
3497
3498 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3499 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3500 if (rc) {
3501 cFYI(1, ("Send error in QFSInfo = %d", rc));
3502 } else { /* decode response */
3503 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3504
3505 if (rc || (pSMBr->ByteCount < 18))
3506 rc = -EIO; /* bad smb */
3507 else {
3508 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3509 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3510 pSMBr->ByteCount, data_offset));
3511
3512 response_data =
3513 (FILE_SYSTEM_ALLOC_INFO *)
3514 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3515 FSData->f_bsize =
3516 le16_to_cpu(response_data->BytesPerSector) *
3517 le32_to_cpu(response_data->
3518 SectorsPerAllocationUnit);
3519 FSData->f_blocks =
3520 le32_to_cpu(response_data->TotalAllocationUnits);
3521 FSData->f_bfree = FSData->f_bavail =
3522 le32_to_cpu(response_data->FreeAllocationUnits);
3523 cFYI(1,
3524 ("Blocks: %lld Free: %lld Block size %ld",
3525 (unsigned long long)FSData->f_blocks,
3526 (unsigned long long)FSData->f_bfree,
3527 FSData->f_bsize));
3528 }
3529 }
3530 cifs_buf_release(pSMB);
3531
3532 if (rc == -EAGAIN)
3533 goto oldQFSInfoRetry;
3534
3535 return rc;
3536}
3537
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538int
Steve French737b7582005-04-28 22:41:06 -07003539CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540{
3541/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3542 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3543 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3544 FILE_SYSTEM_INFO *response_data;
3545 int rc = 0;
3546 int bytes_returned = 0;
3547 __u16 params, byte_count;
3548
3549 cFYI(1, ("In QFSInfo"));
3550QFSInfoRetry:
3551 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3552 (void **) &pSMBr);
3553 if (rc)
3554 return rc;
3555
3556 params = 2; /* level */
3557 pSMB->TotalDataCount = 0;
3558 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003559 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003560 pSMB->MaxSetupCount = 0;
3561 pSMB->Reserved = 0;
3562 pSMB->Flags = 0;
3563 pSMB->Timeout = 0;
3564 pSMB->Reserved2 = 0;
3565 byte_count = params + 1 /* pad */ ;
3566 pSMB->TotalParameterCount = cpu_to_le16(params);
3567 pSMB->ParameterCount = pSMB->TotalParameterCount;
3568 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3569 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3570 pSMB->DataCount = 0;
3571 pSMB->DataOffset = 0;
3572 pSMB->SetupCount = 1;
3573 pSMB->Reserved3 = 0;
3574 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3575 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3576 pSMB->hdr.smb_buf_length += byte_count;
3577 pSMB->ByteCount = cpu_to_le16(byte_count);
3578
3579 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3580 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3581 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003582 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003583 } else { /* decode response */
3584 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3585
Steve French20962432005-09-21 22:05:57 -07003586 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587 rc = -EIO; /* bad smb */
3588 else {
3589 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590
3591 response_data =
3592 (FILE_SYSTEM_INFO
3593 *) (((char *) &pSMBr->hdr.Protocol) +
3594 data_offset);
3595 FSData->f_bsize =
3596 le32_to_cpu(response_data->BytesPerSector) *
3597 le32_to_cpu(response_data->
3598 SectorsPerAllocationUnit);
3599 FSData->f_blocks =
3600 le64_to_cpu(response_data->TotalAllocationUnits);
3601 FSData->f_bfree = FSData->f_bavail =
3602 le64_to_cpu(response_data->FreeAllocationUnits);
3603 cFYI(1,
3604 ("Blocks: %lld Free: %lld Block size %ld",
3605 (unsigned long long)FSData->f_blocks,
3606 (unsigned long long)FSData->f_bfree,
3607 FSData->f_bsize));
3608 }
3609 }
3610 cifs_buf_release(pSMB);
3611
3612 if (rc == -EAGAIN)
3613 goto QFSInfoRetry;
3614
3615 return rc;
3616}
3617
3618int
Steve French737b7582005-04-28 22:41:06 -07003619CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620{
3621/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3622 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3623 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3624 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3625 int rc = 0;
3626 int bytes_returned = 0;
3627 __u16 params, byte_count;
3628
3629 cFYI(1, ("In QFSAttributeInfo"));
3630QFSAttributeRetry:
3631 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3632 (void **) &pSMBr);
3633 if (rc)
3634 return rc;
3635
3636 params = 2; /* level */
3637 pSMB->TotalDataCount = 0;
3638 pSMB->MaxParameterCount = cpu_to_le16(2);
3639 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3640 pSMB->MaxSetupCount = 0;
3641 pSMB->Reserved = 0;
3642 pSMB->Flags = 0;
3643 pSMB->Timeout = 0;
3644 pSMB->Reserved2 = 0;
3645 byte_count = params + 1 /* pad */ ;
3646 pSMB->TotalParameterCount = cpu_to_le16(params);
3647 pSMB->ParameterCount = pSMB->TotalParameterCount;
3648 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3649 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3650 pSMB->DataCount = 0;
3651 pSMB->DataOffset = 0;
3652 pSMB->SetupCount = 1;
3653 pSMB->Reserved3 = 0;
3654 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3655 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3656 pSMB->hdr.smb_buf_length += byte_count;
3657 pSMB->ByteCount = cpu_to_le16(byte_count);
3658
3659 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3660 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3661 if (rc) {
3662 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3663 } else { /* decode response */
3664 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3665
3666 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3667 rc = -EIO; /* bad smb */
3668 } else {
3669 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3670 response_data =
3671 (FILE_SYSTEM_ATTRIBUTE_INFO
3672 *) (((char *) &pSMBr->hdr.Protocol) +
3673 data_offset);
3674 memcpy(&tcon->fsAttrInfo, response_data,
3675 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3676 }
3677 }
3678 cifs_buf_release(pSMB);
3679
3680 if (rc == -EAGAIN)
3681 goto QFSAttributeRetry;
3682
3683 return rc;
3684}
3685
3686int
Steve French737b7582005-04-28 22:41:06 -07003687CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003688{
3689/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3690 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3691 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3692 FILE_SYSTEM_DEVICE_INFO *response_data;
3693 int rc = 0;
3694 int bytes_returned = 0;
3695 __u16 params, byte_count;
3696
3697 cFYI(1, ("In QFSDeviceInfo"));
3698QFSDeviceRetry:
3699 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3700 (void **) &pSMBr);
3701 if (rc)
3702 return rc;
3703
3704 params = 2; /* level */
3705 pSMB->TotalDataCount = 0;
3706 pSMB->MaxParameterCount = cpu_to_le16(2);
3707 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3708 pSMB->MaxSetupCount = 0;
3709 pSMB->Reserved = 0;
3710 pSMB->Flags = 0;
3711 pSMB->Timeout = 0;
3712 pSMB->Reserved2 = 0;
3713 byte_count = params + 1 /* pad */ ;
3714 pSMB->TotalParameterCount = cpu_to_le16(params);
3715 pSMB->ParameterCount = pSMB->TotalParameterCount;
3716 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3717 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3718
3719 pSMB->DataCount = 0;
3720 pSMB->DataOffset = 0;
3721 pSMB->SetupCount = 1;
3722 pSMB->Reserved3 = 0;
3723 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3724 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3725 pSMB->hdr.smb_buf_length += byte_count;
3726 pSMB->ByteCount = cpu_to_le16(byte_count);
3727
3728 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3729 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3730 if (rc) {
3731 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3732 } else { /* decode response */
3733 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3734
3735 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3736 rc = -EIO; /* bad smb */
3737 else {
3738 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3739 response_data =
Steve French737b7582005-04-28 22:41:06 -07003740 (FILE_SYSTEM_DEVICE_INFO *)
3741 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003742 data_offset);
3743 memcpy(&tcon->fsDevInfo, response_data,
3744 sizeof (FILE_SYSTEM_DEVICE_INFO));
3745 }
3746 }
3747 cifs_buf_release(pSMB);
3748
3749 if (rc == -EAGAIN)
3750 goto QFSDeviceRetry;
3751
3752 return rc;
3753}
3754
3755int
Steve French737b7582005-04-28 22:41:06 -07003756CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003757{
3758/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3759 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3760 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3761 FILE_SYSTEM_UNIX_INFO *response_data;
3762 int rc = 0;
3763 int bytes_returned = 0;
3764 __u16 params, byte_count;
3765
3766 cFYI(1, ("In QFSUnixInfo"));
3767QFSUnixRetry:
3768 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3769 (void **) &pSMBr);
3770 if (rc)
3771 return rc;
3772
3773 params = 2; /* level */
3774 pSMB->TotalDataCount = 0;
3775 pSMB->DataCount = 0;
3776 pSMB->DataOffset = 0;
3777 pSMB->MaxParameterCount = cpu_to_le16(2);
3778 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3779 pSMB->MaxSetupCount = 0;
3780 pSMB->Reserved = 0;
3781 pSMB->Flags = 0;
3782 pSMB->Timeout = 0;
3783 pSMB->Reserved2 = 0;
3784 byte_count = params + 1 /* pad */ ;
3785 pSMB->ParameterCount = cpu_to_le16(params);
3786 pSMB->TotalParameterCount = pSMB->ParameterCount;
3787 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3788 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3789 pSMB->SetupCount = 1;
3790 pSMB->Reserved3 = 0;
3791 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3792 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3793 pSMB->hdr.smb_buf_length += byte_count;
3794 pSMB->ByteCount = cpu_to_le16(byte_count);
3795
3796 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3797 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3798 if (rc) {
3799 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3800 } else { /* decode response */
3801 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3802
3803 if (rc || (pSMBr->ByteCount < 13)) {
3804 rc = -EIO; /* bad smb */
3805 } else {
3806 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3807 response_data =
3808 (FILE_SYSTEM_UNIX_INFO
3809 *) (((char *) &pSMBr->hdr.Protocol) +
3810 data_offset);
3811 memcpy(&tcon->fsUnixInfo, response_data,
3812 sizeof (FILE_SYSTEM_UNIX_INFO));
3813 }
3814 }
3815 cifs_buf_release(pSMB);
3816
3817 if (rc == -EAGAIN)
3818 goto QFSUnixRetry;
3819
3820
3821 return rc;
3822}
3823
Jeremy Allisonac670552005-06-22 17:26:35 -07003824int
Steve French45abc6e2005-06-23 13:42:03 -05003825CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07003826{
3827/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3828 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3829 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3830 int rc = 0;
3831 int bytes_returned = 0;
3832 __u16 params, param_offset, offset, byte_count;
3833
3834 cFYI(1, ("In SETFSUnixInfo"));
3835SETFSUnixRetry:
3836 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3837 (void **) &pSMBr);
3838 if (rc)
3839 return rc;
3840
3841 params = 4; /* 2 bytes zero followed by info level. */
3842 pSMB->MaxSetupCount = 0;
3843 pSMB->Reserved = 0;
3844 pSMB->Flags = 0;
3845 pSMB->Timeout = 0;
3846 pSMB->Reserved2 = 0;
3847 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3848 offset = param_offset + params;
3849
3850 pSMB->MaxParameterCount = cpu_to_le16(4);
3851 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3852 pSMB->SetupCount = 1;
3853 pSMB->Reserved3 = 0;
3854 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3855 byte_count = 1 /* pad */ + params + 12;
3856
3857 pSMB->DataCount = cpu_to_le16(12);
3858 pSMB->ParameterCount = cpu_to_le16(params);
3859 pSMB->TotalDataCount = pSMB->DataCount;
3860 pSMB->TotalParameterCount = pSMB->ParameterCount;
3861 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3862 pSMB->DataOffset = cpu_to_le16(offset);
3863
3864 /* Params. */
3865 pSMB->FileNum = 0;
3866 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3867
3868 /* Data. */
3869 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3870 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3871 pSMB->ClientUnixCap = cpu_to_le64(cap);
3872
3873 pSMB->hdr.smb_buf_length += byte_count;
3874 pSMB->ByteCount = cpu_to_le16(byte_count);
3875
3876 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3877 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3878 if (rc) {
3879 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3880 } else { /* decode response */
3881 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3882 if (rc) {
3883 rc = -EIO; /* bad smb */
3884 }
3885 }
3886 cifs_buf_release(pSMB);
3887
3888 if (rc == -EAGAIN)
3889 goto SETFSUnixRetry;
3890
3891 return rc;
3892}
3893
3894
Linus Torvalds1da177e2005-04-16 15:20:36 -07003895
3896int
3897CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003898 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899{
3900/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3901 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3902 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3903 FILE_SYSTEM_POSIX_INFO *response_data;
3904 int rc = 0;
3905 int bytes_returned = 0;
3906 __u16 params, byte_count;
3907
3908 cFYI(1, ("In QFSPosixInfo"));
3909QFSPosixRetry:
3910 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3911 (void **) &pSMBr);
3912 if (rc)
3913 return rc;
3914
3915 params = 2; /* level */
3916 pSMB->TotalDataCount = 0;
3917 pSMB->DataCount = 0;
3918 pSMB->DataOffset = 0;
3919 pSMB->MaxParameterCount = cpu_to_le16(2);
3920 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3921 pSMB->MaxSetupCount = 0;
3922 pSMB->Reserved = 0;
3923 pSMB->Flags = 0;
3924 pSMB->Timeout = 0;
3925 pSMB->Reserved2 = 0;
3926 byte_count = params + 1 /* pad */ ;
3927 pSMB->ParameterCount = cpu_to_le16(params);
3928 pSMB->TotalParameterCount = pSMB->ParameterCount;
3929 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3930 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3931 pSMB->SetupCount = 1;
3932 pSMB->Reserved3 = 0;
3933 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3934 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3935 pSMB->hdr.smb_buf_length += byte_count;
3936 pSMB->ByteCount = cpu_to_le16(byte_count);
3937
3938 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3939 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3940 if (rc) {
3941 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3942 } else { /* decode response */
3943 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3944
3945 if (rc || (pSMBr->ByteCount < 13)) {
3946 rc = -EIO; /* bad smb */
3947 } else {
3948 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3949 response_data =
3950 (FILE_SYSTEM_POSIX_INFO
3951 *) (((char *) &pSMBr->hdr.Protocol) +
3952 data_offset);
3953 FSData->f_bsize =
3954 le32_to_cpu(response_data->BlockSize);
3955 FSData->f_blocks =
3956 le64_to_cpu(response_data->TotalBlocks);
3957 FSData->f_bfree =
3958 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07003959 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 FSData->f_bavail = FSData->f_bfree;
3961 } else {
3962 FSData->f_bavail =
3963 le64_to_cpu(response_data->UserBlocksAvail);
3964 }
Steve French70ca7342005-09-22 16:32:06 -07003965 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 FSData->f_files =
3967 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07003968 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 FSData->f_ffree =
3970 le64_to_cpu(response_data->FreeFileNodes);
3971 }
3972 }
3973 cifs_buf_release(pSMB);
3974
3975 if (rc == -EAGAIN)
3976 goto QFSPosixRetry;
3977
3978 return rc;
3979}
3980
3981
3982/* We can not use write of zero bytes trick to
3983 set file size due to need for large file support. Also note that
3984 this SetPathInfo is preferred to SetFileInfo based method in next
3985 routine which is only needed to work around a sharing violation bug
3986 in Samba which this routine can run into */
3987
3988int
3989CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07003990 __u64 size, int SetAllocation,
3991 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992{
3993 struct smb_com_transaction2_spi_req *pSMB = NULL;
3994 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3995 struct file_end_of_file_info *parm_data;
3996 int name_len;
3997 int rc = 0;
3998 int bytes_returned = 0;
3999 __u16 params, byte_count, data_count, param_offset, offset;
4000
4001 cFYI(1, ("In SetEOF"));
4002SetEOFRetry:
4003 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4004 (void **) &pSMBr);
4005 if (rc)
4006 return rc;
4007
4008 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4009 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004010 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004011 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 name_len++; /* trailing null */
4013 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004014 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004015 name_len = strnlen(fileName, PATH_MAX);
4016 name_len++; /* trailing null */
4017 strncpy(pSMB->FileName, fileName, name_len);
4018 }
4019 params = 6 + name_len;
4020 data_count = sizeof (struct file_end_of_file_info);
4021 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004022 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023 pSMB->MaxSetupCount = 0;
4024 pSMB->Reserved = 0;
4025 pSMB->Flags = 0;
4026 pSMB->Timeout = 0;
4027 pSMB->Reserved2 = 0;
4028 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4029 InformationLevel) - 4;
4030 offset = param_offset + params;
4031 if(SetAllocation) {
4032 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4033 pSMB->InformationLevel =
4034 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4035 else
4036 pSMB->InformationLevel =
4037 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4038 } else /* Set File Size */ {
4039 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4040 pSMB->InformationLevel =
4041 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4042 else
4043 pSMB->InformationLevel =
4044 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4045 }
4046
4047 parm_data =
4048 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4049 offset);
4050 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4051 pSMB->DataOffset = cpu_to_le16(offset);
4052 pSMB->SetupCount = 1;
4053 pSMB->Reserved3 = 0;
4054 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4055 byte_count = 3 /* pad */ + params + data_count;
4056 pSMB->DataCount = cpu_to_le16(data_count);
4057 pSMB->TotalDataCount = pSMB->DataCount;
4058 pSMB->ParameterCount = cpu_to_le16(params);
4059 pSMB->TotalParameterCount = pSMB->ParameterCount;
4060 pSMB->Reserved4 = 0;
4061 pSMB->hdr.smb_buf_length += byte_count;
4062 parm_data->FileSize = cpu_to_le64(size);
4063 pSMB->ByteCount = cpu_to_le16(byte_count);
4064 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4065 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4066 if (rc) {
4067 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4068 }
4069
4070 cifs_buf_release(pSMB);
4071
4072 if (rc == -EAGAIN)
4073 goto SetEOFRetry;
4074
4075 return rc;
4076}
4077
4078int
4079CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4080 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4081{
4082 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4083 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4084 char *data_offset;
4085 struct file_end_of_file_info *parm_data;
4086 int rc = 0;
4087 int bytes_returned = 0;
4088 __u16 params, param_offset, offset, byte_count, count;
4089
4090 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4091 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004092 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4093
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 if (rc)
4095 return rc;
4096
Steve Frenchcd634992005-04-28 22:41:10 -07004097 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4098
Linus Torvalds1da177e2005-04-16 15:20:36 -07004099 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4100 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4101
4102 params = 6;
4103 pSMB->MaxSetupCount = 0;
4104 pSMB->Reserved = 0;
4105 pSMB->Flags = 0;
4106 pSMB->Timeout = 0;
4107 pSMB->Reserved2 = 0;
4108 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4109 offset = param_offset + params;
4110
4111 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4112
4113 count = sizeof(struct file_end_of_file_info);
4114 pSMB->MaxParameterCount = cpu_to_le16(2);
4115 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4116 pSMB->SetupCount = 1;
4117 pSMB->Reserved3 = 0;
4118 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4119 byte_count = 3 /* pad */ + params + count;
4120 pSMB->DataCount = cpu_to_le16(count);
4121 pSMB->ParameterCount = cpu_to_le16(params);
4122 pSMB->TotalDataCount = pSMB->DataCount;
4123 pSMB->TotalParameterCount = pSMB->ParameterCount;
4124 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4125 parm_data =
4126 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4127 offset);
4128 pSMB->DataOffset = cpu_to_le16(offset);
4129 parm_data->FileSize = cpu_to_le64(size);
4130 pSMB->Fid = fid;
4131 if(SetAllocation) {
4132 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4133 pSMB->InformationLevel =
4134 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4135 else
4136 pSMB->InformationLevel =
4137 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4138 } else /* Set File Size */ {
4139 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4140 pSMB->InformationLevel =
4141 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4142 else
4143 pSMB->InformationLevel =
4144 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4145 }
4146 pSMB->Reserved4 = 0;
4147 pSMB->hdr.smb_buf_length += byte_count;
4148 pSMB->ByteCount = cpu_to_le16(byte_count);
4149 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4150 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4151 if (rc) {
4152 cFYI(1,
4153 ("Send error in SetFileInfo (SetFileSize) = %d",
4154 rc));
4155 }
4156
4157 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004158 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159
4160 /* Note: On -EAGAIN error only caller can retry on handle based calls
4161 since file handle passed in no longer valid */
4162
4163 return rc;
4164}
4165
4166/* Some legacy servers such as NT4 require that the file times be set on
4167 an open handle, rather than by pathname - this is awkward due to
4168 potential access conflicts on the open, but it is unavoidable for these
4169 old servers since the only other choice is to go from 100 nanosecond DCE
4170 time and resort to the original setpathinfo level which takes the ancient
4171 DOS time format with 2 second granularity */
4172int
4173CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4174 __u16 fid)
4175{
4176 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4177 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4178 char *data_offset;
4179 int rc = 0;
4180 int bytes_returned = 0;
4181 __u16 params, param_offset, offset, byte_count, count;
4182
4183 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004184 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4185
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 if (rc)
4187 return rc;
4188
Steve Frenchcd634992005-04-28 22:41:10 -07004189 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4190
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 /* At this point there is no need to override the current pid
4192 with the pid of the opener, but that could change if we someday
4193 use an existing handle (rather than opening one on the fly) */
4194 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4195 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4196
4197 params = 6;
4198 pSMB->MaxSetupCount = 0;
4199 pSMB->Reserved = 0;
4200 pSMB->Flags = 0;
4201 pSMB->Timeout = 0;
4202 pSMB->Reserved2 = 0;
4203 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4204 offset = param_offset + params;
4205
4206 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4207
4208 count = sizeof (FILE_BASIC_INFO);
4209 pSMB->MaxParameterCount = cpu_to_le16(2);
4210 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4211 pSMB->SetupCount = 1;
4212 pSMB->Reserved3 = 0;
4213 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4214 byte_count = 3 /* pad */ + params + count;
4215 pSMB->DataCount = cpu_to_le16(count);
4216 pSMB->ParameterCount = cpu_to_le16(params);
4217 pSMB->TotalDataCount = pSMB->DataCount;
4218 pSMB->TotalParameterCount = pSMB->ParameterCount;
4219 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4220 pSMB->DataOffset = cpu_to_le16(offset);
4221 pSMB->Fid = fid;
4222 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4223 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4224 else
4225 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4226 pSMB->Reserved4 = 0;
4227 pSMB->hdr.smb_buf_length += byte_count;
4228 pSMB->ByteCount = cpu_to_le16(byte_count);
4229 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4230 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4231 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4232 if (rc) {
4233 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4234 }
4235
Steve Frenchcd634992005-04-28 22:41:10 -07004236 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237
4238 /* Note: On -EAGAIN error only caller can retry on handle based calls
4239 since file handle passed in no longer valid */
4240
4241 return rc;
4242}
4243
4244
4245int
4246CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4247 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004248 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249{
4250 TRANSACTION2_SPI_REQ *pSMB = NULL;
4251 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4252 int name_len;
4253 int rc = 0;
4254 int bytes_returned = 0;
4255 char *data_offset;
4256 __u16 params, param_offset, offset, byte_count, count;
4257
4258 cFYI(1, ("In SetTimes"));
4259
4260SetTimesRetry:
4261 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4262 (void **) &pSMBr);
4263 if (rc)
4264 return rc;
4265
4266 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4267 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004268 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004269 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 name_len++; /* trailing null */
4271 name_len *= 2;
4272 } else { /* BB improve the check for buffer overruns BB */
4273 name_len = strnlen(fileName, PATH_MAX);
4274 name_len++; /* trailing null */
4275 strncpy(pSMB->FileName, fileName, name_len);
4276 }
4277
4278 params = 6 + name_len;
4279 count = sizeof (FILE_BASIC_INFO);
4280 pSMB->MaxParameterCount = cpu_to_le16(2);
4281 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4282 pSMB->MaxSetupCount = 0;
4283 pSMB->Reserved = 0;
4284 pSMB->Flags = 0;
4285 pSMB->Timeout = 0;
4286 pSMB->Reserved2 = 0;
4287 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4288 InformationLevel) - 4;
4289 offset = param_offset + params;
4290 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4291 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4292 pSMB->DataOffset = cpu_to_le16(offset);
4293 pSMB->SetupCount = 1;
4294 pSMB->Reserved3 = 0;
4295 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4296 byte_count = 3 /* pad */ + params + count;
4297
4298 pSMB->DataCount = cpu_to_le16(count);
4299 pSMB->ParameterCount = cpu_to_le16(params);
4300 pSMB->TotalDataCount = pSMB->DataCount;
4301 pSMB->TotalParameterCount = pSMB->ParameterCount;
4302 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4303 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4304 else
4305 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4306 pSMB->Reserved4 = 0;
4307 pSMB->hdr.smb_buf_length += byte_count;
4308 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4309 pSMB->ByteCount = cpu_to_le16(byte_count);
4310 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4311 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4312 if (rc) {
4313 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4314 }
4315
4316 cifs_buf_release(pSMB);
4317
4318 if (rc == -EAGAIN)
4319 goto SetTimesRetry;
4320
4321 return rc;
4322}
4323
4324/* Can not be used to set time stamps yet (due to old DOS time format) */
4325/* Can be used to set attributes */
4326#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4327 handling it anyway and NT4 was what we thought it would be needed for
4328 Do not delete it until we prove whether needed for Win9x though */
4329int
4330CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4331 __u16 dos_attrs, const struct nls_table *nls_codepage)
4332{
4333 SETATTR_REQ *pSMB = NULL;
4334 SETATTR_RSP *pSMBr = NULL;
4335 int rc = 0;
4336 int bytes_returned;
4337 int name_len;
4338
4339 cFYI(1, ("In SetAttrLegacy"));
4340
4341SetAttrLgcyRetry:
4342 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4343 (void **) &pSMBr);
4344 if (rc)
4345 return rc;
4346
4347 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4348 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004349 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350 PATH_MAX, nls_codepage);
4351 name_len++; /* trailing null */
4352 name_len *= 2;
4353 } else { /* BB improve the check for buffer overruns BB */
4354 name_len = strnlen(fileName, PATH_MAX);
4355 name_len++; /* trailing null */
4356 strncpy(pSMB->fileName, fileName, name_len);
4357 }
4358 pSMB->attr = cpu_to_le16(dos_attrs);
4359 pSMB->BufferFormat = 0x04;
4360 pSMB->hdr.smb_buf_length += name_len + 1;
4361 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4362 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4363 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4364 if (rc) {
4365 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4366 }
4367
4368 cifs_buf_release(pSMB);
4369
4370 if (rc == -EAGAIN)
4371 goto SetAttrLgcyRetry;
4372
4373 return rc;
4374}
4375#endif /* temporarily unneeded SetAttr legacy function */
4376
4377int
4378CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004379 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4380 dev_t device, const struct nls_table *nls_codepage,
4381 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004382{
4383 TRANSACTION2_SPI_REQ *pSMB = NULL;
4384 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4385 int name_len;
4386 int rc = 0;
4387 int bytes_returned = 0;
4388 FILE_UNIX_BASIC_INFO *data_offset;
4389 __u16 params, param_offset, offset, count, byte_count;
4390
4391 cFYI(1, ("In SetUID/GID/Mode"));
4392setPermsRetry:
4393 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4394 (void **) &pSMBr);
4395 if (rc)
4396 return rc;
4397
4398 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4399 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004400 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004401 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402 name_len++; /* trailing null */
4403 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004404 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405 name_len = strnlen(fileName, PATH_MAX);
4406 name_len++; /* trailing null */
4407 strncpy(pSMB->FileName, fileName, name_len);
4408 }
4409
4410 params = 6 + name_len;
4411 count = sizeof (FILE_UNIX_BASIC_INFO);
4412 pSMB->MaxParameterCount = cpu_to_le16(2);
4413 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4414 pSMB->MaxSetupCount = 0;
4415 pSMB->Reserved = 0;
4416 pSMB->Flags = 0;
4417 pSMB->Timeout = 0;
4418 pSMB->Reserved2 = 0;
4419 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4420 InformationLevel) - 4;
4421 offset = param_offset + params;
4422 data_offset =
4423 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4424 offset);
4425 memset(data_offset, 0, count);
4426 pSMB->DataOffset = cpu_to_le16(offset);
4427 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4428 pSMB->SetupCount = 1;
4429 pSMB->Reserved3 = 0;
4430 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4431 byte_count = 3 /* pad */ + params + count;
4432 pSMB->ParameterCount = cpu_to_le16(params);
4433 pSMB->DataCount = cpu_to_le16(count);
4434 pSMB->TotalParameterCount = pSMB->ParameterCount;
4435 pSMB->TotalDataCount = pSMB->DataCount;
4436 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4437 pSMB->Reserved4 = 0;
4438 pSMB->hdr.smb_buf_length += byte_count;
4439 data_offset->Uid = cpu_to_le64(uid);
4440 data_offset->Gid = cpu_to_le64(gid);
4441 /* better to leave device as zero when it is */
4442 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4443 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4444 data_offset->Permissions = cpu_to_le64(mode);
4445
4446 if(S_ISREG(mode))
4447 data_offset->Type = cpu_to_le32(UNIX_FILE);
4448 else if(S_ISDIR(mode))
4449 data_offset->Type = cpu_to_le32(UNIX_DIR);
4450 else if(S_ISLNK(mode))
4451 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4452 else if(S_ISCHR(mode))
4453 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4454 else if(S_ISBLK(mode))
4455 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4456 else if(S_ISFIFO(mode))
4457 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4458 else if(S_ISSOCK(mode))
4459 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4460
4461
4462 pSMB->ByteCount = cpu_to_le16(byte_count);
4463 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4464 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4465 if (rc) {
4466 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4467 }
4468
4469 if (pSMB)
4470 cifs_buf_release(pSMB);
4471 if (rc == -EAGAIN)
4472 goto setPermsRetry;
4473 return rc;
4474}
4475
4476int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004477 const int notify_subdirs, const __u16 netfid,
4478 __u32 filter, struct file * pfile, int multishot,
4479 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480{
4481 int rc = 0;
4482 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004483 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004484 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 int bytes_returned;
4486
4487 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4488 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4489 (void **) &pSMBr);
4490 if (rc)
4491 return rc;
4492
4493 pSMB->TotalParameterCount = 0 ;
4494 pSMB->TotalDataCount = 0;
4495 pSMB->MaxParameterCount = cpu_to_le32(2);
4496 /* BB find exact data count max from sess structure BB */
4497 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004498/* BB VERIFY verify which is correct for above BB */
4499 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4500 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4501
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 pSMB->MaxSetupCount = 4;
4503 pSMB->Reserved = 0;
4504 pSMB->ParameterOffset = 0;
4505 pSMB->DataCount = 0;
4506 pSMB->DataOffset = 0;
4507 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4508 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4509 pSMB->ParameterCount = pSMB->TotalParameterCount;
4510 if(notify_subdirs)
4511 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4512 pSMB->Reserved2 = 0;
4513 pSMB->CompletionFilter = cpu_to_le32(filter);
4514 pSMB->Fid = netfid; /* file handle always le */
4515 pSMB->ByteCount = 0;
4516
4517 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4518 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4519 if (rc) {
4520 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004521 } else {
4522 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004523 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004524 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004525 sizeof(struct dir_notify_req),
4526 GFP_KERNEL);
4527 if(dnotify_req) {
4528 dnotify_req->Pid = pSMB->hdr.Pid;
4529 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4530 dnotify_req->Mid = pSMB->hdr.Mid;
4531 dnotify_req->Tid = pSMB->hdr.Tid;
4532 dnotify_req->Uid = pSMB->hdr.Uid;
4533 dnotify_req->netfid = netfid;
4534 dnotify_req->pfile = pfile;
4535 dnotify_req->filter = filter;
4536 dnotify_req->multishot = multishot;
4537 spin_lock(&GlobalMid_Lock);
4538 list_add_tail(&dnotify_req->lhead,
4539 &GlobalDnotifyReqList);
4540 spin_unlock(&GlobalMid_Lock);
4541 } else
4542 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543 }
4544 cifs_buf_release(pSMB);
4545 return rc;
4546}
4547#ifdef CONFIG_CIFS_XATTR
4548ssize_t
4549CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4550 const unsigned char *searchName,
4551 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004552 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553{
4554 /* BB assumes one setup word */
4555 TRANSACTION2_QPI_REQ *pSMB = NULL;
4556 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4557 int rc = 0;
4558 int bytes_returned;
4559 int name_len;
4560 struct fea * temp_fea;
4561 char * temp_ptr;
4562 __u16 params, byte_count;
4563
4564 cFYI(1, ("In Query All EAs path %s", searchName));
4565QAllEAsRetry:
4566 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4567 (void **) &pSMBr);
4568 if (rc)
4569 return rc;
4570
4571 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4572 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004573 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004574 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 name_len++; /* trailing null */
4576 name_len *= 2;
4577 } else { /* BB improve the check for buffer overruns BB */
4578 name_len = strnlen(searchName, PATH_MAX);
4579 name_len++; /* trailing null */
4580 strncpy(pSMB->FileName, searchName, name_len);
4581 }
4582
4583 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4584 pSMB->TotalDataCount = 0;
4585 pSMB->MaxParameterCount = cpu_to_le16(2);
4586 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4587 pSMB->MaxSetupCount = 0;
4588 pSMB->Reserved = 0;
4589 pSMB->Flags = 0;
4590 pSMB->Timeout = 0;
4591 pSMB->Reserved2 = 0;
4592 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4593 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4594 pSMB->DataCount = 0;
4595 pSMB->DataOffset = 0;
4596 pSMB->SetupCount = 1;
4597 pSMB->Reserved3 = 0;
4598 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4599 byte_count = params + 1 /* pad */ ;
4600 pSMB->TotalParameterCount = cpu_to_le16(params);
4601 pSMB->ParameterCount = pSMB->TotalParameterCount;
4602 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4603 pSMB->Reserved4 = 0;
4604 pSMB->hdr.smb_buf_length += byte_count;
4605 pSMB->ByteCount = cpu_to_le16(byte_count);
4606
4607 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4608 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4609 if (rc) {
4610 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4611 } else { /* decode response */
4612 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4613
4614 /* BB also check enough total bytes returned */
4615 /* BB we need to improve the validity checking
4616 of these trans2 responses */
4617 if (rc || (pSMBr->ByteCount < 4))
4618 rc = -EIO; /* bad smb */
4619 /* else if (pFindData){
4620 memcpy((char *) pFindData,
4621 (char *) &pSMBr->hdr.Protocol +
4622 data_offset, kl);
4623 }*/ else {
4624 /* check that length of list is not more than bcc */
4625 /* check that each entry does not go beyond length
4626 of list */
4627 /* check that each element of each entry does not
4628 go beyond end of list */
4629 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4630 struct fealist * ea_response_data;
4631 rc = 0;
4632 /* validate_trans2_offsets() */
4633 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4634 ea_response_data = (struct fealist *)
4635 (((char *) &pSMBr->hdr.Protocol) +
4636 data_offset);
4637 name_len = le32_to_cpu(ea_response_data->list_len);
4638 cFYI(1,("ea length %d", name_len));
4639 if(name_len <= 8) {
4640 /* returned EA size zeroed at top of function */
4641 cFYI(1,("empty EA list returned from server"));
4642 } else {
4643 /* account for ea list len */
4644 name_len -= 4;
4645 temp_fea = ea_response_data->list;
4646 temp_ptr = (char *)temp_fea;
4647 while(name_len > 0) {
4648 __u16 value_len;
4649 name_len -= 4;
4650 temp_ptr += 4;
4651 rc += temp_fea->name_len;
4652 /* account for prefix user. and trailing null */
4653 rc = rc + 5 + 1;
4654 if(rc<(int)buf_size) {
4655 memcpy(EAData,"user.",5);
4656 EAData+=5;
4657 memcpy(EAData,temp_ptr,temp_fea->name_len);
4658 EAData+=temp_fea->name_len;
4659 /* null terminate name */
4660 *EAData = 0;
4661 EAData = EAData + 1;
4662 } else if(buf_size == 0) {
4663 /* skip copy - calc size only */
4664 } else {
4665 /* stop before overrun buffer */
4666 rc = -ERANGE;
4667 break;
4668 }
4669 name_len -= temp_fea->name_len;
4670 temp_ptr += temp_fea->name_len;
4671 /* account for trailing null */
4672 name_len--;
4673 temp_ptr++;
4674 value_len = le16_to_cpu(temp_fea->value_len);
4675 name_len -= value_len;
4676 temp_ptr += value_len;
4677 /* BB check that temp_ptr is still within smb BB*/
4678 /* no trailing null to account for in value len */
4679 /* go on to next EA */
4680 temp_fea = (struct fea *)temp_ptr;
4681 }
4682 }
4683 }
4684 }
4685 if (pSMB)
4686 cifs_buf_release(pSMB);
4687 if (rc == -EAGAIN)
4688 goto QAllEAsRetry;
4689
4690 return (ssize_t)rc;
4691}
4692
4693ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4694 const unsigned char * searchName,const unsigned char * ea_name,
4695 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004696 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697{
4698 TRANSACTION2_QPI_REQ *pSMB = NULL;
4699 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4700 int rc = 0;
4701 int bytes_returned;
4702 int name_len;
4703 struct fea * temp_fea;
4704 char * temp_ptr;
4705 __u16 params, byte_count;
4706
4707 cFYI(1, ("In Query EA path %s", searchName));
4708QEARetry:
4709 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4710 (void **) &pSMBr);
4711 if (rc)
4712 return rc;
4713
4714 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4715 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004716 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004717 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718 name_len++; /* trailing null */
4719 name_len *= 2;
4720 } else { /* BB improve the check for buffer overruns BB */
4721 name_len = strnlen(searchName, PATH_MAX);
4722 name_len++; /* trailing null */
4723 strncpy(pSMB->FileName, searchName, name_len);
4724 }
4725
4726 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4727 pSMB->TotalDataCount = 0;
4728 pSMB->MaxParameterCount = cpu_to_le16(2);
4729 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4730 pSMB->MaxSetupCount = 0;
4731 pSMB->Reserved = 0;
4732 pSMB->Flags = 0;
4733 pSMB->Timeout = 0;
4734 pSMB->Reserved2 = 0;
4735 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4736 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4737 pSMB->DataCount = 0;
4738 pSMB->DataOffset = 0;
4739 pSMB->SetupCount = 1;
4740 pSMB->Reserved3 = 0;
4741 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4742 byte_count = params + 1 /* pad */ ;
4743 pSMB->TotalParameterCount = cpu_to_le16(params);
4744 pSMB->ParameterCount = pSMB->TotalParameterCount;
4745 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4746 pSMB->Reserved4 = 0;
4747 pSMB->hdr.smb_buf_length += byte_count;
4748 pSMB->ByteCount = cpu_to_le16(byte_count);
4749
4750 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4751 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4752 if (rc) {
4753 cFYI(1, ("Send error in Query EA = %d", rc));
4754 } else { /* decode response */
4755 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4756
4757 /* BB also check enough total bytes returned */
4758 /* BB we need to improve the validity checking
4759 of these trans2 responses */
4760 if (rc || (pSMBr->ByteCount < 4))
4761 rc = -EIO; /* bad smb */
4762 /* else if (pFindData){
4763 memcpy((char *) pFindData,
4764 (char *) &pSMBr->hdr.Protocol +
4765 data_offset, kl);
4766 }*/ else {
4767 /* check that length of list is not more than bcc */
4768 /* check that each entry does not go beyond length
4769 of list */
4770 /* check that each element of each entry does not
4771 go beyond end of list */
4772 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4773 struct fealist * ea_response_data;
4774 rc = -ENODATA;
4775 /* validate_trans2_offsets() */
4776 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4777 ea_response_data = (struct fealist *)
4778 (((char *) &pSMBr->hdr.Protocol) +
4779 data_offset);
4780 name_len = le32_to_cpu(ea_response_data->list_len);
4781 cFYI(1,("ea length %d", name_len));
4782 if(name_len <= 8) {
4783 /* returned EA size zeroed at top of function */
4784 cFYI(1,("empty EA list returned from server"));
4785 } else {
4786 /* account for ea list len */
4787 name_len -= 4;
4788 temp_fea = ea_response_data->list;
4789 temp_ptr = (char *)temp_fea;
4790 /* loop through checking if we have a matching
4791 name and then return the associated value */
4792 while(name_len > 0) {
4793 __u16 value_len;
4794 name_len -= 4;
4795 temp_ptr += 4;
4796 value_len = le16_to_cpu(temp_fea->value_len);
4797 /* BB validate that value_len falls within SMB,
4798 even though maximum for name_len is 255 */
4799 if(memcmp(temp_fea->name,ea_name,
4800 temp_fea->name_len) == 0) {
4801 /* found a match */
4802 rc = value_len;
4803 /* account for prefix user. and trailing null */
4804 if(rc<=(int)buf_size) {
4805 memcpy(ea_value,
4806 temp_fea->name+temp_fea->name_len+1,
4807 rc);
4808 /* ea values, unlike ea names,
4809 are not null terminated */
4810 } else if(buf_size == 0) {
4811 /* skip copy - calc size only */
4812 } else {
4813 /* stop before overrun buffer */
4814 rc = -ERANGE;
4815 }
4816 break;
4817 }
4818 name_len -= temp_fea->name_len;
4819 temp_ptr += temp_fea->name_len;
4820 /* account for trailing null */
4821 name_len--;
4822 temp_ptr++;
4823 name_len -= value_len;
4824 temp_ptr += value_len;
4825 /* no trailing null to account for in value len */
4826 /* go on to next EA */
4827 temp_fea = (struct fea *)temp_ptr;
4828 }
4829 }
4830 }
4831 }
4832 if (pSMB)
4833 cifs_buf_release(pSMB);
4834 if (rc == -EAGAIN)
4835 goto QEARetry;
4836
4837 return (ssize_t)rc;
4838}
4839
4840int
4841CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4842 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004843 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4844 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845{
4846 struct smb_com_transaction2_spi_req *pSMB = NULL;
4847 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4848 struct fealist *parm_data;
4849 int name_len;
4850 int rc = 0;
4851 int bytes_returned = 0;
4852 __u16 params, param_offset, byte_count, offset, count;
4853
4854 cFYI(1, ("In SetEA"));
4855SetEARetry:
4856 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4857 (void **) &pSMBr);
4858 if (rc)
4859 return rc;
4860
4861 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4862 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004863 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004864 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865 name_len++; /* trailing null */
4866 name_len *= 2;
4867 } else { /* BB improve the check for buffer overruns BB */
4868 name_len = strnlen(fileName, PATH_MAX);
4869 name_len++; /* trailing null */
4870 strncpy(pSMB->FileName, fileName, name_len);
4871 }
4872
4873 params = 6 + name_len;
4874
4875 /* done calculating parms using name_len of file name,
4876 now use name_len to calculate length of ea name
4877 we are going to create in the inode xattrs */
4878 if(ea_name == NULL)
4879 name_len = 0;
4880 else
4881 name_len = strnlen(ea_name,255);
4882
4883 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4884 pSMB->MaxParameterCount = cpu_to_le16(2);
4885 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4886 pSMB->MaxSetupCount = 0;
4887 pSMB->Reserved = 0;
4888 pSMB->Flags = 0;
4889 pSMB->Timeout = 0;
4890 pSMB->Reserved2 = 0;
4891 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4892 InformationLevel) - 4;
4893 offset = param_offset + params;
4894 pSMB->InformationLevel =
4895 cpu_to_le16(SMB_SET_FILE_EA);
4896
4897 parm_data =
4898 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4899 offset);
4900 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4901 pSMB->DataOffset = cpu_to_le16(offset);
4902 pSMB->SetupCount = 1;
4903 pSMB->Reserved3 = 0;
4904 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4905 byte_count = 3 /* pad */ + params + count;
4906 pSMB->DataCount = cpu_to_le16(count);
4907 parm_data->list_len = cpu_to_le32(count);
4908 parm_data->list[0].EA_flags = 0;
4909 /* we checked above that name len is less than 255 */
4910 parm_data->list[0].name_len = (__u8)name_len;;
4911 /* EA names are always ASCII */
4912 if(ea_name)
4913 strncpy(parm_data->list[0].name,ea_name,name_len);
4914 parm_data->list[0].name[name_len] = 0;
4915 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4916 /* caller ensures that ea_value_len is less than 64K but
4917 we need to ensure that it fits within the smb */
4918
4919 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4920 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4921 if(ea_value_len)
4922 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4923
4924 pSMB->TotalDataCount = pSMB->DataCount;
4925 pSMB->ParameterCount = cpu_to_le16(params);
4926 pSMB->TotalParameterCount = pSMB->ParameterCount;
4927 pSMB->Reserved4 = 0;
4928 pSMB->hdr.smb_buf_length += byte_count;
4929 pSMB->ByteCount = cpu_to_le16(byte_count);
4930 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4931 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4932 if (rc) {
4933 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4934 }
4935
4936 cifs_buf_release(pSMB);
4937
4938 if (rc == -EAGAIN)
4939 goto SetEARetry;
4940
4941 return rc;
4942}
4943
4944#endif