blob: b41e8b379652b228377f01d1d20bfaa47c3883e8 [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 Frencha45443472005-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 Frencha45443472005-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 Frencha45443472005-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 Frencha45443472005-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 Frencha45443472005-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 Frencha45443472005-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 Frencha45443472005-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);
Steve French6cec2ae2006-02-22 17:31:52 -06001051 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1052 /* return buffer to caller to free */
1053 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001054 if(resp_buf_type == CIFS_SMALL_BUFFER)
1055 *pbuf_type = CIFS_SMALL_BUFFER;
1056 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1057 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001058 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001059
1060 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 since file handle passed in no longer valid */
1062 return rc;
1063}
1064
Steve Frenchec637e32005-12-12 20:53:18 -08001065
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066int
1067CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1068 const int netfid, const unsigned int count,
1069 const __u64 offset, unsigned int *nbytes, const char *buf,
1070 const char __user * ubuf, const int long_op)
1071{
1072 int rc = -EACCES;
1073 WRITE_REQ *pSMB = NULL;
1074 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001075 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 __u32 bytes_sent;
1077 __u16 byte_count;
1078
1079 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001080 if(tcon->ses == NULL)
1081 return -ECONNABORTED;
1082
1083 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1084 wct = 14;
1085 else
1086 wct = 12;
1087
1088 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 (void **) &pSMBr);
1090 if (rc)
1091 return rc;
1092 /* tcon and ses pointer are checked in smb_init */
1093 if (tcon->ses->server == NULL)
1094 return -ECONNABORTED;
1095
1096 pSMB->AndXCommand = 0xFF; /* none */
1097 pSMB->Fid = netfid;
1098 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001099 if(wct == 14)
1100 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1101 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1102 return -EIO;
1103
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 pSMB->Reserved = 0xFFFFFFFF;
1105 pSMB->WriteMode = 0;
1106 pSMB->Remaining = 0;
1107
1108 /* Can increase buffer size if buffer is big enough in some cases - ie we
1109 can send more if LARGE_WRITE_X capability returned by the server and if
1110 our buffer is big enough or if we convert to iovecs on socket writes
1111 and eliminate the copy to the CIFS buffer */
1112 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1113 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1114 } else {
1115 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1116 & ~0xFF;
1117 }
1118
1119 if (bytes_sent > count)
1120 bytes_sent = count;
1121 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001122 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 if(buf)
1124 memcpy(pSMB->Data,buf,bytes_sent);
1125 else if(ubuf) {
1126 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1127 cifs_buf_release(pSMB);
1128 return -EFAULT;
1129 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001130 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 /* No buffer */
1132 cifs_buf_release(pSMB);
1133 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001134 } /* else setting file size with write of zero bytes */
1135 if(wct == 14)
1136 byte_count = bytes_sent + 1; /* pad */
1137 else /* wct == 12 */ {
1138 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1141 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001142 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001143
1144 if(wct == 14)
1145 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001146 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001147 struct smb_com_writex_req * pSMBW =
1148 (struct smb_com_writex_req *)pSMB;
1149 pSMBW->ByteCount = cpu_to_le16(byte_count);
1150 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
1152 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1153 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001154 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 if (rc) {
1156 cFYI(1, ("Send error in write = %d", rc));
1157 *nbytes = 0;
1158 } else {
1159 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1160 *nbytes = (*nbytes) << 16;
1161 *nbytes += le16_to_cpu(pSMBr->Count);
1162 }
1163
1164 cifs_buf_release(pSMB);
1165
1166 /* Note: On -EAGAIN error only caller can retry on handle based calls
1167 since file handle passed in no longer valid */
1168
1169 return rc;
1170}
1171
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001172int
1173CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001175 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1176 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177{
1178 int rc = -EACCES;
1179 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001180 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001181 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001182 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183
Steve Frenchff7feac2005-11-15 16:45:16 -08001184 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1185
Steve French8cc64c62005-10-03 13:49:43 -07001186 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1187 wct = 14;
1188 else
1189 wct = 12;
1190 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 if (rc)
1192 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 /* tcon and ses pointer are checked in smb_init */
1194 if (tcon->ses->server == NULL)
1195 return -ECONNABORTED;
1196
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001197 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 pSMB->Fid = netfid;
1199 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001200 if(wct == 14)
1201 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1202 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1203 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 pSMB->Reserved = 0xFFFFFFFF;
1205 pSMB->WriteMode = 0;
1206 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001207
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 pSMB->DataOffset =
1209 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1210
Steve French3e844692005-10-03 13:37:24 -07001211 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1212 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001213 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001214 if(wct == 14)
1215 pSMB->hdr.smb_buf_length += count+1;
1216 else /* wct == 12 */
1217 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1218 if(wct == 14)
1219 pSMB->ByteCount = cpu_to_le16(count + 1);
1220 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1221 struct smb_com_writex_req * pSMBW =
1222 (struct smb_com_writex_req *)pSMB;
1223 pSMBW->ByteCount = cpu_to_le16(count + 5);
1224 }
Steve French3e844692005-10-03 13:37:24 -07001225 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001226 if(wct == 14)
1227 iov[0].iov_len = smb_hdr_len + 4;
1228 else /* wct == 12 pad bigger by four bytes */
1229 iov[0].iov_len = smb_hdr_len + 8;
1230
Steve French3e844692005-10-03 13:37:24 -07001231
Steve Frenchec637e32005-12-12 20:53:18 -08001232 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001233 long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001234 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001236 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001238 } else if(resp_buf_type == 0) {
1239 /* presumably this can not happen, but best to be safe */
1240 rc = -EIO;
1241 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001242 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001243 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001244 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1245 *nbytes = (*nbytes) << 16;
1246 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001247 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
1249 cifs_small_buf_release(pSMB);
Steve Frenchec637e32005-12-12 20:53:18 -08001250 if(resp_buf_type == CIFS_SMALL_BUFFER)
1251 cifs_small_buf_release(iov[0].iov_base);
1252 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1253 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254
1255 /* Note: On -EAGAIN error only caller can retry on handle based calls
1256 since file handle passed in no longer valid */
1257
1258 return rc;
1259}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001260
1261
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262int
1263CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1264 const __u16 smb_file_id, const __u64 len,
1265 const __u64 offset, const __u32 numUnlock,
1266 const __u32 numLock, const __u8 lockType, const int waitFlag)
1267{
1268 int rc = 0;
1269 LOCK_REQ *pSMB = NULL;
1270 LOCK_RSP *pSMBr = NULL;
1271 int bytes_returned;
1272 int timeout = 0;
1273 __u16 count;
1274
1275 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001276 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1277
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278 if (rc)
1279 return rc;
1280
Steve French46810cb2005-04-28 22:41:09 -07001281 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1282
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1284 timeout = -1; /* no response expected */
1285 pSMB->Timeout = 0;
1286 } else if (waitFlag == TRUE) {
1287 timeout = 3; /* blocking operation, no timeout */
1288 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1289 } else {
1290 pSMB->Timeout = 0;
1291 }
1292
1293 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1294 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1295 pSMB->LockType = lockType;
1296 pSMB->AndXCommand = 0xFF; /* none */
1297 pSMB->Fid = smb_file_id; /* netfid stays le */
1298
1299 if((numLock != 0) || (numUnlock != 0)) {
1300 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1301 /* BB where to store pid high? */
1302 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1303 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1304 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1305 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1306 count = sizeof(LOCKING_ANDX_RANGE);
1307 } else {
1308 /* oplock break */
1309 count = 0;
1310 }
1311 pSMB->hdr.smb_buf_length += count;
1312 pSMB->ByteCount = cpu_to_le16(count);
1313
1314 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1315 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha45443472005-08-24 13:59:35 -07001316 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317 if (rc) {
1318 cFYI(1, ("Send error in Lock = %d", rc));
1319 }
Steve French46810cb2005-04-28 22:41:09 -07001320 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321
1322 /* Note: On -EAGAIN error only caller can retry on handle based calls
1323 since file handle passed in no longer valid */
1324 return rc;
1325}
1326
1327int
1328CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1329{
1330 int rc = 0;
1331 CLOSE_REQ *pSMB = NULL;
1332 CLOSE_RSP *pSMBr = NULL;
1333 int bytes_returned;
1334 cFYI(1, ("In CIFSSMBClose"));
1335
1336/* do not retry on dead session on close */
1337 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1338 if(rc == -EAGAIN)
1339 return 0;
1340 if (rc)
1341 return rc;
1342
1343 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1344
1345 pSMB->FileID = (__u16) smb_file_id;
1346 pSMB->LastWriteTime = 0;
1347 pSMB->ByteCount = 0;
1348 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1349 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001350 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 if (rc) {
1352 if(rc!=-EINTR) {
1353 /* EINTR is expected when user ctl-c to kill app */
1354 cERROR(1, ("Send error in Close = %d", rc));
1355 }
1356 }
1357
1358 cifs_small_buf_release(pSMB);
1359
1360 /* Since session is dead, file will be closed on server already */
1361 if(rc == -EAGAIN)
1362 rc = 0;
1363
1364 return rc;
1365}
1366
1367int
1368CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1369 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001370 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371{
1372 int rc = 0;
1373 RENAME_REQ *pSMB = NULL;
1374 RENAME_RSP *pSMBr = NULL;
1375 int bytes_returned;
1376 int name_len, name_len2;
1377 __u16 count;
1378
1379 cFYI(1, ("In CIFSSMBRename"));
1380renameRetry:
1381 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1382 (void **) &pSMBr);
1383 if (rc)
1384 return rc;
1385
1386 pSMB->BufferFormat = 0x04;
1387 pSMB->SearchAttributes =
1388 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1389 ATTR_DIRECTORY);
1390
1391 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1392 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001393 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001394 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 name_len++; /* trailing null */
1396 name_len *= 2;
1397 pSMB->OldFileName[name_len] = 0x04; /* pad */
1398 /* protocol requires ASCII signature byte on Unicode string */
1399 pSMB->OldFileName[name_len + 1] = 0x00;
1400 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001401 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001402 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1404 name_len2 *= 2; /* convert to bytes */
1405 } else { /* BB improve the check for buffer overruns BB */
1406 name_len = strnlen(fromName, PATH_MAX);
1407 name_len++; /* trailing null */
1408 strncpy(pSMB->OldFileName, fromName, name_len);
1409 name_len2 = strnlen(toName, PATH_MAX);
1410 name_len2++; /* trailing null */
1411 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1412 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1413 name_len2++; /* trailing null */
1414 name_len2++; /* signature byte */
1415 }
1416
1417 count = 1 /* 1st signature byte */ + name_len + name_len2;
1418 pSMB->hdr.smb_buf_length += count;
1419 pSMB->ByteCount = cpu_to_le16(count);
1420
1421 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1422 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001423 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 if (rc) {
1425 cFYI(1, ("Send error in rename = %d", rc));
1426 }
1427
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 cifs_buf_release(pSMB);
1429
1430 if (rc == -EAGAIN)
1431 goto renameRetry;
1432
1433 return rc;
1434}
1435
1436int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001437 int netfid, char * target_name,
1438 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439{
1440 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1441 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1442 struct set_file_rename * rename_info;
1443 char *data_offset;
1444 char dummy_string[30];
1445 int rc = 0;
1446 int bytes_returned = 0;
1447 int len_of_str;
1448 __u16 params, param_offset, offset, count, byte_count;
1449
1450 cFYI(1, ("Rename to File by handle"));
1451 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1452 (void **) &pSMBr);
1453 if (rc)
1454 return rc;
1455
1456 params = 6;
1457 pSMB->MaxSetupCount = 0;
1458 pSMB->Reserved = 0;
1459 pSMB->Flags = 0;
1460 pSMB->Timeout = 0;
1461 pSMB->Reserved2 = 0;
1462 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1463 offset = param_offset + params;
1464
1465 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1466 rename_info = (struct set_file_rename *) data_offset;
1467 pSMB->MaxParameterCount = cpu_to_le16(2);
1468 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1469 pSMB->SetupCount = 1;
1470 pSMB->Reserved3 = 0;
1471 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1472 byte_count = 3 /* pad */ + params;
1473 pSMB->ParameterCount = cpu_to_le16(params);
1474 pSMB->TotalParameterCount = pSMB->ParameterCount;
1475 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1476 pSMB->DataOffset = cpu_to_le16(offset);
1477 /* construct random name ".cifs_tmp<inodenum><mid>" */
1478 rename_info->overwrite = cpu_to_le32(1);
1479 rename_info->root_fid = 0;
1480 /* unicode only call */
1481 if(target_name == NULL) {
1482 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001483 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001484 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001486 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001487 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488 }
1489 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1490 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1491 byte_count += count;
1492 pSMB->DataCount = cpu_to_le16(count);
1493 pSMB->TotalDataCount = pSMB->DataCount;
1494 pSMB->Fid = netfid;
1495 pSMB->InformationLevel =
1496 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1497 pSMB->Reserved4 = 0;
1498 pSMB->hdr.smb_buf_length += byte_count;
1499 pSMB->ByteCount = cpu_to_le16(byte_count);
1500 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1501 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001502 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 if (rc) {
1504 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1505 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001506
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 cifs_buf_release(pSMB);
1508
1509 /* Note: On -EAGAIN error only caller can retry on handle based calls
1510 since file handle passed in no longer valid */
1511
1512 return rc;
1513}
1514
1515int
1516CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1517 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001518 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519{
1520 int rc = 0;
1521 COPY_REQ *pSMB = NULL;
1522 COPY_RSP *pSMBr = NULL;
1523 int bytes_returned;
1524 int name_len, name_len2;
1525 __u16 count;
1526
1527 cFYI(1, ("In CIFSSMBCopy"));
1528copyRetry:
1529 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1530 (void **) &pSMBr);
1531 if (rc)
1532 return rc;
1533
1534 pSMB->BufferFormat = 0x04;
1535 pSMB->Tid2 = target_tid;
1536
1537 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1538
1539 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001540 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001541 fromName, PATH_MAX, nls_codepage,
1542 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 name_len++; /* trailing null */
1544 name_len *= 2;
1545 pSMB->OldFileName[name_len] = 0x04; /* pad */
1546 /* protocol requires ASCII signature byte on Unicode string */
1547 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001548 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001549 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1551 name_len2 *= 2; /* convert to bytes */
1552 } else { /* BB improve the check for buffer overruns BB */
1553 name_len = strnlen(fromName, PATH_MAX);
1554 name_len++; /* trailing null */
1555 strncpy(pSMB->OldFileName, fromName, name_len);
1556 name_len2 = strnlen(toName, PATH_MAX);
1557 name_len2++; /* trailing null */
1558 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1559 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1560 name_len2++; /* trailing null */
1561 name_len2++; /* signature byte */
1562 }
1563
1564 count = 1 /* 1st signature byte */ + name_len + name_len2;
1565 pSMB->hdr.smb_buf_length += count;
1566 pSMB->ByteCount = cpu_to_le16(count);
1567
1568 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1569 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1570 if (rc) {
1571 cFYI(1, ("Send error in copy = %d with %d files copied",
1572 rc, le16_to_cpu(pSMBr->CopyCount)));
1573 }
1574 if (pSMB)
1575 cifs_buf_release(pSMB);
1576
1577 if (rc == -EAGAIN)
1578 goto copyRetry;
1579
1580 return rc;
1581}
1582
1583int
1584CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1585 const char *fromName, const char *toName,
1586 const struct nls_table *nls_codepage)
1587{
1588 TRANSACTION2_SPI_REQ *pSMB = NULL;
1589 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1590 char *data_offset;
1591 int name_len;
1592 int name_len_target;
1593 int rc = 0;
1594 int bytes_returned = 0;
1595 __u16 params, param_offset, offset, byte_count;
1596
1597 cFYI(1, ("In Symlink Unix style"));
1598createSymLinkRetry:
1599 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1600 (void **) &pSMBr);
1601 if (rc)
1602 return rc;
1603
1604 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1605 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001606 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 /* find define for this maxpathcomponent */
1608 , nls_codepage);
1609 name_len++; /* trailing null */
1610 name_len *= 2;
1611
1612 } else { /* BB improve the check for buffer overruns BB */
1613 name_len = strnlen(fromName, PATH_MAX);
1614 name_len++; /* trailing null */
1615 strncpy(pSMB->FileName, fromName, name_len);
1616 }
1617 params = 6 + name_len;
1618 pSMB->MaxSetupCount = 0;
1619 pSMB->Reserved = 0;
1620 pSMB->Flags = 0;
1621 pSMB->Timeout = 0;
1622 pSMB->Reserved2 = 0;
1623 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1624 InformationLevel) - 4;
1625 offset = param_offset + params;
1626
1627 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1628 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1629 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001630 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 /* find define for this maxpathcomponent */
1632 , nls_codepage);
1633 name_len_target++; /* trailing null */
1634 name_len_target *= 2;
1635 } else { /* BB improve the check for buffer overruns BB */
1636 name_len_target = strnlen(toName, PATH_MAX);
1637 name_len_target++; /* trailing null */
1638 strncpy(data_offset, toName, name_len_target);
1639 }
1640
1641 pSMB->MaxParameterCount = cpu_to_le16(2);
1642 /* BB find exact max on data count below from sess */
1643 pSMB->MaxDataCount = cpu_to_le16(1000);
1644 pSMB->SetupCount = 1;
1645 pSMB->Reserved3 = 0;
1646 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1647 byte_count = 3 /* pad */ + params + name_len_target;
1648 pSMB->DataCount = cpu_to_le16(name_len_target);
1649 pSMB->ParameterCount = cpu_to_le16(params);
1650 pSMB->TotalDataCount = pSMB->DataCount;
1651 pSMB->TotalParameterCount = pSMB->ParameterCount;
1652 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1653 pSMB->DataOffset = cpu_to_le16(offset);
1654 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1655 pSMB->Reserved4 = 0;
1656 pSMB->hdr.smb_buf_length += byte_count;
1657 pSMB->ByteCount = cpu_to_le16(byte_count);
1658 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1659 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001660 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 if (rc) {
1662 cFYI(1,
1663 ("Send error in SetPathInfo (create symlink) = %d",
1664 rc));
1665 }
1666
1667 if (pSMB)
1668 cifs_buf_release(pSMB);
1669
1670 if (rc == -EAGAIN)
1671 goto createSymLinkRetry;
1672
1673 return rc;
1674}
1675
1676int
1677CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1678 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001679 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680{
1681 TRANSACTION2_SPI_REQ *pSMB = NULL;
1682 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1683 char *data_offset;
1684 int name_len;
1685 int name_len_target;
1686 int rc = 0;
1687 int bytes_returned = 0;
1688 __u16 params, param_offset, offset, byte_count;
1689
1690 cFYI(1, ("In Create Hard link Unix style"));
1691createHardLinkRetry:
1692 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1693 (void **) &pSMBr);
1694 if (rc)
1695 return rc;
1696
1697 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001698 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001699 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 name_len++; /* trailing null */
1701 name_len *= 2;
1702
1703 } else { /* BB improve the check for buffer overruns BB */
1704 name_len = strnlen(toName, PATH_MAX);
1705 name_len++; /* trailing null */
1706 strncpy(pSMB->FileName, toName, name_len);
1707 }
1708 params = 6 + name_len;
1709 pSMB->MaxSetupCount = 0;
1710 pSMB->Reserved = 0;
1711 pSMB->Flags = 0;
1712 pSMB->Timeout = 0;
1713 pSMB->Reserved2 = 0;
1714 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1715 InformationLevel) - 4;
1716 offset = param_offset + params;
1717
1718 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1719 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1720 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001721 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001722 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 name_len_target++; /* trailing null */
1724 name_len_target *= 2;
1725 } else { /* BB improve the check for buffer overruns BB */
1726 name_len_target = strnlen(fromName, PATH_MAX);
1727 name_len_target++; /* trailing null */
1728 strncpy(data_offset, fromName, name_len_target);
1729 }
1730
1731 pSMB->MaxParameterCount = cpu_to_le16(2);
1732 /* BB find exact max on data count below from sess*/
1733 pSMB->MaxDataCount = cpu_to_le16(1000);
1734 pSMB->SetupCount = 1;
1735 pSMB->Reserved3 = 0;
1736 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1737 byte_count = 3 /* pad */ + params + name_len_target;
1738 pSMB->ParameterCount = cpu_to_le16(params);
1739 pSMB->TotalParameterCount = pSMB->ParameterCount;
1740 pSMB->DataCount = cpu_to_le16(name_len_target);
1741 pSMB->TotalDataCount = pSMB->DataCount;
1742 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1743 pSMB->DataOffset = cpu_to_le16(offset);
1744 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1745 pSMB->Reserved4 = 0;
1746 pSMB->hdr.smb_buf_length += byte_count;
1747 pSMB->ByteCount = cpu_to_le16(byte_count);
1748 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1749 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001750 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 if (rc) {
1752 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1753 }
1754
1755 cifs_buf_release(pSMB);
1756 if (rc == -EAGAIN)
1757 goto createHardLinkRetry;
1758
1759 return rc;
1760}
1761
1762int
1763CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1764 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001765 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766{
1767 int rc = 0;
1768 NT_RENAME_REQ *pSMB = NULL;
1769 RENAME_RSP *pSMBr = NULL;
1770 int bytes_returned;
1771 int name_len, name_len2;
1772 __u16 count;
1773
1774 cFYI(1, ("In CIFSCreateHardLink"));
1775winCreateHardLinkRetry:
1776
1777 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1778 (void **) &pSMBr);
1779 if (rc)
1780 return rc;
1781
1782 pSMB->SearchAttributes =
1783 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1784 ATTR_DIRECTORY);
1785 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1786 pSMB->ClusterCount = 0;
1787
1788 pSMB->BufferFormat = 0x04;
1789
1790 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1791 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001792 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001793 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 name_len++; /* trailing null */
1795 name_len *= 2;
1796 pSMB->OldFileName[name_len] = 0; /* pad */
1797 pSMB->OldFileName[name_len + 1] = 0x04;
1798 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001799 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001800 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1802 name_len2 *= 2; /* convert to bytes */
1803 } else { /* BB improve the check for buffer overruns BB */
1804 name_len = strnlen(fromName, PATH_MAX);
1805 name_len++; /* trailing null */
1806 strncpy(pSMB->OldFileName, fromName, name_len);
1807 name_len2 = strnlen(toName, PATH_MAX);
1808 name_len2++; /* trailing null */
1809 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1810 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1811 name_len2++; /* trailing null */
1812 name_len2++; /* signature byte */
1813 }
1814
1815 count = 1 /* string type byte */ + name_len + name_len2;
1816 pSMB->hdr.smb_buf_length += count;
1817 pSMB->ByteCount = cpu_to_le16(count);
1818
1819 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1820 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001821 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 if (rc) {
1823 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1824 }
1825 cifs_buf_release(pSMB);
1826 if (rc == -EAGAIN)
1827 goto winCreateHardLinkRetry;
1828
1829 return rc;
1830}
1831
1832int
1833CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1834 const unsigned char *searchName,
1835 char *symlinkinfo, const int buflen,
1836 const struct nls_table *nls_codepage)
1837{
1838/* SMB_QUERY_FILE_UNIX_LINK */
1839 TRANSACTION2_QPI_REQ *pSMB = NULL;
1840 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1841 int rc = 0;
1842 int bytes_returned;
1843 int name_len;
1844 __u16 params, byte_count;
1845
1846 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1847
1848querySymLinkRetry:
1849 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1850 (void **) &pSMBr);
1851 if (rc)
1852 return rc;
1853
1854 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1855 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001856 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 /* find define for this maxpathcomponent */
1858 , nls_codepage);
1859 name_len++; /* trailing null */
1860 name_len *= 2;
1861 } else { /* BB improve the check for buffer overruns BB */
1862 name_len = strnlen(searchName, PATH_MAX);
1863 name_len++; /* trailing null */
1864 strncpy(pSMB->FileName, searchName, name_len);
1865 }
1866
1867 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1868 pSMB->TotalDataCount = 0;
1869 pSMB->MaxParameterCount = cpu_to_le16(2);
1870 /* BB find exact max data count below from sess structure BB */
1871 pSMB->MaxDataCount = cpu_to_le16(4000);
1872 pSMB->MaxSetupCount = 0;
1873 pSMB->Reserved = 0;
1874 pSMB->Flags = 0;
1875 pSMB->Timeout = 0;
1876 pSMB->Reserved2 = 0;
1877 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1878 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1879 pSMB->DataCount = 0;
1880 pSMB->DataOffset = 0;
1881 pSMB->SetupCount = 1;
1882 pSMB->Reserved3 = 0;
1883 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1884 byte_count = params + 1 /* pad */ ;
1885 pSMB->TotalParameterCount = cpu_to_le16(params);
1886 pSMB->ParameterCount = pSMB->TotalParameterCount;
1887 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1888 pSMB->Reserved4 = 0;
1889 pSMB->hdr.smb_buf_length += byte_count;
1890 pSMB->ByteCount = cpu_to_le16(byte_count);
1891
1892 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1893 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1894 if (rc) {
1895 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1896 } else {
1897 /* decode response */
1898
1899 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1900 if (rc || (pSMBr->ByteCount < 2))
1901 /* BB also check enough total bytes returned */
1902 rc = -EIO; /* bad smb */
1903 else {
1904 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1905 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1906
1907 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1908 name_len = UniStrnlen((wchar_t *) ((char *)
1909 &pSMBr->hdr.Protocol +data_offset),
1910 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07001911 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08001913 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 data_offset),
1915 name_len, nls_codepage);
1916 } else {
1917 strncpy(symlinkinfo,
1918 (char *) &pSMBr->hdr.Protocol +
1919 data_offset,
1920 min_t(const int, buflen, count));
1921 }
1922 symlinkinfo[buflen] = 0;
1923 /* just in case so calling code does not go off the end of buffer */
1924 }
1925 }
1926 cifs_buf_release(pSMB);
1927 if (rc == -EAGAIN)
1928 goto querySymLinkRetry;
1929 return rc;
1930}
1931
Steve French0a4b92c2006-01-12 15:44:21 -08001932/* Initialize NT TRANSACT SMB into small smb request buffer.
1933 This assumes that all NT TRANSACTS that we init here have
1934 total parm and data under about 400 bytes (to fit in small cifs
1935 buffer size), which is the case so far, it easily fits. NB:
1936 Setup words themselves and ByteCount
1937 MaxSetupCount (size of returned setup area) and
1938 MaxParameterCount (returned parms size) must be set by caller */
1939static int
1940smb_init_ntransact(const __u16 sub_command, const int setup_count,
1941 const int parm_len, struct cifsTconInfo *tcon,
1942 void ** ret_buf)
1943{
1944 int rc;
1945 __u32 temp_offset;
1946 struct smb_com_ntransact_req * pSMB;
1947
1948 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
1949 (void **)&pSMB);
1950 if (rc)
1951 return rc;
1952 *ret_buf = (void *)pSMB;
1953 pSMB->Reserved = 0;
1954 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
1955 pSMB->TotalDataCount = 0;
1956 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
1957 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
1958 pSMB->ParameterCount = pSMB->TotalParameterCount;
1959 pSMB->DataCount = pSMB->TotalDataCount;
1960 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
1961 (setup_count * 2) - 4 /* for rfc1001 length itself */;
1962 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
1963 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
1964 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
1965 pSMB->SubCommand = cpu_to_le16(sub_command);
1966 return 0;
1967}
1968
1969static int
1970validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
1971 int * pdatalen, int * pparmlen)
1972{
1973 char * end_of_smb;
1974 __u32 data_count, data_offset, parm_count, parm_offset;
1975 struct smb_com_ntransact_rsp * pSMBr;
1976
1977 if(buf == NULL)
1978 return -EINVAL;
1979
1980 pSMBr = (struct smb_com_ntransact_rsp *)buf;
1981
1982 /* ByteCount was converted from little endian in SendReceive */
1983 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
1984 (char *)&pSMBr->ByteCount;
1985
1986
1987 data_offset = le32_to_cpu(pSMBr->DataOffset);
1988 data_count = le32_to_cpu(pSMBr->DataCount);
1989 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
1990 parm_count = le32_to_cpu(pSMBr->ParameterCount);
1991
1992 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
1993 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
1994
1995 /* should we also check that parm and data areas do not overlap? */
1996 if(*ppparm > end_of_smb) {
1997 cFYI(1,("parms start after end of smb"));
1998 return -EINVAL;
1999 } else if(parm_count + *ppparm > end_of_smb) {
2000 cFYI(1,("parm end after end of smb"));
2001 return -EINVAL;
2002 } else if(*ppdata > end_of_smb) {
2003 cFYI(1,("data starts after end of smb"));
2004 return -EINVAL;
2005 } else if(data_count + *ppdata > end_of_smb) {
2006 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2007 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2008 return -EINVAL;
2009 } else if(parm_count + data_count > pSMBr->ByteCount) {
2010 cFYI(1,("parm count and data count larger than SMB"));
2011 return -EINVAL;
2012 }
2013 return 0;
2014}
2015
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016int
2017CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2018 const unsigned char *searchName,
2019 char *symlinkinfo, const int buflen,__u16 fid,
2020 const struct nls_table *nls_codepage)
2021{
2022 int rc = 0;
2023 int bytes_returned;
2024 int name_len;
2025 struct smb_com_transaction_ioctl_req * pSMB;
2026 struct smb_com_transaction_ioctl_rsp * pSMBr;
2027
2028 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2029 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2030 (void **) &pSMBr);
2031 if (rc)
2032 return rc;
2033
2034 pSMB->TotalParameterCount = 0 ;
2035 pSMB->TotalDataCount = 0;
2036 pSMB->MaxParameterCount = cpu_to_le32(2);
2037 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002038 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2039 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 pSMB->MaxSetupCount = 4;
2041 pSMB->Reserved = 0;
2042 pSMB->ParameterOffset = 0;
2043 pSMB->DataCount = 0;
2044 pSMB->DataOffset = 0;
2045 pSMB->SetupCount = 4;
2046 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2047 pSMB->ParameterCount = pSMB->TotalParameterCount;
2048 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2049 pSMB->IsFsctl = 1; /* FSCTL */
2050 pSMB->IsRootFlag = 0;
2051 pSMB->Fid = fid; /* file handle always le */
2052 pSMB->ByteCount = 0;
2053
2054 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2055 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2056 if (rc) {
2057 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2058 } else { /* decode response */
2059 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2060 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2061 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2062 /* BB also check enough total bytes returned */
2063 rc = -EIO; /* bad smb */
2064 else {
2065 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002066 char * end_of_smb = 2 /* sizeof byte count */ +
2067 pSMBr->ByteCount +
2068 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069
2070 struct reparse_data * reparse_buf = (struct reparse_data *)
2071 ((char *)&pSMBr->hdr.Protocol + data_offset);
2072 if((char*)reparse_buf >= end_of_smb) {
2073 rc = -EIO;
2074 goto qreparse_out;
2075 }
2076 if((reparse_buf->LinkNamesBuf +
2077 reparse_buf->TargetNameOffset +
2078 reparse_buf->TargetNameLen) >
2079 end_of_smb) {
2080 cFYI(1,("reparse buf extended beyond SMB"));
2081 rc = -EIO;
2082 goto qreparse_out;
2083 }
2084
2085 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2086 name_len = UniStrnlen((wchar_t *)
2087 (reparse_buf->LinkNamesBuf +
2088 reparse_buf->TargetNameOffset),
2089 min(buflen/2, reparse_buf->TargetNameLen / 2));
2090 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002091 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 reparse_buf->TargetNameOffset),
2093 name_len, nls_codepage);
2094 } else { /* ASCII names */
2095 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2096 reparse_buf->TargetNameOffset,
2097 min_t(const int, buflen, reparse_buf->TargetNameLen));
2098 }
2099 } else {
2100 rc = -EIO;
2101 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2102 }
2103 symlinkinfo[buflen] = 0; /* just in case so the caller
2104 does not go off the end of the buffer */
2105 cFYI(1,("readlink result - %s ",symlinkinfo));
2106 }
2107 }
2108qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002109 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110
2111 /* Note: On -EAGAIN error only caller can retry on handle based calls
2112 since file handle passed in no longer valid */
2113
2114 return rc;
2115}
2116
2117#ifdef CONFIG_CIFS_POSIX
2118
2119/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2120static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2121{
2122 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002123 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2124 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2125 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2127
2128 return;
2129}
2130
2131/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002132static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2133 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134{
2135 int size = 0;
2136 int i;
2137 __u16 count;
2138 struct cifs_posix_ace * pACE;
2139 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2140 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2141
2142 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2143 return -EOPNOTSUPP;
2144
2145 if(acl_type & ACL_TYPE_ACCESS) {
2146 count = le16_to_cpu(cifs_acl->access_entry_count);
2147 pACE = &cifs_acl->ace_array[0];
2148 size = sizeof(struct cifs_posix_acl);
2149 size += sizeof(struct cifs_posix_ace) * count;
2150 /* check if we would go beyond end of SMB */
2151 if(size_of_data_area < size) {
2152 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2153 return -EINVAL;
2154 }
2155 } else if(acl_type & ACL_TYPE_DEFAULT) {
2156 count = le16_to_cpu(cifs_acl->access_entry_count);
2157 size = sizeof(struct cifs_posix_acl);
2158 size += sizeof(struct cifs_posix_ace) * count;
2159/* skip past access ACEs to get to default ACEs */
2160 pACE = &cifs_acl->ace_array[count];
2161 count = le16_to_cpu(cifs_acl->default_entry_count);
2162 size += sizeof(struct cifs_posix_ace) * count;
2163 /* check if we would go beyond end of SMB */
2164 if(size_of_data_area < size)
2165 return -EINVAL;
2166 } else {
2167 /* illegal type */
2168 return -EINVAL;
2169 }
2170
2171 size = posix_acl_xattr_size(count);
2172 if((buflen == 0) || (local_acl == NULL)) {
2173 /* used to query ACL EA size */
2174 } else if(size > buflen) {
2175 return -ERANGE;
2176 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002177 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 for(i = 0;i < count ;i++) {
2179 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2180 pACE ++;
2181 }
2182 }
2183 return size;
2184}
2185
2186static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2187 const posix_acl_xattr_entry * local_ace)
2188{
2189 __u16 rc = 0; /* 0 = ACL converted ok */
2190
Steve Frenchff7feac2005-11-15 16:45:16 -08002191 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2192 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002194 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 /* Probably no need to le convert -1 on any arch but can not hurt */
2196 cifs_ace->cifs_uid = cpu_to_le64(-1);
2197 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002198 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002199 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2200 return rc;
2201}
2202
2203/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2204static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2205 const int acl_type)
2206{
2207 __u16 rc = 0;
2208 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2209 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2210 int count;
2211 int i;
2212
2213 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2214 return 0;
2215
2216 count = posix_acl_xattr_count((size_t)buflen);
2217 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002218 count, buflen, le32_to_cpu(local_acl->a_version)));
2219 if(le32_to_cpu(local_acl->a_version) != 2) {
2220 cFYI(1,("unknown POSIX ACL version %d",
2221 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 return 0;
2223 }
2224 cifs_acl->version = cpu_to_le16(1);
2225 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002226 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002228 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 else {
2230 cFYI(1,("unknown ACL type %d",acl_type));
2231 return 0;
2232 }
2233 for(i=0;i<count;i++) {
2234 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2235 &local_acl->a_entries[i]);
2236 if(rc != 0) {
2237 /* ACE not converted */
2238 break;
2239 }
2240 }
2241 if(rc == 0) {
2242 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2243 rc += sizeof(struct cifs_posix_acl);
2244 /* BB add check to make sure ACL does not overflow SMB */
2245 }
2246 return rc;
2247}
2248
2249int
2250CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2251 const unsigned char *searchName,
2252 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002253 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254{
2255/* SMB_QUERY_POSIX_ACL */
2256 TRANSACTION2_QPI_REQ *pSMB = NULL;
2257 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2258 int rc = 0;
2259 int bytes_returned;
2260 int name_len;
2261 __u16 params, byte_count;
2262
2263 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2264
2265queryAclRetry:
2266 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2267 (void **) &pSMBr);
2268 if (rc)
2269 return rc;
2270
2271 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2272 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002273 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002274 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 name_len++; /* trailing null */
2276 name_len *= 2;
2277 pSMB->FileName[name_len] = 0;
2278 pSMB->FileName[name_len+1] = 0;
2279 } else { /* BB improve the check for buffer overruns BB */
2280 name_len = strnlen(searchName, PATH_MAX);
2281 name_len++; /* trailing null */
2282 strncpy(pSMB->FileName, searchName, name_len);
2283 }
2284
2285 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2286 pSMB->TotalDataCount = 0;
2287 pSMB->MaxParameterCount = cpu_to_le16(2);
2288 /* BB find exact max data count below from sess structure BB */
2289 pSMB->MaxDataCount = cpu_to_le16(4000);
2290 pSMB->MaxSetupCount = 0;
2291 pSMB->Reserved = 0;
2292 pSMB->Flags = 0;
2293 pSMB->Timeout = 0;
2294 pSMB->Reserved2 = 0;
2295 pSMB->ParameterOffset = cpu_to_le16(
2296 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2297 pSMB->DataCount = 0;
2298 pSMB->DataOffset = 0;
2299 pSMB->SetupCount = 1;
2300 pSMB->Reserved3 = 0;
2301 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2302 byte_count = params + 1 /* pad */ ;
2303 pSMB->TotalParameterCount = cpu_to_le16(params);
2304 pSMB->ParameterCount = pSMB->TotalParameterCount;
2305 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2306 pSMB->Reserved4 = 0;
2307 pSMB->hdr.smb_buf_length += byte_count;
2308 pSMB->ByteCount = cpu_to_le16(byte_count);
2309
2310 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2311 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002312 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313 if (rc) {
2314 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2315 } else {
2316 /* decode response */
2317
2318 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2319 if (rc || (pSMBr->ByteCount < 2))
2320 /* BB also check enough total bytes returned */
2321 rc = -EIO; /* bad smb */
2322 else {
2323 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2324 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2325 rc = cifs_copy_posix_acl(acl_inf,
2326 (char *)&pSMBr->hdr.Protocol+data_offset,
2327 buflen,acl_type,count);
2328 }
2329 }
2330 cifs_buf_release(pSMB);
2331 if (rc == -EAGAIN)
2332 goto queryAclRetry;
2333 return rc;
2334}
2335
2336int
2337CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2338 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002339 const char *local_acl, const int buflen,
2340 const int acl_type,
2341 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342{
2343 struct smb_com_transaction2_spi_req *pSMB = NULL;
2344 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2345 char *parm_data;
2346 int name_len;
2347 int rc = 0;
2348 int bytes_returned = 0;
2349 __u16 params, byte_count, data_count, param_offset, offset;
2350
2351 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2352setAclRetry:
2353 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2354 (void **) &pSMBr);
2355 if (rc)
2356 return rc;
2357 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2358 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002359 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002360 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 name_len++; /* trailing null */
2362 name_len *= 2;
2363 } else { /* BB improve the check for buffer overruns BB */
2364 name_len = strnlen(fileName, PATH_MAX);
2365 name_len++; /* trailing null */
2366 strncpy(pSMB->FileName, fileName, name_len);
2367 }
2368 params = 6 + name_len;
2369 pSMB->MaxParameterCount = cpu_to_le16(2);
2370 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2371 pSMB->MaxSetupCount = 0;
2372 pSMB->Reserved = 0;
2373 pSMB->Flags = 0;
2374 pSMB->Timeout = 0;
2375 pSMB->Reserved2 = 0;
2376 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2377 InformationLevel) - 4;
2378 offset = param_offset + params;
2379 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2380 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2381
2382 /* convert to on the wire format for POSIX ACL */
2383 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2384
2385 if(data_count == 0) {
2386 rc = -EOPNOTSUPP;
2387 goto setACLerrorExit;
2388 }
2389 pSMB->DataOffset = cpu_to_le16(offset);
2390 pSMB->SetupCount = 1;
2391 pSMB->Reserved3 = 0;
2392 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2393 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2394 byte_count = 3 /* pad */ + params + data_count;
2395 pSMB->DataCount = cpu_to_le16(data_count);
2396 pSMB->TotalDataCount = pSMB->DataCount;
2397 pSMB->ParameterCount = cpu_to_le16(params);
2398 pSMB->TotalParameterCount = pSMB->ParameterCount;
2399 pSMB->Reserved4 = 0;
2400 pSMB->hdr.smb_buf_length += byte_count;
2401 pSMB->ByteCount = cpu_to_le16(byte_count);
2402 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2403 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2404 if (rc) {
2405 cFYI(1, ("Set POSIX ACL returned %d", rc));
2406 }
2407
2408setACLerrorExit:
2409 cifs_buf_release(pSMB);
2410 if (rc == -EAGAIN)
2411 goto setAclRetry;
2412 return rc;
2413}
2414
Steve Frenchf654bac2005-04-28 22:41:04 -07002415/* BB fix tabs in this function FIXME BB */
2416int
2417CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2418 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2419{
2420 int rc = 0;
2421 struct smb_t2_qfi_req *pSMB = NULL;
2422 struct smb_t2_qfi_rsp *pSMBr = NULL;
2423 int bytes_returned;
2424 __u16 params, byte_count;
2425
2426 cFYI(1,("In GetExtAttr"));
2427 if(tcon == NULL)
2428 return -ENODEV;
2429
2430GetExtAttrRetry:
2431 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2432 (void **) &pSMBr);
2433 if (rc)
2434 return rc;
2435
Steve Frenchc67593a2005-04-28 22:41:04 -07002436 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002437 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002438 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002439 /* BB find exact max data count below from sess structure BB */
2440 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2441 pSMB->t2.MaxSetupCount = 0;
2442 pSMB->t2.Reserved = 0;
2443 pSMB->t2.Flags = 0;
2444 pSMB->t2.Timeout = 0;
2445 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002446 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2447 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002448 pSMB->t2.DataCount = 0;
2449 pSMB->t2.DataOffset = 0;
2450 pSMB->t2.SetupCount = 1;
2451 pSMB->t2.Reserved3 = 0;
2452 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002453 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002454 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2455 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2456 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002457 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002458 pSMB->Fid = netfid;
2459 pSMB->hdr.smb_buf_length += byte_count;
2460 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2461
2462 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2463 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2464 if (rc) {
2465 cFYI(1, ("error %d in GetExtAttr", rc));
2466 } else {
2467 /* decode response */
2468 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2469 if (rc || (pSMBr->ByteCount < 2))
2470 /* BB also check enough total bytes returned */
2471 /* If rc should we check for EOPNOSUPP and
2472 disable the srvino flag? or in caller? */
2473 rc = -EIO; /* bad smb */
2474 else {
2475 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2476 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2477 struct file_chattr_info * pfinfo;
2478 /* BB Do we need a cast or hash here ? */
2479 if(count != 16) {
2480 cFYI(1, ("Illegal size ret in GetExtAttr"));
2481 rc = -EIO;
2482 goto GetExtAttrOut;
2483 }
2484 pfinfo = (struct file_chattr_info *)
2485 (data_offset + (char *) &pSMBr->hdr.Protocol);
2486 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2487 *pMask = le64_to_cpu(pfinfo->mask);
2488 }
2489 }
2490GetExtAttrOut:
2491 cifs_buf_release(pSMB);
2492 if (rc == -EAGAIN)
2493 goto GetExtAttrRetry;
2494 return rc;
2495}
2496
2497
2498#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499
Steve Frencheeac8042006-01-13 21:34:58 -08002500
2501/* security id for everyone */
2502const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2503/* group users */
2504const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2505
Steve French0a4b92c2006-01-12 15:44:21 -08002506/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002507static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002508{
Steve French0a4b92c2006-01-12 15:44:21 -08002509 return 0;
2510}
2511
2512/* Get Security Descriptor (by handle) from remote server for a file or dir */
2513int
2514CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2515 /* BB fix up return info */ char *acl_inf, const int buflen,
2516 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2517{
2518 int rc = 0;
2519 int buf_type = 0;
2520 QUERY_SEC_DESC_REQ * pSMB;
2521 struct kvec iov[1];
2522
2523 cFYI(1, ("GetCifsACL"));
2524
2525 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2526 8 /* parm len */, tcon, (void **) &pSMB);
2527 if (rc)
2528 return rc;
2529
2530 pSMB->MaxParameterCount = cpu_to_le32(4);
2531 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2532 pSMB->MaxSetupCount = 0;
2533 pSMB->Fid = fid; /* file handle always le */
2534 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2535 CIFS_ACL_DACL);
2536 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2537 pSMB->hdr.smb_buf_length += 11;
2538 iov[0].iov_base = (char *)pSMB;
2539 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2540
2541 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2542 cifs_stats_inc(&tcon->num_acl_get);
2543 if (rc) {
2544 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2545 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08002546 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08002547 __le32 * parm;
2548 int parm_len;
2549 int data_len;
2550 int acl_len;
2551 struct smb_com_ntransact_rsp * pSMBr;
2552
2553/* validate_nttransact */
2554 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
2555 (char **)&psec_desc,
2556 &parm_len, &data_len);
2557
2558 if(rc)
2559 goto qsec_out;
2560 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2561
2562 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
2563
2564 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2565 rc = -EIO; /* bad smb */
2566 goto qsec_out;
2567 }
2568
2569/* BB check that data area is minimum length and as big as acl_len */
2570
2571 acl_len = le32_to_cpu(*(__le32 *)parm);
2572 /* BB check if(acl_len > bufsize) */
2573
2574 parse_sec_desc(psec_desc, acl_len);
2575 }
2576qsec_out:
2577 if(buf_type == CIFS_SMALL_BUFFER)
2578 cifs_small_buf_release(iov[0].iov_base);
2579 else if(buf_type == CIFS_LARGE_BUFFER)
2580 cifs_buf_release(iov[0].iov_base);
2581 cifs_small_buf_release(pSMB);
2582 return rc;
2583}
2584
2585
Steve French6b8edfe2005-08-23 20:26:03 -07002586/* Legacy Query Path Information call for lookup to old servers such
2587 as Win9x/WinME */
2588int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2589 const unsigned char *searchName,
2590 FILE_ALL_INFO * pFinfo,
2591 const struct nls_table *nls_codepage, int remap)
2592{
2593 QUERY_INFORMATION_REQ * pSMB;
2594 QUERY_INFORMATION_RSP * pSMBr;
2595 int rc = 0;
2596 int bytes_returned;
2597 int name_len;
2598
2599 cFYI(1, ("In SMBQPath path %s", searchName));
2600QInfRetry:
2601 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2602 (void **) &pSMBr);
2603 if (rc)
2604 return rc;
2605
2606 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2607 name_len =
2608 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2609 PATH_MAX, nls_codepage, remap);
2610 name_len++; /* trailing null */
2611 name_len *= 2;
2612 } else {
2613 name_len = strnlen(searchName, PATH_MAX);
2614 name_len++; /* trailing null */
2615 strncpy(pSMB->FileName, searchName, name_len);
2616 }
2617 pSMB->BufferFormat = 0x04;
2618 name_len++; /* account for buffer type byte */
2619 pSMB->hdr.smb_buf_length += (__u16) name_len;
2620 pSMB->ByteCount = cpu_to_le16(name_len);
2621
2622 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2623 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2624 if (rc) {
2625 cFYI(1, ("Send error in QueryInfo = %d", rc));
2626 } else if (pFinfo) { /* decode response */
2627 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002628 pFinfo->AllocationSize =
2629 cpu_to_le64(le32_to_cpu(pSMBr->size));
2630 pFinfo->EndOfFile = pFinfo->AllocationSize;
2631 pFinfo->Attributes =
2632 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002633 } else
2634 rc = -EIO; /* bad buffer passed in */
2635
2636 cifs_buf_release(pSMB);
2637
2638 if (rc == -EAGAIN)
2639 goto QInfRetry;
2640
2641 return rc;
2642}
2643
2644
2645
2646
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647int
2648CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2649 const unsigned char *searchName,
2650 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002651 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652{
2653/* level 263 SMB_QUERY_FILE_ALL_INFO */
2654 TRANSACTION2_QPI_REQ *pSMB = NULL;
2655 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2656 int rc = 0;
2657 int bytes_returned;
2658 int name_len;
2659 __u16 params, byte_count;
2660
2661/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2662QPathInfoRetry:
2663 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2664 (void **) &pSMBr);
2665 if (rc)
2666 return rc;
2667
2668 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2669 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002670 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002671 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 name_len++; /* trailing null */
2673 name_len *= 2;
2674 } else { /* BB improve the check for buffer overruns BB */
2675 name_len = strnlen(searchName, PATH_MAX);
2676 name_len++; /* trailing null */
2677 strncpy(pSMB->FileName, searchName, name_len);
2678 }
2679
2680 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2681 pSMB->TotalDataCount = 0;
2682 pSMB->MaxParameterCount = cpu_to_le16(2);
2683 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2684 pSMB->MaxSetupCount = 0;
2685 pSMB->Reserved = 0;
2686 pSMB->Flags = 0;
2687 pSMB->Timeout = 0;
2688 pSMB->Reserved2 = 0;
2689 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2690 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2691 pSMB->DataCount = 0;
2692 pSMB->DataOffset = 0;
2693 pSMB->SetupCount = 1;
2694 pSMB->Reserved3 = 0;
2695 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2696 byte_count = params + 1 /* pad */ ;
2697 pSMB->TotalParameterCount = cpu_to_le16(params);
2698 pSMB->ParameterCount = pSMB->TotalParameterCount;
2699 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2700 pSMB->Reserved4 = 0;
2701 pSMB->hdr.smb_buf_length += byte_count;
2702 pSMB->ByteCount = cpu_to_le16(byte_count);
2703
2704 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2705 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2706 if (rc) {
2707 cFYI(1, ("Send error in QPathInfo = %d", rc));
2708 } else { /* decode response */
2709 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2710
2711 if (rc || (pSMBr->ByteCount < 40))
2712 rc = -EIO; /* bad smb */
2713 else if (pFindData){
2714 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2715 memcpy((char *) pFindData,
2716 (char *) &pSMBr->hdr.Protocol +
2717 data_offset, sizeof (FILE_ALL_INFO));
2718 } else
2719 rc = -ENOMEM;
2720 }
2721 cifs_buf_release(pSMB);
2722 if (rc == -EAGAIN)
2723 goto QPathInfoRetry;
2724
2725 return rc;
2726}
2727
2728int
2729CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2730 const unsigned char *searchName,
2731 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002732 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733{
2734/* SMB_QUERY_FILE_UNIX_BASIC */
2735 TRANSACTION2_QPI_REQ *pSMB = NULL;
2736 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2737 int rc = 0;
2738 int bytes_returned = 0;
2739 int name_len;
2740 __u16 params, byte_count;
2741
2742 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2743UnixQPathInfoRetry:
2744 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2745 (void **) &pSMBr);
2746 if (rc)
2747 return rc;
2748
2749 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2750 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002751 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002752 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 name_len++; /* trailing null */
2754 name_len *= 2;
2755 } else { /* BB improve the check for buffer overruns BB */
2756 name_len = strnlen(searchName, PATH_MAX);
2757 name_len++; /* trailing null */
2758 strncpy(pSMB->FileName, searchName, name_len);
2759 }
2760
2761 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2762 pSMB->TotalDataCount = 0;
2763 pSMB->MaxParameterCount = cpu_to_le16(2);
2764 /* BB find exact max SMB PDU from sess structure BB */
2765 pSMB->MaxDataCount = cpu_to_le16(4000);
2766 pSMB->MaxSetupCount = 0;
2767 pSMB->Reserved = 0;
2768 pSMB->Flags = 0;
2769 pSMB->Timeout = 0;
2770 pSMB->Reserved2 = 0;
2771 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2772 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2773 pSMB->DataCount = 0;
2774 pSMB->DataOffset = 0;
2775 pSMB->SetupCount = 1;
2776 pSMB->Reserved3 = 0;
2777 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2778 byte_count = params + 1 /* pad */ ;
2779 pSMB->TotalParameterCount = cpu_to_le16(params);
2780 pSMB->ParameterCount = pSMB->TotalParameterCount;
2781 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2782 pSMB->Reserved4 = 0;
2783 pSMB->hdr.smb_buf_length += byte_count;
2784 pSMB->ByteCount = cpu_to_le16(byte_count);
2785
2786 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2787 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2788 if (rc) {
2789 cFYI(1, ("Send error in QPathInfo = %d", rc));
2790 } else { /* decode response */
2791 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2792
2793 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2794 rc = -EIO; /* bad smb */
2795 } else {
2796 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2797 memcpy((char *) pFindData,
2798 (char *) &pSMBr->hdr.Protocol +
2799 data_offset,
2800 sizeof (FILE_UNIX_BASIC_INFO));
2801 }
2802 }
2803 cifs_buf_release(pSMB);
2804 if (rc == -EAGAIN)
2805 goto UnixQPathInfoRetry;
2806
2807 return rc;
2808}
2809
2810#if 0 /* function unused at present */
2811int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2812 const char *searchName, FILE_ALL_INFO * findData,
2813 const struct nls_table *nls_codepage)
2814{
2815/* level 257 SMB_ */
2816 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2817 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2818 int rc = 0;
2819 int bytes_returned;
2820 int name_len;
2821 __u16 params, byte_count;
2822
2823 cFYI(1, ("In FindUnique"));
2824findUniqueRetry:
2825 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2826 (void **) &pSMBr);
2827 if (rc)
2828 return rc;
2829
2830 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2831 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002832 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002833 /* find define for this maxpathcomponent */
2834 , nls_codepage);
2835 name_len++; /* trailing null */
2836 name_len *= 2;
2837 } else { /* BB improve the check for buffer overruns BB */
2838 name_len = strnlen(searchName, PATH_MAX);
2839 name_len++; /* trailing null */
2840 strncpy(pSMB->FileName, searchName, name_len);
2841 }
2842
2843 params = 12 + name_len /* includes null */ ;
2844 pSMB->TotalDataCount = 0; /* no EAs */
2845 pSMB->MaxParameterCount = cpu_to_le16(2);
2846 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2847 pSMB->MaxSetupCount = 0;
2848 pSMB->Reserved = 0;
2849 pSMB->Flags = 0;
2850 pSMB->Timeout = 0;
2851 pSMB->Reserved2 = 0;
2852 pSMB->ParameterOffset = cpu_to_le16(
2853 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2854 pSMB->DataCount = 0;
2855 pSMB->DataOffset = 0;
2856 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2857 pSMB->Reserved3 = 0;
2858 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2859 byte_count = params + 1 /* pad */ ;
2860 pSMB->TotalParameterCount = cpu_to_le16(params);
2861 pSMB->ParameterCount = pSMB->TotalParameterCount;
2862 pSMB->SearchAttributes =
2863 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2864 ATTR_DIRECTORY);
2865 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2866 pSMB->SearchFlags = cpu_to_le16(1);
2867 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2868 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2869 pSMB->hdr.smb_buf_length += byte_count;
2870 pSMB->ByteCount = cpu_to_le16(byte_count);
2871
2872 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2873 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2874
2875 if (rc) {
2876 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2877 } else { /* decode response */
Steve Frencha45443472005-08-24 13:59:35 -07002878 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 /* BB fill in */
2880 }
2881
2882 cifs_buf_release(pSMB);
2883 if (rc == -EAGAIN)
2884 goto findUniqueRetry;
2885
2886 return rc;
2887}
2888#endif /* end unused (temporarily) function */
2889
2890/* xid, tcon, searchName and codepage are input parms, rest are returned */
2891int
2892CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2893 const char *searchName,
2894 const struct nls_table *nls_codepage,
2895 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07002896 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897{
2898/* level 257 SMB_ */
2899 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2900 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2901 T2_FFIRST_RSP_PARMS * parms;
2902 int rc = 0;
2903 int bytes_returned = 0;
2904 int name_len;
2905 __u16 params, byte_count;
2906
Steve French737b7582005-04-28 22:41:06 -07002907 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908
2909findFirstRetry:
2910 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2911 (void **) &pSMBr);
2912 if (rc)
2913 return rc;
2914
2915 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2916 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002917 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07002918 PATH_MAX, nls_codepage, remap);
2919 /* We can not add the asterik earlier in case
2920 it got remapped to 0xF03A as if it were part of the
2921 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07002923 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07002924 pSMB->FileName[name_len+1] = 0;
2925 pSMB->FileName[name_len+2] = '*';
2926 pSMB->FileName[name_len+3] = 0;
2927 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2929 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07002930 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 } else { /* BB add check for overrun of SMB buf BB */
2932 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933/* BB fix here and in unicode clause above ie
2934 if(name_len > buffersize-header)
2935 free buffer exit; BB */
2936 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07002937 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07002938 pSMB->FileName[name_len+1] = '*';
2939 pSMB->FileName[name_len+2] = 0;
2940 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002941 }
2942
2943 params = 12 + name_len /* includes null */ ;
2944 pSMB->TotalDataCount = 0; /* no EAs */
2945 pSMB->MaxParameterCount = cpu_to_le16(10);
2946 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2947 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2948 pSMB->MaxSetupCount = 0;
2949 pSMB->Reserved = 0;
2950 pSMB->Flags = 0;
2951 pSMB->Timeout = 0;
2952 pSMB->Reserved2 = 0;
2953 byte_count = params + 1 /* pad */ ;
2954 pSMB->TotalParameterCount = cpu_to_le16(params);
2955 pSMB->ParameterCount = pSMB->TotalParameterCount;
2956 pSMB->ParameterOffset = cpu_to_le16(
2957 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2958 pSMB->DataCount = 0;
2959 pSMB->DataOffset = 0;
2960 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2961 pSMB->Reserved3 = 0;
2962 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2963 pSMB->SearchAttributes =
2964 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2965 ATTR_DIRECTORY);
2966 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2967 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2968 CIFS_SEARCH_RETURN_RESUME);
2969 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2970
2971 /* BB what should we set StorageType to? Does it matter? BB */
2972 pSMB->SearchStorageType = 0;
2973 pSMB->hdr.smb_buf_length += byte_count;
2974 pSMB->ByteCount = cpu_to_le16(byte_count);
2975
2976 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2977 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002978 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979
Steve French1982c342005-08-17 12:38:22 -07002980 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 /* BB Add code to handle unsupported level rc */
2982 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07002983
2984 if (pSMB)
2985 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002986
2987 /* BB eventually could optimize out free and realloc of buf */
2988 /* for this case */
2989 if (rc == -EAGAIN)
2990 goto findFirstRetry;
2991 } else { /* decode response */
2992 /* BB remember to free buffer if error BB */
2993 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2994 if(rc == 0) {
2995 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2996 psrch_inf->unicode = TRUE;
2997 else
2998 psrch_inf->unicode = FALSE;
2999
3000 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
3001 psrch_inf->srch_entries_start =
3002 (char *) &pSMBr->hdr.Protocol +
3003 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3005 le16_to_cpu(pSMBr->t2.ParameterOffset));
3006
3007 if(parms->EndofSearch)
3008 psrch_inf->endOfSearch = TRUE;
3009 else
3010 psrch_inf->endOfSearch = FALSE;
3011
3012 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3013 psrch_inf->index_of_last_entry =
3014 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 *pnetfid = parms->SearchHandle;
3016 } else {
3017 cifs_buf_release(pSMB);
3018 }
3019 }
3020
3021 return rc;
3022}
3023
3024int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3025 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3026{
3027 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3028 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3029 T2_FNEXT_RSP_PARMS * parms;
3030 char *response_data;
3031 int rc = 0;
3032 int bytes_returned, name_len;
3033 __u16 params, byte_count;
3034
3035 cFYI(1, ("In FindNext"));
3036
3037 if(psrch_inf->endOfSearch == TRUE)
3038 return -ENOENT;
3039
3040 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3041 (void **) &pSMBr);
3042 if (rc)
3043 return rc;
3044
3045 params = 14; /* includes 2 bytes of null string, converted to LE below */
3046 byte_count = 0;
3047 pSMB->TotalDataCount = 0; /* no EAs */
3048 pSMB->MaxParameterCount = cpu_to_le16(8);
3049 pSMB->MaxDataCount =
3050 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3051 pSMB->MaxSetupCount = 0;
3052 pSMB->Reserved = 0;
3053 pSMB->Flags = 0;
3054 pSMB->Timeout = 0;
3055 pSMB->Reserved2 = 0;
3056 pSMB->ParameterOffset = cpu_to_le16(
3057 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3058 pSMB->DataCount = 0;
3059 pSMB->DataOffset = 0;
3060 pSMB->SetupCount = 1;
3061 pSMB->Reserved3 = 0;
3062 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3063 pSMB->SearchHandle = searchHandle; /* always kept as le */
3064 pSMB->SearchCount =
3065 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3066 /* test for Unix extensions */
3067/* if (tcon->ses->capabilities & CAP_UNIX) {
3068 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3069 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3070 } else {
3071 pSMB->InformationLevel =
3072 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3073 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3074 } */
3075 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3076 pSMB->ResumeKey = psrch_inf->resume_key;
3077 pSMB->SearchFlags =
3078 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3079
3080 name_len = psrch_inf->resume_name_len;
3081 params += name_len;
3082 if(name_len < PATH_MAX) {
3083 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3084 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003085 /* 14 byte parm len above enough for 2 byte null terminator */
3086 pSMB->ResumeFileName[name_len] = 0;
3087 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 } else {
3089 rc = -EINVAL;
3090 goto FNext2_err_exit;
3091 }
3092 byte_count = params + 1 /* pad */ ;
3093 pSMB->TotalParameterCount = cpu_to_le16(params);
3094 pSMB->ParameterCount = pSMB->TotalParameterCount;
3095 pSMB->hdr.smb_buf_length += byte_count;
3096 pSMB->ByteCount = cpu_to_le16(byte_count);
3097
3098 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3099 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07003100 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 if (rc) {
3102 if (rc == -EBADF) {
3103 psrch_inf->endOfSearch = TRUE;
3104 rc = 0; /* search probably was closed at end of search above */
3105 } else
3106 cFYI(1, ("FindNext returned = %d", rc));
3107 } else { /* decode response */
3108 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3109
3110 if(rc == 0) {
3111 /* BB fixme add lock for file (srch_info) struct here */
3112 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3113 psrch_inf->unicode = TRUE;
3114 else
3115 psrch_inf->unicode = FALSE;
3116 response_data = (char *) &pSMBr->hdr.Protocol +
3117 le16_to_cpu(pSMBr->t2.ParameterOffset);
3118 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3119 response_data = (char *)&pSMBr->hdr.Protocol +
3120 le16_to_cpu(pSMBr->t2.DataOffset);
3121 cifs_buf_release(psrch_inf->ntwrk_buf_start);
3122 psrch_inf->srch_entries_start = response_data;
3123 psrch_inf->ntwrk_buf_start = (char *)pSMB;
3124 if(parms->EndofSearch)
3125 psrch_inf->endOfSearch = TRUE;
3126 else
3127 psrch_inf->endOfSearch = FALSE;
3128
3129 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3130 psrch_inf->index_of_last_entry +=
3131 psrch_inf->entries_in_buffer;
3132/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3133
3134 /* BB fixme add unlock here */
3135 }
3136
3137 }
3138
3139 /* BB On error, should we leave previous search buf (and count and
3140 last entry fields) intact or free the previous one? */
3141
3142 /* Note: On -EAGAIN error only caller can retry on handle based calls
3143 since file handle passed in no longer valid */
3144FNext2_err_exit:
3145 if (rc != 0)
3146 cifs_buf_release(pSMB);
3147
3148 return rc;
3149}
3150
3151int
3152CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3153{
3154 int rc = 0;
3155 FINDCLOSE_REQ *pSMB = NULL;
3156 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3157 int bytes_returned;
3158
3159 cFYI(1, ("In CIFSSMBFindClose"));
3160 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3161
3162 /* no sense returning error if session restarted
3163 as file handle has been closed */
3164 if(rc == -EAGAIN)
3165 return 0;
3166 if (rc)
3167 return rc;
3168
3169 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3170 pSMB->FileID = searchHandle;
3171 pSMB->ByteCount = 0;
3172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3173 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3174 if (rc) {
3175 cERROR(1, ("Send error in FindClose = %d", rc));
3176 }
Steve Frencha45443472005-08-24 13:59:35 -07003177 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178 cifs_small_buf_release(pSMB);
3179
3180 /* Since session is dead, search handle closed on server already */
3181 if (rc == -EAGAIN)
3182 rc = 0;
3183
3184 return rc;
3185}
3186
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187int
3188CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3189 const unsigned char *searchName,
3190 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003191 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192{
3193 int rc = 0;
3194 TRANSACTION2_QPI_REQ *pSMB = NULL;
3195 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3196 int name_len, bytes_returned;
3197 __u16 params, byte_count;
3198
3199 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3200 if(tcon == NULL)
3201 return -ENODEV;
3202
3203GetInodeNumberRetry:
3204 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3205 (void **) &pSMBr);
3206 if (rc)
3207 return rc;
3208
3209
3210 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3211 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003212 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003213 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003214 name_len++; /* trailing null */
3215 name_len *= 2;
3216 } else { /* BB improve the check for buffer overruns BB */
3217 name_len = strnlen(searchName, PATH_MAX);
3218 name_len++; /* trailing null */
3219 strncpy(pSMB->FileName, searchName, name_len);
3220 }
3221
3222 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3223 pSMB->TotalDataCount = 0;
3224 pSMB->MaxParameterCount = cpu_to_le16(2);
3225 /* BB find exact max data count below from sess structure BB */
3226 pSMB->MaxDataCount = cpu_to_le16(4000);
3227 pSMB->MaxSetupCount = 0;
3228 pSMB->Reserved = 0;
3229 pSMB->Flags = 0;
3230 pSMB->Timeout = 0;
3231 pSMB->Reserved2 = 0;
3232 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3233 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3234 pSMB->DataCount = 0;
3235 pSMB->DataOffset = 0;
3236 pSMB->SetupCount = 1;
3237 pSMB->Reserved3 = 0;
3238 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3239 byte_count = params + 1 /* pad */ ;
3240 pSMB->TotalParameterCount = cpu_to_le16(params);
3241 pSMB->ParameterCount = pSMB->TotalParameterCount;
3242 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3243 pSMB->Reserved4 = 0;
3244 pSMB->hdr.smb_buf_length += byte_count;
3245 pSMB->ByteCount = cpu_to_le16(byte_count);
3246
3247 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3248 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3249 if (rc) {
3250 cFYI(1, ("error %d in QueryInternalInfo", rc));
3251 } else {
3252 /* decode response */
3253 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3254 if (rc || (pSMBr->ByteCount < 2))
3255 /* BB also check enough total bytes returned */
3256 /* If rc should we check for EOPNOSUPP and
3257 disable the srvino flag? or in caller? */
3258 rc = -EIO; /* bad smb */
3259 else {
3260 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3261 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3262 struct file_internal_info * pfinfo;
3263 /* BB Do we need a cast or hash here ? */
3264 if(count < 8) {
3265 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3266 rc = -EIO;
3267 goto GetInodeNumOut;
3268 }
3269 pfinfo = (struct file_internal_info *)
3270 (data_offset + (char *) &pSMBr->hdr.Protocol);
3271 *inode_number = pfinfo->UniqueId;
3272 }
3273 }
3274GetInodeNumOut:
3275 cifs_buf_release(pSMB);
3276 if (rc == -EAGAIN)
3277 goto GetInodeNumberRetry;
3278 return rc;
3279}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280
3281int
3282CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3283 const unsigned char *searchName,
3284 unsigned char **targetUNCs,
3285 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003286 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287{
3288/* TRANS2_GET_DFS_REFERRAL */
3289 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3290 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3291 struct dfs_referral_level_3 * referrals = NULL;
3292 int rc = 0;
3293 int bytes_returned;
3294 int name_len;
3295 unsigned int i;
3296 char * temp;
3297 __u16 params, byte_count;
3298 *number_of_UNC_in_array = 0;
3299 *targetUNCs = NULL;
3300
3301 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3302 if (ses == NULL)
3303 return -ENODEV;
3304getDFSRetry:
3305 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3306 (void **) &pSMBr);
3307 if (rc)
3308 return rc;
Steve French1982c342005-08-17 12:38:22 -07003309
3310 /* server pointer checked in called function,
3311 but should never be null here anyway */
3312 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 pSMB->hdr.Tid = ses->ipc_tid;
3314 pSMB->hdr.Uid = ses->Suid;
3315 if (ses->capabilities & CAP_STATUS32) {
3316 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3317 }
3318 if (ses->capabilities & CAP_DFS) {
3319 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3320 }
3321
3322 if (ses->capabilities & CAP_UNICODE) {
3323 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3324 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003325 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003326 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003327 name_len++; /* trailing null */
3328 name_len *= 2;
3329 } else { /* BB improve the check for buffer overruns BB */
3330 name_len = strnlen(searchName, PATH_MAX);
3331 name_len++; /* trailing null */
3332 strncpy(pSMB->RequestFileName, searchName, name_len);
3333 }
3334
3335 params = 2 /* level */ + name_len /*includes null */ ;
3336 pSMB->TotalDataCount = 0;
3337 pSMB->DataCount = 0;
3338 pSMB->DataOffset = 0;
3339 pSMB->MaxParameterCount = 0;
3340 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3341 pSMB->MaxSetupCount = 0;
3342 pSMB->Reserved = 0;
3343 pSMB->Flags = 0;
3344 pSMB->Timeout = 0;
3345 pSMB->Reserved2 = 0;
3346 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3347 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3348 pSMB->SetupCount = 1;
3349 pSMB->Reserved3 = 0;
3350 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3351 byte_count = params + 3 /* pad */ ;
3352 pSMB->ParameterCount = cpu_to_le16(params);
3353 pSMB->TotalParameterCount = pSMB->ParameterCount;
3354 pSMB->MaxReferralLevel = cpu_to_le16(3);
3355 pSMB->hdr.smb_buf_length += byte_count;
3356 pSMB->ByteCount = cpu_to_le16(byte_count);
3357
3358 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3359 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3360 if (rc) {
3361 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3362 } else { /* decode response */
3363/* BB Add logic to parse referrals here */
3364 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3365
3366 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3367 rc = -EIO; /* bad smb */
3368 else {
3369 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3370 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3371
3372 cFYI(1,
3373 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3374 pSMBr->ByteCount, data_offset));
3375 referrals =
3376 (struct dfs_referral_level_3 *)
3377 (8 /* sizeof start of data block */ +
3378 data_offset +
3379 (char *) &pSMBr->hdr.Protocol);
3380 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",
3381 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)));
3382 /* BB This field is actually two bytes in from start of
3383 data block so we could do safety check that DataBlock
3384 begins at address of pSMBr->NumberOfReferrals */
3385 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3386
3387 /* BB Fix below so can return more than one referral */
3388 if(*number_of_UNC_in_array > 1)
3389 *number_of_UNC_in_array = 1;
3390
3391 /* get the length of the strings describing refs */
3392 name_len = 0;
3393 for(i=0;i<*number_of_UNC_in_array;i++) {
3394 /* make sure that DfsPathOffset not past end */
3395 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3396 if (offset > data_count) {
3397 /* if invalid referral, stop here and do
3398 not try to copy any more */
3399 *number_of_UNC_in_array = i;
3400 break;
3401 }
3402 temp = ((char *)referrals) + offset;
3403
3404 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3405 name_len += UniStrnlen((wchar_t *)temp,data_count);
3406 } else {
3407 name_len += strnlen(temp,data_count);
3408 }
3409 referrals++;
3410 /* BB add check that referral pointer does not fall off end PDU */
3411
3412 }
3413 /* BB add check for name_len bigger than bcc */
3414 *targetUNCs =
3415 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3416 if(*targetUNCs == NULL) {
3417 rc = -ENOMEM;
3418 goto GetDFSRefExit;
3419 }
3420 /* copy the ref strings */
3421 referrals =
3422 (struct dfs_referral_level_3 *)
3423 (8 /* sizeof data hdr */ +
3424 data_offset +
3425 (char *) &pSMBr->hdr.Protocol);
3426
3427 for(i=0;i<*number_of_UNC_in_array;i++) {
3428 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3429 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3430 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003431 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 } else {
3433 strncpy(*targetUNCs,temp,name_len);
3434 }
3435 /* BB update target_uncs pointers */
3436 referrals++;
3437 }
3438 temp = *targetUNCs;
3439 temp[name_len] = 0;
3440 }
3441
3442 }
3443GetDFSRefExit:
3444 if (pSMB)
3445 cifs_buf_release(pSMB);
3446
3447 if (rc == -EAGAIN)
3448 goto getDFSRetry;
3449
3450 return rc;
3451}
3452
Steve French20962432005-09-21 22:05:57 -07003453/* Query File System Info such as free space to old servers such as Win 9x */
3454int
3455SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3456{
3457/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3458 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3459 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3460 FILE_SYSTEM_ALLOC_INFO *response_data;
3461 int rc = 0;
3462 int bytes_returned = 0;
3463 __u16 params, byte_count;
3464
3465 cFYI(1, ("OldQFSInfo"));
3466oldQFSInfoRetry:
3467 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3468 (void **) &pSMBr);
3469 if (rc)
3470 return rc;
3471 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3472 (void **) &pSMBr);
3473 if (rc)
3474 return rc;
3475
3476 params = 2; /* level */
3477 pSMB->TotalDataCount = 0;
3478 pSMB->MaxParameterCount = cpu_to_le16(2);
3479 pSMB->MaxDataCount = cpu_to_le16(1000);
3480 pSMB->MaxSetupCount = 0;
3481 pSMB->Reserved = 0;
3482 pSMB->Flags = 0;
3483 pSMB->Timeout = 0;
3484 pSMB->Reserved2 = 0;
3485 byte_count = params + 1 /* pad */ ;
3486 pSMB->TotalParameterCount = cpu_to_le16(params);
3487 pSMB->ParameterCount = pSMB->TotalParameterCount;
3488 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3489 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3490 pSMB->DataCount = 0;
3491 pSMB->DataOffset = 0;
3492 pSMB->SetupCount = 1;
3493 pSMB->Reserved3 = 0;
3494 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3495 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3496 pSMB->hdr.smb_buf_length += byte_count;
3497 pSMB->ByteCount = cpu_to_le16(byte_count);
3498
3499 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3500 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3501 if (rc) {
3502 cFYI(1, ("Send error in QFSInfo = %d", rc));
3503 } else { /* decode response */
3504 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3505
3506 if (rc || (pSMBr->ByteCount < 18))
3507 rc = -EIO; /* bad smb */
3508 else {
3509 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3510 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3511 pSMBr->ByteCount, data_offset));
3512
3513 response_data =
3514 (FILE_SYSTEM_ALLOC_INFO *)
3515 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3516 FSData->f_bsize =
3517 le16_to_cpu(response_data->BytesPerSector) *
3518 le32_to_cpu(response_data->
3519 SectorsPerAllocationUnit);
3520 FSData->f_blocks =
3521 le32_to_cpu(response_data->TotalAllocationUnits);
3522 FSData->f_bfree = FSData->f_bavail =
3523 le32_to_cpu(response_data->FreeAllocationUnits);
3524 cFYI(1,
3525 ("Blocks: %lld Free: %lld Block size %ld",
3526 (unsigned long long)FSData->f_blocks,
3527 (unsigned long long)FSData->f_bfree,
3528 FSData->f_bsize));
3529 }
3530 }
3531 cifs_buf_release(pSMB);
3532
3533 if (rc == -EAGAIN)
3534 goto oldQFSInfoRetry;
3535
3536 return rc;
3537}
3538
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539int
Steve French737b7582005-04-28 22:41:06 -07003540CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541{
3542/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3543 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3544 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3545 FILE_SYSTEM_INFO *response_data;
3546 int rc = 0;
3547 int bytes_returned = 0;
3548 __u16 params, byte_count;
3549
3550 cFYI(1, ("In QFSInfo"));
3551QFSInfoRetry:
3552 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3553 (void **) &pSMBr);
3554 if (rc)
3555 return rc;
3556
3557 params = 2; /* level */
3558 pSMB->TotalDataCount = 0;
3559 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003560 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561 pSMB->MaxSetupCount = 0;
3562 pSMB->Reserved = 0;
3563 pSMB->Flags = 0;
3564 pSMB->Timeout = 0;
3565 pSMB->Reserved2 = 0;
3566 byte_count = params + 1 /* pad */ ;
3567 pSMB->TotalParameterCount = cpu_to_le16(params);
3568 pSMB->ParameterCount = pSMB->TotalParameterCount;
3569 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3570 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3571 pSMB->DataCount = 0;
3572 pSMB->DataOffset = 0;
3573 pSMB->SetupCount = 1;
3574 pSMB->Reserved3 = 0;
3575 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3576 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3577 pSMB->hdr.smb_buf_length += byte_count;
3578 pSMB->ByteCount = cpu_to_le16(byte_count);
3579
3580 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3581 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3582 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003583 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584 } else { /* decode response */
3585 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3586
Steve French20962432005-09-21 22:05:57 -07003587 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 rc = -EIO; /* bad smb */
3589 else {
3590 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591
3592 response_data =
3593 (FILE_SYSTEM_INFO
3594 *) (((char *) &pSMBr->hdr.Protocol) +
3595 data_offset);
3596 FSData->f_bsize =
3597 le32_to_cpu(response_data->BytesPerSector) *
3598 le32_to_cpu(response_data->
3599 SectorsPerAllocationUnit);
3600 FSData->f_blocks =
3601 le64_to_cpu(response_data->TotalAllocationUnits);
3602 FSData->f_bfree = FSData->f_bavail =
3603 le64_to_cpu(response_data->FreeAllocationUnits);
3604 cFYI(1,
3605 ("Blocks: %lld Free: %lld Block size %ld",
3606 (unsigned long long)FSData->f_blocks,
3607 (unsigned long long)FSData->f_bfree,
3608 FSData->f_bsize));
3609 }
3610 }
3611 cifs_buf_release(pSMB);
3612
3613 if (rc == -EAGAIN)
3614 goto QFSInfoRetry;
3615
3616 return rc;
3617}
3618
3619int
Steve French737b7582005-04-28 22:41:06 -07003620CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621{
3622/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3623 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3624 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3625 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3626 int rc = 0;
3627 int bytes_returned = 0;
3628 __u16 params, byte_count;
3629
3630 cFYI(1, ("In QFSAttributeInfo"));
3631QFSAttributeRetry:
3632 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3633 (void **) &pSMBr);
3634 if (rc)
3635 return rc;
3636
3637 params = 2; /* level */
3638 pSMB->TotalDataCount = 0;
3639 pSMB->MaxParameterCount = cpu_to_le16(2);
3640 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3641 pSMB->MaxSetupCount = 0;
3642 pSMB->Reserved = 0;
3643 pSMB->Flags = 0;
3644 pSMB->Timeout = 0;
3645 pSMB->Reserved2 = 0;
3646 byte_count = params + 1 /* pad */ ;
3647 pSMB->TotalParameterCount = cpu_to_le16(params);
3648 pSMB->ParameterCount = pSMB->TotalParameterCount;
3649 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3650 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3651 pSMB->DataCount = 0;
3652 pSMB->DataOffset = 0;
3653 pSMB->SetupCount = 1;
3654 pSMB->Reserved3 = 0;
3655 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3656 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3657 pSMB->hdr.smb_buf_length += byte_count;
3658 pSMB->ByteCount = cpu_to_le16(byte_count);
3659
3660 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3661 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3662 if (rc) {
3663 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3664 } else { /* decode response */
3665 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3666
3667 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3668 rc = -EIO; /* bad smb */
3669 } else {
3670 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3671 response_data =
3672 (FILE_SYSTEM_ATTRIBUTE_INFO
3673 *) (((char *) &pSMBr->hdr.Protocol) +
3674 data_offset);
3675 memcpy(&tcon->fsAttrInfo, response_data,
3676 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3677 }
3678 }
3679 cifs_buf_release(pSMB);
3680
3681 if (rc == -EAGAIN)
3682 goto QFSAttributeRetry;
3683
3684 return rc;
3685}
3686
3687int
Steve French737b7582005-04-28 22:41:06 -07003688CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689{
3690/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3691 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3692 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3693 FILE_SYSTEM_DEVICE_INFO *response_data;
3694 int rc = 0;
3695 int bytes_returned = 0;
3696 __u16 params, byte_count;
3697
3698 cFYI(1, ("In QFSDeviceInfo"));
3699QFSDeviceRetry:
3700 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3701 (void **) &pSMBr);
3702 if (rc)
3703 return rc;
3704
3705 params = 2; /* level */
3706 pSMB->TotalDataCount = 0;
3707 pSMB->MaxParameterCount = cpu_to_le16(2);
3708 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3709 pSMB->MaxSetupCount = 0;
3710 pSMB->Reserved = 0;
3711 pSMB->Flags = 0;
3712 pSMB->Timeout = 0;
3713 pSMB->Reserved2 = 0;
3714 byte_count = params + 1 /* pad */ ;
3715 pSMB->TotalParameterCount = cpu_to_le16(params);
3716 pSMB->ParameterCount = pSMB->TotalParameterCount;
3717 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3718 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3719
3720 pSMB->DataCount = 0;
3721 pSMB->DataOffset = 0;
3722 pSMB->SetupCount = 1;
3723 pSMB->Reserved3 = 0;
3724 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3725 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3726 pSMB->hdr.smb_buf_length += byte_count;
3727 pSMB->ByteCount = cpu_to_le16(byte_count);
3728
3729 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3730 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3731 if (rc) {
3732 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3733 } else { /* decode response */
3734 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3735
3736 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3737 rc = -EIO; /* bad smb */
3738 else {
3739 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3740 response_data =
Steve French737b7582005-04-28 22:41:06 -07003741 (FILE_SYSTEM_DEVICE_INFO *)
3742 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003743 data_offset);
3744 memcpy(&tcon->fsDevInfo, response_data,
3745 sizeof (FILE_SYSTEM_DEVICE_INFO));
3746 }
3747 }
3748 cifs_buf_release(pSMB);
3749
3750 if (rc == -EAGAIN)
3751 goto QFSDeviceRetry;
3752
3753 return rc;
3754}
3755
3756int
Steve French737b7582005-04-28 22:41:06 -07003757CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003758{
3759/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3760 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3761 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3762 FILE_SYSTEM_UNIX_INFO *response_data;
3763 int rc = 0;
3764 int bytes_returned = 0;
3765 __u16 params, byte_count;
3766
3767 cFYI(1, ("In QFSUnixInfo"));
3768QFSUnixRetry:
3769 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3770 (void **) &pSMBr);
3771 if (rc)
3772 return rc;
3773
3774 params = 2; /* level */
3775 pSMB->TotalDataCount = 0;
3776 pSMB->DataCount = 0;
3777 pSMB->DataOffset = 0;
3778 pSMB->MaxParameterCount = cpu_to_le16(2);
3779 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3780 pSMB->MaxSetupCount = 0;
3781 pSMB->Reserved = 0;
3782 pSMB->Flags = 0;
3783 pSMB->Timeout = 0;
3784 pSMB->Reserved2 = 0;
3785 byte_count = params + 1 /* pad */ ;
3786 pSMB->ParameterCount = cpu_to_le16(params);
3787 pSMB->TotalParameterCount = pSMB->ParameterCount;
3788 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3789 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3790 pSMB->SetupCount = 1;
3791 pSMB->Reserved3 = 0;
3792 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3793 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3794 pSMB->hdr.smb_buf_length += byte_count;
3795 pSMB->ByteCount = cpu_to_le16(byte_count);
3796
3797 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3798 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3799 if (rc) {
3800 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3801 } else { /* decode response */
3802 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3803
3804 if (rc || (pSMBr->ByteCount < 13)) {
3805 rc = -EIO; /* bad smb */
3806 } else {
3807 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3808 response_data =
3809 (FILE_SYSTEM_UNIX_INFO
3810 *) (((char *) &pSMBr->hdr.Protocol) +
3811 data_offset);
3812 memcpy(&tcon->fsUnixInfo, response_data,
3813 sizeof (FILE_SYSTEM_UNIX_INFO));
3814 }
3815 }
3816 cifs_buf_release(pSMB);
3817
3818 if (rc == -EAGAIN)
3819 goto QFSUnixRetry;
3820
3821
3822 return rc;
3823}
3824
Jeremy Allisonac670552005-06-22 17:26:35 -07003825int
Steve French45abc6e2005-06-23 13:42:03 -05003826CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07003827{
3828/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3829 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3830 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3831 int rc = 0;
3832 int bytes_returned = 0;
3833 __u16 params, param_offset, offset, byte_count;
3834
3835 cFYI(1, ("In SETFSUnixInfo"));
3836SETFSUnixRetry:
3837 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3838 (void **) &pSMBr);
3839 if (rc)
3840 return rc;
3841
3842 params = 4; /* 2 bytes zero followed by info level. */
3843 pSMB->MaxSetupCount = 0;
3844 pSMB->Reserved = 0;
3845 pSMB->Flags = 0;
3846 pSMB->Timeout = 0;
3847 pSMB->Reserved2 = 0;
3848 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3849 offset = param_offset + params;
3850
3851 pSMB->MaxParameterCount = cpu_to_le16(4);
3852 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3853 pSMB->SetupCount = 1;
3854 pSMB->Reserved3 = 0;
3855 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3856 byte_count = 1 /* pad */ + params + 12;
3857
3858 pSMB->DataCount = cpu_to_le16(12);
3859 pSMB->ParameterCount = cpu_to_le16(params);
3860 pSMB->TotalDataCount = pSMB->DataCount;
3861 pSMB->TotalParameterCount = pSMB->ParameterCount;
3862 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3863 pSMB->DataOffset = cpu_to_le16(offset);
3864
3865 /* Params. */
3866 pSMB->FileNum = 0;
3867 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3868
3869 /* Data. */
3870 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3871 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3872 pSMB->ClientUnixCap = cpu_to_le64(cap);
3873
3874 pSMB->hdr.smb_buf_length += byte_count;
3875 pSMB->ByteCount = cpu_to_le16(byte_count);
3876
3877 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3878 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3879 if (rc) {
3880 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3881 } else { /* decode response */
3882 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3883 if (rc) {
3884 rc = -EIO; /* bad smb */
3885 }
3886 }
3887 cifs_buf_release(pSMB);
3888
3889 if (rc == -EAGAIN)
3890 goto SETFSUnixRetry;
3891
3892 return rc;
3893}
3894
3895
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896
3897int
3898CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003899 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900{
3901/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3902 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3903 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3904 FILE_SYSTEM_POSIX_INFO *response_data;
3905 int rc = 0;
3906 int bytes_returned = 0;
3907 __u16 params, byte_count;
3908
3909 cFYI(1, ("In QFSPosixInfo"));
3910QFSPosixRetry:
3911 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3912 (void **) &pSMBr);
3913 if (rc)
3914 return rc;
3915
3916 params = 2; /* level */
3917 pSMB->TotalDataCount = 0;
3918 pSMB->DataCount = 0;
3919 pSMB->DataOffset = 0;
3920 pSMB->MaxParameterCount = cpu_to_le16(2);
3921 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3922 pSMB->MaxSetupCount = 0;
3923 pSMB->Reserved = 0;
3924 pSMB->Flags = 0;
3925 pSMB->Timeout = 0;
3926 pSMB->Reserved2 = 0;
3927 byte_count = params + 1 /* pad */ ;
3928 pSMB->ParameterCount = cpu_to_le16(params);
3929 pSMB->TotalParameterCount = pSMB->ParameterCount;
3930 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3931 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3932 pSMB->SetupCount = 1;
3933 pSMB->Reserved3 = 0;
3934 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3935 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3936 pSMB->hdr.smb_buf_length += byte_count;
3937 pSMB->ByteCount = cpu_to_le16(byte_count);
3938
3939 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3940 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3941 if (rc) {
3942 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3943 } else { /* decode response */
3944 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3945
3946 if (rc || (pSMBr->ByteCount < 13)) {
3947 rc = -EIO; /* bad smb */
3948 } else {
3949 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3950 response_data =
3951 (FILE_SYSTEM_POSIX_INFO
3952 *) (((char *) &pSMBr->hdr.Protocol) +
3953 data_offset);
3954 FSData->f_bsize =
3955 le32_to_cpu(response_data->BlockSize);
3956 FSData->f_blocks =
3957 le64_to_cpu(response_data->TotalBlocks);
3958 FSData->f_bfree =
3959 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07003960 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 FSData->f_bavail = FSData->f_bfree;
3962 } else {
3963 FSData->f_bavail =
3964 le64_to_cpu(response_data->UserBlocksAvail);
3965 }
Steve French70ca7342005-09-22 16:32:06 -07003966 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 FSData->f_files =
3968 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07003969 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 FSData->f_ffree =
3971 le64_to_cpu(response_data->FreeFileNodes);
3972 }
3973 }
3974 cifs_buf_release(pSMB);
3975
3976 if (rc == -EAGAIN)
3977 goto QFSPosixRetry;
3978
3979 return rc;
3980}
3981
3982
3983/* We can not use write of zero bytes trick to
3984 set file size due to need for large file support. Also note that
3985 this SetPathInfo is preferred to SetFileInfo based method in next
3986 routine which is only needed to work around a sharing violation bug
3987 in Samba which this routine can run into */
3988
3989int
3990CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07003991 __u64 size, int SetAllocation,
3992 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993{
3994 struct smb_com_transaction2_spi_req *pSMB = NULL;
3995 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3996 struct file_end_of_file_info *parm_data;
3997 int name_len;
3998 int rc = 0;
3999 int bytes_returned = 0;
4000 __u16 params, byte_count, data_count, param_offset, offset;
4001
4002 cFYI(1, ("In SetEOF"));
4003SetEOFRetry:
4004 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4005 (void **) &pSMBr);
4006 if (rc)
4007 return rc;
4008
4009 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4010 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004011 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004012 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 name_len++; /* trailing null */
4014 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004015 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 name_len = strnlen(fileName, PATH_MAX);
4017 name_len++; /* trailing null */
4018 strncpy(pSMB->FileName, fileName, name_len);
4019 }
4020 params = 6 + name_len;
4021 data_count = sizeof (struct file_end_of_file_info);
4022 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004023 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 pSMB->MaxSetupCount = 0;
4025 pSMB->Reserved = 0;
4026 pSMB->Flags = 0;
4027 pSMB->Timeout = 0;
4028 pSMB->Reserved2 = 0;
4029 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4030 InformationLevel) - 4;
4031 offset = param_offset + params;
4032 if(SetAllocation) {
4033 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4034 pSMB->InformationLevel =
4035 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4036 else
4037 pSMB->InformationLevel =
4038 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4039 } else /* Set File Size */ {
4040 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4041 pSMB->InformationLevel =
4042 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4043 else
4044 pSMB->InformationLevel =
4045 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4046 }
4047
4048 parm_data =
4049 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4050 offset);
4051 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4052 pSMB->DataOffset = cpu_to_le16(offset);
4053 pSMB->SetupCount = 1;
4054 pSMB->Reserved3 = 0;
4055 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4056 byte_count = 3 /* pad */ + params + data_count;
4057 pSMB->DataCount = cpu_to_le16(data_count);
4058 pSMB->TotalDataCount = pSMB->DataCount;
4059 pSMB->ParameterCount = cpu_to_le16(params);
4060 pSMB->TotalParameterCount = pSMB->ParameterCount;
4061 pSMB->Reserved4 = 0;
4062 pSMB->hdr.smb_buf_length += byte_count;
4063 parm_data->FileSize = cpu_to_le64(size);
4064 pSMB->ByteCount = cpu_to_le16(byte_count);
4065 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4066 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4067 if (rc) {
4068 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4069 }
4070
4071 cifs_buf_release(pSMB);
4072
4073 if (rc == -EAGAIN)
4074 goto SetEOFRetry;
4075
4076 return rc;
4077}
4078
4079int
4080CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4081 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4082{
4083 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4084 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4085 char *data_offset;
4086 struct file_end_of_file_info *parm_data;
4087 int rc = 0;
4088 int bytes_returned = 0;
4089 __u16 params, param_offset, offset, byte_count, count;
4090
4091 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4092 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004093 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4094
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095 if (rc)
4096 return rc;
4097
Steve Frenchcd634992005-04-28 22:41:10 -07004098 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4099
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4101 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4102
4103 params = 6;
4104 pSMB->MaxSetupCount = 0;
4105 pSMB->Reserved = 0;
4106 pSMB->Flags = 0;
4107 pSMB->Timeout = 0;
4108 pSMB->Reserved2 = 0;
4109 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4110 offset = param_offset + params;
4111
4112 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4113
4114 count = sizeof(struct file_end_of_file_info);
4115 pSMB->MaxParameterCount = cpu_to_le16(2);
4116 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4117 pSMB->SetupCount = 1;
4118 pSMB->Reserved3 = 0;
4119 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4120 byte_count = 3 /* pad */ + params + count;
4121 pSMB->DataCount = cpu_to_le16(count);
4122 pSMB->ParameterCount = cpu_to_le16(params);
4123 pSMB->TotalDataCount = pSMB->DataCount;
4124 pSMB->TotalParameterCount = pSMB->ParameterCount;
4125 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4126 parm_data =
4127 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4128 offset);
4129 pSMB->DataOffset = cpu_to_le16(offset);
4130 parm_data->FileSize = cpu_to_le64(size);
4131 pSMB->Fid = fid;
4132 if(SetAllocation) {
4133 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4134 pSMB->InformationLevel =
4135 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4136 else
4137 pSMB->InformationLevel =
4138 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4139 } else /* Set File Size */ {
4140 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4141 pSMB->InformationLevel =
4142 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4143 else
4144 pSMB->InformationLevel =
4145 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4146 }
4147 pSMB->Reserved4 = 0;
4148 pSMB->hdr.smb_buf_length += byte_count;
4149 pSMB->ByteCount = cpu_to_le16(byte_count);
4150 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4151 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4152 if (rc) {
4153 cFYI(1,
4154 ("Send error in SetFileInfo (SetFileSize) = %d",
4155 rc));
4156 }
4157
4158 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004159 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160
4161 /* Note: On -EAGAIN error only caller can retry on handle based calls
4162 since file handle passed in no longer valid */
4163
4164 return rc;
4165}
4166
4167/* Some legacy servers such as NT4 require that the file times be set on
4168 an open handle, rather than by pathname - this is awkward due to
4169 potential access conflicts on the open, but it is unavoidable for these
4170 old servers since the only other choice is to go from 100 nanosecond DCE
4171 time and resort to the original setpathinfo level which takes the ancient
4172 DOS time format with 2 second granularity */
4173int
4174CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4175 __u16 fid)
4176{
4177 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4178 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4179 char *data_offset;
4180 int rc = 0;
4181 int bytes_returned = 0;
4182 __u16 params, param_offset, offset, byte_count, count;
4183
4184 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004185 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4186
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 if (rc)
4188 return rc;
4189
Steve Frenchcd634992005-04-28 22:41:10 -07004190 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4191
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 /* At this point there is no need to override the current pid
4193 with the pid of the opener, but that could change if we someday
4194 use an existing handle (rather than opening one on the fly) */
4195 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4196 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4197
4198 params = 6;
4199 pSMB->MaxSetupCount = 0;
4200 pSMB->Reserved = 0;
4201 pSMB->Flags = 0;
4202 pSMB->Timeout = 0;
4203 pSMB->Reserved2 = 0;
4204 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4205 offset = param_offset + params;
4206
4207 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4208
4209 count = sizeof (FILE_BASIC_INFO);
4210 pSMB->MaxParameterCount = cpu_to_le16(2);
4211 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4212 pSMB->SetupCount = 1;
4213 pSMB->Reserved3 = 0;
4214 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4215 byte_count = 3 /* pad */ + params + count;
4216 pSMB->DataCount = cpu_to_le16(count);
4217 pSMB->ParameterCount = cpu_to_le16(params);
4218 pSMB->TotalDataCount = pSMB->DataCount;
4219 pSMB->TotalParameterCount = pSMB->ParameterCount;
4220 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4221 pSMB->DataOffset = cpu_to_le16(offset);
4222 pSMB->Fid = fid;
4223 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4224 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4225 else
4226 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4227 pSMB->Reserved4 = 0;
4228 pSMB->hdr.smb_buf_length += byte_count;
4229 pSMB->ByteCount = cpu_to_le16(byte_count);
4230 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4231 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4232 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4233 if (rc) {
4234 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4235 }
4236
Steve Frenchcd634992005-04-28 22:41:10 -07004237 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238
4239 /* Note: On -EAGAIN error only caller can retry on handle based calls
4240 since file handle passed in no longer valid */
4241
4242 return rc;
4243}
4244
4245
4246int
4247CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4248 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004249 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250{
4251 TRANSACTION2_SPI_REQ *pSMB = NULL;
4252 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4253 int name_len;
4254 int rc = 0;
4255 int bytes_returned = 0;
4256 char *data_offset;
4257 __u16 params, param_offset, offset, byte_count, count;
4258
4259 cFYI(1, ("In SetTimes"));
4260
4261SetTimesRetry:
4262 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4263 (void **) &pSMBr);
4264 if (rc)
4265 return rc;
4266
4267 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4268 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004269 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004270 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271 name_len++; /* trailing null */
4272 name_len *= 2;
4273 } else { /* BB improve the check for buffer overruns BB */
4274 name_len = strnlen(fileName, PATH_MAX);
4275 name_len++; /* trailing null */
4276 strncpy(pSMB->FileName, fileName, name_len);
4277 }
4278
4279 params = 6 + name_len;
4280 count = sizeof (FILE_BASIC_INFO);
4281 pSMB->MaxParameterCount = cpu_to_le16(2);
4282 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4283 pSMB->MaxSetupCount = 0;
4284 pSMB->Reserved = 0;
4285 pSMB->Flags = 0;
4286 pSMB->Timeout = 0;
4287 pSMB->Reserved2 = 0;
4288 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4289 InformationLevel) - 4;
4290 offset = param_offset + params;
4291 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4292 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4293 pSMB->DataOffset = cpu_to_le16(offset);
4294 pSMB->SetupCount = 1;
4295 pSMB->Reserved3 = 0;
4296 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4297 byte_count = 3 /* pad */ + params + count;
4298
4299 pSMB->DataCount = cpu_to_le16(count);
4300 pSMB->ParameterCount = cpu_to_le16(params);
4301 pSMB->TotalDataCount = pSMB->DataCount;
4302 pSMB->TotalParameterCount = pSMB->ParameterCount;
4303 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4304 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4305 else
4306 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4307 pSMB->Reserved4 = 0;
4308 pSMB->hdr.smb_buf_length += byte_count;
4309 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4310 pSMB->ByteCount = cpu_to_le16(byte_count);
4311 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4312 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4313 if (rc) {
4314 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4315 }
4316
4317 cifs_buf_release(pSMB);
4318
4319 if (rc == -EAGAIN)
4320 goto SetTimesRetry;
4321
4322 return rc;
4323}
4324
4325/* Can not be used to set time stamps yet (due to old DOS time format) */
4326/* Can be used to set attributes */
4327#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4328 handling it anyway and NT4 was what we thought it would be needed for
4329 Do not delete it until we prove whether needed for Win9x though */
4330int
4331CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4332 __u16 dos_attrs, const struct nls_table *nls_codepage)
4333{
4334 SETATTR_REQ *pSMB = NULL;
4335 SETATTR_RSP *pSMBr = NULL;
4336 int rc = 0;
4337 int bytes_returned;
4338 int name_len;
4339
4340 cFYI(1, ("In SetAttrLegacy"));
4341
4342SetAttrLgcyRetry:
4343 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4344 (void **) &pSMBr);
4345 if (rc)
4346 return rc;
4347
4348 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4349 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004350 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004351 PATH_MAX, nls_codepage);
4352 name_len++; /* trailing null */
4353 name_len *= 2;
4354 } else { /* BB improve the check for buffer overruns BB */
4355 name_len = strnlen(fileName, PATH_MAX);
4356 name_len++; /* trailing null */
4357 strncpy(pSMB->fileName, fileName, name_len);
4358 }
4359 pSMB->attr = cpu_to_le16(dos_attrs);
4360 pSMB->BufferFormat = 0x04;
4361 pSMB->hdr.smb_buf_length += name_len + 1;
4362 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4363 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4364 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4365 if (rc) {
4366 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4367 }
4368
4369 cifs_buf_release(pSMB);
4370
4371 if (rc == -EAGAIN)
4372 goto SetAttrLgcyRetry;
4373
4374 return rc;
4375}
4376#endif /* temporarily unneeded SetAttr legacy function */
4377
4378int
4379CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004380 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4381 dev_t device, const struct nls_table *nls_codepage,
4382 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004383{
4384 TRANSACTION2_SPI_REQ *pSMB = NULL;
4385 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4386 int name_len;
4387 int rc = 0;
4388 int bytes_returned = 0;
4389 FILE_UNIX_BASIC_INFO *data_offset;
4390 __u16 params, param_offset, offset, count, byte_count;
4391
4392 cFYI(1, ("In SetUID/GID/Mode"));
4393setPermsRetry:
4394 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4395 (void **) &pSMBr);
4396 if (rc)
4397 return rc;
4398
4399 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4400 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004401 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004402 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 name_len++; /* trailing null */
4404 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004405 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406 name_len = strnlen(fileName, PATH_MAX);
4407 name_len++; /* trailing null */
4408 strncpy(pSMB->FileName, fileName, name_len);
4409 }
4410
4411 params = 6 + name_len;
4412 count = sizeof (FILE_UNIX_BASIC_INFO);
4413 pSMB->MaxParameterCount = cpu_to_le16(2);
4414 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4415 pSMB->MaxSetupCount = 0;
4416 pSMB->Reserved = 0;
4417 pSMB->Flags = 0;
4418 pSMB->Timeout = 0;
4419 pSMB->Reserved2 = 0;
4420 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4421 InformationLevel) - 4;
4422 offset = param_offset + params;
4423 data_offset =
4424 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4425 offset);
4426 memset(data_offset, 0, count);
4427 pSMB->DataOffset = cpu_to_le16(offset);
4428 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4429 pSMB->SetupCount = 1;
4430 pSMB->Reserved3 = 0;
4431 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4432 byte_count = 3 /* pad */ + params + count;
4433 pSMB->ParameterCount = cpu_to_le16(params);
4434 pSMB->DataCount = cpu_to_le16(count);
4435 pSMB->TotalParameterCount = pSMB->ParameterCount;
4436 pSMB->TotalDataCount = pSMB->DataCount;
4437 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4438 pSMB->Reserved4 = 0;
4439 pSMB->hdr.smb_buf_length += byte_count;
4440 data_offset->Uid = cpu_to_le64(uid);
4441 data_offset->Gid = cpu_to_le64(gid);
4442 /* better to leave device as zero when it is */
4443 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4444 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4445 data_offset->Permissions = cpu_to_le64(mode);
4446
4447 if(S_ISREG(mode))
4448 data_offset->Type = cpu_to_le32(UNIX_FILE);
4449 else if(S_ISDIR(mode))
4450 data_offset->Type = cpu_to_le32(UNIX_DIR);
4451 else if(S_ISLNK(mode))
4452 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4453 else if(S_ISCHR(mode))
4454 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4455 else if(S_ISBLK(mode))
4456 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4457 else if(S_ISFIFO(mode))
4458 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4459 else if(S_ISSOCK(mode))
4460 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4461
4462
4463 pSMB->ByteCount = cpu_to_le16(byte_count);
4464 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4465 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4466 if (rc) {
4467 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4468 }
4469
4470 if (pSMB)
4471 cifs_buf_release(pSMB);
4472 if (rc == -EAGAIN)
4473 goto setPermsRetry;
4474 return rc;
4475}
4476
4477int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004478 const int notify_subdirs, const __u16 netfid,
4479 __u32 filter, struct file * pfile, int multishot,
4480 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004481{
4482 int rc = 0;
4483 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004484 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004485 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 int bytes_returned;
4487
4488 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4489 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4490 (void **) &pSMBr);
4491 if (rc)
4492 return rc;
4493
4494 pSMB->TotalParameterCount = 0 ;
4495 pSMB->TotalDataCount = 0;
4496 pSMB->MaxParameterCount = cpu_to_le32(2);
4497 /* BB find exact data count max from sess structure BB */
4498 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08004499/* BB VERIFY verify which is correct for above BB */
4500 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4501 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4502
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 pSMB->MaxSetupCount = 4;
4504 pSMB->Reserved = 0;
4505 pSMB->ParameterOffset = 0;
4506 pSMB->DataCount = 0;
4507 pSMB->DataOffset = 0;
4508 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4509 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4510 pSMB->ParameterCount = pSMB->TotalParameterCount;
4511 if(notify_subdirs)
4512 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4513 pSMB->Reserved2 = 0;
4514 pSMB->CompletionFilter = cpu_to_le32(filter);
4515 pSMB->Fid = netfid; /* file handle always le */
4516 pSMB->ByteCount = 0;
4517
4518 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4519 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4520 if (rc) {
4521 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004522 } else {
4523 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004524 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004525 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004526 sizeof(struct dir_notify_req),
4527 GFP_KERNEL);
4528 if(dnotify_req) {
4529 dnotify_req->Pid = pSMB->hdr.Pid;
4530 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4531 dnotify_req->Mid = pSMB->hdr.Mid;
4532 dnotify_req->Tid = pSMB->hdr.Tid;
4533 dnotify_req->Uid = pSMB->hdr.Uid;
4534 dnotify_req->netfid = netfid;
4535 dnotify_req->pfile = pfile;
4536 dnotify_req->filter = filter;
4537 dnotify_req->multishot = multishot;
4538 spin_lock(&GlobalMid_Lock);
4539 list_add_tail(&dnotify_req->lhead,
4540 &GlobalDnotifyReqList);
4541 spin_unlock(&GlobalMid_Lock);
4542 } else
4543 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004544 }
4545 cifs_buf_release(pSMB);
4546 return rc;
4547}
4548#ifdef CONFIG_CIFS_XATTR
4549ssize_t
4550CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4551 const unsigned char *searchName,
4552 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004553 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004554{
4555 /* BB assumes one setup word */
4556 TRANSACTION2_QPI_REQ *pSMB = NULL;
4557 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4558 int rc = 0;
4559 int bytes_returned;
4560 int name_len;
4561 struct fea * temp_fea;
4562 char * temp_ptr;
4563 __u16 params, byte_count;
4564
4565 cFYI(1, ("In Query All EAs path %s", searchName));
4566QAllEAsRetry:
4567 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4568 (void **) &pSMBr);
4569 if (rc)
4570 return rc;
4571
4572 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4573 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004574 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004575 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 name_len++; /* trailing null */
4577 name_len *= 2;
4578 } else { /* BB improve the check for buffer overruns BB */
4579 name_len = strnlen(searchName, PATH_MAX);
4580 name_len++; /* trailing null */
4581 strncpy(pSMB->FileName, searchName, name_len);
4582 }
4583
4584 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4585 pSMB->TotalDataCount = 0;
4586 pSMB->MaxParameterCount = cpu_to_le16(2);
4587 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4588 pSMB->MaxSetupCount = 0;
4589 pSMB->Reserved = 0;
4590 pSMB->Flags = 0;
4591 pSMB->Timeout = 0;
4592 pSMB->Reserved2 = 0;
4593 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4594 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4595 pSMB->DataCount = 0;
4596 pSMB->DataOffset = 0;
4597 pSMB->SetupCount = 1;
4598 pSMB->Reserved3 = 0;
4599 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4600 byte_count = params + 1 /* pad */ ;
4601 pSMB->TotalParameterCount = cpu_to_le16(params);
4602 pSMB->ParameterCount = pSMB->TotalParameterCount;
4603 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4604 pSMB->Reserved4 = 0;
4605 pSMB->hdr.smb_buf_length += byte_count;
4606 pSMB->ByteCount = cpu_to_le16(byte_count);
4607
4608 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4609 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4610 if (rc) {
4611 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4612 } else { /* decode response */
4613 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4614
4615 /* BB also check enough total bytes returned */
4616 /* BB we need to improve the validity checking
4617 of these trans2 responses */
4618 if (rc || (pSMBr->ByteCount < 4))
4619 rc = -EIO; /* bad smb */
4620 /* else if (pFindData){
4621 memcpy((char *) pFindData,
4622 (char *) &pSMBr->hdr.Protocol +
4623 data_offset, kl);
4624 }*/ else {
4625 /* check that length of list is not more than bcc */
4626 /* check that each entry does not go beyond length
4627 of list */
4628 /* check that each element of each entry does not
4629 go beyond end of list */
4630 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4631 struct fealist * ea_response_data;
4632 rc = 0;
4633 /* validate_trans2_offsets() */
4634 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4635 ea_response_data = (struct fealist *)
4636 (((char *) &pSMBr->hdr.Protocol) +
4637 data_offset);
4638 name_len = le32_to_cpu(ea_response_data->list_len);
4639 cFYI(1,("ea length %d", name_len));
4640 if(name_len <= 8) {
4641 /* returned EA size zeroed at top of function */
4642 cFYI(1,("empty EA list returned from server"));
4643 } else {
4644 /* account for ea list len */
4645 name_len -= 4;
4646 temp_fea = ea_response_data->list;
4647 temp_ptr = (char *)temp_fea;
4648 while(name_len > 0) {
4649 __u16 value_len;
4650 name_len -= 4;
4651 temp_ptr += 4;
4652 rc += temp_fea->name_len;
4653 /* account for prefix user. and trailing null */
4654 rc = rc + 5 + 1;
4655 if(rc<(int)buf_size) {
4656 memcpy(EAData,"user.",5);
4657 EAData+=5;
4658 memcpy(EAData,temp_ptr,temp_fea->name_len);
4659 EAData+=temp_fea->name_len;
4660 /* null terminate name */
4661 *EAData = 0;
4662 EAData = EAData + 1;
4663 } else if(buf_size == 0) {
4664 /* skip copy - calc size only */
4665 } else {
4666 /* stop before overrun buffer */
4667 rc = -ERANGE;
4668 break;
4669 }
4670 name_len -= temp_fea->name_len;
4671 temp_ptr += temp_fea->name_len;
4672 /* account for trailing null */
4673 name_len--;
4674 temp_ptr++;
4675 value_len = le16_to_cpu(temp_fea->value_len);
4676 name_len -= value_len;
4677 temp_ptr += value_len;
4678 /* BB check that temp_ptr is still within smb BB*/
4679 /* no trailing null to account for in value len */
4680 /* go on to next EA */
4681 temp_fea = (struct fea *)temp_ptr;
4682 }
4683 }
4684 }
4685 }
4686 if (pSMB)
4687 cifs_buf_release(pSMB);
4688 if (rc == -EAGAIN)
4689 goto QAllEAsRetry;
4690
4691 return (ssize_t)rc;
4692}
4693
4694ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4695 const unsigned char * searchName,const unsigned char * ea_name,
4696 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004697 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698{
4699 TRANSACTION2_QPI_REQ *pSMB = NULL;
4700 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4701 int rc = 0;
4702 int bytes_returned;
4703 int name_len;
4704 struct fea * temp_fea;
4705 char * temp_ptr;
4706 __u16 params, byte_count;
4707
4708 cFYI(1, ("In Query EA path %s", searchName));
4709QEARetry:
4710 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4711 (void **) &pSMBr);
4712 if (rc)
4713 return rc;
4714
4715 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4716 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004717 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004718 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004719 name_len++; /* trailing null */
4720 name_len *= 2;
4721 } else { /* BB improve the check for buffer overruns BB */
4722 name_len = strnlen(searchName, PATH_MAX);
4723 name_len++; /* trailing null */
4724 strncpy(pSMB->FileName, searchName, name_len);
4725 }
4726
4727 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4728 pSMB->TotalDataCount = 0;
4729 pSMB->MaxParameterCount = cpu_to_le16(2);
4730 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4731 pSMB->MaxSetupCount = 0;
4732 pSMB->Reserved = 0;
4733 pSMB->Flags = 0;
4734 pSMB->Timeout = 0;
4735 pSMB->Reserved2 = 0;
4736 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4737 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4738 pSMB->DataCount = 0;
4739 pSMB->DataOffset = 0;
4740 pSMB->SetupCount = 1;
4741 pSMB->Reserved3 = 0;
4742 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4743 byte_count = params + 1 /* pad */ ;
4744 pSMB->TotalParameterCount = cpu_to_le16(params);
4745 pSMB->ParameterCount = pSMB->TotalParameterCount;
4746 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4747 pSMB->Reserved4 = 0;
4748 pSMB->hdr.smb_buf_length += byte_count;
4749 pSMB->ByteCount = cpu_to_le16(byte_count);
4750
4751 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4752 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4753 if (rc) {
4754 cFYI(1, ("Send error in Query EA = %d", rc));
4755 } else { /* decode response */
4756 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4757
4758 /* BB also check enough total bytes returned */
4759 /* BB we need to improve the validity checking
4760 of these trans2 responses */
4761 if (rc || (pSMBr->ByteCount < 4))
4762 rc = -EIO; /* bad smb */
4763 /* else if (pFindData){
4764 memcpy((char *) pFindData,
4765 (char *) &pSMBr->hdr.Protocol +
4766 data_offset, kl);
4767 }*/ else {
4768 /* check that length of list is not more than bcc */
4769 /* check that each entry does not go beyond length
4770 of list */
4771 /* check that each element of each entry does not
4772 go beyond end of list */
4773 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4774 struct fealist * ea_response_data;
4775 rc = -ENODATA;
4776 /* validate_trans2_offsets() */
4777 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4778 ea_response_data = (struct fealist *)
4779 (((char *) &pSMBr->hdr.Protocol) +
4780 data_offset);
4781 name_len = le32_to_cpu(ea_response_data->list_len);
4782 cFYI(1,("ea length %d", name_len));
4783 if(name_len <= 8) {
4784 /* returned EA size zeroed at top of function */
4785 cFYI(1,("empty EA list returned from server"));
4786 } else {
4787 /* account for ea list len */
4788 name_len -= 4;
4789 temp_fea = ea_response_data->list;
4790 temp_ptr = (char *)temp_fea;
4791 /* loop through checking if we have a matching
4792 name and then return the associated value */
4793 while(name_len > 0) {
4794 __u16 value_len;
4795 name_len -= 4;
4796 temp_ptr += 4;
4797 value_len = le16_to_cpu(temp_fea->value_len);
4798 /* BB validate that value_len falls within SMB,
4799 even though maximum for name_len is 255 */
4800 if(memcmp(temp_fea->name,ea_name,
4801 temp_fea->name_len) == 0) {
4802 /* found a match */
4803 rc = value_len;
4804 /* account for prefix user. and trailing null */
4805 if(rc<=(int)buf_size) {
4806 memcpy(ea_value,
4807 temp_fea->name+temp_fea->name_len+1,
4808 rc);
4809 /* ea values, unlike ea names,
4810 are not null terminated */
4811 } else if(buf_size == 0) {
4812 /* skip copy - calc size only */
4813 } else {
4814 /* stop before overrun buffer */
4815 rc = -ERANGE;
4816 }
4817 break;
4818 }
4819 name_len -= temp_fea->name_len;
4820 temp_ptr += temp_fea->name_len;
4821 /* account for trailing null */
4822 name_len--;
4823 temp_ptr++;
4824 name_len -= value_len;
4825 temp_ptr += value_len;
4826 /* no trailing null to account for in value len */
4827 /* go on to next EA */
4828 temp_fea = (struct fea *)temp_ptr;
4829 }
4830 }
4831 }
4832 }
4833 if (pSMB)
4834 cifs_buf_release(pSMB);
4835 if (rc == -EAGAIN)
4836 goto QEARetry;
4837
4838 return (ssize_t)rc;
4839}
4840
4841int
4842CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4843 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004844 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4845 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846{
4847 struct smb_com_transaction2_spi_req *pSMB = NULL;
4848 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4849 struct fealist *parm_data;
4850 int name_len;
4851 int rc = 0;
4852 int bytes_returned = 0;
4853 __u16 params, param_offset, byte_count, offset, count;
4854
4855 cFYI(1, ("In SetEA"));
4856SetEARetry:
4857 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4858 (void **) &pSMBr);
4859 if (rc)
4860 return rc;
4861
4862 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4863 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004864 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004865 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 name_len++; /* trailing null */
4867 name_len *= 2;
4868 } else { /* BB improve the check for buffer overruns BB */
4869 name_len = strnlen(fileName, PATH_MAX);
4870 name_len++; /* trailing null */
4871 strncpy(pSMB->FileName, fileName, name_len);
4872 }
4873
4874 params = 6 + name_len;
4875
4876 /* done calculating parms using name_len of file name,
4877 now use name_len to calculate length of ea name
4878 we are going to create in the inode xattrs */
4879 if(ea_name == NULL)
4880 name_len = 0;
4881 else
4882 name_len = strnlen(ea_name,255);
4883
4884 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4885 pSMB->MaxParameterCount = cpu_to_le16(2);
4886 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4887 pSMB->MaxSetupCount = 0;
4888 pSMB->Reserved = 0;
4889 pSMB->Flags = 0;
4890 pSMB->Timeout = 0;
4891 pSMB->Reserved2 = 0;
4892 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4893 InformationLevel) - 4;
4894 offset = param_offset + params;
4895 pSMB->InformationLevel =
4896 cpu_to_le16(SMB_SET_FILE_EA);
4897
4898 parm_data =
4899 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4900 offset);
4901 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4902 pSMB->DataOffset = cpu_to_le16(offset);
4903 pSMB->SetupCount = 1;
4904 pSMB->Reserved3 = 0;
4905 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4906 byte_count = 3 /* pad */ + params + count;
4907 pSMB->DataCount = cpu_to_le16(count);
4908 parm_data->list_len = cpu_to_le32(count);
4909 parm_data->list[0].EA_flags = 0;
4910 /* we checked above that name len is less than 255 */
4911 parm_data->list[0].name_len = (__u8)name_len;;
4912 /* EA names are always ASCII */
4913 if(ea_name)
4914 strncpy(parm_data->list[0].name,ea_name,name_len);
4915 parm_data->list[0].name[name_len] = 0;
4916 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4917 /* caller ensures that ea_value_len is less than 64K but
4918 we need to ensure that it fits within the smb */
4919
4920 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4921 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4922 if(ea_value_len)
4923 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4924
4925 pSMB->TotalDataCount = pSMB->DataCount;
4926 pSMB->ParameterCount = cpu_to_le16(params);
4927 pSMB->TotalParameterCount = pSMB->ParameterCount;
4928 pSMB->Reserved4 = 0;
4929 pSMB->hdr.smb_buf_length += byte_count;
4930 pSMB->ByteCount = cpu_to_le16(byte_count);
4931 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4932 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4933 if (rc) {
4934 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4935 }
4936
4937 cifs_buf_release(pSMB);
4938
4939 if (rc == -EAGAIN)
4940 goto SetEARetry;
4941
4942 return rc;
4943}
4944
4945#endif