blob: 67a6240ff2ba8dc588dff9701498c242f412e7ae [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
4 * Copyright (C) International Business Machines Corp., 2002,2005
5 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
27 /* treated slightly different for reconnection purposes since we never want */
28 /* to reuse a stale file handle and the caller knows the file handle */
29
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
33#include <linux/posix_acl_xattr.h>
34#include <asm/uaccess.h>
35#include "cifspdu.h"
36#include "cifsglob.h"
37#include "cifsproto.h"
38#include "cifs_unicode.h"
39#include "cifs_debug.h"
40
41#ifdef CONFIG_CIFS_POSIX
42static struct {
43 int index;
44 char *name;
45} protocols[] = {
46 {CIFS_PROT, "\2NT LM 0.12"},
47 {CIFS_PROT, "\2POSIX 2"},
48 {BAD_PROT, "\2"}
49};
50#else
51static struct {
52 int index;
53 char *name;
54} protocols[] = {
55 {CIFS_PROT, "\2NT LM 0.12"},
56 {BAD_PROT, "\2"}
57};
58#endif
59
60
61/* Mark as invalid, all open files on tree connections since they
62 were closed when session to server was lost */
63static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
64{
65 struct cifsFileInfo *open_file = NULL;
66 struct list_head * tmp;
67 struct list_head * tmp1;
68
69/* list all files open on tree connection and mark them invalid */
70 write_lock(&GlobalSMBSeslock);
71 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
72 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
73 if(open_file) {
74 open_file->invalidHandle = TRUE;
75 }
76 }
77 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -070078 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
79 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -070080}
81
82/* If the return code is zero, this function must fill in request_buf pointer */
83static int
84small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
85 void **request_buf /* returned */)
86{
87 int rc = 0;
88
89 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
90 check for tcp and smb session status done differently
91 for those three - in the calling routine */
92 if(tcon) {
Steve French31ca3bc2005-04-28 22:41:11 -070093 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
94 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 struct nls_table *nls_codepage;
96 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -070097 reconnect, should be greater than cifs socket
98 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
100 wait_event_interruptible_timeout(tcon->ses->server->response_q,
101 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
102 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
103 /* on "soft" mounts we wait once */
104 if((tcon->retry == FALSE) ||
105 (tcon->ses->status == CifsExiting)) {
106 cFYI(1,("gave up waiting on reconnect in smb_init"));
107 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700108 } /* else "hard" mount - keep retrying
109 until process is killed or server
110 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 } else /* TCP session is reestablished now */
112 break;
113
114 }
115
116 nls_codepage = load_nls_default();
117 /* need to prevent multiple threads trying to
118 simultaneously reconnect the same SMB session */
119 down(&tcon->ses->sesSem);
120 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700121 rc = cifs_setup_session(0, tcon->ses,
122 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
124 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700125 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
126 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 up(&tcon->ses->sesSem);
128 if(rc == 0)
129 atomic_inc(&tconInfoReconnectCount);
130
131 cFYI(1, ("reconnect tcon rc = %d", rc));
132 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700133 it is safer (and faster) to reopen files
134 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
136 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700137 know whether we can continue or not without
138 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 switch(smb_command) {
140 case SMB_COM_READ_ANDX:
141 case SMB_COM_WRITE_ANDX:
142 case SMB_COM_CLOSE:
143 case SMB_COM_FIND_CLOSE2:
144 case SMB_COM_LOCKING_ANDX: {
145 unload_nls(nls_codepage);
146 return -EAGAIN;
147 }
148 }
149 } else {
150 up(&tcon->ses->sesSem);
151 }
152 unload_nls(nls_codepage);
153
154 } else {
155 return -EIO;
156 }
157 }
158 if(rc)
159 return rc;
160
161 *request_buf = cifs_small_buf_get();
162 if (*request_buf == NULL) {
163 /* BB should we add a retry in here if not a writepage? */
164 return -ENOMEM;
165 }
166
167 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
168
Steve Frencha45443472005-08-24 13:59:35 -0700169 if(tcon != NULL)
170 cifs_stats_inc(&tcon->num_smbs_sent);
171
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 return rc;
173}
174
175/* If the return code is zero, this function must fill in request_buf pointer */
176static int
177smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
178 void **request_buf /* returned */ ,
179 void **response_buf /* returned */ )
180{
181 int rc = 0;
182
183 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
184 check for tcp and smb session status done differently
185 for those three - in the calling routine */
186 if(tcon) {
Steve French31ca3bc2005-04-28 22:41:11 -0700187 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
188 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700190 /* Give Demultiplex thread up to 10 seconds to
191 reconnect, should be greater than cifs socket
192 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
194 wait_event_interruptible_timeout(tcon->ses->server->response_q,
195 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
Steve French09d1db52005-04-28 22:41:08 -0700196 if(tcon->ses->server->tcpStatus ==
197 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 /* on "soft" mounts we wait once */
199 if((tcon->retry == FALSE) ||
200 (tcon->ses->status == CifsExiting)) {
201 cFYI(1,("gave up waiting on reconnect in smb_init"));
202 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700203 } /* else "hard" mount - keep retrying
204 until process is killed or server
205 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 } else /* TCP session is reestablished now */
207 break;
208
209 }
210
211 nls_codepage = load_nls_default();
212 /* need to prevent multiple threads trying to
213 simultaneously reconnect the same SMB session */
214 down(&tcon->ses->sesSem);
215 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700216 rc = cifs_setup_session(0, tcon->ses,
217 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
219 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700220 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
221 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 up(&tcon->ses->sesSem);
223 if(rc == 0)
224 atomic_inc(&tconInfoReconnectCount);
225
226 cFYI(1, ("reconnect tcon rc = %d", rc));
227 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700228 it is safer (and faster) to reopen files
229 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
231 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700232 know whether we can continue or not without
233 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 switch(smb_command) {
235 case SMB_COM_READ_ANDX:
236 case SMB_COM_WRITE_ANDX:
237 case SMB_COM_CLOSE:
238 case SMB_COM_FIND_CLOSE2:
239 case SMB_COM_LOCKING_ANDX: {
240 unload_nls(nls_codepage);
241 return -EAGAIN;
242 }
243 }
244 } else {
245 up(&tcon->ses->sesSem);
246 }
247 unload_nls(nls_codepage);
248
249 } else {
250 return -EIO;
251 }
252 }
253 if(rc)
254 return rc;
255
256 *request_buf = cifs_buf_get();
257 if (*request_buf == NULL) {
258 /* BB should we add a retry in here if not a writepage? */
259 return -ENOMEM;
260 }
261 /* Although the original thought was we needed the response buf for */
262 /* potential retries of smb operations it turns out we can determine */
263 /* from the mid flags when the request buffer can be resent without */
264 /* having to use a second distinct buffer for the response */
265 *response_buf = *request_buf;
266
267 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
268 wct /*wct */ );
269
Steve Frencha45443472005-08-24 13:59:35 -0700270 if(tcon != NULL)
271 cifs_stats_inc(&tcon->num_smbs_sent);
272
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 return rc;
274}
275
276static int validate_t2(struct smb_t2_rsp * pSMB)
277{
278 int rc = -EINVAL;
279 int total_size;
280 char * pBCC;
281
282 /* check for plausible wct, bcc and t2 data and parm sizes */
283 /* check for parm and data offset going beyond end of smb */
284 if(pSMB->hdr.WordCount >= 10) {
285 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
286 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
287 /* check that bcc is at least as big as parms + data */
288 /* check that bcc is less than negotiated smb buffer */
289 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
290 if(total_size < 512) {
291 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
292 /* BCC le converted in SendReceive */
Steve French09d1db52005-04-28 22:41:08 -0700293 pBCC = (pSMB->hdr.WordCount * 2) +
294 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 (char *)pSMB;
296 if((total_size <= (*(u16 *)pBCC)) &&
297 (total_size <
298 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
299 return 0;
300 }
301
302 }
303 }
304 }
305 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
306 sizeof(struct smb_t2_rsp) + 16);
307 return rc;
308}
309int
310CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
311{
312 NEGOTIATE_REQ *pSMB;
313 NEGOTIATE_RSP *pSMBr;
314 int rc = 0;
315 int bytes_returned;
316 struct TCP_Server_Info * server;
317 u16 count;
318
319 if(ses->server)
320 server = ses->server;
321 else {
322 rc = -EIO;
323 return rc;
324 }
325 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
326 (void **) &pSMB, (void **) &pSMBr);
327 if (rc)
328 return rc;
Steve French1982c342005-08-17 12:38:22 -0700329 pSMB->hdr.Mid = GetNextMid(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
331 if (extended_security)
332 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
333
334 count = strlen(protocols[0].name) + 1;
335 strncpy(pSMB->DialectsArray, protocols[0].name, 30);
336 /* null guaranteed to be at end of source and target buffers anyway */
337
338 pSMB->hdr.smb_buf_length += count;
339 pSMB->ByteCount = cpu_to_le16(count);
340
341 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
342 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
343 if (rc == 0) {
344 server->secMode = pSMBr->SecurityMode;
Steve French09d1db52005-04-28 22:41:08 -0700345 server->secType = NTLM; /* BB override default for
346 NTLMv2 or kerberos v5 */
347 /* one byte - no need to convert this or EncryptionKeyLen
348 from little endian */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
350 /* probably no need to store and check maxvcs */
351 server->maxBuf =
352 min(le32_to_cpu(pSMBr->MaxBufferSize),
353 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
354 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
355 cFYI(0, ("Max buf = %d ", ses->server->maxBuf));
356 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
357 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
358 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
359 /* BB with UTC do we ever need to be using srvr timezone? */
360 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
361 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
362 CIFS_CRYPTO_KEY_SIZE);
363 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
364 && (pSMBr->EncryptionKeyLength == 0)) {
365 /* decode security blob */
366 } else
367 rc = -EIO;
368
369 /* BB might be helpful to save off the domain of server here */
370
371 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
372 (server->capabilities & CAP_EXTENDED_SECURITY)) {
373 count = pSMBr->ByteCount;
374 if (count < 16)
375 rc = -EIO;
376 else if (count == 16) {
377 server->secType = RawNTLMSSP;
378 if (server->socketUseCount.counter > 1) {
379 if (memcmp
380 (server->server_GUID,
381 pSMBr->u.extended_response.
382 GUID, 16) != 0) {
383 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700384 ("UID of server does not match previous connection to same ip address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 memcpy(server->
386 server_GUID,
387 pSMBr->u.
388 extended_response.
389 GUID, 16);
390 }
391 } else
392 memcpy(server->server_GUID,
393 pSMBr->u.extended_response.
394 GUID, 16);
395 } else {
396 rc = decode_negTokenInit(pSMBr->u.
397 extended_response.
398 SecurityBlob,
399 count - 16,
400 &server->secType);
401 if(rc == 1) {
402 /* BB Need to fill struct for sessetup here */
403 rc = -EOPNOTSUPP;
404 } else {
405 rc = -EINVAL;
406 }
407 }
408 } else
409 server->capabilities &= ~CAP_EXTENDED_SECURITY;
410 if(sign_CIFS_PDUs == FALSE) {
411 if(server->secMode & SECMODE_SIGN_REQUIRED)
412 cERROR(1,
413 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
Steve French1982c342005-08-17 12:38:22 -0700414 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 } else if(sign_CIFS_PDUs == 1) {
416 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French1982c342005-08-17 12:38:22 -0700417 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 }
419
420 }
Steve French1982c342005-08-17 12:38:22 -0700421
Steve French4a6d87f2005-08-13 08:15:54 -0700422 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 return rc;
424}
425
426int
427CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
428{
429 struct smb_hdr *smb_buffer;
430 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
431 int rc = 0;
432 int length;
433
434 cFYI(1, ("In tree disconnect"));
435 /*
436 * If last user of the connection and
437 * connection alive - disconnect it
438 * If this is the last connection on the server session disconnect it
439 * (and inside session disconnect we should check if tcp socket needs
440 * to be freed and kernel thread woken up).
441 */
442 if (tcon)
443 down(&tcon->tconSem);
444 else
445 return -EIO;
446
447 atomic_dec(&tcon->useCount);
448 if (atomic_read(&tcon->useCount) > 0) {
449 up(&tcon->tconSem);
450 return -EBUSY;
451 }
452
453 /* No need to return error on this operation if tid invalidated and
454 closed on server already e.g. due to tcp session crashing */
455 if(tcon->tidStatus == CifsNeedReconnect) {
456 up(&tcon->tconSem);
457 return 0;
458 }
459
460 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
461 up(&tcon->tconSem);
462 return -EIO;
463 }
Steve French09d1db52005-04-28 22:41:08 -0700464 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
465 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 if (rc) {
467 up(&tcon->tconSem);
468 return rc;
469 } else {
470 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700471 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
473 &length, 0);
474 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700475 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
477 if (smb_buffer)
478 cifs_small_buf_release(smb_buffer);
479 up(&tcon->tconSem);
480
481 /* No need to return error on this operation if tid invalidated and
482 closed on server already e.g. due to tcp session crashing */
483 if (rc == -EAGAIN)
484 rc = 0;
485
486 return rc;
487}
488
489int
490CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
491{
492 struct smb_hdr *smb_buffer_response;
493 LOGOFF_ANDX_REQ *pSMB;
494 int rc = 0;
495 int length;
496
497 cFYI(1, ("In SMBLogoff for session disconnect"));
498 if (ses)
499 down(&ses->sesSem);
500 else
501 return -EIO;
502
503 atomic_dec(&ses->inUse);
504 if (atomic_read(&ses->inUse) > 0) {
505 up(&ses->sesSem);
506 return -EBUSY;
507 }
508 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
509 if (rc) {
510 up(&ses->sesSem);
511 return rc;
512 }
513
514 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
515
516 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700517 pSMB->hdr.Mid = GetNextMid(ses->server);
518
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 if(ses->server->secMode &
520 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
521 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
522 }
523
524 pSMB->hdr.Uid = ses->Suid;
525
526 pSMB->AndXCommand = 0xFF;
527 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
528 smb_buffer_response, &length, 0);
529 if (ses->server) {
530 atomic_dec(&ses->server->socketUseCount);
531 if (atomic_read(&ses->server->socketUseCount) == 0) {
532 spin_lock(&GlobalMid_Lock);
533 ses->server->tcpStatus = CifsExiting;
534 spin_unlock(&GlobalMid_Lock);
535 rc = -ESHUTDOWN;
536 }
537 }
Steve Frencha59c6582005-08-17 12:12:19 -0700538 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700539 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
541 /* if session dead then we do not need to do ulogoff,
542 since server closed smb session, no sense reporting
543 error */
544 if (rc == -EAGAIN)
545 rc = 0;
546 return rc;
547}
548
549int
Steve French737b7582005-04-28 22:41:06 -0700550CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
551 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552{
553 DELETE_FILE_REQ *pSMB = NULL;
554 DELETE_FILE_RSP *pSMBr = NULL;
555 int rc = 0;
556 int bytes_returned;
557 int name_len;
558
559DelFileRetry:
560 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
561 (void **) &pSMBr);
562 if (rc)
563 return rc;
564
565 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
566 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500567 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700568 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 name_len++; /* trailing null */
570 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700571 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 name_len = strnlen(fileName, PATH_MAX);
573 name_len++; /* trailing null */
574 strncpy(pSMB->fileName, fileName, name_len);
575 }
576 pSMB->SearchAttributes =
577 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
578 pSMB->BufferFormat = 0x04;
579 pSMB->hdr.smb_buf_length += name_len + 1;
580 pSMB->ByteCount = cpu_to_le16(name_len + 1);
581 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
582 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700583 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 if (rc) {
585 cFYI(1, ("Error in RMFile = %d", rc));
586 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587
588 cifs_buf_release(pSMB);
589 if (rc == -EAGAIN)
590 goto DelFileRetry;
591
592 return rc;
593}
594
595int
Steve French737b7582005-04-28 22:41:06 -0700596CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
597 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598{
599 DELETE_DIRECTORY_REQ *pSMB = NULL;
600 DELETE_DIRECTORY_RSP *pSMBr = NULL;
601 int rc = 0;
602 int bytes_returned;
603 int name_len;
604
605 cFYI(1, ("In CIFSSMBRmDir"));
606RmDirRetry:
607 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
608 (void **) &pSMBr);
609 if (rc)
610 return rc;
611
612 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700613 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
614 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 name_len++; /* trailing null */
616 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700617 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618 name_len = strnlen(dirName, PATH_MAX);
619 name_len++; /* trailing null */
620 strncpy(pSMB->DirName, dirName, name_len);
621 }
622
623 pSMB->BufferFormat = 0x04;
624 pSMB->hdr.smb_buf_length += name_len + 1;
625 pSMB->ByteCount = cpu_to_le16(name_len + 1);
626 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
627 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700628 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 if (rc) {
630 cFYI(1, ("Error in RMDir = %d", rc));
631 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632
633 cifs_buf_release(pSMB);
634 if (rc == -EAGAIN)
635 goto RmDirRetry;
636 return rc;
637}
638
639int
640CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700641 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642{
643 int rc = 0;
644 CREATE_DIRECTORY_REQ *pSMB = NULL;
645 CREATE_DIRECTORY_RSP *pSMBr = NULL;
646 int bytes_returned;
647 int name_len;
648
649 cFYI(1, ("In CIFSSMBMkDir"));
650MkDirRetry:
651 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
652 (void **) &pSMBr);
653 if (rc)
654 return rc;
655
656 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500657 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700658 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 name_len++; /* trailing null */
660 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700661 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 name_len = strnlen(name, PATH_MAX);
663 name_len++; /* trailing null */
664 strncpy(pSMB->DirName, name, name_len);
665 }
666
667 pSMB->BufferFormat = 0x04;
668 pSMB->hdr.smb_buf_length += name_len + 1;
669 pSMB->ByteCount = cpu_to_le16(name_len + 1);
670 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
671 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700672 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 if (rc) {
674 cFYI(1, ("Error in Mkdir = %d", rc));
675 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700676
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 cifs_buf_release(pSMB);
678 if (rc == -EAGAIN)
679 goto MkDirRetry;
680 return rc;
681}
682
683int
684CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
685 const char *fileName, const int openDisposition,
686 const int access_flags, const int create_options, __u16 * netfid,
687 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -0700688 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689{
690 int rc = -EACCES;
691 OPEN_REQ *pSMB = NULL;
692 OPEN_RSP *pSMBr = NULL;
693 int bytes_returned;
694 int name_len;
695 __u16 count;
696
697openRetry:
698 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
699 (void **) &pSMBr);
700 if (rc)
701 return rc;
702
703 pSMB->AndXCommand = 0xFF; /* none */
704
705 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
706 count = 1; /* account for one byte pad to word boundary */
707 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500708 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -0700709 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 name_len++; /* trailing null */
711 name_len *= 2;
712 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -0700713 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 count = 0; /* no pad */
715 name_len = strnlen(fileName, PATH_MAX);
716 name_len++; /* trailing null */
717 pSMB->NameLength = cpu_to_le16(name_len);
718 strncpy(pSMB->fileName, fileName, name_len);
719 }
720 if (*pOplock & REQ_OPLOCK)
721 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
722 else if (*pOplock & REQ_BATCHOPLOCK) {
723 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
724 }
725 pSMB->DesiredAccess = cpu_to_le32(access_flags);
726 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -0700727 /* set file as system file if special file such
728 as fifo and server expecting SFU style and
729 no Unix extensions */
730 if(create_options & CREATE_OPTION_SPECIAL)
731 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
732 else
733 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 /* XP does not handle ATTR_POSIX_SEMANTICS */
735 /* but it helps speed up case sensitive checks for other
736 servers such as Samba */
737 if (tcon->ses->capabilities & CAP_UNIX)
738 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
739
740 /* if ((omode & S_IWUGO) == 0)
741 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
742 /* Above line causes problems due to vfs splitting create into two
743 pieces - need to set mode after file created not while it is
744 being created */
745 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
746 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -0700747 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -0700748 /* BB Expirement with various impersonation levels and verify */
749 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 pSMB->SecurityFlags =
751 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
752
753 count += name_len;
754 pSMB->hdr.smb_buf_length += count;
755
756 pSMB->ByteCount = cpu_to_le16(count);
757 /* long_op set to 1 to allow for oplock break timeouts */
758 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
759 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha45443472005-08-24 13:59:35 -0700760 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761 if (rc) {
762 cFYI(1, ("Error in Open = %d", rc));
763 } else {
Steve French09d1db52005-04-28 22:41:08 -0700764 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 *netfid = pSMBr->Fid; /* cifs fid stays in le */
766 /* Let caller know file was created so we can set the mode. */
767 /* Do we care about the CreateAction in any other cases? */
768 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
769 *pOplock |= CIFS_CREATE_ACTION;
770 if(pfile_info) {
771 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
772 36 /* CreationTime to Attributes */);
773 /* the file_info buf is endian converted by caller */
774 pfile_info->AllocationSize = pSMBr->AllocationSize;
775 pfile_info->EndOfFile = pSMBr->EndOfFile;
776 pfile_info->NumberOfLinks = cpu_to_le32(1);
777 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700779
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 cifs_buf_release(pSMB);
781 if (rc == -EAGAIN)
782 goto openRetry;
783 return rc;
784}
785
786/* If no buffer passed in, then caller wants to do the copy
787 as in the case of readpages so the SMB buffer must be
788 freed by the caller */
789
790int
791CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
792 const int netfid, const unsigned int count,
793 const __u64 lseek, unsigned int *nbytes, char **buf)
794{
795 int rc = -EACCES;
796 READ_REQ *pSMB = NULL;
797 READ_RSP *pSMBr = NULL;
798 char *pReadData = NULL;
799 int bytes_returned;
800
801 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
802
803 *nbytes = 0;
804 rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
805 (void **) &pSMBr);
806 if (rc)
807 return rc;
808
809 /* tcon and ses pointer are checked in smb_init */
810 if (tcon->ses->server == NULL)
811 return -ECONNABORTED;
812
813 pSMB->AndXCommand = 0xFF; /* none */
814 pSMB->Fid = netfid;
815 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
816 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
817 pSMB->Remaining = 0;
818 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
819 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
820 pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */
821
822 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
823 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700824 cifs_stats_inc(&tcon->num_reads);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 if (rc) {
826 cERROR(1, ("Send error in read = %d", rc));
827 } else {
828 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
829 data_length = data_length << 16;
830 data_length += le16_to_cpu(pSMBr->DataLength);
831 *nbytes = data_length;
832
833 /*check that DataLength would not go beyond end of SMB */
834 if ((data_length > CIFSMaxBufSize)
835 || (data_length > count)) {
836 cFYI(1,("bad length %d for count %d",data_length,count));
837 rc = -EIO;
838 *nbytes = 0;
839 } else {
840 pReadData =
841 (char *) (&pSMBr->hdr.Protocol) +
842 le16_to_cpu(pSMBr->DataOffset);
843/* if(rc = copy_to_user(buf, pReadData, data_length)) {
844 cERROR(1,("Faulting on read rc = %d",rc));
845 rc = -EFAULT;
846 }*/ /* can not use copy_to_user when using page cache*/
847 if(*buf)
848 memcpy(*buf,pReadData,data_length);
849 }
850 }
851 if(*buf)
852 cifs_buf_release(pSMB);
853 else
854 *buf = (char *)pSMB;
855
856 /* Note: On -EAGAIN error only caller can retry on handle based calls
857 since file handle passed in no longer valid */
858 return rc;
859}
860
861int
862CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
863 const int netfid, const unsigned int count,
864 const __u64 offset, unsigned int *nbytes, const char *buf,
865 const char __user * ubuf, const int long_op)
866{
867 int rc = -EACCES;
868 WRITE_REQ *pSMB = NULL;
869 WRITE_RSP *pSMBr = NULL;
870 int bytes_returned;
871 __u32 bytes_sent;
872 __u16 byte_count;
873
874 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
875 rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
876 (void **) &pSMBr);
877 if (rc)
878 return rc;
879 /* tcon and ses pointer are checked in smb_init */
880 if (tcon->ses->server == NULL)
881 return -ECONNABORTED;
882
883 pSMB->AndXCommand = 0xFF; /* none */
884 pSMB->Fid = netfid;
885 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
886 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
887 pSMB->Reserved = 0xFFFFFFFF;
888 pSMB->WriteMode = 0;
889 pSMB->Remaining = 0;
890
891 /* Can increase buffer size if buffer is big enough in some cases - ie we
892 can send more if LARGE_WRITE_X capability returned by the server and if
893 our buffer is big enough or if we convert to iovecs on socket writes
894 and eliminate the copy to the CIFS buffer */
895 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
896 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
897 } else {
898 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
899 & ~0xFF;
900 }
901
902 if (bytes_sent > count)
903 bytes_sent = count;
904 pSMB->DataOffset =
905 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
906 if(buf)
907 memcpy(pSMB->Data,buf,bytes_sent);
908 else if(ubuf) {
909 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
910 cifs_buf_release(pSMB);
911 return -EFAULT;
912 }
913 } else {
914 /* No buffer */
915 cifs_buf_release(pSMB);
916 return -EINVAL;
917 }
918
919 byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
920 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
921 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
922 pSMB->hdr.smb_buf_length += bytes_sent+1;
923 pSMB->ByteCount = cpu_to_le16(byte_count);
924
925 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
926 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha45443472005-08-24 13:59:35 -0700927 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 if (rc) {
929 cFYI(1, ("Send error in write = %d", rc));
930 *nbytes = 0;
931 } else {
932 *nbytes = le16_to_cpu(pSMBr->CountHigh);
933 *nbytes = (*nbytes) << 16;
934 *nbytes += le16_to_cpu(pSMBr->Count);
935 }
936
937 cifs_buf_release(pSMB);
938
939 /* Note: On -EAGAIN error only caller can retry on handle based calls
940 since file handle passed in no longer valid */
941
942 return rc;
943}
944
945#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500946int
947CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 const int netfid, const unsigned int count,
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500949 const __u64 offset, unsigned int *nbytes, const char *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 const int long_op)
951{
952 int rc = -EACCES;
953 WRITE_REQ *pSMB = NULL;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500954 int bytes_returned;
955 int smb_hdr_len;
956 __u32 bytes_sent;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 __u16 byte_count;
958
Steve French0c0ff092005-06-23 19:31:17 -0500959 cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 if (rc)
962 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 /* tcon and ses pointer are checked in smb_init */
964 if (tcon->ses->server == NULL)
965 return -ECONNABORTED;
966
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500967 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 pSMB->Fid = netfid;
969 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
970 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
971 pSMB->Reserved = 0xFFFFFFFF;
972 pSMB->WriteMode = 0;
973 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500974
975 /* Can increase buffer size if buffer is big enough in some cases - ie
976 can send more if LARGE_WRITE_X capability returned by the server and if
977 our buffer is big enough or if we convert to iovecs on socket writes
978 and eliminate the copy to the CIFS buffer */
979 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
980 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
981 } else {
982 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
983 & ~0xFF;
984 }
985
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 if (bytes_sent > count)
987 bytes_sent = count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 pSMB->DataOffset =
989 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
990
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500991 byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
992 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
993 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
994 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
995 pSMB->hdr.smb_buf_length += bytes_sent+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 pSMB->ByteCount = cpu_to_le16(byte_count);
997
Steve Frenchd6e04ae2005-06-13 13:24:43 -0500998 rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
999 buf, bytes_sent, &bytes_returned, long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001000 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 if (rc) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001002 cFYI(1, ("Send error in write = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001004 } else {
1005 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
1006 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1007 *nbytes = (*nbytes) << 16;
1008 *nbytes += le16_to_cpu(pSMBr->Count);
1009 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
1011 cifs_small_buf_release(pSMB);
1012
1013 /* Note: On -EAGAIN error only caller can retry on handle based calls
1014 since file handle passed in no longer valid */
1015
1016 return rc;
1017}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001018
1019
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020#endif /* CIFS_EXPERIMENTAL */
1021
1022int
1023CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1024 const __u16 smb_file_id, const __u64 len,
1025 const __u64 offset, const __u32 numUnlock,
1026 const __u32 numLock, const __u8 lockType, const int waitFlag)
1027{
1028 int rc = 0;
1029 LOCK_REQ *pSMB = NULL;
1030 LOCK_RSP *pSMBr = NULL;
1031 int bytes_returned;
1032 int timeout = 0;
1033 __u16 count;
1034
1035 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001036 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1037
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 if (rc)
1039 return rc;
1040
Steve French46810cb2005-04-28 22:41:09 -07001041 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1042
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1044 timeout = -1; /* no response expected */
1045 pSMB->Timeout = 0;
1046 } else if (waitFlag == TRUE) {
1047 timeout = 3; /* blocking operation, no timeout */
1048 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1049 } else {
1050 pSMB->Timeout = 0;
1051 }
1052
1053 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1054 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1055 pSMB->LockType = lockType;
1056 pSMB->AndXCommand = 0xFF; /* none */
1057 pSMB->Fid = smb_file_id; /* netfid stays le */
1058
1059 if((numLock != 0) || (numUnlock != 0)) {
1060 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1061 /* BB where to store pid high? */
1062 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1063 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1064 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1065 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1066 count = sizeof(LOCKING_ANDX_RANGE);
1067 } else {
1068 /* oplock break */
1069 count = 0;
1070 }
1071 pSMB->hdr.smb_buf_length += count;
1072 pSMB->ByteCount = cpu_to_le16(count);
1073
1074 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1075 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha45443472005-08-24 13:59:35 -07001076 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 if (rc) {
1078 cFYI(1, ("Send error in Lock = %d", rc));
1079 }
Steve French46810cb2005-04-28 22:41:09 -07001080 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
1082 /* Note: On -EAGAIN error only caller can retry on handle based calls
1083 since file handle passed in no longer valid */
1084 return rc;
1085}
1086
1087int
1088CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1089{
1090 int rc = 0;
1091 CLOSE_REQ *pSMB = NULL;
1092 CLOSE_RSP *pSMBr = NULL;
1093 int bytes_returned;
1094 cFYI(1, ("In CIFSSMBClose"));
1095
1096/* do not retry on dead session on close */
1097 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1098 if(rc == -EAGAIN)
1099 return 0;
1100 if (rc)
1101 return rc;
1102
1103 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1104
1105 pSMB->FileID = (__u16) smb_file_id;
1106 pSMB->LastWriteTime = 0;
1107 pSMB->ByteCount = 0;
1108 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1109 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001110 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 if (rc) {
1112 if(rc!=-EINTR) {
1113 /* EINTR is expected when user ctl-c to kill app */
1114 cERROR(1, ("Send error in Close = %d", rc));
1115 }
1116 }
1117
1118 cifs_small_buf_release(pSMB);
1119
1120 /* Since session is dead, file will be closed on server already */
1121 if(rc == -EAGAIN)
1122 rc = 0;
1123
1124 return rc;
1125}
1126
1127int
1128CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1129 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001130 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131{
1132 int rc = 0;
1133 RENAME_REQ *pSMB = NULL;
1134 RENAME_RSP *pSMBr = NULL;
1135 int bytes_returned;
1136 int name_len, name_len2;
1137 __u16 count;
1138
1139 cFYI(1, ("In CIFSSMBRename"));
1140renameRetry:
1141 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1142 (void **) &pSMBr);
1143 if (rc)
1144 return rc;
1145
1146 pSMB->BufferFormat = 0x04;
1147 pSMB->SearchAttributes =
1148 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1149 ATTR_DIRECTORY);
1150
1151 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1152 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001153 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001154 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 name_len++; /* trailing null */
1156 name_len *= 2;
1157 pSMB->OldFileName[name_len] = 0x04; /* pad */
1158 /* protocol requires ASCII signature byte on Unicode string */
1159 pSMB->OldFileName[name_len + 1] = 0x00;
1160 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001161 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001162 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1164 name_len2 *= 2; /* convert to bytes */
1165 } else { /* BB improve the check for buffer overruns BB */
1166 name_len = strnlen(fromName, PATH_MAX);
1167 name_len++; /* trailing null */
1168 strncpy(pSMB->OldFileName, fromName, name_len);
1169 name_len2 = strnlen(toName, PATH_MAX);
1170 name_len2++; /* trailing null */
1171 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1172 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1173 name_len2++; /* trailing null */
1174 name_len2++; /* signature byte */
1175 }
1176
1177 count = 1 /* 1st signature byte */ + name_len + name_len2;
1178 pSMB->hdr.smb_buf_length += count;
1179 pSMB->ByteCount = cpu_to_le16(count);
1180
1181 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1182 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001183 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 if (rc) {
1185 cFYI(1, ("Send error in rename = %d", rc));
1186 }
1187
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 cifs_buf_release(pSMB);
1189
1190 if (rc == -EAGAIN)
1191 goto renameRetry;
1192
1193 return rc;
1194}
1195
1196int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001197 int netfid, char * target_name,
1198 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199{
1200 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1201 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1202 struct set_file_rename * rename_info;
1203 char *data_offset;
1204 char dummy_string[30];
1205 int rc = 0;
1206 int bytes_returned = 0;
1207 int len_of_str;
1208 __u16 params, param_offset, offset, count, byte_count;
1209
1210 cFYI(1, ("Rename to File by handle"));
1211 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1212 (void **) &pSMBr);
1213 if (rc)
1214 return rc;
1215
1216 params = 6;
1217 pSMB->MaxSetupCount = 0;
1218 pSMB->Reserved = 0;
1219 pSMB->Flags = 0;
1220 pSMB->Timeout = 0;
1221 pSMB->Reserved2 = 0;
1222 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1223 offset = param_offset + params;
1224
1225 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1226 rename_info = (struct set_file_rename *) data_offset;
1227 pSMB->MaxParameterCount = cpu_to_le16(2);
1228 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1229 pSMB->SetupCount = 1;
1230 pSMB->Reserved3 = 0;
1231 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1232 byte_count = 3 /* pad */ + params;
1233 pSMB->ParameterCount = cpu_to_le16(params);
1234 pSMB->TotalParameterCount = pSMB->ParameterCount;
1235 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1236 pSMB->DataOffset = cpu_to_le16(offset);
1237 /* construct random name ".cifs_tmp<inodenum><mid>" */
1238 rename_info->overwrite = cpu_to_le32(1);
1239 rename_info->root_fid = 0;
1240 /* unicode only call */
1241 if(target_name == NULL) {
1242 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001243 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001244 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001246 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001247 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 }
1249 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1250 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1251 byte_count += count;
1252 pSMB->DataCount = cpu_to_le16(count);
1253 pSMB->TotalDataCount = pSMB->DataCount;
1254 pSMB->Fid = netfid;
1255 pSMB->InformationLevel =
1256 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1257 pSMB->Reserved4 = 0;
1258 pSMB->hdr.smb_buf_length += byte_count;
1259 pSMB->ByteCount = cpu_to_le16(byte_count);
1260 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1261 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001262 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 if (rc) {
1264 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1265 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001266
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 cifs_buf_release(pSMB);
1268
1269 /* Note: On -EAGAIN error only caller can retry on handle based calls
1270 since file handle passed in no longer valid */
1271
1272 return rc;
1273}
1274
1275int
1276CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1277 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001278 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279{
1280 int rc = 0;
1281 COPY_REQ *pSMB = NULL;
1282 COPY_RSP *pSMBr = NULL;
1283 int bytes_returned;
1284 int name_len, name_len2;
1285 __u16 count;
1286
1287 cFYI(1, ("In CIFSSMBCopy"));
1288copyRetry:
1289 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1290 (void **) &pSMBr);
1291 if (rc)
1292 return rc;
1293
1294 pSMB->BufferFormat = 0x04;
1295 pSMB->Tid2 = target_tid;
1296
1297 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1298
1299 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001300 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001301 fromName, PATH_MAX, nls_codepage,
1302 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 name_len++; /* trailing null */
1304 name_len *= 2;
1305 pSMB->OldFileName[name_len] = 0x04; /* pad */
1306 /* protocol requires ASCII signature byte on Unicode string */
1307 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001308 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001309 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1311 name_len2 *= 2; /* convert to bytes */
1312 } else { /* BB improve the check for buffer overruns BB */
1313 name_len = strnlen(fromName, PATH_MAX);
1314 name_len++; /* trailing null */
1315 strncpy(pSMB->OldFileName, fromName, name_len);
1316 name_len2 = strnlen(toName, PATH_MAX);
1317 name_len2++; /* trailing null */
1318 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1319 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1320 name_len2++; /* trailing null */
1321 name_len2++; /* signature byte */
1322 }
1323
1324 count = 1 /* 1st signature byte */ + name_len + name_len2;
1325 pSMB->hdr.smb_buf_length += count;
1326 pSMB->ByteCount = cpu_to_le16(count);
1327
1328 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1329 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1330 if (rc) {
1331 cFYI(1, ("Send error in copy = %d with %d files copied",
1332 rc, le16_to_cpu(pSMBr->CopyCount)));
1333 }
1334 if (pSMB)
1335 cifs_buf_release(pSMB);
1336
1337 if (rc == -EAGAIN)
1338 goto copyRetry;
1339
1340 return rc;
1341}
1342
1343int
1344CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1345 const char *fromName, const char *toName,
1346 const struct nls_table *nls_codepage)
1347{
1348 TRANSACTION2_SPI_REQ *pSMB = NULL;
1349 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1350 char *data_offset;
1351 int name_len;
1352 int name_len_target;
1353 int rc = 0;
1354 int bytes_returned = 0;
1355 __u16 params, param_offset, offset, byte_count;
1356
1357 cFYI(1, ("In Symlink Unix style"));
1358createSymLinkRetry:
1359 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1360 (void **) &pSMBr);
1361 if (rc)
1362 return rc;
1363
1364 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1365 name_len =
1366 cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
1367 /* find define for this maxpathcomponent */
1368 , nls_codepage);
1369 name_len++; /* trailing null */
1370 name_len *= 2;
1371
1372 } else { /* BB improve the check for buffer overruns BB */
1373 name_len = strnlen(fromName, PATH_MAX);
1374 name_len++; /* trailing null */
1375 strncpy(pSMB->FileName, fromName, name_len);
1376 }
1377 params = 6 + name_len;
1378 pSMB->MaxSetupCount = 0;
1379 pSMB->Reserved = 0;
1380 pSMB->Flags = 0;
1381 pSMB->Timeout = 0;
1382 pSMB->Reserved2 = 0;
1383 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1384 InformationLevel) - 4;
1385 offset = param_offset + params;
1386
1387 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1388 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1389 name_len_target =
1390 cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
1391 /* find define for this maxpathcomponent */
1392 , nls_codepage);
1393 name_len_target++; /* trailing null */
1394 name_len_target *= 2;
1395 } else { /* BB improve the check for buffer overruns BB */
1396 name_len_target = strnlen(toName, PATH_MAX);
1397 name_len_target++; /* trailing null */
1398 strncpy(data_offset, toName, name_len_target);
1399 }
1400
1401 pSMB->MaxParameterCount = cpu_to_le16(2);
1402 /* BB find exact max on data count below from sess */
1403 pSMB->MaxDataCount = cpu_to_le16(1000);
1404 pSMB->SetupCount = 1;
1405 pSMB->Reserved3 = 0;
1406 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1407 byte_count = 3 /* pad */ + params + name_len_target;
1408 pSMB->DataCount = cpu_to_le16(name_len_target);
1409 pSMB->ParameterCount = cpu_to_le16(params);
1410 pSMB->TotalDataCount = pSMB->DataCount;
1411 pSMB->TotalParameterCount = pSMB->ParameterCount;
1412 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1413 pSMB->DataOffset = cpu_to_le16(offset);
1414 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1415 pSMB->Reserved4 = 0;
1416 pSMB->hdr.smb_buf_length += byte_count;
1417 pSMB->ByteCount = cpu_to_le16(byte_count);
1418 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1419 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001420 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 if (rc) {
1422 cFYI(1,
1423 ("Send error in SetPathInfo (create symlink) = %d",
1424 rc));
1425 }
1426
1427 if (pSMB)
1428 cifs_buf_release(pSMB);
1429
1430 if (rc == -EAGAIN)
1431 goto createSymLinkRetry;
1432
1433 return rc;
1434}
1435
1436int
1437CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1438 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001439 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440{
1441 TRANSACTION2_SPI_REQ *pSMB = NULL;
1442 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1443 char *data_offset;
1444 int name_len;
1445 int name_len_target;
1446 int rc = 0;
1447 int bytes_returned = 0;
1448 __u16 params, param_offset, offset, byte_count;
1449
1450 cFYI(1, ("In Create Hard link Unix style"));
1451createHardLinkRetry:
1452 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1453 (void **) &pSMBr);
1454 if (rc)
1455 return rc;
1456
1457 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001458 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001459 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 name_len++; /* trailing null */
1461 name_len *= 2;
1462
1463 } else { /* BB improve the check for buffer overruns BB */
1464 name_len = strnlen(toName, PATH_MAX);
1465 name_len++; /* trailing null */
1466 strncpy(pSMB->FileName, toName, name_len);
1467 }
1468 params = 6 + name_len;
1469 pSMB->MaxSetupCount = 0;
1470 pSMB->Reserved = 0;
1471 pSMB->Flags = 0;
1472 pSMB->Timeout = 0;
1473 pSMB->Reserved2 = 0;
1474 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1475 InformationLevel) - 4;
1476 offset = param_offset + params;
1477
1478 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1479 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1480 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001481 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001482 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 name_len_target++; /* trailing null */
1484 name_len_target *= 2;
1485 } else { /* BB improve the check for buffer overruns BB */
1486 name_len_target = strnlen(fromName, PATH_MAX);
1487 name_len_target++; /* trailing null */
1488 strncpy(data_offset, fromName, name_len_target);
1489 }
1490
1491 pSMB->MaxParameterCount = cpu_to_le16(2);
1492 /* BB find exact max on data count below from sess*/
1493 pSMB->MaxDataCount = cpu_to_le16(1000);
1494 pSMB->SetupCount = 1;
1495 pSMB->Reserved3 = 0;
1496 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1497 byte_count = 3 /* pad */ + params + name_len_target;
1498 pSMB->ParameterCount = cpu_to_le16(params);
1499 pSMB->TotalParameterCount = pSMB->ParameterCount;
1500 pSMB->DataCount = cpu_to_le16(name_len_target);
1501 pSMB->TotalDataCount = pSMB->DataCount;
1502 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1503 pSMB->DataOffset = cpu_to_le16(offset);
1504 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1505 pSMB->Reserved4 = 0;
1506 pSMB->hdr.smb_buf_length += byte_count;
1507 pSMB->ByteCount = cpu_to_le16(byte_count);
1508 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1509 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001510 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 if (rc) {
1512 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1513 }
1514
1515 cifs_buf_release(pSMB);
1516 if (rc == -EAGAIN)
1517 goto createHardLinkRetry;
1518
1519 return rc;
1520}
1521
1522int
1523CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1524 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001525 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526{
1527 int rc = 0;
1528 NT_RENAME_REQ *pSMB = NULL;
1529 RENAME_RSP *pSMBr = NULL;
1530 int bytes_returned;
1531 int name_len, name_len2;
1532 __u16 count;
1533
1534 cFYI(1, ("In CIFSCreateHardLink"));
1535winCreateHardLinkRetry:
1536
1537 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1538 (void **) &pSMBr);
1539 if (rc)
1540 return rc;
1541
1542 pSMB->SearchAttributes =
1543 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1544 ATTR_DIRECTORY);
1545 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1546 pSMB->ClusterCount = 0;
1547
1548 pSMB->BufferFormat = 0x04;
1549
1550 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1551 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001552 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001553 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 name_len++; /* trailing null */
1555 name_len *= 2;
1556 pSMB->OldFileName[name_len] = 0; /* pad */
1557 pSMB->OldFileName[name_len + 1] = 0x04;
1558 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001559 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001560 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1562 name_len2 *= 2; /* convert to bytes */
1563 } else { /* BB improve the check for buffer overruns BB */
1564 name_len = strnlen(fromName, PATH_MAX);
1565 name_len++; /* trailing null */
1566 strncpy(pSMB->OldFileName, fromName, name_len);
1567 name_len2 = strnlen(toName, PATH_MAX);
1568 name_len2++; /* trailing null */
1569 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1570 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1571 name_len2++; /* trailing null */
1572 name_len2++; /* signature byte */
1573 }
1574
1575 count = 1 /* string type byte */ + name_len + name_len2;
1576 pSMB->hdr.smb_buf_length += count;
1577 pSMB->ByteCount = cpu_to_le16(count);
1578
1579 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1580 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001581 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582 if (rc) {
1583 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1584 }
1585 cifs_buf_release(pSMB);
1586 if (rc == -EAGAIN)
1587 goto winCreateHardLinkRetry;
1588
1589 return rc;
1590}
1591
1592int
1593CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1594 const unsigned char *searchName,
1595 char *symlinkinfo, const int buflen,
1596 const struct nls_table *nls_codepage)
1597{
1598/* SMB_QUERY_FILE_UNIX_LINK */
1599 TRANSACTION2_QPI_REQ *pSMB = NULL;
1600 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1601 int rc = 0;
1602 int bytes_returned;
1603 int name_len;
1604 __u16 params, byte_count;
1605
1606 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1607
1608querySymLinkRetry:
1609 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1610 (void **) &pSMBr);
1611 if (rc)
1612 return rc;
1613
1614 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1615 name_len =
1616 cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1617 /* find define for this maxpathcomponent */
1618 , nls_codepage);
1619 name_len++; /* trailing null */
1620 name_len *= 2;
1621 } else { /* BB improve the check for buffer overruns BB */
1622 name_len = strnlen(searchName, PATH_MAX);
1623 name_len++; /* trailing null */
1624 strncpy(pSMB->FileName, searchName, name_len);
1625 }
1626
1627 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1628 pSMB->TotalDataCount = 0;
1629 pSMB->MaxParameterCount = cpu_to_le16(2);
1630 /* BB find exact max data count below from sess structure BB */
1631 pSMB->MaxDataCount = cpu_to_le16(4000);
1632 pSMB->MaxSetupCount = 0;
1633 pSMB->Reserved = 0;
1634 pSMB->Flags = 0;
1635 pSMB->Timeout = 0;
1636 pSMB->Reserved2 = 0;
1637 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1638 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1639 pSMB->DataCount = 0;
1640 pSMB->DataOffset = 0;
1641 pSMB->SetupCount = 1;
1642 pSMB->Reserved3 = 0;
1643 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1644 byte_count = params + 1 /* pad */ ;
1645 pSMB->TotalParameterCount = cpu_to_le16(params);
1646 pSMB->ParameterCount = pSMB->TotalParameterCount;
1647 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1648 pSMB->Reserved4 = 0;
1649 pSMB->hdr.smb_buf_length += byte_count;
1650 pSMB->ByteCount = cpu_to_le16(byte_count);
1651
1652 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1653 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1654 if (rc) {
1655 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1656 } else {
1657 /* decode response */
1658
1659 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1660 if (rc || (pSMBr->ByteCount < 2))
1661 /* BB also check enough total bytes returned */
1662 rc = -EIO; /* bad smb */
1663 else {
1664 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1665 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1666
1667 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1668 name_len = UniStrnlen((wchar_t *) ((char *)
1669 &pSMBr->hdr.Protocol +data_offset),
1670 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07001671 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 cifs_strfromUCS_le(symlinkinfo,
1673 (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1674 data_offset),
1675 name_len, nls_codepage);
1676 } else {
1677 strncpy(symlinkinfo,
1678 (char *) &pSMBr->hdr.Protocol +
1679 data_offset,
1680 min_t(const int, buflen, count));
1681 }
1682 symlinkinfo[buflen] = 0;
1683 /* just in case so calling code does not go off the end of buffer */
1684 }
1685 }
1686 cifs_buf_release(pSMB);
1687 if (rc == -EAGAIN)
1688 goto querySymLinkRetry;
1689 return rc;
1690}
1691
1692int
1693CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1694 const unsigned char *searchName,
1695 char *symlinkinfo, const int buflen,__u16 fid,
1696 const struct nls_table *nls_codepage)
1697{
1698 int rc = 0;
1699 int bytes_returned;
1700 int name_len;
1701 struct smb_com_transaction_ioctl_req * pSMB;
1702 struct smb_com_transaction_ioctl_rsp * pSMBr;
1703
1704 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1705 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1706 (void **) &pSMBr);
1707 if (rc)
1708 return rc;
1709
1710 pSMB->TotalParameterCount = 0 ;
1711 pSMB->TotalDataCount = 0;
1712 pSMB->MaxParameterCount = cpu_to_le32(2);
1713 /* BB find exact data count max from sess structure BB */
1714 pSMB->MaxDataCount = cpu_to_le32(4000);
1715 pSMB->MaxSetupCount = 4;
1716 pSMB->Reserved = 0;
1717 pSMB->ParameterOffset = 0;
1718 pSMB->DataCount = 0;
1719 pSMB->DataOffset = 0;
1720 pSMB->SetupCount = 4;
1721 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1722 pSMB->ParameterCount = pSMB->TotalParameterCount;
1723 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1724 pSMB->IsFsctl = 1; /* FSCTL */
1725 pSMB->IsRootFlag = 0;
1726 pSMB->Fid = fid; /* file handle always le */
1727 pSMB->ByteCount = 0;
1728
1729 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1730 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1731 if (rc) {
1732 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1733 } else { /* decode response */
1734 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1735 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1736 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1737 /* BB also check enough total bytes returned */
1738 rc = -EIO; /* bad smb */
1739 else {
1740 if(data_count && (data_count < 2048)) {
1741 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1742
1743 struct reparse_data * reparse_buf = (struct reparse_data *)
1744 ((char *)&pSMBr->hdr.Protocol + data_offset);
1745 if((char*)reparse_buf >= end_of_smb) {
1746 rc = -EIO;
1747 goto qreparse_out;
1748 }
1749 if((reparse_buf->LinkNamesBuf +
1750 reparse_buf->TargetNameOffset +
1751 reparse_buf->TargetNameLen) >
1752 end_of_smb) {
1753 cFYI(1,("reparse buf extended beyond SMB"));
1754 rc = -EIO;
1755 goto qreparse_out;
1756 }
1757
1758 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1759 name_len = UniStrnlen((wchar_t *)
1760 (reparse_buf->LinkNamesBuf +
1761 reparse_buf->TargetNameOffset),
1762 min(buflen/2, reparse_buf->TargetNameLen / 2));
1763 cifs_strfromUCS_le(symlinkinfo,
1764 (wchar_t *) (reparse_buf->LinkNamesBuf +
1765 reparse_buf->TargetNameOffset),
1766 name_len, nls_codepage);
1767 } else { /* ASCII names */
1768 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
1769 reparse_buf->TargetNameOffset,
1770 min_t(const int, buflen, reparse_buf->TargetNameLen));
1771 }
1772 } else {
1773 rc = -EIO;
1774 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1775 }
1776 symlinkinfo[buflen] = 0; /* just in case so the caller
1777 does not go off the end of the buffer */
1778 cFYI(1,("readlink result - %s ",symlinkinfo));
1779 }
1780 }
1781qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07001782 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783
1784 /* Note: On -EAGAIN error only caller can retry on handle based calls
1785 since file handle passed in no longer valid */
1786
1787 return rc;
1788}
1789
1790#ifdef CONFIG_CIFS_POSIX
1791
1792/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
1793static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
1794{
1795 /* u8 cifs fields do not need le conversion */
1796 ace->e_perm = (__u16)cifs_ace->cifs_e_perm;
1797 ace->e_tag = (__u16)cifs_ace->cifs_e_tag;
1798 ace->e_id = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
1799 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
1800
1801 return;
1802}
1803
1804/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07001805static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
1806 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807{
1808 int size = 0;
1809 int i;
1810 __u16 count;
1811 struct cifs_posix_ace * pACE;
1812 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
1813 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
1814
1815 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
1816 return -EOPNOTSUPP;
1817
1818 if(acl_type & ACL_TYPE_ACCESS) {
1819 count = le16_to_cpu(cifs_acl->access_entry_count);
1820 pACE = &cifs_acl->ace_array[0];
1821 size = sizeof(struct cifs_posix_acl);
1822 size += sizeof(struct cifs_posix_ace) * count;
1823 /* check if we would go beyond end of SMB */
1824 if(size_of_data_area < size) {
1825 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
1826 return -EINVAL;
1827 }
1828 } else if(acl_type & ACL_TYPE_DEFAULT) {
1829 count = le16_to_cpu(cifs_acl->access_entry_count);
1830 size = sizeof(struct cifs_posix_acl);
1831 size += sizeof(struct cifs_posix_ace) * count;
1832/* skip past access ACEs to get to default ACEs */
1833 pACE = &cifs_acl->ace_array[count];
1834 count = le16_to_cpu(cifs_acl->default_entry_count);
1835 size += sizeof(struct cifs_posix_ace) * count;
1836 /* check if we would go beyond end of SMB */
1837 if(size_of_data_area < size)
1838 return -EINVAL;
1839 } else {
1840 /* illegal type */
1841 return -EINVAL;
1842 }
1843
1844 size = posix_acl_xattr_size(count);
1845 if((buflen == 0) || (local_acl == NULL)) {
1846 /* used to query ACL EA size */
1847 } else if(size > buflen) {
1848 return -ERANGE;
1849 } else /* buffer big enough */ {
1850 local_acl->a_version = POSIX_ACL_XATTR_VERSION;
1851 for(i = 0;i < count ;i++) {
1852 cifs_convert_ace(&local_acl->a_entries[i],pACE);
1853 pACE ++;
1854 }
1855 }
1856 return size;
1857}
1858
1859static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
1860 const posix_acl_xattr_entry * local_ace)
1861{
1862 __u16 rc = 0; /* 0 = ACL converted ok */
1863
1864 cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
1865 cifs_ace->cifs_e_tag = (__u8)cpu_to_le16(local_ace->e_tag);
1866 /* BB is there a better way to handle the large uid? */
1867 if(local_ace->e_id == -1) {
1868 /* Probably no need to le convert -1 on any arch but can not hurt */
1869 cifs_ace->cifs_uid = cpu_to_le64(-1);
1870 } else
1871 cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
1872 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
1873 return rc;
1874}
1875
1876/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
1877static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
1878 const int acl_type)
1879{
1880 __u16 rc = 0;
1881 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
1882 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
1883 int count;
1884 int i;
1885
1886 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
1887 return 0;
1888
1889 count = posix_acl_xattr_count((size_t)buflen);
1890 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
1891 count,buflen,local_acl->a_version));
1892 if(local_acl->a_version != 2) {
1893 cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
1894 return 0;
1895 }
1896 cifs_acl->version = cpu_to_le16(1);
1897 if(acl_type == ACL_TYPE_ACCESS)
1898 cifs_acl->access_entry_count = count;
1899 else if(acl_type == ACL_TYPE_DEFAULT)
1900 cifs_acl->default_entry_count = count;
1901 else {
1902 cFYI(1,("unknown ACL type %d",acl_type));
1903 return 0;
1904 }
1905 for(i=0;i<count;i++) {
1906 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
1907 &local_acl->a_entries[i]);
1908 if(rc != 0) {
1909 /* ACE not converted */
1910 break;
1911 }
1912 }
1913 if(rc == 0) {
1914 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
1915 rc += sizeof(struct cifs_posix_acl);
1916 /* BB add check to make sure ACL does not overflow SMB */
1917 }
1918 return rc;
1919}
1920
1921int
1922CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
1923 const unsigned char *searchName,
1924 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07001925 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926{
1927/* SMB_QUERY_POSIX_ACL */
1928 TRANSACTION2_QPI_REQ *pSMB = NULL;
1929 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1930 int rc = 0;
1931 int bytes_returned;
1932 int name_len;
1933 __u16 params, byte_count;
1934
1935 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
1936
1937queryAclRetry:
1938 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1939 (void **) &pSMBr);
1940 if (rc)
1941 return rc;
1942
1943 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1944 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001945 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07001946 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001947 name_len++; /* trailing null */
1948 name_len *= 2;
1949 pSMB->FileName[name_len] = 0;
1950 pSMB->FileName[name_len+1] = 0;
1951 } else { /* BB improve the check for buffer overruns BB */
1952 name_len = strnlen(searchName, PATH_MAX);
1953 name_len++; /* trailing null */
1954 strncpy(pSMB->FileName, searchName, name_len);
1955 }
1956
1957 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1958 pSMB->TotalDataCount = 0;
1959 pSMB->MaxParameterCount = cpu_to_le16(2);
1960 /* BB find exact max data count below from sess structure BB */
1961 pSMB->MaxDataCount = cpu_to_le16(4000);
1962 pSMB->MaxSetupCount = 0;
1963 pSMB->Reserved = 0;
1964 pSMB->Flags = 0;
1965 pSMB->Timeout = 0;
1966 pSMB->Reserved2 = 0;
1967 pSMB->ParameterOffset = cpu_to_le16(
1968 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1969 pSMB->DataCount = 0;
1970 pSMB->DataOffset = 0;
1971 pSMB->SetupCount = 1;
1972 pSMB->Reserved3 = 0;
1973 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1974 byte_count = params + 1 /* pad */ ;
1975 pSMB->TotalParameterCount = cpu_to_le16(params);
1976 pSMB->ParameterCount = pSMB->TotalParameterCount;
1977 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
1978 pSMB->Reserved4 = 0;
1979 pSMB->hdr.smb_buf_length += byte_count;
1980 pSMB->ByteCount = cpu_to_le16(byte_count);
1981
1982 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1983 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1984 if (rc) {
1985 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
1986 } else {
1987 /* decode response */
1988
1989 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1990 if (rc || (pSMBr->ByteCount < 2))
1991 /* BB also check enough total bytes returned */
1992 rc = -EIO; /* bad smb */
1993 else {
1994 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1995 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1996 rc = cifs_copy_posix_acl(acl_inf,
1997 (char *)&pSMBr->hdr.Protocol+data_offset,
1998 buflen,acl_type,count);
1999 }
2000 }
2001 cifs_buf_release(pSMB);
2002 if (rc == -EAGAIN)
2003 goto queryAclRetry;
2004 return rc;
2005}
2006
2007int
2008CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2009 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002010 const char *local_acl, const int buflen,
2011 const int acl_type,
2012 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013{
2014 struct smb_com_transaction2_spi_req *pSMB = NULL;
2015 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2016 char *parm_data;
2017 int name_len;
2018 int rc = 0;
2019 int bytes_returned = 0;
2020 __u16 params, byte_count, data_count, param_offset, offset;
2021
2022 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2023setAclRetry:
2024 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2025 (void **) &pSMBr);
2026 if (rc)
2027 return rc;
2028 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2029 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002030 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002031 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002032 name_len++; /* trailing null */
2033 name_len *= 2;
2034 } else { /* BB improve the check for buffer overruns BB */
2035 name_len = strnlen(fileName, PATH_MAX);
2036 name_len++; /* trailing null */
2037 strncpy(pSMB->FileName, fileName, name_len);
2038 }
2039 params = 6 + name_len;
2040 pSMB->MaxParameterCount = cpu_to_le16(2);
2041 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2042 pSMB->MaxSetupCount = 0;
2043 pSMB->Reserved = 0;
2044 pSMB->Flags = 0;
2045 pSMB->Timeout = 0;
2046 pSMB->Reserved2 = 0;
2047 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2048 InformationLevel) - 4;
2049 offset = param_offset + params;
2050 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2051 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2052
2053 /* convert to on the wire format for POSIX ACL */
2054 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2055
2056 if(data_count == 0) {
2057 rc = -EOPNOTSUPP;
2058 goto setACLerrorExit;
2059 }
2060 pSMB->DataOffset = cpu_to_le16(offset);
2061 pSMB->SetupCount = 1;
2062 pSMB->Reserved3 = 0;
2063 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2064 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2065 byte_count = 3 /* pad */ + params + data_count;
2066 pSMB->DataCount = cpu_to_le16(data_count);
2067 pSMB->TotalDataCount = pSMB->DataCount;
2068 pSMB->ParameterCount = cpu_to_le16(params);
2069 pSMB->TotalParameterCount = pSMB->ParameterCount;
2070 pSMB->Reserved4 = 0;
2071 pSMB->hdr.smb_buf_length += byte_count;
2072 pSMB->ByteCount = cpu_to_le16(byte_count);
2073 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2074 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2075 if (rc) {
2076 cFYI(1, ("Set POSIX ACL returned %d", rc));
2077 }
2078
2079setACLerrorExit:
2080 cifs_buf_release(pSMB);
2081 if (rc == -EAGAIN)
2082 goto setAclRetry;
2083 return rc;
2084}
2085
Steve Frenchf654bac2005-04-28 22:41:04 -07002086/* BB fix tabs in this function FIXME BB */
2087int
2088CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2089 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2090{
2091 int rc = 0;
2092 struct smb_t2_qfi_req *pSMB = NULL;
2093 struct smb_t2_qfi_rsp *pSMBr = NULL;
2094 int bytes_returned;
2095 __u16 params, byte_count;
2096
2097 cFYI(1,("In GetExtAttr"));
2098 if(tcon == NULL)
2099 return -ENODEV;
2100
2101GetExtAttrRetry:
2102 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2103 (void **) &pSMBr);
2104 if (rc)
2105 return rc;
2106
Steve Frenchc67593a2005-04-28 22:41:04 -07002107 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002108 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002109 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002110 /* BB find exact max data count below from sess structure BB */
2111 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2112 pSMB->t2.MaxSetupCount = 0;
2113 pSMB->t2.Reserved = 0;
2114 pSMB->t2.Flags = 0;
2115 pSMB->t2.Timeout = 0;
2116 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002117 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2118 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002119 pSMB->t2.DataCount = 0;
2120 pSMB->t2.DataOffset = 0;
2121 pSMB->t2.SetupCount = 1;
2122 pSMB->t2.Reserved3 = 0;
2123 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002124 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002125 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2126 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2127 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002128 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002129 pSMB->Fid = netfid;
2130 pSMB->hdr.smb_buf_length += byte_count;
2131 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2132
2133 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2134 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2135 if (rc) {
2136 cFYI(1, ("error %d in GetExtAttr", rc));
2137 } else {
2138 /* decode response */
2139 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2140 if (rc || (pSMBr->ByteCount < 2))
2141 /* BB also check enough total bytes returned */
2142 /* If rc should we check for EOPNOSUPP and
2143 disable the srvino flag? or in caller? */
2144 rc = -EIO; /* bad smb */
2145 else {
2146 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2147 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2148 struct file_chattr_info * pfinfo;
2149 /* BB Do we need a cast or hash here ? */
2150 if(count != 16) {
2151 cFYI(1, ("Illegal size ret in GetExtAttr"));
2152 rc = -EIO;
2153 goto GetExtAttrOut;
2154 }
2155 pfinfo = (struct file_chattr_info *)
2156 (data_offset + (char *) &pSMBr->hdr.Protocol);
2157 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2158 *pMask = le64_to_cpu(pfinfo->mask);
2159 }
2160 }
2161GetExtAttrOut:
2162 cifs_buf_release(pSMB);
2163 if (rc == -EAGAIN)
2164 goto GetExtAttrRetry;
2165 return rc;
2166}
2167
2168
2169#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002170
Steve French6b8edfe2005-08-23 20:26:03 -07002171/* Legacy Query Path Information call for lookup to old servers such
2172 as Win9x/WinME */
2173int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2174 const unsigned char *searchName,
2175 FILE_ALL_INFO * pFinfo,
2176 const struct nls_table *nls_codepage, int remap)
2177{
2178 QUERY_INFORMATION_REQ * pSMB;
2179 QUERY_INFORMATION_RSP * pSMBr;
2180 int rc = 0;
2181 int bytes_returned;
2182 int name_len;
2183
2184 cFYI(1, ("In SMBQPath path %s", searchName));
2185QInfRetry:
2186 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2187 (void **) &pSMBr);
2188 if (rc)
2189 return rc;
2190
2191 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2192 name_len =
2193 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2194 PATH_MAX, nls_codepage, remap);
2195 name_len++; /* trailing null */
2196 name_len *= 2;
2197 } else {
2198 name_len = strnlen(searchName, PATH_MAX);
2199 name_len++; /* trailing null */
2200 strncpy(pSMB->FileName, searchName, name_len);
2201 }
2202 pSMB->BufferFormat = 0x04;
2203 name_len++; /* account for buffer type byte */
2204 pSMB->hdr.smb_buf_length += (__u16) name_len;
2205 pSMB->ByteCount = cpu_to_le16(name_len);
2206
2207 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2208 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2209 if (rc) {
2210 cFYI(1, ("Send error in QueryInfo = %d", rc));
2211 } else if (pFinfo) { /* decode response */
2212 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2213 pFinfo->AllocationSize = (__le64) pSMBr->size;
2214 pFinfo->EndOfFile = (__le64) pSMBr->size;
2215 pFinfo->Attributes = (__le32) pSMBr->attr;
2216 } else
2217 rc = -EIO; /* bad buffer passed in */
2218
2219 cifs_buf_release(pSMB);
2220
2221 if (rc == -EAGAIN)
2222 goto QInfRetry;
2223
2224 return rc;
2225}
2226
2227
2228
2229
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230int
2231CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2232 const unsigned char *searchName,
2233 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002234 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235{
2236/* level 263 SMB_QUERY_FILE_ALL_INFO */
2237 TRANSACTION2_QPI_REQ *pSMB = NULL;
2238 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2239 int rc = 0;
2240 int bytes_returned;
2241 int name_len;
2242 __u16 params, byte_count;
2243
2244/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2245QPathInfoRetry:
2246 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2247 (void **) &pSMBr);
2248 if (rc)
2249 return rc;
2250
2251 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2252 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002253 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002254 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 name_len++; /* trailing null */
2256 name_len *= 2;
2257 } else { /* BB improve the check for buffer overruns BB */
2258 name_len = strnlen(searchName, PATH_MAX);
2259 name_len++; /* trailing null */
2260 strncpy(pSMB->FileName, searchName, name_len);
2261 }
2262
2263 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2264 pSMB->TotalDataCount = 0;
2265 pSMB->MaxParameterCount = cpu_to_le16(2);
2266 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2267 pSMB->MaxSetupCount = 0;
2268 pSMB->Reserved = 0;
2269 pSMB->Flags = 0;
2270 pSMB->Timeout = 0;
2271 pSMB->Reserved2 = 0;
2272 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2273 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2274 pSMB->DataCount = 0;
2275 pSMB->DataOffset = 0;
2276 pSMB->SetupCount = 1;
2277 pSMB->Reserved3 = 0;
2278 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2279 byte_count = params + 1 /* pad */ ;
2280 pSMB->TotalParameterCount = cpu_to_le16(params);
2281 pSMB->ParameterCount = pSMB->TotalParameterCount;
2282 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2283 pSMB->Reserved4 = 0;
2284 pSMB->hdr.smb_buf_length += byte_count;
2285 pSMB->ByteCount = cpu_to_le16(byte_count);
2286
2287 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2288 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2289 if (rc) {
2290 cFYI(1, ("Send error in QPathInfo = %d", rc));
2291 } else { /* decode response */
2292 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2293
2294 if (rc || (pSMBr->ByteCount < 40))
2295 rc = -EIO; /* bad smb */
2296 else if (pFindData){
2297 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2298 memcpy((char *) pFindData,
2299 (char *) &pSMBr->hdr.Protocol +
2300 data_offset, sizeof (FILE_ALL_INFO));
2301 } else
2302 rc = -ENOMEM;
2303 }
2304 cifs_buf_release(pSMB);
2305 if (rc == -EAGAIN)
2306 goto QPathInfoRetry;
2307
2308 return rc;
2309}
2310
2311int
2312CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2313 const unsigned char *searchName,
2314 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002315 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002316{
2317/* SMB_QUERY_FILE_UNIX_BASIC */
2318 TRANSACTION2_QPI_REQ *pSMB = NULL;
2319 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2320 int rc = 0;
2321 int bytes_returned = 0;
2322 int name_len;
2323 __u16 params, byte_count;
2324
2325 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2326UnixQPathInfoRetry:
2327 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2328 (void **) &pSMBr);
2329 if (rc)
2330 return rc;
2331
2332 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2333 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002334 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002335 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 name_len++; /* trailing null */
2337 name_len *= 2;
2338 } else { /* BB improve the check for buffer overruns BB */
2339 name_len = strnlen(searchName, PATH_MAX);
2340 name_len++; /* trailing null */
2341 strncpy(pSMB->FileName, searchName, name_len);
2342 }
2343
2344 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2345 pSMB->TotalDataCount = 0;
2346 pSMB->MaxParameterCount = cpu_to_le16(2);
2347 /* BB find exact max SMB PDU from sess structure BB */
2348 pSMB->MaxDataCount = cpu_to_le16(4000);
2349 pSMB->MaxSetupCount = 0;
2350 pSMB->Reserved = 0;
2351 pSMB->Flags = 0;
2352 pSMB->Timeout = 0;
2353 pSMB->Reserved2 = 0;
2354 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2355 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2356 pSMB->DataCount = 0;
2357 pSMB->DataOffset = 0;
2358 pSMB->SetupCount = 1;
2359 pSMB->Reserved3 = 0;
2360 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2361 byte_count = params + 1 /* pad */ ;
2362 pSMB->TotalParameterCount = cpu_to_le16(params);
2363 pSMB->ParameterCount = pSMB->TotalParameterCount;
2364 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2365 pSMB->Reserved4 = 0;
2366 pSMB->hdr.smb_buf_length += byte_count;
2367 pSMB->ByteCount = cpu_to_le16(byte_count);
2368
2369 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2370 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2371 if (rc) {
2372 cFYI(1, ("Send error in QPathInfo = %d", rc));
2373 } else { /* decode response */
2374 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2375
2376 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2377 rc = -EIO; /* bad smb */
2378 } else {
2379 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2380 memcpy((char *) pFindData,
2381 (char *) &pSMBr->hdr.Protocol +
2382 data_offset,
2383 sizeof (FILE_UNIX_BASIC_INFO));
2384 }
2385 }
2386 cifs_buf_release(pSMB);
2387 if (rc == -EAGAIN)
2388 goto UnixQPathInfoRetry;
2389
2390 return rc;
2391}
2392
2393#if 0 /* function unused at present */
2394int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2395 const char *searchName, FILE_ALL_INFO * findData,
2396 const struct nls_table *nls_codepage)
2397{
2398/* level 257 SMB_ */
2399 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2400 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2401 int rc = 0;
2402 int bytes_returned;
2403 int name_len;
2404 __u16 params, byte_count;
2405
2406 cFYI(1, ("In FindUnique"));
2407findUniqueRetry:
2408 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2409 (void **) &pSMBr);
2410 if (rc)
2411 return rc;
2412
2413 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2414 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002415 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 /* find define for this maxpathcomponent */
2417 , nls_codepage);
2418 name_len++; /* trailing null */
2419 name_len *= 2;
2420 } else { /* BB improve the check for buffer overruns BB */
2421 name_len = strnlen(searchName, PATH_MAX);
2422 name_len++; /* trailing null */
2423 strncpy(pSMB->FileName, searchName, name_len);
2424 }
2425
2426 params = 12 + name_len /* includes null */ ;
2427 pSMB->TotalDataCount = 0; /* no EAs */
2428 pSMB->MaxParameterCount = cpu_to_le16(2);
2429 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2430 pSMB->MaxSetupCount = 0;
2431 pSMB->Reserved = 0;
2432 pSMB->Flags = 0;
2433 pSMB->Timeout = 0;
2434 pSMB->Reserved2 = 0;
2435 pSMB->ParameterOffset = cpu_to_le16(
2436 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2437 pSMB->DataCount = 0;
2438 pSMB->DataOffset = 0;
2439 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2440 pSMB->Reserved3 = 0;
2441 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2442 byte_count = params + 1 /* pad */ ;
2443 pSMB->TotalParameterCount = cpu_to_le16(params);
2444 pSMB->ParameterCount = pSMB->TotalParameterCount;
2445 pSMB->SearchAttributes =
2446 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2447 ATTR_DIRECTORY);
2448 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2449 pSMB->SearchFlags = cpu_to_le16(1);
2450 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2451 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2452 pSMB->hdr.smb_buf_length += byte_count;
2453 pSMB->ByteCount = cpu_to_le16(byte_count);
2454
2455 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2456 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2457
2458 if (rc) {
2459 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2460 } else { /* decode response */
Steve Frencha45443472005-08-24 13:59:35 -07002461 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 /* BB fill in */
2463 }
2464
2465 cifs_buf_release(pSMB);
2466 if (rc == -EAGAIN)
2467 goto findUniqueRetry;
2468
2469 return rc;
2470}
2471#endif /* end unused (temporarily) function */
2472
2473/* xid, tcon, searchName and codepage are input parms, rest are returned */
2474int
2475CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2476 const char *searchName,
2477 const struct nls_table *nls_codepage,
2478 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07002479 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480{
2481/* level 257 SMB_ */
2482 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2483 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2484 T2_FFIRST_RSP_PARMS * parms;
2485 int rc = 0;
2486 int bytes_returned = 0;
2487 int name_len;
2488 __u16 params, byte_count;
2489
Steve French737b7582005-04-28 22:41:06 -07002490 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491
2492findFirstRetry:
2493 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2494 (void **) &pSMBr);
2495 if (rc)
2496 return rc;
2497
2498 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2499 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002500 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07002501 PATH_MAX, nls_codepage, remap);
2502 /* We can not add the asterik earlier in case
2503 it got remapped to 0xF03A as if it were part of the
2504 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002505 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07002506 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07002507 pSMB->FileName[name_len+1] = 0;
2508 pSMB->FileName[name_len+2] = '*';
2509 pSMB->FileName[name_len+3] = 0;
2510 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2512 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07002513 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 } else { /* BB add check for overrun of SMB buf BB */
2515 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516/* BB fix here and in unicode clause above ie
2517 if(name_len > buffersize-header)
2518 free buffer exit; BB */
2519 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07002520 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07002521 pSMB->FileName[name_len+1] = '*';
2522 pSMB->FileName[name_len+2] = 0;
2523 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524 }
2525
2526 params = 12 + name_len /* includes null */ ;
2527 pSMB->TotalDataCount = 0; /* no EAs */
2528 pSMB->MaxParameterCount = cpu_to_le16(10);
2529 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2530 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2531 pSMB->MaxSetupCount = 0;
2532 pSMB->Reserved = 0;
2533 pSMB->Flags = 0;
2534 pSMB->Timeout = 0;
2535 pSMB->Reserved2 = 0;
2536 byte_count = params + 1 /* pad */ ;
2537 pSMB->TotalParameterCount = cpu_to_le16(params);
2538 pSMB->ParameterCount = pSMB->TotalParameterCount;
2539 pSMB->ParameterOffset = cpu_to_le16(
2540 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2541 pSMB->DataCount = 0;
2542 pSMB->DataOffset = 0;
2543 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2544 pSMB->Reserved3 = 0;
2545 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2546 pSMB->SearchAttributes =
2547 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2548 ATTR_DIRECTORY);
2549 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2550 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2551 CIFS_SEARCH_RETURN_RESUME);
2552 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2553
2554 /* BB what should we set StorageType to? Does it matter? BB */
2555 pSMB->SearchStorageType = 0;
2556 pSMB->hdr.smb_buf_length += byte_count;
2557 pSMB->ByteCount = cpu_to_le16(byte_count);
2558
2559 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2560 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002561 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562
Steve French1982c342005-08-17 12:38:22 -07002563 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564 /* BB Add code to handle unsupported level rc */
2565 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07002566
2567 if (pSMB)
2568 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569
2570 /* BB eventually could optimize out free and realloc of buf */
2571 /* for this case */
2572 if (rc == -EAGAIN)
2573 goto findFirstRetry;
2574 } else { /* decode response */
2575 /* BB remember to free buffer if error BB */
2576 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2577 if(rc == 0) {
2578 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2579 psrch_inf->unicode = TRUE;
2580 else
2581 psrch_inf->unicode = FALSE;
2582
2583 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2584 psrch_inf->srch_entries_start =
2585 (char *) &pSMBr->hdr.Protocol +
2586 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2588 le16_to_cpu(pSMBr->t2.ParameterOffset));
2589
2590 if(parms->EndofSearch)
2591 psrch_inf->endOfSearch = TRUE;
2592 else
2593 psrch_inf->endOfSearch = FALSE;
2594
2595 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2596 psrch_inf->index_of_last_entry =
2597 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 *pnetfid = parms->SearchHandle;
2599 } else {
2600 cifs_buf_release(pSMB);
2601 }
2602 }
2603
2604 return rc;
2605}
2606
2607int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2608 __u16 searchHandle, struct cifs_search_info * psrch_inf)
2609{
2610 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2611 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2612 T2_FNEXT_RSP_PARMS * parms;
2613 char *response_data;
2614 int rc = 0;
2615 int bytes_returned, name_len;
2616 __u16 params, byte_count;
2617
2618 cFYI(1, ("In FindNext"));
2619
2620 if(psrch_inf->endOfSearch == TRUE)
2621 return -ENOENT;
2622
2623 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2624 (void **) &pSMBr);
2625 if (rc)
2626 return rc;
2627
2628 params = 14; /* includes 2 bytes of null string, converted to LE below */
2629 byte_count = 0;
2630 pSMB->TotalDataCount = 0; /* no EAs */
2631 pSMB->MaxParameterCount = cpu_to_le16(8);
2632 pSMB->MaxDataCount =
2633 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2634 pSMB->MaxSetupCount = 0;
2635 pSMB->Reserved = 0;
2636 pSMB->Flags = 0;
2637 pSMB->Timeout = 0;
2638 pSMB->Reserved2 = 0;
2639 pSMB->ParameterOffset = cpu_to_le16(
2640 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2641 pSMB->DataCount = 0;
2642 pSMB->DataOffset = 0;
2643 pSMB->SetupCount = 1;
2644 pSMB->Reserved3 = 0;
2645 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2646 pSMB->SearchHandle = searchHandle; /* always kept as le */
2647 pSMB->SearchCount =
2648 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2649 /* test for Unix extensions */
2650/* if (tcon->ses->capabilities & CAP_UNIX) {
2651 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2652 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2653 } else {
2654 pSMB->InformationLevel =
2655 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2656 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2657 } */
2658 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2659 pSMB->ResumeKey = psrch_inf->resume_key;
2660 pSMB->SearchFlags =
2661 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2662
2663 name_len = psrch_inf->resume_name_len;
2664 params += name_len;
2665 if(name_len < PATH_MAX) {
2666 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2667 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07002668 /* 14 byte parm len above enough for 2 byte null terminator */
2669 pSMB->ResumeFileName[name_len] = 0;
2670 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 } else {
2672 rc = -EINVAL;
2673 goto FNext2_err_exit;
2674 }
2675 byte_count = params + 1 /* pad */ ;
2676 pSMB->TotalParameterCount = cpu_to_le16(params);
2677 pSMB->ParameterCount = pSMB->TotalParameterCount;
2678 pSMB->hdr.smb_buf_length += byte_count;
2679 pSMB->ByteCount = cpu_to_le16(byte_count);
2680
2681 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2682 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002683 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 if (rc) {
2685 if (rc == -EBADF) {
2686 psrch_inf->endOfSearch = TRUE;
2687 rc = 0; /* search probably was closed at end of search above */
2688 } else
2689 cFYI(1, ("FindNext returned = %d", rc));
2690 } else { /* decode response */
2691 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2692
2693 if(rc == 0) {
2694 /* BB fixme add lock for file (srch_info) struct here */
2695 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2696 psrch_inf->unicode = TRUE;
2697 else
2698 psrch_inf->unicode = FALSE;
2699 response_data = (char *) &pSMBr->hdr.Protocol +
2700 le16_to_cpu(pSMBr->t2.ParameterOffset);
2701 parms = (T2_FNEXT_RSP_PARMS *)response_data;
2702 response_data = (char *)&pSMBr->hdr.Protocol +
2703 le16_to_cpu(pSMBr->t2.DataOffset);
2704 cifs_buf_release(psrch_inf->ntwrk_buf_start);
2705 psrch_inf->srch_entries_start = response_data;
2706 psrch_inf->ntwrk_buf_start = (char *)pSMB;
2707 if(parms->EndofSearch)
2708 psrch_inf->endOfSearch = TRUE;
2709 else
2710 psrch_inf->endOfSearch = FALSE;
2711
2712 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2713 psrch_inf->index_of_last_entry +=
2714 psrch_inf->entries_in_buffer;
2715/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2716
2717 /* BB fixme add unlock here */
2718 }
2719
2720 }
2721
2722 /* BB On error, should we leave previous search buf (and count and
2723 last entry fields) intact or free the previous one? */
2724
2725 /* Note: On -EAGAIN error only caller can retry on handle based calls
2726 since file handle passed in no longer valid */
2727FNext2_err_exit:
2728 if (rc != 0)
2729 cifs_buf_release(pSMB);
2730
2731 return rc;
2732}
2733
2734int
2735CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2736{
2737 int rc = 0;
2738 FINDCLOSE_REQ *pSMB = NULL;
2739 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2740 int bytes_returned;
2741
2742 cFYI(1, ("In CIFSSMBFindClose"));
2743 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2744
2745 /* no sense returning error if session restarted
2746 as file handle has been closed */
2747 if(rc == -EAGAIN)
2748 return 0;
2749 if (rc)
2750 return rc;
2751
2752 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
2753 pSMB->FileID = searchHandle;
2754 pSMB->ByteCount = 0;
2755 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2756 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2757 if (rc) {
2758 cERROR(1, ("Send error in FindClose = %d", rc));
2759 }
Steve Frencha45443472005-08-24 13:59:35 -07002760 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002761 cifs_small_buf_release(pSMB);
2762
2763 /* Since session is dead, search handle closed on server already */
2764 if (rc == -EAGAIN)
2765 rc = 0;
2766
2767 return rc;
2768}
2769
2770#ifdef CONFIG_CIFS_EXPERIMENTAL
2771int
2772CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2773 const unsigned char *searchName,
2774 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07002775 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776{
2777 int rc = 0;
2778 TRANSACTION2_QPI_REQ *pSMB = NULL;
2779 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2780 int name_len, bytes_returned;
2781 __u16 params, byte_count;
2782
2783 cFYI(1,("In GetSrvInodeNum for %s",searchName));
2784 if(tcon == NULL)
2785 return -ENODEV;
2786
2787GetInodeNumberRetry:
2788 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2789 (void **) &pSMBr);
2790 if (rc)
2791 return rc;
2792
2793
2794 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2795 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002796 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002797 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 name_len++; /* trailing null */
2799 name_len *= 2;
2800 } else { /* BB improve the check for buffer overruns BB */
2801 name_len = strnlen(searchName, PATH_MAX);
2802 name_len++; /* trailing null */
2803 strncpy(pSMB->FileName, searchName, name_len);
2804 }
2805
2806 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2807 pSMB->TotalDataCount = 0;
2808 pSMB->MaxParameterCount = cpu_to_le16(2);
2809 /* BB find exact max data count below from sess structure BB */
2810 pSMB->MaxDataCount = cpu_to_le16(4000);
2811 pSMB->MaxSetupCount = 0;
2812 pSMB->Reserved = 0;
2813 pSMB->Flags = 0;
2814 pSMB->Timeout = 0;
2815 pSMB->Reserved2 = 0;
2816 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2817 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2818 pSMB->DataCount = 0;
2819 pSMB->DataOffset = 0;
2820 pSMB->SetupCount = 1;
2821 pSMB->Reserved3 = 0;
2822 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2823 byte_count = params + 1 /* pad */ ;
2824 pSMB->TotalParameterCount = cpu_to_le16(params);
2825 pSMB->ParameterCount = pSMB->TotalParameterCount;
2826 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
2827 pSMB->Reserved4 = 0;
2828 pSMB->hdr.smb_buf_length += byte_count;
2829 pSMB->ByteCount = cpu_to_le16(byte_count);
2830
2831 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2832 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2833 if (rc) {
2834 cFYI(1, ("error %d in QueryInternalInfo", rc));
2835 } else {
2836 /* decode response */
2837 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2838 if (rc || (pSMBr->ByteCount < 2))
2839 /* BB also check enough total bytes returned */
2840 /* If rc should we check for EOPNOSUPP and
2841 disable the srvino flag? or in caller? */
2842 rc = -EIO; /* bad smb */
2843 else {
2844 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2845 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2846 struct file_internal_info * pfinfo;
2847 /* BB Do we need a cast or hash here ? */
2848 if(count < 8) {
2849 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
2850 rc = -EIO;
2851 goto GetInodeNumOut;
2852 }
2853 pfinfo = (struct file_internal_info *)
2854 (data_offset + (char *) &pSMBr->hdr.Protocol);
2855 *inode_number = pfinfo->UniqueId;
2856 }
2857 }
2858GetInodeNumOut:
2859 cifs_buf_release(pSMB);
2860 if (rc == -EAGAIN)
2861 goto GetInodeNumberRetry;
2862 return rc;
2863}
2864#endif /* CIFS_EXPERIMENTAL */
2865
2866int
2867CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
2868 const unsigned char *searchName,
2869 unsigned char **targetUNCs,
2870 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07002871 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872{
2873/* TRANS2_GET_DFS_REFERRAL */
2874 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
2875 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
2876 struct dfs_referral_level_3 * referrals = NULL;
2877 int rc = 0;
2878 int bytes_returned;
2879 int name_len;
2880 unsigned int i;
2881 char * temp;
2882 __u16 params, byte_count;
2883 *number_of_UNC_in_array = 0;
2884 *targetUNCs = NULL;
2885
2886 cFYI(1, ("In GetDFSRefer the path %s", searchName));
2887 if (ses == NULL)
2888 return -ENODEV;
2889getDFSRetry:
2890 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
2891 (void **) &pSMBr);
2892 if (rc)
2893 return rc;
Steve French1982c342005-08-17 12:38:22 -07002894
2895 /* server pointer checked in called function,
2896 but should never be null here anyway */
2897 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 pSMB->hdr.Tid = ses->ipc_tid;
2899 pSMB->hdr.Uid = ses->Suid;
2900 if (ses->capabilities & CAP_STATUS32) {
2901 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
2902 }
2903 if (ses->capabilities & CAP_DFS) {
2904 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
2905 }
2906
2907 if (ses->capabilities & CAP_UNICODE) {
2908 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
2909 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002910 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07002911 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002912 name_len++; /* trailing null */
2913 name_len *= 2;
2914 } else { /* BB improve the check for buffer overruns BB */
2915 name_len = strnlen(searchName, PATH_MAX);
2916 name_len++; /* trailing null */
2917 strncpy(pSMB->RequestFileName, searchName, name_len);
2918 }
2919
2920 params = 2 /* level */ + name_len /*includes null */ ;
2921 pSMB->TotalDataCount = 0;
2922 pSMB->DataCount = 0;
2923 pSMB->DataOffset = 0;
2924 pSMB->MaxParameterCount = 0;
2925 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2926 pSMB->MaxSetupCount = 0;
2927 pSMB->Reserved = 0;
2928 pSMB->Flags = 0;
2929 pSMB->Timeout = 0;
2930 pSMB->Reserved2 = 0;
2931 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2932 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
2933 pSMB->SetupCount = 1;
2934 pSMB->Reserved3 = 0;
2935 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
2936 byte_count = params + 3 /* pad */ ;
2937 pSMB->ParameterCount = cpu_to_le16(params);
2938 pSMB->TotalParameterCount = pSMB->ParameterCount;
2939 pSMB->MaxReferralLevel = cpu_to_le16(3);
2940 pSMB->hdr.smb_buf_length += byte_count;
2941 pSMB->ByteCount = cpu_to_le16(byte_count);
2942
2943 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
2944 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2945 if (rc) {
2946 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
2947 } else { /* decode response */
2948/* BB Add logic to parse referrals here */
2949 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2950
2951 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
2952 rc = -EIO; /* bad smb */
2953 else {
2954 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2955 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
2956
2957 cFYI(1,
2958 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
2959 pSMBr->ByteCount, data_offset));
2960 referrals =
2961 (struct dfs_referral_level_3 *)
2962 (8 /* sizeof start of data block */ +
2963 data_offset +
2964 (char *) &pSMBr->hdr.Protocol);
2965 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",
2966 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)));
2967 /* BB This field is actually two bytes in from start of
2968 data block so we could do safety check that DataBlock
2969 begins at address of pSMBr->NumberOfReferrals */
2970 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
2971
2972 /* BB Fix below so can return more than one referral */
2973 if(*number_of_UNC_in_array > 1)
2974 *number_of_UNC_in_array = 1;
2975
2976 /* get the length of the strings describing refs */
2977 name_len = 0;
2978 for(i=0;i<*number_of_UNC_in_array;i++) {
2979 /* make sure that DfsPathOffset not past end */
2980 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
2981 if (offset > data_count) {
2982 /* if invalid referral, stop here and do
2983 not try to copy any more */
2984 *number_of_UNC_in_array = i;
2985 break;
2986 }
2987 temp = ((char *)referrals) + offset;
2988
2989 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2990 name_len += UniStrnlen((wchar_t *)temp,data_count);
2991 } else {
2992 name_len += strnlen(temp,data_count);
2993 }
2994 referrals++;
2995 /* BB add check that referral pointer does not fall off end PDU */
2996
2997 }
2998 /* BB add check for name_len bigger than bcc */
2999 *targetUNCs =
3000 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3001 if(*targetUNCs == NULL) {
3002 rc = -ENOMEM;
3003 goto GetDFSRefExit;
3004 }
3005 /* copy the ref strings */
3006 referrals =
3007 (struct dfs_referral_level_3 *)
3008 (8 /* sizeof data hdr */ +
3009 data_offset +
3010 (char *) &pSMBr->hdr.Protocol);
3011
3012 for(i=0;i<*number_of_UNC_in_array;i++) {
3013 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3014 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3015 cifs_strfromUCS_le(*targetUNCs,
3016 (wchar_t *) temp, name_len, nls_codepage);
3017 } else {
3018 strncpy(*targetUNCs,temp,name_len);
3019 }
3020 /* BB update target_uncs pointers */
3021 referrals++;
3022 }
3023 temp = *targetUNCs;
3024 temp[name_len] = 0;
3025 }
3026
3027 }
3028GetDFSRefExit:
3029 if (pSMB)
3030 cifs_buf_release(pSMB);
3031
3032 if (rc == -EAGAIN)
3033 goto getDFSRetry;
3034
3035 return rc;
3036}
3037
3038int
Steve French737b7582005-04-28 22:41:06 -07003039CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040{
3041/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3042 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3043 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3044 FILE_SYSTEM_INFO *response_data;
3045 int rc = 0;
3046 int bytes_returned = 0;
3047 __u16 params, byte_count;
3048
3049 cFYI(1, ("In QFSInfo"));
3050QFSInfoRetry:
3051 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3052 (void **) &pSMBr);
3053 if (rc)
3054 return rc;
3055
3056 params = 2; /* level */
3057 pSMB->TotalDataCount = 0;
3058 pSMB->MaxParameterCount = cpu_to_le16(2);
3059 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3060 pSMB->MaxSetupCount = 0;
3061 pSMB->Reserved = 0;
3062 pSMB->Flags = 0;
3063 pSMB->Timeout = 0;
3064 pSMB->Reserved2 = 0;
3065 byte_count = params + 1 /* pad */ ;
3066 pSMB->TotalParameterCount = cpu_to_le16(params);
3067 pSMB->ParameterCount = pSMB->TotalParameterCount;
3068 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3069 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3070 pSMB->DataCount = 0;
3071 pSMB->DataOffset = 0;
3072 pSMB->SetupCount = 1;
3073 pSMB->Reserved3 = 0;
3074 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3075 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3076 pSMB->hdr.smb_buf_length += byte_count;
3077 pSMB->ByteCount = cpu_to_le16(byte_count);
3078
3079 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3080 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3081 if (rc) {
3082 cERROR(1, ("Send error in QFSInfo = %d", rc));
3083 } else { /* decode response */
3084 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3085
3086 if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
3087 rc = -EIO; /* bad smb */
3088 else {
3089 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3090 cFYI(1,
3091 ("Decoding qfsinfo response. BCC: %d Offset %d",
3092 pSMBr->ByteCount, data_offset));
3093
3094 response_data =
3095 (FILE_SYSTEM_INFO
3096 *) (((char *) &pSMBr->hdr.Protocol) +
3097 data_offset);
3098 FSData->f_bsize =
3099 le32_to_cpu(response_data->BytesPerSector) *
3100 le32_to_cpu(response_data->
3101 SectorsPerAllocationUnit);
3102 FSData->f_blocks =
3103 le64_to_cpu(response_data->TotalAllocationUnits);
3104 FSData->f_bfree = FSData->f_bavail =
3105 le64_to_cpu(response_data->FreeAllocationUnits);
3106 cFYI(1,
3107 ("Blocks: %lld Free: %lld Block size %ld",
3108 (unsigned long long)FSData->f_blocks,
3109 (unsigned long long)FSData->f_bfree,
3110 FSData->f_bsize));
3111 }
3112 }
3113 cifs_buf_release(pSMB);
3114
3115 if (rc == -EAGAIN)
3116 goto QFSInfoRetry;
3117
3118 return rc;
3119}
3120
3121int
Steve French737b7582005-04-28 22:41:06 -07003122CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123{
3124/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3125 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3126 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3127 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3128 int rc = 0;
3129 int bytes_returned = 0;
3130 __u16 params, byte_count;
3131
3132 cFYI(1, ("In QFSAttributeInfo"));
3133QFSAttributeRetry:
3134 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3135 (void **) &pSMBr);
3136 if (rc)
3137 return rc;
3138
3139 params = 2; /* level */
3140 pSMB->TotalDataCount = 0;
3141 pSMB->MaxParameterCount = cpu_to_le16(2);
3142 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3143 pSMB->MaxSetupCount = 0;
3144 pSMB->Reserved = 0;
3145 pSMB->Flags = 0;
3146 pSMB->Timeout = 0;
3147 pSMB->Reserved2 = 0;
3148 byte_count = params + 1 /* pad */ ;
3149 pSMB->TotalParameterCount = cpu_to_le16(params);
3150 pSMB->ParameterCount = pSMB->TotalParameterCount;
3151 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3152 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3153 pSMB->DataCount = 0;
3154 pSMB->DataOffset = 0;
3155 pSMB->SetupCount = 1;
3156 pSMB->Reserved3 = 0;
3157 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3158 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3159 pSMB->hdr.smb_buf_length += byte_count;
3160 pSMB->ByteCount = cpu_to_le16(byte_count);
3161
3162 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3163 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3164 if (rc) {
3165 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3166 } else { /* decode response */
3167 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3168
3169 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3170 rc = -EIO; /* bad smb */
3171 } else {
3172 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3173 response_data =
3174 (FILE_SYSTEM_ATTRIBUTE_INFO
3175 *) (((char *) &pSMBr->hdr.Protocol) +
3176 data_offset);
3177 memcpy(&tcon->fsAttrInfo, response_data,
3178 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3179 }
3180 }
3181 cifs_buf_release(pSMB);
3182
3183 if (rc == -EAGAIN)
3184 goto QFSAttributeRetry;
3185
3186 return rc;
3187}
3188
3189int
Steve French737b7582005-04-28 22:41:06 -07003190CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191{
3192/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3193 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3194 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3195 FILE_SYSTEM_DEVICE_INFO *response_data;
3196 int rc = 0;
3197 int bytes_returned = 0;
3198 __u16 params, byte_count;
3199
3200 cFYI(1, ("In QFSDeviceInfo"));
3201QFSDeviceRetry:
3202 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3203 (void **) &pSMBr);
3204 if (rc)
3205 return rc;
3206
3207 params = 2; /* level */
3208 pSMB->TotalDataCount = 0;
3209 pSMB->MaxParameterCount = cpu_to_le16(2);
3210 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3211 pSMB->MaxSetupCount = 0;
3212 pSMB->Reserved = 0;
3213 pSMB->Flags = 0;
3214 pSMB->Timeout = 0;
3215 pSMB->Reserved2 = 0;
3216 byte_count = params + 1 /* pad */ ;
3217 pSMB->TotalParameterCount = cpu_to_le16(params);
3218 pSMB->ParameterCount = pSMB->TotalParameterCount;
3219 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3220 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3221
3222 pSMB->DataCount = 0;
3223 pSMB->DataOffset = 0;
3224 pSMB->SetupCount = 1;
3225 pSMB->Reserved3 = 0;
3226 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3227 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3228 pSMB->hdr.smb_buf_length += byte_count;
3229 pSMB->ByteCount = cpu_to_le16(byte_count);
3230
3231 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3232 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3233 if (rc) {
3234 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3235 } else { /* decode response */
3236 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3237
3238 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3239 rc = -EIO; /* bad smb */
3240 else {
3241 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3242 response_data =
Steve French737b7582005-04-28 22:41:06 -07003243 (FILE_SYSTEM_DEVICE_INFO *)
3244 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003245 data_offset);
3246 memcpy(&tcon->fsDevInfo, response_data,
3247 sizeof (FILE_SYSTEM_DEVICE_INFO));
3248 }
3249 }
3250 cifs_buf_release(pSMB);
3251
3252 if (rc == -EAGAIN)
3253 goto QFSDeviceRetry;
3254
3255 return rc;
3256}
3257
3258int
Steve French737b7582005-04-28 22:41:06 -07003259CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260{
3261/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3262 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3263 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3264 FILE_SYSTEM_UNIX_INFO *response_data;
3265 int rc = 0;
3266 int bytes_returned = 0;
3267 __u16 params, byte_count;
3268
3269 cFYI(1, ("In QFSUnixInfo"));
3270QFSUnixRetry:
3271 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3272 (void **) &pSMBr);
3273 if (rc)
3274 return rc;
3275
3276 params = 2; /* level */
3277 pSMB->TotalDataCount = 0;
3278 pSMB->DataCount = 0;
3279 pSMB->DataOffset = 0;
3280 pSMB->MaxParameterCount = cpu_to_le16(2);
3281 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3282 pSMB->MaxSetupCount = 0;
3283 pSMB->Reserved = 0;
3284 pSMB->Flags = 0;
3285 pSMB->Timeout = 0;
3286 pSMB->Reserved2 = 0;
3287 byte_count = params + 1 /* pad */ ;
3288 pSMB->ParameterCount = cpu_to_le16(params);
3289 pSMB->TotalParameterCount = pSMB->ParameterCount;
3290 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3291 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3292 pSMB->SetupCount = 1;
3293 pSMB->Reserved3 = 0;
3294 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3295 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3296 pSMB->hdr.smb_buf_length += byte_count;
3297 pSMB->ByteCount = cpu_to_le16(byte_count);
3298
3299 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3300 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3301 if (rc) {
3302 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3303 } else { /* decode response */
3304 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3305
3306 if (rc || (pSMBr->ByteCount < 13)) {
3307 rc = -EIO; /* bad smb */
3308 } else {
3309 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3310 response_data =
3311 (FILE_SYSTEM_UNIX_INFO
3312 *) (((char *) &pSMBr->hdr.Protocol) +
3313 data_offset);
3314 memcpy(&tcon->fsUnixInfo, response_data,
3315 sizeof (FILE_SYSTEM_UNIX_INFO));
3316 }
3317 }
3318 cifs_buf_release(pSMB);
3319
3320 if (rc == -EAGAIN)
3321 goto QFSUnixRetry;
3322
3323
3324 return rc;
3325}
3326
Jeremy Allisonac670552005-06-22 17:26:35 -07003327int
Steve French45abc6e2005-06-23 13:42:03 -05003328CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07003329{
3330/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3331 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3332 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3333 int rc = 0;
3334 int bytes_returned = 0;
3335 __u16 params, param_offset, offset, byte_count;
3336
3337 cFYI(1, ("In SETFSUnixInfo"));
3338SETFSUnixRetry:
3339 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3340 (void **) &pSMBr);
3341 if (rc)
3342 return rc;
3343
3344 params = 4; /* 2 bytes zero followed by info level. */
3345 pSMB->MaxSetupCount = 0;
3346 pSMB->Reserved = 0;
3347 pSMB->Flags = 0;
3348 pSMB->Timeout = 0;
3349 pSMB->Reserved2 = 0;
3350 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3351 offset = param_offset + params;
3352
3353 pSMB->MaxParameterCount = cpu_to_le16(4);
3354 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3355 pSMB->SetupCount = 1;
3356 pSMB->Reserved3 = 0;
3357 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3358 byte_count = 1 /* pad */ + params + 12;
3359
3360 pSMB->DataCount = cpu_to_le16(12);
3361 pSMB->ParameterCount = cpu_to_le16(params);
3362 pSMB->TotalDataCount = pSMB->DataCount;
3363 pSMB->TotalParameterCount = pSMB->ParameterCount;
3364 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3365 pSMB->DataOffset = cpu_to_le16(offset);
3366
3367 /* Params. */
3368 pSMB->FileNum = 0;
3369 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3370
3371 /* Data. */
3372 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3373 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3374 pSMB->ClientUnixCap = cpu_to_le64(cap);
3375
3376 pSMB->hdr.smb_buf_length += byte_count;
3377 pSMB->ByteCount = cpu_to_le16(byte_count);
3378
3379 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3380 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3381 if (rc) {
3382 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3383 } else { /* decode response */
3384 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3385 if (rc) {
3386 rc = -EIO; /* bad smb */
3387 }
3388 }
3389 cifs_buf_release(pSMB);
3390
3391 if (rc == -EAGAIN)
3392 goto SETFSUnixRetry;
3393
3394 return rc;
3395}
3396
3397
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398
3399int
3400CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003401 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003402{
3403/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3404 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3405 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3406 FILE_SYSTEM_POSIX_INFO *response_data;
3407 int rc = 0;
3408 int bytes_returned = 0;
3409 __u16 params, byte_count;
3410
3411 cFYI(1, ("In QFSPosixInfo"));
3412QFSPosixRetry:
3413 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3414 (void **) &pSMBr);
3415 if (rc)
3416 return rc;
3417
3418 params = 2; /* level */
3419 pSMB->TotalDataCount = 0;
3420 pSMB->DataCount = 0;
3421 pSMB->DataOffset = 0;
3422 pSMB->MaxParameterCount = cpu_to_le16(2);
3423 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3424 pSMB->MaxSetupCount = 0;
3425 pSMB->Reserved = 0;
3426 pSMB->Flags = 0;
3427 pSMB->Timeout = 0;
3428 pSMB->Reserved2 = 0;
3429 byte_count = params + 1 /* pad */ ;
3430 pSMB->ParameterCount = cpu_to_le16(params);
3431 pSMB->TotalParameterCount = pSMB->ParameterCount;
3432 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3433 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3434 pSMB->SetupCount = 1;
3435 pSMB->Reserved3 = 0;
3436 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3437 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3438 pSMB->hdr.smb_buf_length += byte_count;
3439 pSMB->ByteCount = cpu_to_le16(byte_count);
3440
3441 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3442 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3443 if (rc) {
3444 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3445 } else { /* decode response */
3446 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3447
3448 if (rc || (pSMBr->ByteCount < 13)) {
3449 rc = -EIO; /* bad smb */
3450 } else {
3451 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3452 response_data =
3453 (FILE_SYSTEM_POSIX_INFO
3454 *) (((char *) &pSMBr->hdr.Protocol) +
3455 data_offset);
3456 FSData->f_bsize =
3457 le32_to_cpu(response_data->BlockSize);
3458 FSData->f_blocks =
3459 le64_to_cpu(response_data->TotalBlocks);
3460 FSData->f_bfree =
3461 le64_to_cpu(response_data->BlocksAvail);
3462 if(response_data->UserBlocksAvail == -1) {
3463 FSData->f_bavail = FSData->f_bfree;
3464 } else {
3465 FSData->f_bavail =
3466 le64_to_cpu(response_data->UserBlocksAvail);
3467 }
3468 if(response_data->TotalFileNodes != -1)
3469 FSData->f_files =
3470 le64_to_cpu(response_data->TotalFileNodes);
3471 if(response_data->FreeFileNodes != -1)
3472 FSData->f_ffree =
3473 le64_to_cpu(response_data->FreeFileNodes);
3474 }
3475 }
3476 cifs_buf_release(pSMB);
3477
3478 if (rc == -EAGAIN)
3479 goto QFSPosixRetry;
3480
3481 return rc;
3482}
3483
3484
3485/* We can not use write of zero bytes trick to
3486 set file size due to need for large file support. Also note that
3487 this SetPathInfo is preferred to SetFileInfo based method in next
3488 routine which is only needed to work around a sharing violation bug
3489 in Samba which this routine can run into */
3490
3491int
3492CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07003493 __u64 size, int SetAllocation,
3494 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495{
3496 struct smb_com_transaction2_spi_req *pSMB = NULL;
3497 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3498 struct file_end_of_file_info *parm_data;
3499 int name_len;
3500 int rc = 0;
3501 int bytes_returned = 0;
3502 __u16 params, byte_count, data_count, param_offset, offset;
3503
3504 cFYI(1, ("In SetEOF"));
3505SetEOFRetry:
3506 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3507 (void **) &pSMBr);
3508 if (rc)
3509 return rc;
3510
3511 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3512 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003513 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003514 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 name_len++; /* trailing null */
3516 name_len *= 2;
3517 } else { /* BB improve the check for buffer overruns BB */
3518 name_len = strnlen(fileName, PATH_MAX);
3519 name_len++; /* trailing null */
3520 strncpy(pSMB->FileName, fileName, name_len);
3521 }
3522 params = 6 + name_len;
3523 data_count = sizeof (struct file_end_of_file_info);
3524 pSMB->MaxParameterCount = cpu_to_le16(2);
3525 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
3526 pSMB->MaxSetupCount = 0;
3527 pSMB->Reserved = 0;
3528 pSMB->Flags = 0;
3529 pSMB->Timeout = 0;
3530 pSMB->Reserved2 = 0;
3531 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3532 InformationLevel) - 4;
3533 offset = param_offset + params;
3534 if(SetAllocation) {
3535 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3536 pSMB->InformationLevel =
3537 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3538 else
3539 pSMB->InformationLevel =
3540 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3541 } else /* Set File Size */ {
3542 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3543 pSMB->InformationLevel =
3544 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3545 else
3546 pSMB->InformationLevel =
3547 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3548 }
3549
3550 parm_data =
3551 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3552 offset);
3553 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3554 pSMB->DataOffset = cpu_to_le16(offset);
3555 pSMB->SetupCount = 1;
3556 pSMB->Reserved3 = 0;
3557 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3558 byte_count = 3 /* pad */ + params + data_count;
3559 pSMB->DataCount = cpu_to_le16(data_count);
3560 pSMB->TotalDataCount = pSMB->DataCount;
3561 pSMB->ParameterCount = cpu_to_le16(params);
3562 pSMB->TotalParameterCount = pSMB->ParameterCount;
3563 pSMB->Reserved4 = 0;
3564 pSMB->hdr.smb_buf_length += byte_count;
3565 parm_data->FileSize = cpu_to_le64(size);
3566 pSMB->ByteCount = cpu_to_le16(byte_count);
3567 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3568 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3569 if (rc) {
3570 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3571 }
3572
3573 cifs_buf_release(pSMB);
3574
3575 if (rc == -EAGAIN)
3576 goto SetEOFRetry;
3577
3578 return rc;
3579}
3580
3581int
3582CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
3583 __u16 fid, __u32 pid_of_opener, int SetAllocation)
3584{
3585 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3586 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3587 char *data_offset;
3588 struct file_end_of_file_info *parm_data;
3589 int rc = 0;
3590 int bytes_returned = 0;
3591 __u16 params, param_offset, offset, byte_count, count;
3592
3593 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3594 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07003595 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3596
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597 if (rc)
3598 return rc;
3599
Steve Frenchcd634992005-04-28 22:41:10 -07003600 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3601
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3603 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3604
3605 params = 6;
3606 pSMB->MaxSetupCount = 0;
3607 pSMB->Reserved = 0;
3608 pSMB->Flags = 0;
3609 pSMB->Timeout = 0;
3610 pSMB->Reserved2 = 0;
3611 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3612 offset = param_offset + params;
3613
3614 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3615
3616 count = sizeof(struct file_end_of_file_info);
3617 pSMB->MaxParameterCount = cpu_to_le16(2);
3618 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3619 pSMB->SetupCount = 1;
3620 pSMB->Reserved3 = 0;
3621 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3622 byte_count = 3 /* pad */ + params + count;
3623 pSMB->DataCount = cpu_to_le16(count);
3624 pSMB->ParameterCount = cpu_to_le16(params);
3625 pSMB->TotalDataCount = pSMB->DataCount;
3626 pSMB->TotalParameterCount = pSMB->ParameterCount;
3627 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3628 parm_data =
3629 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3630 offset);
3631 pSMB->DataOffset = cpu_to_le16(offset);
3632 parm_data->FileSize = cpu_to_le64(size);
3633 pSMB->Fid = fid;
3634 if(SetAllocation) {
3635 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3636 pSMB->InformationLevel =
3637 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3638 else
3639 pSMB->InformationLevel =
3640 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3641 } else /* Set File Size */ {
3642 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3643 pSMB->InformationLevel =
3644 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3645 else
3646 pSMB->InformationLevel =
3647 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3648 }
3649 pSMB->Reserved4 = 0;
3650 pSMB->hdr.smb_buf_length += byte_count;
3651 pSMB->ByteCount = cpu_to_le16(byte_count);
3652 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3653 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3654 if (rc) {
3655 cFYI(1,
3656 ("Send error in SetFileInfo (SetFileSize) = %d",
3657 rc));
3658 }
3659
3660 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07003661 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662
3663 /* Note: On -EAGAIN error only caller can retry on handle based calls
3664 since file handle passed in no longer valid */
3665
3666 return rc;
3667}
3668
3669/* Some legacy servers such as NT4 require that the file times be set on
3670 an open handle, rather than by pathname - this is awkward due to
3671 potential access conflicts on the open, but it is unavoidable for these
3672 old servers since the only other choice is to go from 100 nanosecond DCE
3673 time and resort to the original setpathinfo level which takes the ancient
3674 DOS time format with 2 second granularity */
3675int
3676CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
3677 __u16 fid)
3678{
3679 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3680 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3681 char *data_offset;
3682 int rc = 0;
3683 int bytes_returned = 0;
3684 __u16 params, param_offset, offset, byte_count, count;
3685
3686 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07003687 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3688
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 if (rc)
3690 return rc;
3691
Steve Frenchcd634992005-04-28 22:41:10 -07003692 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3693
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 /* At this point there is no need to override the current pid
3695 with the pid of the opener, but that could change if we someday
3696 use an existing handle (rather than opening one on the fly) */
3697 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3698 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3699
3700 params = 6;
3701 pSMB->MaxSetupCount = 0;
3702 pSMB->Reserved = 0;
3703 pSMB->Flags = 0;
3704 pSMB->Timeout = 0;
3705 pSMB->Reserved2 = 0;
3706 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3707 offset = param_offset + params;
3708
3709 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3710
3711 count = sizeof (FILE_BASIC_INFO);
3712 pSMB->MaxParameterCount = cpu_to_le16(2);
3713 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3714 pSMB->SetupCount = 1;
3715 pSMB->Reserved3 = 0;
3716 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3717 byte_count = 3 /* pad */ + params + count;
3718 pSMB->DataCount = cpu_to_le16(count);
3719 pSMB->ParameterCount = cpu_to_le16(params);
3720 pSMB->TotalDataCount = pSMB->DataCount;
3721 pSMB->TotalParameterCount = pSMB->ParameterCount;
3722 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3723 pSMB->DataOffset = cpu_to_le16(offset);
3724 pSMB->Fid = fid;
3725 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3726 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3727 else
3728 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3729 pSMB->Reserved4 = 0;
3730 pSMB->hdr.smb_buf_length += byte_count;
3731 pSMB->ByteCount = cpu_to_le16(byte_count);
3732 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
3733 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3734 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3735 if (rc) {
3736 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
3737 }
3738
Steve Frenchcd634992005-04-28 22:41:10 -07003739 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740
3741 /* Note: On -EAGAIN error only caller can retry on handle based calls
3742 since file handle passed in no longer valid */
3743
3744 return rc;
3745}
3746
3747
3748int
3749CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3750 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07003751 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752{
3753 TRANSACTION2_SPI_REQ *pSMB = NULL;
3754 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3755 int name_len;
3756 int rc = 0;
3757 int bytes_returned = 0;
3758 char *data_offset;
3759 __u16 params, param_offset, offset, byte_count, count;
3760
3761 cFYI(1, ("In SetTimes"));
3762
3763SetTimesRetry:
3764 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3765 (void **) &pSMBr);
3766 if (rc)
3767 return rc;
3768
3769 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3770 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003771 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003772 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773 name_len++; /* trailing null */
3774 name_len *= 2;
3775 } else { /* BB improve the check for buffer overruns BB */
3776 name_len = strnlen(fileName, PATH_MAX);
3777 name_len++; /* trailing null */
3778 strncpy(pSMB->FileName, fileName, name_len);
3779 }
3780
3781 params = 6 + name_len;
3782 count = sizeof (FILE_BASIC_INFO);
3783 pSMB->MaxParameterCount = cpu_to_le16(2);
3784 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3785 pSMB->MaxSetupCount = 0;
3786 pSMB->Reserved = 0;
3787 pSMB->Flags = 0;
3788 pSMB->Timeout = 0;
3789 pSMB->Reserved2 = 0;
3790 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3791 InformationLevel) - 4;
3792 offset = param_offset + params;
3793 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3794 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3795 pSMB->DataOffset = cpu_to_le16(offset);
3796 pSMB->SetupCount = 1;
3797 pSMB->Reserved3 = 0;
3798 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3799 byte_count = 3 /* pad */ + params + count;
3800
3801 pSMB->DataCount = cpu_to_le16(count);
3802 pSMB->ParameterCount = cpu_to_le16(params);
3803 pSMB->TotalDataCount = pSMB->DataCount;
3804 pSMB->TotalParameterCount = pSMB->ParameterCount;
3805 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3806 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3807 else
3808 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3809 pSMB->Reserved4 = 0;
3810 pSMB->hdr.smb_buf_length += byte_count;
3811 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
3812 pSMB->ByteCount = cpu_to_le16(byte_count);
3813 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3814 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3815 if (rc) {
3816 cFYI(1, ("SetPathInfo (times) returned %d", rc));
3817 }
3818
3819 cifs_buf_release(pSMB);
3820
3821 if (rc == -EAGAIN)
3822 goto SetTimesRetry;
3823
3824 return rc;
3825}
3826
3827/* Can not be used to set time stamps yet (due to old DOS time format) */
3828/* Can be used to set attributes */
3829#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
3830 handling it anyway and NT4 was what we thought it would be needed for
3831 Do not delete it until we prove whether needed for Win9x though */
3832int
3833CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
3834 __u16 dos_attrs, const struct nls_table *nls_codepage)
3835{
3836 SETATTR_REQ *pSMB = NULL;
3837 SETATTR_RSP *pSMBr = NULL;
3838 int rc = 0;
3839 int bytes_returned;
3840 int name_len;
3841
3842 cFYI(1, ("In SetAttrLegacy"));
3843
3844SetAttrLgcyRetry:
3845 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
3846 (void **) &pSMBr);
3847 if (rc)
3848 return rc;
3849
3850 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3851 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003852 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853 PATH_MAX, nls_codepage);
3854 name_len++; /* trailing null */
3855 name_len *= 2;
3856 } else { /* BB improve the check for buffer overruns BB */
3857 name_len = strnlen(fileName, PATH_MAX);
3858 name_len++; /* trailing null */
3859 strncpy(pSMB->fileName, fileName, name_len);
3860 }
3861 pSMB->attr = cpu_to_le16(dos_attrs);
3862 pSMB->BufferFormat = 0x04;
3863 pSMB->hdr.smb_buf_length += name_len + 1;
3864 pSMB->ByteCount = cpu_to_le16(name_len + 1);
3865 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3866 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3867 if (rc) {
3868 cFYI(1, ("Error in LegacySetAttr = %d", rc));
3869 }
3870
3871 cifs_buf_release(pSMB);
3872
3873 if (rc == -EAGAIN)
3874 goto SetAttrLgcyRetry;
3875
3876 return rc;
3877}
3878#endif /* temporarily unneeded SetAttr legacy function */
3879
3880int
3881CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003882 char *fileName, __u64 mode, __u64 uid, __u64 gid,
3883 dev_t device, const struct nls_table *nls_codepage,
3884 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885{
3886 TRANSACTION2_SPI_REQ *pSMB = NULL;
3887 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3888 int name_len;
3889 int rc = 0;
3890 int bytes_returned = 0;
3891 FILE_UNIX_BASIC_INFO *data_offset;
3892 __u16 params, param_offset, offset, count, byte_count;
3893
3894 cFYI(1, ("In SetUID/GID/Mode"));
3895setPermsRetry:
3896 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3897 (void **) &pSMBr);
3898 if (rc)
3899 return rc;
3900
3901 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3902 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003903 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003904 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003905 name_len++; /* trailing null */
3906 name_len *= 2;
3907 } else { /* BB improve the check for buffer overruns BB */
3908 name_len = strnlen(fileName, PATH_MAX);
3909 name_len++; /* trailing null */
3910 strncpy(pSMB->FileName, fileName, name_len);
3911 }
3912
3913 params = 6 + name_len;
3914 count = sizeof (FILE_UNIX_BASIC_INFO);
3915 pSMB->MaxParameterCount = cpu_to_le16(2);
3916 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3917 pSMB->MaxSetupCount = 0;
3918 pSMB->Reserved = 0;
3919 pSMB->Flags = 0;
3920 pSMB->Timeout = 0;
3921 pSMB->Reserved2 = 0;
3922 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3923 InformationLevel) - 4;
3924 offset = param_offset + params;
3925 data_offset =
3926 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
3927 offset);
3928 memset(data_offset, 0, count);
3929 pSMB->DataOffset = cpu_to_le16(offset);
3930 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3931 pSMB->SetupCount = 1;
3932 pSMB->Reserved3 = 0;
3933 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3934 byte_count = 3 /* pad */ + params + count;
3935 pSMB->ParameterCount = cpu_to_le16(params);
3936 pSMB->DataCount = cpu_to_le16(count);
3937 pSMB->TotalParameterCount = pSMB->ParameterCount;
3938 pSMB->TotalDataCount = pSMB->DataCount;
3939 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
3940 pSMB->Reserved4 = 0;
3941 pSMB->hdr.smb_buf_length += byte_count;
3942 data_offset->Uid = cpu_to_le64(uid);
3943 data_offset->Gid = cpu_to_le64(gid);
3944 /* better to leave device as zero when it is */
3945 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
3946 data_offset->DevMinor = cpu_to_le64(MINOR(device));
3947 data_offset->Permissions = cpu_to_le64(mode);
3948
3949 if(S_ISREG(mode))
3950 data_offset->Type = cpu_to_le32(UNIX_FILE);
3951 else if(S_ISDIR(mode))
3952 data_offset->Type = cpu_to_le32(UNIX_DIR);
3953 else if(S_ISLNK(mode))
3954 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
3955 else if(S_ISCHR(mode))
3956 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
3957 else if(S_ISBLK(mode))
3958 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
3959 else if(S_ISFIFO(mode))
3960 data_offset->Type = cpu_to_le32(UNIX_FIFO);
3961 else if(S_ISSOCK(mode))
3962 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
3963
3964
3965 pSMB->ByteCount = cpu_to_le16(byte_count);
3966 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3967 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3968 if (rc) {
3969 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
3970 }
3971
3972 if (pSMB)
3973 cifs_buf_release(pSMB);
3974 if (rc == -EAGAIN)
3975 goto setPermsRetry;
3976 return rc;
3977}
3978
3979int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07003980 const int notify_subdirs, const __u16 netfid,
3981 __u32 filter, struct file * pfile, int multishot,
3982 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983{
3984 int rc = 0;
3985 struct smb_com_transaction_change_notify_req * pSMB = NULL;
3986 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07003987 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 int bytes_returned;
3989
3990 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
3991 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3992 (void **) &pSMBr);
3993 if (rc)
3994 return rc;
3995
3996 pSMB->TotalParameterCount = 0 ;
3997 pSMB->TotalDataCount = 0;
3998 pSMB->MaxParameterCount = cpu_to_le32(2);
3999 /* BB find exact data count max from sess structure BB */
4000 pSMB->MaxDataCount = 0; /* same in little endian or be */
4001 pSMB->MaxSetupCount = 4;
4002 pSMB->Reserved = 0;
4003 pSMB->ParameterOffset = 0;
4004 pSMB->DataCount = 0;
4005 pSMB->DataOffset = 0;
4006 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4007 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4008 pSMB->ParameterCount = pSMB->TotalParameterCount;
4009 if(notify_subdirs)
4010 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4011 pSMB->Reserved2 = 0;
4012 pSMB->CompletionFilter = cpu_to_le32(filter);
4013 pSMB->Fid = netfid; /* file handle always le */
4014 pSMB->ByteCount = 0;
4015
4016 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4017 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4018 if (rc) {
4019 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004020 } else {
4021 /* Add file to outstanding requests */
4022 dnotify_req = (struct dir_notify_req *) kmalloc(
4023 sizeof(struct dir_notify_req), GFP_KERNEL);
4024 dnotify_req->Pid = pSMB->hdr.Pid;
4025 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4026 dnotify_req->Mid = pSMB->hdr.Mid;
4027 dnotify_req->Tid = pSMB->hdr.Tid;
4028 dnotify_req->Uid = pSMB->hdr.Uid;
4029 dnotify_req->netfid = netfid;
Steve French167a2512005-08-24 20:03:11 -07004030 dnotify_req->pfile = pfile;
Steve Frenchff5dbd92005-08-24 17:10:36 -07004031 dnotify_req->filter = filter;
4032 dnotify_req->multishot = multishot;
4033 spin_lock(&GlobalMid_Lock);
4034 list_add_tail(&dnotify_req->lhead, &GlobalDnotifyReqList);
4035 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 }
4037 cifs_buf_release(pSMB);
4038 return rc;
4039}
4040#ifdef CONFIG_CIFS_XATTR
4041ssize_t
4042CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4043 const unsigned char *searchName,
4044 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004045 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046{
4047 /* BB assumes one setup word */
4048 TRANSACTION2_QPI_REQ *pSMB = NULL;
4049 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4050 int rc = 0;
4051 int bytes_returned;
4052 int name_len;
4053 struct fea * temp_fea;
4054 char * temp_ptr;
4055 __u16 params, byte_count;
4056
4057 cFYI(1, ("In Query All EAs path %s", searchName));
4058QAllEAsRetry:
4059 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4060 (void **) &pSMBr);
4061 if (rc)
4062 return rc;
4063
4064 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4065 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004066 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004067 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 name_len++; /* trailing null */
4069 name_len *= 2;
4070 } else { /* BB improve the check for buffer overruns BB */
4071 name_len = strnlen(searchName, PATH_MAX);
4072 name_len++; /* trailing null */
4073 strncpy(pSMB->FileName, searchName, name_len);
4074 }
4075
4076 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4077 pSMB->TotalDataCount = 0;
4078 pSMB->MaxParameterCount = cpu_to_le16(2);
4079 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4080 pSMB->MaxSetupCount = 0;
4081 pSMB->Reserved = 0;
4082 pSMB->Flags = 0;
4083 pSMB->Timeout = 0;
4084 pSMB->Reserved2 = 0;
4085 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4086 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4087 pSMB->DataCount = 0;
4088 pSMB->DataOffset = 0;
4089 pSMB->SetupCount = 1;
4090 pSMB->Reserved3 = 0;
4091 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4092 byte_count = params + 1 /* pad */ ;
4093 pSMB->TotalParameterCount = cpu_to_le16(params);
4094 pSMB->ParameterCount = pSMB->TotalParameterCount;
4095 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4096 pSMB->Reserved4 = 0;
4097 pSMB->hdr.smb_buf_length += byte_count;
4098 pSMB->ByteCount = cpu_to_le16(byte_count);
4099
4100 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4101 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4102 if (rc) {
4103 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4104 } else { /* decode response */
4105 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4106
4107 /* BB also check enough total bytes returned */
4108 /* BB we need to improve the validity checking
4109 of these trans2 responses */
4110 if (rc || (pSMBr->ByteCount < 4))
4111 rc = -EIO; /* bad smb */
4112 /* else if (pFindData){
4113 memcpy((char *) pFindData,
4114 (char *) &pSMBr->hdr.Protocol +
4115 data_offset, kl);
4116 }*/ else {
4117 /* check that length of list is not more than bcc */
4118 /* check that each entry does not go beyond length
4119 of list */
4120 /* check that each element of each entry does not
4121 go beyond end of list */
4122 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4123 struct fealist * ea_response_data;
4124 rc = 0;
4125 /* validate_trans2_offsets() */
4126 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4127 ea_response_data = (struct fealist *)
4128 (((char *) &pSMBr->hdr.Protocol) +
4129 data_offset);
4130 name_len = le32_to_cpu(ea_response_data->list_len);
4131 cFYI(1,("ea length %d", name_len));
4132 if(name_len <= 8) {
4133 /* returned EA size zeroed at top of function */
4134 cFYI(1,("empty EA list returned from server"));
4135 } else {
4136 /* account for ea list len */
4137 name_len -= 4;
4138 temp_fea = ea_response_data->list;
4139 temp_ptr = (char *)temp_fea;
4140 while(name_len > 0) {
4141 __u16 value_len;
4142 name_len -= 4;
4143 temp_ptr += 4;
4144 rc += temp_fea->name_len;
4145 /* account for prefix user. and trailing null */
4146 rc = rc + 5 + 1;
4147 if(rc<(int)buf_size) {
4148 memcpy(EAData,"user.",5);
4149 EAData+=5;
4150 memcpy(EAData,temp_ptr,temp_fea->name_len);
4151 EAData+=temp_fea->name_len;
4152 /* null terminate name */
4153 *EAData = 0;
4154 EAData = EAData + 1;
4155 } else if(buf_size == 0) {
4156 /* skip copy - calc size only */
4157 } else {
4158 /* stop before overrun buffer */
4159 rc = -ERANGE;
4160 break;
4161 }
4162 name_len -= temp_fea->name_len;
4163 temp_ptr += temp_fea->name_len;
4164 /* account for trailing null */
4165 name_len--;
4166 temp_ptr++;
4167 value_len = le16_to_cpu(temp_fea->value_len);
4168 name_len -= value_len;
4169 temp_ptr += value_len;
4170 /* BB check that temp_ptr is still within smb BB*/
4171 /* no trailing null to account for in value len */
4172 /* go on to next EA */
4173 temp_fea = (struct fea *)temp_ptr;
4174 }
4175 }
4176 }
4177 }
4178 if (pSMB)
4179 cifs_buf_release(pSMB);
4180 if (rc == -EAGAIN)
4181 goto QAllEAsRetry;
4182
4183 return (ssize_t)rc;
4184}
4185
4186ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4187 const unsigned char * searchName,const unsigned char * ea_name,
4188 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004189 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190{
4191 TRANSACTION2_QPI_REQ *pSMB = NULL;
4192 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4193 int rc = 0;
4194 int bytes_returned;
4195 int name_len;
4196 struct fea * temp_fea;
4197 char * temp_ptr;
4198 __u16 params, byte_count;
4199
4200 cFYI(1, ("In Query EA path %s", searchName));
4201QEARetry:
4202 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4203 (void **) &pSMBr);
4204 if (rc)
4205 return rc;
4206
4207 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4208 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004209 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004210 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 name_len++; /* trailing null */
4212 name_len *= 2;
4213 } else { /* BB improve the check for buffer overruns BB */
4214 name_len = strnlen(searchName, PATH_MAX);
4215 name_len++; /* trailing null */
4216 strncpy(pSMB->FileName, searchName, name_len);
4217 }
4218
4219 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4220 pSMB->TotalDataCount = 0;
4221 pSMB->MaxParameterCount = cpu_to_le16(2);
4222 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4223 pSMB->MaxSetupCount = 0;
4224 pSMB->Reserved = 0;
4225 pSMB->Flags = 0;
4226 pSMB->Timeout = 0;
4227 pSMB->Reserved2 = 0;
4228 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4229 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4230 pSMB->DataCount = 0;
4231 pSMB->DataOffset = 0;
4232 pSMB->SetupCount = 1;
4233 pSMB->Reserved3 = 0;
4234 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4235 byte_count = params + 1 /* pad */ ;
4236 pSMB->TotalParameterCount = cpu_to_le16(params);
4237 pSMB->ParameterCount = pSMB->TotalParameterCount;
4238 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4239 pSMB->Reserved4 = 0;
4240 pSMB->hdr.smb_buf_length += byte_count;
4241 pSMB->ByteCount = cpu_to_le16(byte_count);
4242
4243 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4244 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4245 if (rc) {
4246 cFYI(1, ("Send error in Query EA = %d", rc));
4247 } else { /* decode response */
4248 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4249
4250 /* BB also check enough total bytes returned */
4251 /* BB we need to improve the validity checking
4252 of these trans2 responses */
4253 if (rc || (pSMBr->ByteCount < 4))
4254 rc = -EIO; /* bad smb */
4255 /* else if (pFindData){
4256 memcpy((char *) pFindData,
4257 (char *) &pSMBr->hdr.Protocol +
4258 data_offset, kl);
4259 }*/ else {
4260 /* check that length of list is not more than bcc */
4261 /* check that each entry does not go beyond length
4262 of list */
4263 /* check that each element of each entry does not
4264 go beyond end of list */
4265 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4266 struct fealist * ea_response_data;
4267 rc = -ENODATA;
4268 /* validate_trans2_offsets() */
4269 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4270 ea_response_data = (struct fealist *)
4271 (((char *) &pSMBr->hdr.Protocol) +
4272 data_offset);
4273 name_len = le32_to_cpu(ea_response_data->list_len);
4274 cFYI(1,("ea length %d", name_len));
4275 if(name_len <= 8) {
4276 /* returned EA size zeroed at top of function */
4277 cFYI(1,("empty EA list returned from server"));
4278 } else {
4279 /* account for ea list len */
4280 name_len -= 4;
4281 temp_fea = ea_response_data->list;
4282 temp_ptr = (char *)temp_fea;
4283 /* loop through checking if we have a matching
4284 name and then return the associated value */
4285 while(name_len > 0) {
4286 __u16 value_len;
4287 name_len -= 4;
4288 temp_ptr += 4;
4289 value_len = le16_to_cpu(temp_fea->value_len);
4290 /* BB validate that value_len falls within SMB,
4291 even though maximum for name_len is 255 */
4292 if(memcmp(temp_fea->name,ea_name,
4293 temp_fea->name_len) == 0) {
4294 /* found a match */
4295 rc = value_len;
4296 /* account for prefix user. and trailing null */
4297 if(rc<=(int)buf_size) {
4298 memcpy(ea_value,
4299 temp_fea->name+temp_fea->name_len+1,
4300 rc);
4301 /* ea values, unlike ea names,
4302 are not null terminated */
4303 } else if(buf_size == 0) {
4304 /* skip copy - calc size only */
4305 } else {
4306 /* stop before overrun buffer */
4307 rc = -ERANGE;
4308 }
4309 break;
4310 }
4311 name_len -= temp_fea->name_len;
4312 temp_ptr += temp_fea->name_len;
4313 /* account for trailing null */
4314 name_len--;
4315 temp_ptr++;
4316 name_len -= value_len;
4317 temp_ptr += value_len;
4318 /* no trailing null to account for in value len */
4319 /* go on to next EA */
4320 temp_fea = (struct fea *)temp_ptr;
4321 }
4322 }
4323 }
4324 }
4325 if (pSMB)
4326 cifs_buf_release(pSMB);
4327 if (rc == -EAGAIN)
4328 goto QEARetry;
4329
4330 return (ssize_t)rc;
4331}
4332
4333int
4334CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4335 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004336 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4337 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338{
4339 struct smb_com_transaction2_spi_req *pSMB = NULL;
4340 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4341 struct fealist *parm_data;
4342 int name_len;
4343 int rc = 0;
4344 int bytes_returned = 0;
4345 __u16 params, param_offset, byte_count, offset, count;
4346
4347 cFYI(1, ("In SetEA"));
4348SetEARetry:
4349 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4350 (void **) &pSMBr);
4351 if (rc)
4352 return rc;
4353
4354 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4355 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004356 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004357 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358 name_len++; /* trailing null */
4359 name_len *= 2;
4360 } else { /* BB improve the check for buffer overruns BB */
4361 name_len = strnlen(fileName, PATH_MAX);
4362 name_len++; /* trailing null */
4363 strncpy(pSMB->FileName, fileName, name_len);
4364 }
4365
4366 params = 6 + name_len;
4367
4368 /* done calculating parms using name_len of file name,
4369 now use name_len to calculate length of ea name
4370 we are going to create in the inode xattrs */
4371 if(ea_name == NULL)
4372 name_len = 0;
4373 else
4374 name_len = strnlen(ea_name,255);
4375
4376 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4377 pSMB->MaxParameterCount = cpu_to_le16(2);
4378 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4379 pSMB->MaxSetupCount = 0;
4380 pSMB->Reserved = 0;
4381 pSMB->Flags = 0;
4382 pSMB->Timeout = 0;
4383 pSMB->Reserved2 = 0;
4384 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4385 InformationLevel) - 4;
4386 offset = param_offset + params;
4387 pSMB->InformationLevel =
4388 cpu_to_le16(SMB_SET_FILE_EA);
4389
4390 parm_data =
4391 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4392 offset);
4393 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4394 pSMB->DataOffset = cpu_to_le16(offset);
4395 pSMB->SetupCount = 1;
4396 pSMB->Reserved3 = 0;
4397 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4398 byte_count = 3 /* pad */ + params + count;
4399 pSMB->DataCount = cpu_to_le16(count);
4400 parm_data->list_len = cpu_to_le32(count);
4401 parm_data->list[0].EA_flags = 0;
4402 /* we checked above that name len is less than 255 */
4403 parm_data->list[0].name_len = (__u8)name_len;;
4404 /* EA names are always ASCII */
4405 if(ea_name)
4406 strncpy(parm_data->list[0].name,ea_name,name_len);
4407 parm_data->list[0].name[name_len] = 0;
4408 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4409 /* caller ensures that ea_value_len is less than 64K but
4410 we need to ensure that it fits within the smb */
4411
4412 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4413 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4414 if(ea_value_len)
4415 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4416
4417 pSMB->TotalDataCount = pSMB->DataCount;
4418 pSMB->ParameterCount = cpu_to_le16(params);
4419 pSMB->TotalParameterCount = pSMB->ParameterCount;
4420 pSMB->Reserved4 = 0;
4421 pSMB->hdr.smb_buf_length += byte_count;
4422 pSMB->ByteCount = cpu_to_le16(byte_count);
4423 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4424 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4425 if (rc) {
4426 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4427 }
4428
4429 cifs_buf_release(pSMB);
4430
4431 if (rc == -EAGAIN)
4432 goto SetEARetry;
4433
4434 return rc;
4435}
4436
4437#endif