blob: b8830118f09a0f755e1d733553c06be842ac43b8 [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
Steve Frencha9d02ad2005-08-24 23:06:05 -0700683static __u16 convert_disposition(int disposition)
684{
685 __u16 ofun = 0;
686
687 switch (disposition) {
688 case FILE_SUPERSEDE:
689 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
690 break;
691 case FILE_OPEN:
692 ofun = SMBOPEN_OAPPEND;
693 break;
694 case FILE_CREATE:
695 ofun = SMBOPEN_OCREATE;
696 break;
697 case FILE_OPEN_IF:
698 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
699 break;
700 case FILE_OVERWRITE:
701 ofun = SMBOPEN_OTRUNC;
702 break;
703 case FILE_OVERWRITE_IF:
704 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
705 break;
706 default:
707 cFYI(1,("unknown disposition %d",disposition));
708 ofun = SMBOPEN_OAPPEND; /* regular open */
709 }
710 return ofun;
711}
712
713int
714SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
715 const char *fileName, const int openDisposition,
716 const int access_flags, const int create_options, __u16 * netfid,
717 int *pOplock, FILE_ALL_INFO * pfile_info,
718 const struct nls_table *nls_codepage, int remap)
719{
720 int rc = -EACCES;
721 OPENX_REQ *pSMB = NULL;
722 OPENX_RSP *pSMBr = NULL;
723 int bytes_returned;
724 int name_len;
725 __u16 count;
726
727OldOpenRetry:
728 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
729 (void **) &pSMBr);
730 if (rc)
731 return rc;
732
733 pSMB->AndXCommand = 0xFF; /* none */
734
735 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
736 count = 1; /* account for one byte pad to word boundary */
737 name_len =
738 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
739 fileName, PATH_MAX, nls_codepage, remap);
740 name_len++; /* trailing null */
741 name_len *= 2;
742 } else { /* BB improve check for buffer overruns BB */
743 count = 0; /* no pad */
744 name_len = strnlen(fileName, PATH_MAX);
745 name_len++; /* trailing null */
746 strncpy(pSMB->fileName, fileName, name_len);
747 }
748 if (*pOplock & REQ_OPLOCK)
749 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
750 else if (*pOplock & REQ_BATCHOPLOCK) {
751 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
752 }
753 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
754 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
755 /* 0 = read
756 1 = write
757 2 = rw
758 3 = execute
759 */
760 pSMB->Mode = cpu_to_le16(2);
761 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
762 /* set file as system file if special file such
763 as fifo and server expecting SFU style and
764 no Unix extensions */
765
766 if(create_options & CREATE_OPTION_SPECIAL)
767 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
768 else
769 pSMB->FileAttributes = cpu_to_le16(ATTR_NORMAL);
770
771 /* if ((omode & S_IWUGO) == 0)
772 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
773 /* Above line causes problems due to vfs splitting create into two
774 pieces - need to set mode after file created not while it is
775 being created */
776
777 /* BB FIXME BB */
778/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
779 /* BB FIXME END BB */
780 pSMB->OpenFunction = convert_disposition(openDisposition);
781 count += name_len;
782 pSMB->hdr.smb_buf_length += count;
783
784 pSMB->ByteCount = cpu_to_le16(count);
785 /* long_op set to 1 to allow for oplock break timeouts */
786 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
787 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
788 cifs_stats_inc(&tcon->num_opens);
789 if (rc) {
790 cFYI(1, ("Error in Open = %d", rc));
791 } else {
792 /* BB verify if wct == 15 */
793
794/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
795
796 *netfid = pSMBr->Fid; /* cifs fid stays in le */
797 /* Let caller know file was created so we can set the mode. */
798 /* Do we care about the CreateAction in any other cases? */
799 /* BB FIXME BB */
800/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
801 *pOplock |= CIFS_CREATE_ACTION; */
802 /* BB FIXME END */
803
804 if(pfile_info) {
805 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
806 pfile_info->LastAccessTime = 0; /* BB fixme */
807 pfile_info->LastWriteTime = 0; /* BB fixme */
808 pfile_info->ChangeTime = 0; /* BB fixme */
809 pfile_info->Attributes = pSMBr->FileAttributes;
810 /* the file_info buf is endian converted by caller */
811 pfile_info->AllocationSize = pSMBr->EndOfFile;
812 pfile_info->EndOfFile = pSMBr->EndOfFile;
813 pfile_info->NumberOfLinks = cpu_to_le32(1);
814 }
815 }
816
817 cifs_buf_release(pSMB);
818 if (rc == -EAGAIN)
819 goto OldOpenRetry;
820 return rc;
821}
822
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823int
824CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
825 const char *fileName, const int openDisposition,
826 const int access_flags, const int create_options, __u16 * netfid,
827 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -0700828 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829{
830 int rc = -EACCES;
831 OPEN_REQ *pSMB = NULL;
832 OPEN_RSP *pSMBr = NULL;
833 int bytes_returned;
834 int name_len;
835 __u16 count;
836
837openRetry:
838 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
839 (void **) &pSMBr);
840 if (rc)
841 return rc;
842
843 pSMB->AndXCommand = 0xFF; /* none */
844
845 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
846 count = 1; /* account for one byte pad to word boundary */
847 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500848 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -0700849 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 name_len++; /* trailing null */
851 name_len *= 2;
852 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -0700853 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 count = 0; /* no pad */
855 name_len = strnlen(fileName, PATH_MAX);
856 name_len++; /* trailing null */
857 pSMB->NameLength = cpu_to_le16(name_len);
858 strncpy(pSMB->fileName, fileName, name_len);
859 }
860 if (*pOplock & REQ_OPLOCK)
861 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
862 else if (*pOplock & REQ_BATCHOPLOCK) {
863 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
864 }
865 pSMB->DesiredAccess = cpu_to_le32(access_flags);
866 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -0700867 /* set file as system file if special file such
868 as fifo and server expecting SFU style and
869 no Unix extensions */
870 if(create_options & CREATE_OPTION_SPECIAL)
871 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
872 else
873 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 /* XP does not handle ATTR_POSIX_SEMANTICS */
875 /* but it helps speed up case sensitive checks for other
876 servers such as Samba */
877 if (tcon->ses->capabilities & CAP_UNIX)
878 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
879
880 /* if ((omode & S_IWUGO) == 0)
881 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
882 /* Above line causes problems due to vfs splitting create into two
883 pieces - need to set mode after file created not while it is
884 being created */
885 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
886 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -0700887 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -0700888 /* BB Expirement with various impersonation levels and verify */
889 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 pSMB->SecurityFlags =
891 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
892
893 count += name_len;
894 pSMB->hdr.smb_buf_length += count;
895
896 pSMB->ByteCount = cpu_to_le16(count);
897 /* long_op set to 1 to allow for oplock break timeouts */
898 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
899 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha45443472005-08-24 13:59:35 -0700900 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 if (rc) {
902 cFYI(1, ("Error in Open = %d", rc));
903 } else {
Steve French09d1db52005-04-28 22:41:08 -0700904 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 *netfid = pSMBr->Fid; /* cifs fid stays in le */
906 /* Let caller know file was created so we can set the mode. */
907 /* Do we care about the CreateAction in any other cases? */
908 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
909 *pOplock |= CIFS_CREATE_ACTION;
910 if(pfile_info) {
911 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
912 36 /* CreationTime to Attributes */);
913 /* the file_info buf is endian converted by caller */
914 pfile_info->AllocationSize = pSMBr->AllocationSize;
915 pfile_info->EndOfFile = pSMBr->EndOfFile;
916 pfile_info->NumberOfLinks = cpu_to_le32(1);
917 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700919
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 cifs_buf_release(pSMB);
921 if (rc == -EAGAIN)
922 goto openRetry;
923 return rc;
924}
925
926/* If no buffer passed in, then caller wants to do the copy
927 as in the case of readpages so the SMB buffer must be
928 freed by the caller */
929
930int
931CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
932 const int netfid, const unsigned int count,
933 const __u64 lseek, unsigned int *nbytes, char **buf)
934{
935 int rc = -EACCES;
936 READ_REQ *pSMB = NULL;
937 READ_RSP *pSMBr = NULL;
938 char *pReadData = NULL;
939 int bytes_returned;
Steve Frenchbfa0d752005-08-31 21:50:37 -0700940 int wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
942 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -0700943 if(tcon->ses->capabilities & CAP_LARGE_FILES)
944 wct = 12;
945 else
946 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
948 *nbytes = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -0700949 rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 (void **) &pSMBr);
951 if (rc)
952 return rc;
953
954 /* tcon and ses pointer are checked in smb_init */
955 if (tcon->ses->server == NULL)
956 return -ECONNABORTED;
957
958 pSMB->AndXCommand = 0xFF; /* none */
959 pSMB->Fid = netfid;
960 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -0700961 if(wct == 12)
962 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
963 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
964 return -EIO;
965
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 pSMB->Remaining = 0;
967 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
968 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -0700969 if(wct == 12)
970 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
971 else {
972 /* old style read */
973 struct smb_com_readx_req * pSMBW =
974 (struct smb_com_readx_req *)pSMB;
975 pSMBW->ByteCount = 0;
976 }
977
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
979 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700980 cifs_stats_inc(&tcon->num_reads);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 if (rc) {
982 cERROR(1, ("Send error in read = %d", rc));
983 } else {
984 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
985 data_length = data_length << 16;
986 data_length += le16_to_cpu(pSMBr->DataLength);
987 *nbytes = data_length;
988
989 /*check that DataLength would not go beyond end of SMB */
990 if ((data_length > CIFSMaxBufSize)
991 || (data_length > count)) {
992 cFYI(1,("bad length %d for count %d",data_length,count));
993 rc = -EIO;
994 *nbytes = 0;
995 } else {
996 pReadData =
997 (char *) (&pSMBr->hdr.Protocol) +
998 le16_to_cpu(pSMBr->DataOffset);
999/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1000 cERROR(1,("Faulting on read rc = %d",rc));
1001 rc = -EFAULT;
1002 }*/ /* can not use copy_to_user when using page cache*/
1003 if(*buf)
1004 memcpy(*buf,pReadData,data_length);
1005 }
1006 }
1007 if(*buf)
1008 cifs_buf_release(pSMB);
1009 else
1010 *buf = (char *)pSMB;
1011
1012 /* Note: On -EAGAIN error only caller can retry on handle based calls
1013 since file handle passed in no longer valid */
1014 return rc;
1015}
1016
1017int
1018CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1019 const int netfid, const unsigned int count,
1020 const __u64 offset, unsigned int *nbytes, const char *buf,
1021 const char __user * ubuf, const int long_op)
1022{
1023 int rc = -EACCES;
1024 WRITE_REQ *pSMB = NULL;
1025 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001026 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 __u32 bytes_sent;
1028 __u16 byte_count;
1029
1030 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001031 if(tcon->ses == NULL)
1032 return -ECONNABORTED;
1033
1034 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1035 wct = 14;
1036 else
1037 wct = 12;
1038
1039 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 (void **) &pSMBr);
1041 if (rc)
1042 return rc;
1043 /* tcon and ses pointer are checked in smb_init */
1044 if (tcon->ses->server == NULL)
1045 return -ECONNABORTED;
1046
1047 pSMB->AndXCommand = 0xFF; /* none */
1048 pSMB->Fid = netfid;
1049 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001050 if(wct == 14)
1051 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1052 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1053 return -EIO;
1054
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 pSMB->Reserved = 0xFFFFFFFF;
1056 pSMB->WriteMode = 0;
1057 pSMB->Remaining = 0;
1058
1059 /* Can increase buffer size if buffer is big enough in some cases - ie we
1060 can send more if LARGE_WRITE_X capability returned by the server and if
1061 our buffer is big enough or if we convert to iovecs on socket writes
1062 and eliminate the copy to the CIFS buffer */
1063 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1064 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1065 } else {
1066 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1067 & ~0xFF;
1068 }
1069
1070 if (bytes_sent > count)
1071 bytes_sent = count;
1072 pSMB->DataOffset =
1073 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1074 if(buf)
1075 memcpy(pSMB->Data,buf,bytes_sent);
1076 else if(ubuf) {
1077 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1078 cifs_buf_release(pSMB);
1079 return -EFAULT;
1080 }
1081 } else {
1082 /* No buffer */
1083 cifs_buf_release(pSMB);
1084 return -EINVAL;
1085 }
1086
1087 byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
1088 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1089 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1090 pSMB->hdr.smb_buf_length += bytes_sent+1;
Steve French1c955182005-08-30 20:58:07 -07001091
1092 if(wct == 14)
1093 pSMB->ByteCount = cpu_to_le16(byte_count);
1094 else { /* old style write has byte count 4 bytes earlier */
1095 struct smb_com_writex_req * pSMBW =
1096 (struct smb_com_writex_req *)pSMB;
1097 pSMBW->ByteCount = cpu_to_le16(byte_count);
1098 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099
1100 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1101 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001102 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 if (rc) {
1104 cFYI(1, ("Send error in write = %d", rc));
1105 *nbytes = 0;
1106 } else {
1107 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1108 *nbytes = (*nbytes) << 16;
1109 *nbytes += le16_to_cpu(pSMBr->Count);
1110 }
1111
1112 cifs_buf_release(pSMB);
1113
1114 /* Note: On -EAGAIN error only caller can retry on handle based calls
1115 since file handle passed in no longer valid */
1116
1117 return rc;
1118}
1119
1120#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001121int
1122CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 const int netfid, const unsigned int count,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001124 const __u64 offset, unsigned int *nbytes, const char *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 const int long_op)
1126{
1127 int rc = -EACCES;
1128 WRITE_REQ *pSMB = NULL;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001129 int bytes_returned;
1130 int smb_hdr_len;
1131 __u32 bytes_sent;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 __u16 byte_count;
1133
Steve French0c0ff092005-06-23 19:31:17 -05001134 cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 if (rc)
1137 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 /* tcon and ses pointer are checked in smb_init */
1139 if (tcon->ses->server == NULL)
1140 return -ECONNABORTED;
1141
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001142 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 pSMB->Fid = netfid;
1144 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1145 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1146 pSMB->Reserved = 0xFFFFFFFF;
1147 pSMB->WriteMode = 0;
1148 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001149
1150 /* Can increase buffer size if buffer is big enough in some cases - ie
1151 can send more if LARGE_WRITE_X capability returned by the server and if
1152 our buffer is big enough or if we convert to iovecs on socket writes
1153 and eliminate the copy to the CIFS buffer */
1154 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1155 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1156 } else {
1157 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1158 & ~0xFF;
1159 }
1160
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 if (bytes_sent > count)
1162 bytes_sent = count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 pSMB->DataOffset =
1164 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1165
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001166 byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
1167 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1168 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1169 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1170 pSMB->hdr.smb_buf_length += bytes_sent+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 pSMB->ByteCount = cpu_to_le16(byte_count);
1172
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001173 rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
1174 buf, bytes_sent, &bytes_returned, long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001175 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 if (rc) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001177 cFYI(1, ("Send error in write = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001179 } else {
1180 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
1181 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1182 *nbytes = (*nbytes) << 16;
1183 *nbytes += le16_to_cpu(pSMBr->Count);
1184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185
1186 cifs_small_buf_release(pSMB);
1187
1188 /* Note: On -EAGAIN error only caller can retry on handle based calls
1189 since file handle passed in no longer valid */
1190
1191 return rc;
1192}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001193
1194
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195#endif /* CIFS_EXPERIMENTAL */
1196
1197int
1198CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1199 const __u16 smb_file_id, const __u64 len,
1200 const __u64 offset, const __u32 numUnlock,
1201 const __u32 numLock, const __u8 lockType, const int waitFlag)
1202{
1203 int rc = 0;
1204 LOCK_REQ *pSMB = NULL;
1205 LOCK_RSP *pSMBr = NULL;
1206 int bytes_returned;
1207 int timeout = 0;
1208 __u16 count;
1209
1210 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001211 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1212
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 if (rc)
1214 return rc;
1215
Steve French46810cb2005-04-28 22:41:09 -07001216 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1217
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1219 timeout = -1; /* no response expected */
1220 pSMB->Timeout = 0;
1221 } else if (waitFlag == TRUE) {
1222 timeout = 3; /* blocking operation, no timeout */
1223 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1224 } else {
1225 pSMB->Timeout = 0;
1226 }
1227
1228 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1229 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1230 pSMB->LockType = lockType;
1231 pSMB->AndXCommand = 0xFF; /* none */
1232 pSMB->Fid = smb_file_id; /* netfid stays le */
1233
1234 if((numLock != 0) || (numUnlock != 0)) {
1235 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1236 /* BB where to store pid high? */
1237 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1238 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1239 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1240 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1241 count = sizeof(LOCKING_ANDX_RANGE);
1242 } else {
1243 /* oplock break */
1244 count = 0;
1245 }
1246 pSMB->hdr.smb_buf_length += count;
1247 pSMB->ByteCount = cpu_to_le16(count);
1248
1249 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1250 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha45443472005-08-24 13:59:35 -07001251 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 if (rc) {
1253 cFYI(1, ("Send error in Lock = %d", rc));
1254 }
Steve French46810cb2005-04-28 22:41:09 -07001255 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
1257 /* Note: On -EAGAIN error only caller can retry on handle based calls
1258 since file handle passed in no longer valid */
1259 return rc;
1260}
1261
1262int
1263CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1264{
1265 int rc = 0;
1266 CLOSE_REQ *pSMB = NULL;
1267 CLOSE_RSP *pSMBr = NULL;
1268 int bytes_returned;
1269 cFYI(1, ("In CIFSSMBClose"));
1270
1271/* do not retry on dead session on close */
1272 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1273 if(rc == -EAGAIN)
1274 return 0;
1275 if (rc)
1276 return rc;
1277
1278 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1279
1280 pSMB->FileID = (__u16) smb_file_id;
1281 pSMB->LastWriteTime = 0;
1282 pSMB->ByteCount = 0;
1283 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1284 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001285 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 if (rc) {
1287 if(rc!=-EINTR) {
1288 /* EINTR is expected when user ctl-c to kill app */
1289 cERROR(1, ("Send error in Close = %d", rc));
1290 }
1291 }
1292
1293 cifs_small_buf_release(pSMB);
1294
1295 /* Since session is dead, file will be closed on server already */
1296 if(rc == -EAGAIN)
1297 rc = 0;
1298
1299 return rc;
1300}
1301
1302int
1303CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1304 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001305 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306{
1307 int rc = 0;
1308 RENAME_REQ *pSMB = NULL;
1309 RENAME_RSP *pSMBr = NULL;
1310 int bytes_returned;
1311 int name_len, name_len2;
1312 __u16 count;
1313
1314 cFYI(1, ("In CIFSSMBRename"));
1315renameRetry:
1316 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1317 (void **) &pSMBr);
1318 if (rc)
1319 return rc;
1320
1321 pSMB->BufferFormat = 0x04;
1322 pSMB->SearchAttributes =
1323 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1324 ATTR_DIRECTORY);
1325
1326 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1327 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001328 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001329 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 name_len++; /* trailing null */
1331 name_len *= 2;
1332 pSMB->OldFileName[name_len] = 0x04; /* pad */
1333 /* protocol requires ASCII signature byte on Unicode string */
1334 pSMB->OldFileName[name_len + 1] = 0x00;
1335 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001336 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001337 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1339 name_len2 *= 2; /* convert to bytes */
1340 } else { /* BB improve the check for buffer overruns BB */
1341 name_len = strnlen(fromName, PATH_MAX);
1342 name_len++; /* trailing null */
1343 strncpy(pSMB->OldFileName, fromName, name_len);
1344 name_len2 = strnlen(toName, PATH_MAX);
1345 name_len2++; /* trailing null */
1346 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1347 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1348 name_len2++; /* trailing null */
1349 name_len2++; /* signature byte */
1350 }
1351
1352 count = 1 /* 1st signature byte */ + name_len + name_len2;
1353 pSMB->hdr.smb_buf_length += count;
1354 pSMB->ByteCount = cpu_to_le16(count);
1355
1356 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1357 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001358 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 if (rc) {
1360 cFYI(1, ("Send error in rename = %d", rc));
1361 }
1362
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 cifs_buf_release(pSMB);
1364
1365 if (rc == -EAGAIN)
1366 goto renameRetry;
1367
1368 return rc;
1369}
1370
1371int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001372 int netfid, char * target_name,
1373 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374{
1375 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1376 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1377 struct set_file_rename * rename_info;
1378 char *data_offset;
1379 char dummy_string[30];
1380 int rc = 0;
1381 int bytes_returned = 0;
1382 int len_of_str;
1383 __u16 params, param_offset, offset, count, byte_count;
1384
1385 cFYI(1, ("Rename to File by handle"));
1386 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1387 (void **) &pSMBr);
1388 if (rc)
1389 return rc;
1390
1391 params = 6;
1392 pSMB->MaxSetupCount = 0;
1393 pSMB->Reserved = 0;
1394 pSMB->Flags = 0;
1395 pSMB->Timeout = 0;
1396 pSMB->Reserved2 = 0;
1397 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1398 offset = param_offset + params;
1399
1400 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1401 rename_info = (struct set_file_rename *) data_offset;
1402 pSMB->MaxParameterCount = cpu_to_le16(2);
1403 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1404 pSMB->SetupCount = 1;
1405 pSMB->Reserved3 = 0;
1406 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1407 byte_count = 3 /* pad */ + params;
1408 pSMB->ParameterCount = cpu_to_le16(params);
1409 pSMB->TotalParameterCount = pSMB->ParameterCount;
1410 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1411 pSMB->DataOffset = cpu_to_le16(offset);
1412 /* construct random name ".cifs_tmp<inodenum><mid>" */
1413 rename_info->overwrite = cpu_to_le32(1);
1414 rename_info->root_fid = 0;
1415 /* unicode only call */
1416 if(target_name == NULL) {
1417 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001418 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001419 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001421 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001422 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 }
1424 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1425 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1426 byte_count += count;
1427 pSMB->DataCount = cpu_to_le16(count);
1428 pSMB->TotalDataCount = pSMB->DataCount;
1429 pSMB->Fid = netfid;
1430 pSMB->InformationLevel =
1431 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1432 pSMB->Reserved4 = 0;
1433 pSMB->hdr.smb_buf_length += byte_count;
1434 pSMB->ByteCount = cpu_to_le16(byte_count);
1435 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1436 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001437 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 if (rc) {
1439 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1440 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001441
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 cifs_buf_release(pSMB);
1443
1444 /* Note: On -EAGAIN error only caller can retry on handle based calls
1445 since file handle passed in no longer valid */
1446
1447 return rc;
1448}
1449
1450int
1451CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1452 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001453 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454{
1455 int rc = 0;
1456 COPY_REQ *pSMB = NULL;
1457 COPY_RSP *pSMBr = NULL;
1458 int bytes_returned;
1459 int name_len, name_len2;
1460 __u16 count;
1461
1462 cFYI(1, ("In CIFSSMBCopy"));
1463copyRetry:
1464 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1465 (void **) &pSMBr);
1466 if (rc)
1467 return rc;
1468
1469 pSMB->BufferFormat = 0x04;
1470 pSMB->Tid2 = target_tid;
1471
1472 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1473
1474 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001475 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001476 fromName, PATH_MAX, nls_codepage,
1477 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 name_len++; /* trailing null */
1479 name_len *= 2;
1480 pSMB->OldFileName[name_len] = 0x04; /* pad */
1481 /* protocol requires ASCII signature byte on Unicode string */
1482 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001483 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001484 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1486 name_len2 *= 2; /* convert to bytes */
1487 } else { /* BB improve the check for buffer overruns BB */
1488 name_len = strnlen(fromName, PATH_MAX);
1489 name_len++; /* trailing null */
1490 strncpy(pSMB->OldFileName, fromName, name_len);
1491 name_len2 = strnlen(toName, PATH_MAX);
1492 name_len2++; /* trailing null */
1493 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1494 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1495 name_len2++; /* trailing null */
1496 name_len2++; /* signature byte */
1497 }
1498
1499 count = 1 /* 1st signature byte */ + name_len + name_len2;
1500 pSMB->hdr.smb_buf_length += count;
1501 pSMB->ByteCount = cpu_to_le16(count);
1502
1503 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1504 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1505 if (rc) {
1506 cFYI(1, ("Send error in copy = %d with %d files copied",
1507 rc, le16_to_cpu(pSMBr->CopyCount)));
1508 }
1509 if (pSMB)
1510 cifs_buf_release(pSMB);
1511
1512 if (rc == -EAGAIN)
1513 goto copyRetry;
1514
1515 return rc;
1516}
1517
1518int
1519CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1520 const char *fromName, const char *toName,
1521 const struct nls_table *nls_codepage)
1522{
1523 TRANSACTION2_SPI_REQ *pSMB = NULL;
1524 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1525 char *data_offset;
1526 int name_len;
1527 int name_len_target;
1528 int rc = 0;
1529 int bytes_returned = 0;
1530 __u16 params, param_offset, offset, byte_count;
1531
1532 cFYI(1, ("In Symlink Unix style"));
1533createSymLinkRetry:
1534 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1535 (void **) &pSMBr);
1536 if (rc)
1537 return rc;
1538
1539 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1540 name_len =
1541 cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
1542 /* find define for this maxpathcomponent */
1543 , nls_codepage);
1544 name_len++; /* trailing null */
1545 name_len *= 2;
1546
1547 } else { /* BB improve the check for buffer overruns BB */
1548 name_len = strnlen(fromName, PATH_MAX);
1549 name_len++; /* trailing null */
1550 strncpy(pSMB->FileName, fromName, name_len);
1551 }
1552 params = 6 + name_len;
1553 pSMB->MaxSetupCount = 0;
1554 pSMB->Reserved = 0;
1555 pSMB->Flags = 0;
1556 pSMB->Timeout = 0;
1557 pSMB->Reserved2 = 0;
1558 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1559 InformationLevel) - 4;
1560 offset = param_offset + params;
1561
1562 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1563 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1564 name_len_target =
1565 cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
1566 /* find define for this maxpathcomponent */
1567 , nls_codepage);
1568 name_len_target++; /* trailing null */
1569 name_len_target *= 2;
1570 } else { /* BB improve the check for buffer overruns BB */
1571 name_len_target = strnlen(toName, PATH_MAX);
1572 name_len_target++; /* trailing null */
1573 strncpy(data_offset, toName, name_len_target);
1574 }
1575
1576 pSMB->MaxParameterCount = cpu_to_le16(2);
1577 /* BB find exact max on data count below from sess */
1578 pSMB->MaxDataCount = cpu_to_le16(1000);
1579 pSMB->SetupCount = 1;
1580 pSMB->Reserved3 = 0;
1581 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1582 byte_count = 3 /* pad */ + params + name_len_target;
1583 pSMB->DataCount = cpu_to_le16(name_len_target);
1584 pSMB->ParameterCount = cpu_to_le16(params);
1585 pSMB->TotalDataCount = pSMB->DataCount;
1586 pSMB->TotalParameterCount = pSMB->ParameterCount;
1587 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1588 pSMB->DataOffset = cpu_to_le16(offset);
1589 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1590 pSMB->Reserved4 = 0;
1591 pSMB->hdr.smb_buf_length += byte_count;
1592 pSMB->ByteCount = cpu_to_le16(byte_count);
1593 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1594 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001595 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 if (rc) {
1597 cFYI(1,
1598 ("Send error in SetPathInfo (create symlink) = %d",
1599 rc));
1600 }
1601
1602 if (pSMB)
1603 cifs_buf_release(pSMB);
1604
1605 if (rc == -EAGAIN)
1606 goto createSymLinkRetry;
1607
1608 return rc;
1609}
1610
1611int
1612CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1613 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001614 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615{
1616 TRANSACTION2_SPI_REQ *pSMB = NULL;
1617 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1618 char *data_offset;
1619 int name_len;
1620 int name_len_target;
1621 int rc = 0;
1622 int bytes_returned = 0;
1623 __u16 params, param_offset, offset, byte_count;
1624
1625 cFYI(1, ("In Create Hard link Unix style"));
1626createHardLinkRetry:
1627 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1628 (void **) &pSMBr);
1629 if (rc)
1630 return rc;
1631
1632 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001633 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001634 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 name_len++; /* trailing null */
1636 name_len *= 2;
1637
1638 } else { /* BB improve the check for buffer overruns BB */
1639 name_len = strnlen(toName, PATH_MAX);
1640 name_len++; /* trailing null */
1641 strncpy(pSMB->FileName, toName, name_len);
1642 }
1643 params = 6 + name_len;
1644 pSMB->MaxSetupCount = 0;
1645 pSMB->Reserved = 0;
1646 pSMB->Flags = 0;
1647 pSMB->Timeout = 0;
1648 pSMB->Reserved2 = 0;
1649 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1650 InformationLevel) - 4;
1651 offset = param_offset + params;
1652
1653 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1654 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1655 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001656 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001657 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 name_len_target++; /* trailing null */
1659 name_len_target *= 2;
1660 } else { /* BB improve the check for buffer overruns BB */
1661 name_len_target = strnlen(fromName, PATH_MAX);
1662 name_len_target++; /* trailing null */
1663 strncpy(data_offset, fromName, name_len_target);
1664 }
1665
1666 pSMB->MaxParameterCount = cpu_to_le16(2);
1667 /* BB find exact max on data count below from sess*/
1668 pSMB->MaxDataCount = cpu_to_le16(1000);
1669 pSMB->SetupCount = 1;
1670 pSMB->Reserved3 = 0;
1671 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1672 byte_count = 3 /* pad */ + params + name_len_target;
1673 pSMB->ParameterCount = cpu_to_le16(params);
1674 pSMB->TotalParameterCount = pSMB->ParameterCount;
1675 pSMB->DataCount = cpu_to_le16(name_len_target);
1676 pSMB->TotalDataCount = pSMB->DataCount;
1677 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1678 pSMB->DataOffset = cpu_to_le16(offset);
1679 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1680 pSMB->Reserved4 = 0;
1681 pSMB->hdr.smb_buf_length += byte_count;
1682 pSMB->ByteCount = cpu_to_le16(byte_count);
1683 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1684 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001685 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 if (rc) {
1687 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1688 }
1689
1690 cifs_buf_release(pSMB);
1691 if (rc == -EAGAIN)
1692 goto createHardLinkRetry;
1693
1694 return rc;
1695}
1696
1697int
1698CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1699 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001700 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701{
1702 int rc = 0;
1703 NT_RENAME_REQ *pSMB = NULL;
1704 RENAME_RSP *pSMBr = NULL;
1705 int bytes_returned;
1706 int name_len, name_len2;
1707 __u16 count;
1708
1709 cFYI(1, ("In CIFSCreateHardLink"));
1710winCreateHardLinkRetry:
1711
1712 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1713 (void **) &pSMBr);
1714 if (rc)
1715 return rc;
1716
1717 pSMB->SearchAttributes =
1718 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1719 ATTR_DIRECTORY);
1720 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1721 pSMB->ClusterCount = 0;
1722
1723 pSMB->BufferFormat = 0x04;
1724
1725 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1726 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001727 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001728 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 name_len++; /* trailing null */
1730 name_len *= 2;
1731 pSMB->OldFileName[name_len] = 0; /* pad */
1732 pSMB->OldFileName[name_len + 1] = 0x04;
1733 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001734 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001735 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1737 name_len2 *= 2; /* convert to bytes */
1738 } else { /* BB improve the check for buffer overruns BB */
1739 name_len = strnlen(fromName, PATH_MAX);
1740 name_len++; /* trailing null */
1741 strncpy(pSMB->OldFileName, fromName, name_len);
1742 name_len2 = strnlen(toName, PATH_MAX);
1743 name_len2++; /* trailing null */
1744 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1745 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1746 name_len2++; /* trailing null */
1747 name_len2++; /* signature byte */
1748 }
1749
1750 count = 1 /* string type byte */ + name_len + name_len2;
1751 pSMB->hdr.smb_buf_length += count;
1752 pSMB->ByteCount = cpu_to_le16(count);
1753
1754 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1755 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001756 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 if (rc) {
1758 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1759 }
1760 cifs_buf_release(pSMB);
1761 if (rc == -EAGAIN)
1762 goto winCreateHardLinkRetry;
1763
1764 return rc;
1765}
1766
1767int
1768CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1769 const unsigned char *searchName,
1770 char *symlinkinfo, const int buflen,
1771 const struct nls_table *nls_codepage)
1772{
1773/* SMB_QUERY_FILE_UNIX_LINK */
1774 TRANSACTION2_QPI_REQ *pSMB = NULL;
1775 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1776 int rc = 0;
1777 int bytes_returned;
1778 int name_len;
1779 __u16 params, byte_count;
1780
1781 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1782
1783querySymLinkRetry:
1784 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1785 (void **) &pSMBr);
1786 if (rc)
1787 return rc;
1788
1789 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1790 name_len =
1791 cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1792 /* find define for this maxpathcomponent */
1793 , nls_codepage);
1794 name_len++; /* trailing null */
1795 name_len *= 2;
1796 } else { /* BB improve the check for buffer overruns BB */
1797 name_len = strnlen(searchName, PATH_MAX);
1798 name_len++; /* trailing null */
1799 strncpy(pSMB->FileName, searchName, name_len);
1800 }
1801
1802 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1803 pSMB->TotalDataCount = 0;
1804 pSMB->MaxParameterCount = cpu_to_le16(2);
1805 /* BB find exact max data count below from sess structure BB */
1806 pSMB->MaxDataCount = cpu_to_le16(4000);
1807 pSMB->MaxSetupCount = 0;
1808 pSMB->Reserved = 0;
1809 pSMB->Flags = 0;
1810 pSMB->Timeout = 0;
1811 pSMB->Reserved2 = 0;
1812 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1813 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1814 pSMB->DataCount = 0;
1815 pSMB->DataOffset = 0;
1816 pSMB->SetupCount = 1;
1817 pSMB->Reserved3 = 0;
1818 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1819 byte_count = params + 1 /* pad */ ;
1820 pSMB->TotalParameterCount = cpu_to_le16(params);
1821 pSMB->ParameterCount = pSMB->TotalParameterCount;
1822 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1823 pSMB->Reserved4 = 0;
1824 pSMB->hdr.smb_buf_length += byte_count;
1825 pSMB->ByteCount = cpu_to_le16(byte_count);
1826
1827 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1828 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1829 if (rc) {
1830 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1831 } else {
1832 /* decode response */
1833
1834 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1835 if (rc || (pSMBr->ByteCount < 2))
1836 /* BB also check enough total bytes returned */
1837 rc = -EIO; /* bad smb */
1838 else {
1839 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1840 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1841
1842 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1843 name_len = UniStrnlen((wchar_t *) ((char *)
1844 &pSMBr->hdr.Protocol +data_offset),
1845 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07001846 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 cifs_strfromUCS_le(symlinkinfo,
1848 (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1849 data_offset),
1850 name_len, nls_codepage);
1851 } else {
1852 strncpy(symlinkinfo,
1853 (char *) &pSMBr->hdr.Protocol +
1854 data_offset,
1855 min_t(const int, buflen, count));
1856 }
1857 symlinkinfo[buflen] = 0;
1858 /* just in case so calling code does not go off the end of buffer */
1859 }
1860 }
1861 cifs_buf_release(pSMB);
1862 if (rc == -EAGAIN)
1863 goto querySymLinkRetry;
1864 return rc;
1865}
1866
1867int
1868CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1869 const unsigned char *searchName,
1870 char *symlinkinfo, const int buflen,__u16 fid,
1871 const struct nls_table *nls_codepage)
1872{
1873 int rc = 0;
1874 int bytes_returned;
1875 int name_len;
1876 struct smb_com_transaction_ioctl_req * pSMB;
1877 struct smb_com_transaction_ioctl_rsp * pSMBr;
1878
1879 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1880 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1881 (void **) &pSMBr);
1882 if (rc)
1883 return rc;
1884
1885 pSMB->TotalParameterCount = 0 ;
1886 pSMB->TotalDataCount = 0;
1887 pSMB->MaxParameterCount = cpu_to_le32(2);
1888 /* BB find exact data count max from sess structure BB */
1889 pSMB->MaxDataCount = cpu_to_le32(4000);
1890 pSMB->MaxSetupCount = 4;
1891 pSMB->Reserved = 0;
1892 pSMB->ParameterOffset = 0;
1893 pSMB->DataCount = 0;
1894 pSMB->DataOffset = 0;
1895 pSMB->SetupCount = 4;
1896 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1897 pSMB->ParameterCount = pSMB->TotalParameterCount;
1898 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1899 pSMB->IsFsctl = 1; /* FSCTL */
1900 pSMB->IsRootFlag = 0;
1901 pSMB->Fid = fid; /* file handle always le */
1902 pSMB->ByteCount = 0;
1903
1904 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1905 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1906 if (rc) {
1907 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1908 } else { /* decode response */
1909 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1910 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1911 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1912 /* BB also check enough total bytes returned */
1913 rc = -EIO; /* bad smb */
1914 else {
1915 if(data_count && (data_count < 2048)) {
1916 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1917
1918 struct reparse_data * reparse_buf = (struct reparse_data *)
1919 ((char *)&pSMBr->hdr.Protocol + data_offset);
1920 if((char*)reparse_buf >= end_of_smb) {
1921 rc = -EIO;
1922 goto qreparse_out;
1923 }
1924 if((reparse_buf->LinkNamesBuf +
1925 reparse_buf->TargetNameOffset +
1926 reparse_buf->TargetNameLen) >
1927 end_of_smb) {
1928 cFYI(1,("reparse buf extended beyond SMB"));
1929 rc = -EIO;
1930 goto qreparse_out;
1931 }
1932
1933 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1934 name_len = UniStrnlen((wchar_t *)
1935 (reparse_buf->LinkNamesBuf +
1936 reparse_buf->TargetNameOffset),
1937 min(buflen/2, reparse_buf->TargetNameLen / 2));
1938 cifs_strfromUCS_le(symlinkinfo,
1939 (wchar_t *) (reparse_buf->LinkNamesBuf +
1940 reparse_buf->TargetNameOffset),
1941 name_len, nls_codepage);
1942 } else { /* ASCII names */
1943 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
1944 reparse_buf->TargetNameOffset,
1945 min_t(const int, buflen, reparse_buf->TargetNameLen));
1946 }
1947 } else {
1948 rc = -EIO;
1949 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1950 }
1951 symlinkinfo[buflen] = 0; /* just in case so the caller
1952 does not go off the end of the buffer */
1953 cFYI(1,("readlink result - %s ",symlinkinfo));
1954 }
1955 }
1956qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07001957 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958
1959 /* Note: On -EAGAIN error only caller can retry on handle based calls
1960 since file handle passed in no longer valid */
1961
1962 return rc;
1963}
1964
1965#ifdef CONFIG_CIFS_POSIX
1966
1967/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
1968static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
1969{
1970 /* u8 cifs fields do not need le conversion */
1971 ace->e_perm = (__u16)cifs_ace->cifs_e_perm;
1972 ace->e_tag = (__u16)cifs_ace->cifs_e_tag;
1973 ace->e_id = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
1974 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
1975
1976 return;
1977}
1978
1979/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07001980static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
1981 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982{
1983 int size = 0;
1984 int i;
1985 __u16 count;
1986 struct cifs_posix_ace * pACE;
1987 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
1988 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
1989
1990 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
1991 return -EOPNOTSUPP;
1992
1993 if(acl_type & ACL_TYPE_ACCESS) {
1994 count = le16_to_cpu(cifs_acl->access_entry_count);
1995 pACE = &cifs_acl->ace_array[0];
1996 size = sizeof(struct cifs_posix_acl);
1997 size += sizeof(struct cifs_posix_ace) * count;
1998 /* check if we would go beyond end of SMB */
1999 if(size_of_data_area < size) {
2000 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2001 return -EINVAL;
2002 }
2003 } else if(acl_type & ACL_TYPE_DEFAULT) {
2004 count = le16_to_cpu(cifs_acl->access_entry_count);
2005 size = sizeof(struct cifs_posix_acl);
2006 size += sizeof(struct cifs_posix_ace) * count;
2007/* skip past access ACEs to get to default ACEs */
2008 pACE = &cifs_acl->ace_array[count];
2009 count = le16_to_cpu(cifs_acl->default_entry_count);
2010 size += sizeof(struct cifs_posix_ace) * count;
2011 /* check if we would go beyond end of SMB */
2012 if(size_of_data_area < size)
2013 return -EINVAL;
2014 } else {
2015 /* illegal type */
2016 return -EINVAL;
2017 }
2018
2019 size = posix_acl_xattr_size(count);
2020 if((buflen == 0) || (local_acl == NULL)) {
2021 /* used to query ACL EA size */
2022 } else if(size > buflen) {
2023 return -ERANGE;
2024 } else /* buffer big enough */ {
2025 local_acl->a_version = POSIX_ACL_XATTR_VERSION;
2026 for(i = 0;i < count ;i++) {
2027 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2028 pACE ++;
2029 }
2030 }
2031 return size;
2032}
2033
2034static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2035 const posix_acl_xattr_entry * local_ace)
2036{
2037 __u16 rc = 0; /* 0 = ACL converted ok */
2038
2039 cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
2040 cifs_ace->cifs_e_tag = (__u8)cpu_to_le16(local_ace->e_tag);
2041 /* BB is there a better way to handle the large uid? */
2042 if(local_ace->e_id == -1) {
2043 /* Probably no need to le convert -1 on any arch but can not hurt */
2044 cifs_ace->cifs_uid = cpu_to_le64(-1);
2045 } else
2046 cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
2047 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2048 return rc;
2049}
2050
2051/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2052static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2053 const int acl_type)
2054{
2055 __u16 rc = 0;
2056 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2057 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2058 int count;
2059 int i;
2060
2061 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2062 return 0;
2063
2064 count = posix_acl_xattr_count((size_t)buflen);
2065 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2066 count,buflen,local_acl->a_version));
2067 if(local_acl->a_version != 2) {
2068 cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
2069 return 0;
2070 }
2071 cifs_acl->version = cpu_to_le16(1);
2072 if(acl_type == ACL_TYPE_ACCESS)
2073 cifs_acl->access_entry_count = count;
2074 else if(acl_type == ACL_TYPE_DEFAULT)
2075 cifs_acl->default_entry_count = count;
2076 else {
2077 cFYI(1,("unknown ACL type %d",acl_type));
2078 return 0;
2079 }
2080 for(i=0;i<count;i++) {
2081 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2082 &local_acl->a_entries[i]);
2083 if(rc != 0) {
2084 /* ACE not converted */
2085 break;
2086 }
2087 }
2088 if(rc == 0) {
2089 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2090 rc += sizeof(struct cifs_posix_acl);
2091 /* BB add check to make sure ACL does not overflow SMB */
2092 }
2093 return rc;
2094}
2095
2096int
2097CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2098 const unsigned char *searchName,
2099 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002100 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101{
2102/* SMB_QUERY_POSIX_ACL */
2103 TRANSACTION2_QPI_REQ *pSMB = NULL;
2104 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2105 int rc = 0;
2106 int bytes_returned;
2107 int name_len;
2108 __u16 params, byte_count;
2109
2110 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2111
2112queryAclRetry:
2113 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2114 (void **) &pSMBr);
2115 if (rc)
2116 return rc;
2117
2118 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2119 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002120 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002121 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 name_len++; /* trailing null */
2123 name_len *= 2;
2124 pSMB->FileName[name_len] = 0;
2125 pSMB->FileName[name_len+1] = 0;
2126 } else { /* BB improve the check for buffer overruns BB */
2127 name_len = strnlen(searchName, PATH_MAX);
2128 name_len++; /* trailing null */
2129 strncpy(pSMB->FileName, searchName, name_len);
2130 }
2131
2132 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2133 pSMB->TotalDataCount = 0;
2134 pSMB->MaxParameterCount = cpu_to_le16(2);
2135 /* BB find exact max data count below from sess structure BB */
2136 pSMB->MaxDataCount = cpu_to_le16(4000);
2137 pSMB->MaxSetupCount = 0;
2138 pSMB->Reserved = 0;
2139 pSMB->Flags = 0;
2140 pSMB->Timeout = 0;
2141 pSMB->Reserved2 = 0;
2142 pSMB->ParameterOffset = cpu_to_le16(
2143 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2144 pSMB->DataCount = 0;
2145 pSMB->DataOffset = 0;
2146 pSMB->SetupCount = 1;
2147 pSMB->Reserved3 = 0;
2148 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2149 byte_count = params + 1 /* pad */ ;
2150 pSMB->TotalParameterCount = cpu_to_le16(params);
2151 pSMB->ParameterCount = pSMB->TotalParameterCount;
2152 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2153 pSMB->Reserved4 = 0;
2154 pSMB->hdr.smb_buf_length += byte_count;
2155 pSMB->ByteCount = cpu_to_le16(byte_count);
2156
2157 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2158 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2159 if (rc) {
2160 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2161 } else {
2162 /* decode response */
2163
2164 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2165 if (rc || (pSMBr->ByteCount < 2))
2166 /* BB also check enough total bytes returned */
2167 rc = -EIO; /* bad smb */
2168 else {
2169 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2170 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2171 rc = cifs_copy_posix_acl(acl_inf,
2172 (char *)&pSMBr->hdr.Protocol+data_offset,
2173 buflen,acl_type,count);
2174 }
2175 }
2176 cifs_buf_release(pSMB);
2177 if (rc == -EAGAIN)
2178 goto queryAclRetry;
2179 return rc;
2180}
2181
2182int
2183CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2184 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002185 const char *local_acl, const int buflen,
2186 const int acl_type,
2187 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188{
2189 struct smb_com_transaction2_spi_req *pSMB = NULL;
2190 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2191 char *parm_data;
2192 int name_len;
2193 int rc = 0;
2194 int bytes_returned = 0;
2195 __u16 params, byte_count, data_count, param_offset, offset;
2196
2197 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2198setAclRetry:
2199 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2200 (void **) &pSMBr);
2201 if (rc)
2202 return rc;
2203 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2204 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002205 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002206 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 name_len++; /* trailing null */
2208 name_len *= 2;
2209 } else { /* BB improve the check for buffer overruns BB */
2210 name_len = strnlen(fileName, PATH_MAX);
2211 name_len++; /* trailing null */
2212 strncpy(pSMB->FileName, fileName, name_len);
2213 }
2214 params = 6 + name_len;
2215 pSMB->MaxParameterCount = cpu_to_le16(2);
2216 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2217 pSMB->MaxSetupCount = 0;
2218 pSMB->Reserved = 0;
2219 pSMB->Flags = 0;
2220 pSMB->Timeout = 0;
2221 pSMB->Reserved2 = 0;
2222 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2223 InformationLevel) - 4;
2224 offset = param_offset + params;
2225 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2226 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2227
2228 /* convert to on the wire format for POSIX ACL */
2229 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2230
2231 if(data_count == 0) {
2232 rc = -EOPNOTSUPP;
2233 goto setACLerrorExit;
2234 }
2235 pSMB->DataOffset = cpu_to_le16(offset);
2236 pSMB->SetupCount = 1;
2237 pSMB->Reserved3 = 0;
2238 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2239 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2240 byte_count = 3 /* pad */ + params + data_count;
2241 pSMB->DataCount = cpu_to_le16(data_count);
2242 pSMB->TotalDataCount = pSMB->DataCount;
2243 pSMB->ParameterCount = cpu_to_le16(params);
2244 pSMB->TotalParameterCount = pSMB->ParameterCount;
2245 pSMB->Reserved4 = 0;
2246 pSMB->hdr.smb_buf_length += byte_count;
2247 pSMB->ByteCount = cpu_to_le16(byte_count);
2248 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2249 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2250 if (rc) {
2251 cFYI(1, ("Set POSIX ACL returned %d", rc));
2252 }
2253
2254setACLerrorExit:
2255 cifs_buf_release(pSMB);
2256 if (rc == -EAGAIN)
2257 goto setAclRetry;
2258 return rc;
2259}
2260
Steve Frenchf654bac2005-04-28 22:41:04 -07002261/* BB fix tabs in this function FIXME BB */
2262int
2263CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2264 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2265{
2266 int rc = 0;
2267 struct smb_t2_qfi_req *pSMB = NULL;
2268 struct smb_t2_qfi_rsp *pSMBr = NULL;
2269 int bytes_returned;
2270 __u16 params, byte_count;
2271
2272 cFYI(1,("In GetExtAttr"));
2273 if(tcon == NULL)
2274 return -ENODEV;
2275
2276GetExtAttrRetry:
2277 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2278 (void **) &pSMBr);
2279 if (rc)
2280 return rc;
2281
Steve Frenchc67593a2005-04-28 22:41:04 -07002282 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002283 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002284 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002285 /* BB find exact max data count below from sess structure BB */
2286 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2287 pSMB->t2.MaxSetupCount = 0;
2288 pSMB->t2.Reserved = 0;
2289 pSMB->t2.Flags = 0;
2290 pSMB->t2.Timeout = 0;
2291 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002292 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2293 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002294 pSMB->t2.DataCount = 0;
2295 pSMB->t2.DataOffset = 0;
2296 pSMB->t2.SetupCount = 1;
2297 pSMB->t2.Reserved3 = 0;
2298 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002299 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002300 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2301 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2302 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002303 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002304 pSMB->Fid = netfid;
2305 pSMB->hdr.smb_buf_length += byte_count;
2306 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2307
2308 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2309 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2310 if (rc) {
2311 cFYI(1, ("error %d in GetExtAttr", rc));
2312 } else {
2313 /* decode response */
2314 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2315 if (rc || (pSMBr->ByteCount < 2))
2316 /* BB also check enough total bytes returned */
2317 /* If rc should we check for EOPNOSUPP and
2318 disable the srvino flag? or in caller? */
2319 rc = -EIO; /* bad smb */
2320 else {
2321 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2322 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2323 struct file_chattr_info * pfinfo;
2324 /* BB Do we need a cast or hash here ? */
2325 if(count != 16) {
2326 cFYI(1, ("Illegal size ret in GetExtAttr"));
2327 rc = -EIO;
2328 goto GetExtAttrOut;
2329 }
2330 pfinfo = (struct file_chattr_info *)
2331 (data_offset + (char *) &pSMBr->hdr.Protocol);
2332 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2333 *pMask = le64_to_cpu(pfinfo->mask);
2334 }
2335 }
2336GetExtAttrOut:
2337 cifs_buf_release(pSMB);
2338 if (rc == -EAGAIN)
2339 goto GetExtAttrRetry;
2340 return rc;
2341}
2342
2343
2344#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345
Steve French6b8edfe2005-08-23 20:26:03 -07002346/* Legacy Query Path Information call for lookup to old servers such
2347 as Win9x/WinME */
2348int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2349 const unsigned char *searchName,
2350 FILE_ALL_INFO * pFinfo,
2351 const struct nls_table *nls_codepage, int remap)
2352{
2353 QUERY_INFORMATION_REQ * pSMB;
2354 QUERY_INFORMATION_RSP * pSMBr;
2355 int rc = 0;
2356 int bytes_returned;
2357 int name_len;
2358
2359 cFYI(1, ("In SMBQPath path %s", searchName));
2360QInfRetry:
2361 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2362 (void **) &pSMBr);
2363 if (rc)
2364 return rc;
2365
2366 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2367 name_len =
2368 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2369 PATH_MAX, nls_codepage, remap);
2370 name_len++; /* trailing null */
2371 name_len *= 2;
2372 } else {
2373 name_len = strnlen(searchName, PATH_MAX);
2374 name_len++; /* trailing null */
2375 strncpy(pSMB->FileName, searchName, name_len);
2376 }
2377 pSMB->BufferFormat = 0x04;
2378 name_len++; /* account for buffer type byte */
2379 pSMB->hdr.smb_buf_length += (__u16) name_len;
2380 pSMB->ByteCount = cpu_to_le16(name_len);
2381
2382 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2383 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2384 if (rc) {
2385 cFYI(1, ("Send error in QueryInfo = %d", rc));
2386 } else if (pFinfo) { /* decode response */
2387 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2388 pFinfo->AllocationSize = (__le64) pSMBr->size;
2389 pFinfo->EndOfFile = (__le64) pSMBr->size;
2390 pFinfo->Attributes = (__le32) pSMBr->attr;
2391 } else
2392 rc = -EIO; /* bad buffer passed in */
2393
2394 cifs_buf_release(pSMB);
2395
2396 if (rc == -EAGAIN)
2397 goto QInfRetry;
2398
2399 return rc;
2400}
2401
2402
2403
2404
Linus Torvalds1da177e2005-04-16 15:20:36 -07002405int
2406CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2407 const unsigned char *searchName,
2408 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002409 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410{
2411/* level 263 SMB_QUERY_FILE_ALL_INFO */
2412 TRANSACTION2_QPI_REQ *pSMB = NULL;
2413 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2414 int rc = 0;
2415 int bytes_returned;
2416 int name_len;
2417 __u16 params, byte_count;
2418
2419/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2420QPathInfoRetry:
2421 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2422 (void **) &pSMBr);
2423 if (rc)
2424 return rc;
2425
2426 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2427 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002428 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002429 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 name_len++; /* trailing null */
2431 name_len *= 2;
2432 } else { /* BB improve the check for buffer overruns BB */
2433 name_len = strnlen(searchName, PATH_MAX);
2434 name_len++; /* trailing null */
2435 strncpy(pSMB->FileName, searchName, name_len);
2436 }
2437
2438 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2439 pSMB->TotalDataCount = 0;
2440 pSMB->MaxParameterCount = cpu_to_le16(2);
2441 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2442 pSMB->MaxSetupCount = 0;
2443 pSMB->Reserved = 0;
2444 pSMB->Flags = 0;
2445 pSMB->Timeout = 0;
2446 pSMB->Reserved2 = 0;
2447 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2448 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2449 pSMB->DataCount = 0;
2450 pSMB->DataOffset = 0;
2451 pSMB->SetupCount = 1;
2452 pSMB->Reserved3 = 0;
2453 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2454 byte_count = params + 1 /* pad */ ;
2455 pSMB->TotalParameterCount = cpu_to_le16(params);
2456 pSMB->ParameterCount = pSMB->TotalParameterCount;
2457 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2458 pSMB->Reserved4 = 0;
2459 pSMB->hdr.smb_buf_length += byte_count;
2460 pSMB->ByteCount = cpu_to_le16(byte_count);
2461
2462 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2463 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2464 if (rc) {
2465 cFYI(1, ("Send error in QPathInfo = %d", rc));
2466 } else { /* decode response */
2467 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2468
2469 if (rc || (pSMBr->ByteCount < 40))
2470 rc = -EIO; /* bad smb */
2471 else if (pFindData){
2472 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2473 memcpy((char *) pFindData,
2474 (char *) &pSMBr->hdr.Protocol +
2475 data_offset, sizeof (FILE_ALL_INFO));
2476 } else
2477 rc = -ENOMEM;
2478 }
2479 cifs_buf_release(pSMB);
2480 if (rc == -EAGAIN)
2481 goto QPathInfoRetry;
2482
2483 return rc;
2484}
2485
2486int
2487CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2488 const unsigned char *searchName,
2489 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002490 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491{
2492/* SMB_QUERY_FILE_UNIX_BASIC */
2493 TRANSACTION2_QPI_REQ *pSMB = NULL;
2494 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2495 int rc = 0;
2496 int bytes_returned = 0;
2497 int name_len;
2498 __u16 params, byte_count;
2499
2500 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2501UnixQPathInfoRetry:
2502 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2503 (void **) &pSMBr);
2504 if (rc)
2505 return rc;
2506
2507 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2508 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002509 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002510 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511 name_len++; /* trailing null */
2512 name_len *= 2;
2513 } else { /* BB improve the check for buffer overruns BB */
2514 name_len = strnlen(searchName, PATH_MAX);
2515 name_len++; /* trailing null */
2516 strncpy(pSMB->FileName, searchName, name_len);
2517 }
2518
2519 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2520 pSMB->TotalDataCount = 0;
2521 pSMB->MaxParameterCount = cpu_to_le16(2);
2522 /* BB find exact max SMB PDU from sess structure BB */
2523 pSMB->MaxDataCount = cpu_to_le16(4000);
2524 pSMB->MaxSetupCount = 0;
2525 pSMB->Reserved = 0;
2526 pSMB->Flags = 0;
2527 pSMB->Timeout = 0;
2528 pSMB->Reserved2 = 0;
2529 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2530 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2531 pSMB->DataCount = 0;
2532 pSMB->DataOffset = 0;
2533 pSMB->SetupCount = 1;
2534 pSMB->Reserved3 = 0;
2535 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2536 byte_count = params + 1 /* pad */ ;
2537 pSMB->TotalParameterCount = cpu_to_le16(params);
2538 pSMB->ParameterCount = pSMB->TotalParameterCount;
2539 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2540 pSMB->Reserved4 = 0;
2541 pSMB->hdr.smb_buf_length += byte_count;
2542 pSMB->ByteCount = cpu_to_le16(byte_count);
2543
2544 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2545 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2546 if (rc) {
2547 cFYI(1, ("Send error in QPathInfo = %d", rc));
2548 } else { /* decode response */
2549 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2550
2551 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2552 rc = -EIO; /* bad smb */
2553 } else {
2554 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2555 memcpy((char *) pFindData,
2556 (char *) &pSMBr->hdr.Protocol +
2557 data_offset,
2558 sizeof (FILE_UNIX_BASIC_INFO));
2559 }
2560 }
2561 cifs_buf_release(pSMB);
2562 if (rc == -EAGAIN)
2563 goto UnixQPathInfoRetry;
2564
2565 return rc;
2566}
2567
2568#if 0 /* function unused at present */
2569int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2570 const char *searchName, FILE_ALL_INFO * findData,
2571 const struct nls_table *nls_codepage)
2572{
2573/* level 257 SMB_ */
2574 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2575 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2576 int rc = 0;
2577 int bytes_returned;
2578 int name_len;
2579 __u16 params, byte_count;
2580
2581 cFYI(1, ("In FindUnique"));
2582findUniqueRetry:
2583 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2584 (void **) &pSMBr);
2585 if (rc)
2586 return rc;
2587
2588 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2589 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002590 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 /* find define for this maxpathcomponent */
2592 , nls_codepage);
2593 name_len++; /* trailing null */
2594 name_len *= 2;
2595 } else { /* BB improve the check for buffer overruns BB */
2596 name_len = strnlen(searchName, PATH_MAX);
2597 name_len++; /* trailing null */
2598 strncpy(pSMB->FileName, searchName, name_len);
2599 }
2600
2601 params = 12 + name_len /* includes null */ ;
2602 pSMB->TotalDataCount = 0; /* no EAs */
2603 pSMB->MaxParameterCount = cpu_to_le16(2);
2604 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2605 pSMB->MaxSetupCount = 0;
2606 pSMB->Reserved = 0;
2607 pSMB->Flags = 0;
2608 pSMB->Timeout = 0;
2609 pSMB->Reserved2 = 0;
2610 pSMB->ParameterOffset = cpu_to_le16(
2611 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2612 pSMB->DataCount = 0;
2613 pSMB->DataOffset = 0;
2614 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2615 pSMB->Reserved3 = 0;
2616 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2617 byte_count = params + 1 /* pad */ ;
2618 pSMB->TotalParameterCount = cpu_to_le16(params);
2619 pSMB->ParameterCount = pSMB->TotalParameterCount;
2620 pSMB->SearchAttributes =
2621 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2622 ATTR_DIRECTORY);
2623 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2624 pSMB->SearchFlags = cpu_to_le16(1);
2625 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2626 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2627 pSMB->hdr.smb_buf_length += byte_count;
2628 pSMB->ByteCount = cpu_to_le16(byte_count);
2629
2630 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2631 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2632
2633 if (rc) {
2634 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2635 } else { /* decode response */
Steve Frencha45443472005-08-24 13:59:35 -07002636 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 /* BB fill in */
2638 }
2639
2640 cifs_buf_release(pSMB);
2641 if (rc == -EAGAIN)
2642 goto findUniqueRetry;
2643
2644 return rc;
2645}
2646#endif /* end unused (temporarily) function */
2647
2648/* xid, tcon, searchName and codepage are input parms, rest are returned */
2649int
2650CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2651 const char *searchName,
2652 const struct nls_table *nls_codepage,
2653 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07002654 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655{
2656/* level 257 SMB_ */
2657 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2658 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2659 T2_FFIRST_RSP_PARMS * parms;
2660 int rc = 0;
2661 int bytes_returned = 0;
2662 int name_len;
2663 __u16 params, byte_count;
2664
Steve French737b7582005-04-28 22:41:06 -07002665 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666
2667findFirstRetry:
2668 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2669 (void **) &pSMBr);
2670 if (rc)
2671 return rc;
2672
2673 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2674 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002675 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07002676 PATH_MAX, nls_codepage, remap);
2677 /* We can not add the asterik earlier in case
2678 it got remapped to 0xF03A as if it were part of the
2679 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07002681 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07002682 pSMB->FileName[name_len+1] = 0;
2683 pSMB->FileName[name_len+2] = '*';
2684 pSMB->FileName[name_len+3] = 0;
2685 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2687 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07002688 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 } else { /* BB add check for overrun of SMB buf BB */
2690 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691/* BB fix here and in unicode clause above ie
2692 if(name_len > buffersize-header)
2693 free buffer exit; BB */
2694 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07002695 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07002696 pSMB->FileName[name_len+1] = '*';
2697 pSMB->FileName[name_len+2] = 0;
2698 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002699 }
2700
2701 params = 12 + name_len /* includes null */ ;
2702 pSMB->TotalDataCount = 0; /* no EAs */
2703 pSMB->MaxParameterCount = cpu_to_le16(10);
2704 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2705 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2706 pSMB->MaxSetupCount = 0;
2707 pSMB->Reserved = 0;
2708 pSMB->Flags = 0;
2709 pSMB->Timeout = 0;
2710 pSMB->Reserved2 = 0;
2711 byte_count = params + 1 /* pad */ ;
2712 pSMB->TotalParameterCount = cpu_to_le16(params);
2713 pSMB->ParameterCount = pSMB->TotalParameterCount;
2714 pSMB->ParameterOffset = cpu_to_le16(
2715 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2716 pSMB->DataCount = 0;
2717 pSMB->DataOffset = 0;
2718 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2719 pSMB->Reserved3 = 0;
2720 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2721 pSMB->SearchAttributes =
2722 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2723 ATTR_DIRECTORY);
2724 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2725 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2726 CIFS_SEARCH_RETURN_RESUME);
2727 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2728
2729 /* BB what should we set StorageType to? Does it matter? BB */
2730 pSMB->SearchStorageType = 0;
2731 pSMB->hdr.smb_buf_length += byte_count;
2732 pSMB->ByteCount = cpu_to_le16(byte_count);
2733
2734 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2735 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002736 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737
Steve French1982c342005-08-17 12:38:22 -07002738 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 /* BB Add code to handle unsupported level rc */
2740 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07002741
2742 if (pSMB)
2743 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744
2745 /* BB eventually could optimize out free and realloc of buf */
2746 /* for this case */
2747 if (rc == -EAGAIN)
2748 goto findFirstRetry;
2749 } else { /* decode response */
2750 /* BB remember to free buffer if error BB */
2751 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2752 if(rc == 0) {
2753 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2754 psrch_inf->unicode = TRUE;
2755 else
2756 psrch_inf->unicode = FALSE;
2757
2758 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2759 psrch_inf->srch_entries_start =
2760 (char *) &pSMBr->hdr.Protocol +
2761 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2763 le16_to_cpu(pSMBr->t2.ParameterOffset));
2764
2765 if(parms->EndofSearch)
2766 psrch_inf->endOfSearch = TRUE;
2767 else
2768 psrch_inf->endOfSearch = FALSE;
2769
2770 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2771 psrch_inf->index_of_last_entry =
2772 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 *pnetfid = parms->SearchHandle;
2774 } else {
2775 cifs_buf_release(pSMB);
2776 }
2777 }
2778
2779 return rc;
2780}
2781
2782int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2783 __u16 searchHandle, struct cifs_search_info * psrch_inf)
2784{
2785 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2786 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2787 T2_FNEXT_RSP_PARMS * parms;
2788 char *response_data;
2789 int rc = 0;
2790 int bytes_returned, name_len;
2791 __u16 params, byte_count;
2792
2793 cFYI(1, ("In FindNext"));
2794
2795 if(psrch_inf->endOfSearch == TRUE)
2796 return -ENOENT;
2797
2798 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2799 (void **) &pSMBr);
2800 if (rc)
2801 return rc;
2802
2803 params = 14; /* includes 2 bytes of null string, converted to LE below */
2804 byte_count = 0;
2805 pSMB->TotalDataCount = 0; /* no EAs */
2806 pSMB->MaxParameterCount = cpu_to_le16(8);
2807 pSMB->MaxDataCount =
2808 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2809 pSMB->MaxSetupCount = 0;
2810 pSMB->Reserved = 0;
2811 pSMB->Flags = 0;
2812 pSMB->Timeout = 0;
2813 pSMB->Reserved2 = 0;
2814 pSMB->ParameterOffset = cpu_to_le16(
2815 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2816 pSMB->DataCount = 0;
2817 pSMB->DataOffset = 0;
2818 pSMB->SetupCount = 1;
2819 pSMB->Reserved3 = 0;
2820 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2821 pSMB->SearchHandle = searchHandle; /* always kept as le */
2822 pSMB->SearchCount =
2823 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2824 /* test for Unix extensions */
2825/* if (tcon->ses->capabilities & CAP_UNIX) {
2826 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2827 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2828 } else {
2829 pSMB->InformationLevel =
2830 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2831 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2832 } */
2833 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2834 pSMB->ResumeKey = psrch_inf->resume_key;
2835 pSMB->SearchFlags =
2836 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2837
2838 name_len = psrch_inf->resume_name_len;
2839 params += name_len;
2840 if(name_len < PATH_MAX) {
2841 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2842 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07002843 /* 14 byte parm len above enough for 2 byte null terminator */
2844 pSMB->ResumeFileName[name_len] = 0;
2845 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 } else {
2847 rc = -EINVAL;
2848 goto FNext2_err_exit;
2849 }
2850 byte_count = params + 1 /* pad */ ;
2851 pSMB->TotalParameterCount = cpu_to_le16(params);
2852 pSMB->ParameterCount = pSMB->TotalParameterCount;
2853 pSMB->hdr.smb_buf_length += byte_count;
2854 pSMB->ByteCount = cpu_to_le16(byte_count);
2855
2856 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2857 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002858 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 if (rc) {
2860 if (rc == -EBADF) {
2861 psrch_inf->endOfSearch = TRUE;
2862 rc = 0; /* search probably was closed at end of search above */
2863 } else
2864 cFYI(1, ("FindNext returned = %d", rc));
2865 } else { /* decode response */
2866 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2867
2868 if(rc == 0) {
2869 /* BB fixme add lock for file (srch_info) struct here */
2870 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2871 psrch_inf->unicode = TRUE;
2872 else
2873 psrch_inf->unicode = FALSE;
2874 response_data = (char *) &pSMBr->hdr.Protocol +
2875 le16_to_cpu(pSMBr->t2.ParameterOffset);
2876 parms = (T2_FNEXT_RSP_PARMS *)response_data;
2877 response_data = (char *)&pSMBr->hdr.Protocol +
2878 le16_to_cpu(pSMBr->t2.DataOffset);
2879 cifs_buf_release(psrch_inf->ntwrk_buf_start);
2880 psrch_inf->srch_entries_start = response_data;
2881 psrch_inf->ntwrk_buf_start = (char *)pSMB;
2882 if(parms->EndofSearch)
2883 psrch_inf->endOfSearch = TRUE;
2884 else
2885 psrch_inf->endOfSearch = FALSE;
2886
2887 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2888 psrch_inf->index_of_last_entry +=
2889 psrch_inf->entries_in_buffer;
2890/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2891
2892 /* BB fixme add unlock here */
2893 }
2894
2895 }
2896
2897 /* BB On error, should we leave previous search buf (and count and
2898 last entry fields) intact or free the previous one? */
2899
2900 /* Note: On -EAGAIN error only caller can retry on handle based calls
2901 since file handle passed in no longer valid */
2902FNext2_err_exit:
2903 if (rc != 0)
2904 cifs_buf_release(pSMB);
2905
2906 return rc;
2907}
2908
2909int
2910CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2911{
2912 int rc = 0;
2913 FINDCLOSE_REQ *pSMB = NULL;
2914 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2915 int bytes_returned;
2916
2917 cFYI(1, ("In CIFSSMBFindClose"));
2918 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2919
2920 /* no sense returning error if session restarted
2921 as file handle has been closed */
2922 if(rc == -EAGAIN)
2923 return 0;
2924 if (rc)
2925 return rc;
2926
2927 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
2928 pSMB->FileID = searchHandle;
2929 pSMB->ByteCount = 0;
2930 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2931 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2932 if (rc) {
2933 cERROR(1, ("Send error in FindClose = %d", rc));
2934 }
Steve Frencha45443472005-08-24 13:59:35 -07002935 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 cifs_small_buf_release(pSMB);
2937
2938 /* Since session is dead, search handle closed on server already */
2939 if (rc == -EAGAIN)
2940 rc = 0;
2941
2942 return rc;
2943}
2944
2945#ifdef CONFIG_CIFS_EXPERIMENTAL
2946int
2947CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2948 const unsigned char *searchName,
2949 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07002950 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951{
2952 int rc = 0;
2953 TRANSACTION2_QPI_REQ *pSMB = NULL;
2954 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2955 int name_len, bytes_returned;
2956 __u16 params, byte_count;
2957
2958 cFYI(1,("In GetSrvInodeNum for %s",searchName));
2959 if(tcon == NULL)
2960 return -ENODEV;
2961
2962GetInodeNumberRetry:
2963 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2964 (void **) &pSMBr);
2965 if (rc)
2966 return rc;
2967
2968
2969 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2970 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002971 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002972 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 name_len++; /* trailing null */
2974 name_len *= 2;
2975 } else { /* BB improve the check for buffer overruns BB */
2976 name_len = strnlen(searchName, PATH_MAX);
2977 name_len++; /* trailing null */
2978 strncpy(pSMB->FileName, searchName, name_len);
2979 }
2980
2981 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2982 pSMB->TotalDataCount = 0;
2983 pSMB->MaxParameterCount = cpu_to_le16(2);
2984 /* BB find exact max data count below from sess structure BB */
2985 pSMB->MaxDataCount = cpu_to_le16(4000);
2986 pSMB->MaxSetupCount = 0;
2987 pSMB->Reserved = 0;
2988 pSMB->Flags = 0;
2989 pSMB->Timeout = 0;
2990 pSMB->Reserved2 = 0;
2991 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2992 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2993 pSMB->DataCount = 0;
2994 pSMB->DataOffset = 0;
2995 pSMB->SetupCount = 1;
2996 pSMB->Reserved3 = 0;
2997 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2998 byte_count = params + 1 /* pad */ ;
2999 pSMB->TotalParameterCount = cpu_to_le16(params);
3000 pSMB->ParameterCount = pSMB->TotalParameterCount;
3001 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3002 pSMB->Reserved4 = 0;
3003 pSMB->hdr.smb_buf_length += byte_count;
3004 pSMB->ByteCount = cpu_to_le16(byte_count);
3005
3006 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3007 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3008 if (rc) {
3009 cFYI(1, ("error %d in QueryInternalInfo", rc));
3010 } else {
3011 /* decode response */
3012 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3013 if (rc || (pSMBr->ByteCount < 2))
3014 /* BB also check enough total bytes returned */
3015 /* If rc should we check for EOPNOSUPP and
3016 disable the srvino flag? or in caller? */
3017 rc = -EIO; /* bad smb */
3018 else {
3019 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3020 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3021 struct file_internal_info * pfinfo;
3022 /* BB Do we need a cast or hash here ? */
3023 if(count < 8) {
3024 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3025 rc = -EIO;
3026 goto GetInodeNumOut;
3027 }
3028 pfinfo = (struct file_internal_info *)
3029 (data_offset + (char *) &pSMBr->hdr.Protocol);
3030 *inode_number = pfinfo->UniqueId;
3031 }
3032 }
3033GetInodeNumOut:
3034 cifs_buf_release(pSMB);
3035 if (rc == -EAGAIN)
3036 goto GetInodeNumberRetry;
3037 return rc;
3038}
3039#endif /* CIFS_EXPERIMENTAL */
3040
3041int
3042CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3043 const unsigned char *searchName,
3044 unsigned char **targetUNCs,
3045 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003046 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047{
3048/* TRANS2_GET_DFS_REFERRAL */
3049 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3050 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3051 struct dfs_referral_level_3 * referrals = NULL;
3052 int rc = 0;
3053 int bytes_returned;
3054 int name_len;
3055 unsigned int i;
3056 char * temp;
3057 __u16 params, byte_count;
3058 *number_of_UNC_in_array = 0;
3059 *targetUNCs = NULL;
3060
3061 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3062 if (ses == NULL)
3063 return -ENODEV;
3064getDFSRetry:
3065 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3066 (void **) &pSMBr);
3067 if (rc)
3068 return rc;
Steve French1982c342005-08-17 12:38:22 -07003069
3070 /* server pointer checked in called function,
3071 but should never be null here anyway */
3072 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073 pSMB->hdr.Tid = ses->ipc_tid;
3074 pSMB->hdr.Uid = ses->Suid;
3075 if (ses->capabilities & CAP_STATUS32) {
3076 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3077 }
3078 if (ses->capabilities & CAP_DFS) {
3079 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3080 }
3081
3082 if (ses->capabilities & CAP_UNICODE) {
3083 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3084 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003085 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003086 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 name_len++; /* trailing null */
3088 name_len *= 2;
3089 } else { /* BB improve the check for buffer overruns BB */
3090 name_len = strnlen(searchName, PATH_MAX);
3091 name_len++; /* trailing null */
3092 strncpy(pSMB->RequestFileName, searchName, name_len);
3093 }
3094
3095 params = 2 /* level */ + name_len /*includes null */ ;
3096 pSMB->TotalDataCount = 0;
3097 pSMB->DataCount = 0;
3098 pSMB->DataOffset = 0;
3099 pSMB->MaxParameterCount = 0;
3100 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3101 pSMB->MaxSetupCount = 0;
3102 pSMB->Reserved = 0;
3103 pSMB->Flags = 0;
3104 pSMB->Timeout = 0;
3105 pSMB->Reserved2 = 0;
3106 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3107 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3108 pSMB->SetupCount = 1;
3109 pSMB->Reserved3 = 0;
3110 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3111 byte_count = params + 3 /* pad */ ;
3112 pSMB->ParameterCount = cpu_to_le16(params);
3113 pSMB->TotalParameterCount = pSMB->ParameterCount;
3114 pSMB->MaxReferralLevel = cpu_to_le16(3);
3115 pSMB->hdr.smb_buf_length += byte_count;
3116 pSMB->ByteCount = cpu_to_le16(byte_count);
3117
3118 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3119 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3120 if (rc) {
3121 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3122 } else { /* decode response */
3123/* BB Add logic to parse referrals here */
3124 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3125
3126 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3127 rc = -EIO; /* bad smb */
3128 else {
3129 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3130 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3131
3132 cFYI(1,
3133 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3134 pSMBr->ByteCount, data_offset));
3135 referrals =
3136 (struct dfs_referral_level_3 *)
3137 (8 /* sizeof start of data block */ +
3138 data_offset +
3139 (char *) &pSMBr->hdr.Protocol);
3140 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",
3141 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)));
3142 /* BB This field is actually two bytes in from start of
3143 data block so we could do safety check that DataBlock
3144 begins at address of pSMBr->NumberOfReferrals */
3145 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3146
3147 /* BB Fix below so can return more than one referral */
3148 if(*number_of_UNC_in_array > 1)
3149 *number_of_UNC_in_array = 1;
3150
3151 /* get the length of the strings describing refs */
3152 name_len = 0;
3153 for(i=0;i<*number_of_UNC_in_array;i++) {
3154 /* make sure that DfsPathOffset not past end */
3155 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3156 if (offset > data_count) {
3157 /* if invalid referral, stop here and do
3158 not try to copy any more */
3159 *number_of_UNC_in_array = i;
3160 break;
3161 }
3162 temp = ((char *)referrals) + offset;
3163
3164 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3165 name_len += UniStrnlen((wchar_t *)temp,data_count);
3166 } else {
3167 name_len += strnlen(temp,data_count);
3168 }
3169 referrals++;
3170 /* BB add check that referral pointer does not fall off end PDU */
3171
3172 }
3173 /* BB add check for name_len bigger than bcc */
3174 *targetUNCs =
3175 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3176 if(*targetUNCs == NULL) {
3177 rc = -ENOMEM;
3178 goto GetDFSRefExit;
3179 }
3180 /* copy the ref strings */
3181 referrals =
3182 (struct dfs_referral_level_3 *)
3183 (8 /* sizeof data hdr */ +
3184 data_offset +
3185 (char *) &pSMBr->hdr.Protocol);
3186
3187 for(i=0;i<*number_of_UNC_in_array;i++) {
3188 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3189 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3190 cifs_strfromUCS_le(*targetUNCs,
3191 (wchar_t *) temp, name_len, nls_codepage);
3192 } else {
3193 strncpy(*targetUNCs,temp,name_len);
3194 }
3195 /* BB update target_uncs pointers */
3196 referrals++;
3197 }
3198 temp = *targetUNCs;
3199 temp[name_len] = 0;
3200 }
3201
3202 }
3203GetDFSRefExit:
3204 if (pSMB)
3205 cifs_buf_release(pSMB);
3206
3207 if (rc == -EAGAIN)
3208 goto getDFSRetry;
3209
3210 return rc;
3211}
3212
3213int
Steve French737b7582005-04-28 22:41:06 -07003214CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215{
3216/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3217 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3218 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3219 FILE_SYSTEM_INFO *response_data;
3220 int rc = 0;
3221 int bytes_returned = 0;
3222 __u16 params, byte_count;
3223
3224 cFYI(1, ("In QFSInfo"));
3225QFSInfoRetry:
3226 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3227 (void **) &pSMBr);
3228 if (rc)
3229 return rc;
3230
3231 params = 2; /* level */
3232 pSMB->TotalDataCount = 0;
3233 pSMB->MaxParameterCount = cpu_to_le16(2);
3234 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3235 pSMB->MaxSetupCount = 0;
3236 pSMB->Reserved = 0;
3237 pSMB->Flags = 0;
3238 pSMB->Timeout = 0;
3239 pSMB->Reserved2 = 0;
3240 byte_count = params + 1 /* pad */ ;
3241 pSMB->TotalParameterCount = cpu_to_le16(params);
3242 pSMB->ParameterCount = pSMB->TotalParameterCount;
3243 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3244 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3245 pSMB->DataCount = 0;
3246 pSMB->DataOffset = 0;
3247 pSMB->SetupCount = 1;
3248 pSMB->Reserved3 = 0;
3249 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3250 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3251 pSMB->hdr.smb_buf_length += byte_count;
3252 pSMB->ByteCount = cpu_to_le16(byte_count);
3253
3254 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3255 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3256 if (rc) {
3257 cERROR(1, ("Send error in QFSInfo = %d", rc));
3258 } else { /* decode response */
3259 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3260
3261 if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
3262 rc = -EIO; /* bad smb */
3263 else {
3264 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3265 cFYI(1,
3266 ("Decoding qfsinfo response. BCC: %d Offset %d",
3267 pSMBr->ByteCount, data_offset));
3268
3269 response_data =
3270 (FILE_SYSTEM_INFO
3271 *) (((char *) &pSMBr->hdr.Protocol) +
3272 data_offset);
3273 FSData->f_bsize =
3274 le32_to_cpu(response_data->BytesPerSector) *
3275 le32_to_cpu(response_data->
3276 SectorsPerAllocationUnit);
3277 FSData->f_blocks =
3278 le64_to_cpu(response_data->TotalAllocationUnits);
3279 FSData->f_bfree = FSData->f_bavail =
3280 le64_to_cpu(response_data->FreeAllocationUnits);
3281 cFYI(1,
3282 ("Blocks: %lld Free: %lld Block size %ld",
3283 (unsigned long long)FSData->f_blocks,
3284 (unsigned long long)FSData->f_bfree,
3285 FSData->f_bsize));
3286 }
3287 }
3288 cifs_buf_release(pSMB);
3289
3290 if (rc == -EAGAIN)
3291 goto QFSInfoRetry;
3292
3293 return rc;
3294}
3295
3296int
Steve French737b7582005-04-28 22:41:06 -07003297CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298{
3299/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3300 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3301 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3302 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3303 int rc = 0;
3304 int bytes_returned = 0;
3305 __u16 params, byte_count;
3306
3307 cFYI(1, ("In QFSAttributeInfo"));
3308QFSAttributeRetry:
3309 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3310 (void **) &pSMBr);
3311 if (rc)
3312 return rc;
3313
3314 params = 2; /* level */
3315 pSMB->TotalDataCount = 0;
3316 pSMB->MaxParameterCount = cpu_to_le16(2);
3317 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3318 pSMB->MaxSetupCount = 0;
3319 pSMB->Reserved = 0;
3320 pSMB->Flags = 0;
3321 pSMB->Timeout = 0;
3322 pSMB->Reserved2 = 0;
3323 byte_count = params + 1 /* pad */ ;
3324 pSMB->TotalParameterCount = cpu_to_le16(params);
3325 pSMB->ParameterCount = pSMB->TotalParameterCount;
3326 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3327 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3328 pSMB->DataCount = 0;
3329 pSMB->DataOffset = 0;
3330 pSMB->SetupCount = 1;
3331 pSMB->Reserved3 = 0;
3332 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3333 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3334 pSMB->hdr.smb_buf_length += byte_count;
3335 pSMB->ByteCount = cpu_to_le16(byte_count);
3336
3337 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3338 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3339 if (rc) {
3340 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3341 } else { /* decode response */
3342 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3343
3344 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3345 rc = -EIO; /* bad smb */
3346 } else {
3347 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3348 response_data =
3349 (FILE_SYSTEM_ATTRIBUTE_INFO
3350 *) (((char *) &pSMBr->hdr.Protocol) +
3351 data_offset);
3352 memcpy(&tcon->fsAttrInfo, response_data,
3353 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3354 }
3355 }
3356 cifs_buf_release(pSMB);
3357
3358 if (rc == -EAGAIN)
3359 goto QFSAttributeRetry;
3360
3361 return rc;
3362}
3363
3364int
Steve French737b7582005-04-28 22:41:06 -07003365CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366{
3367/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3368 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3369 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3370 FILE_SYSTEM_DEVICE_INFO *response_data;
3371 int rc = 0;
3372 int bytes_returned = 0;
3373 __u16 params, byte_count;
3374
3375 cFYI(1, ("In QFSDeviceInfo"));
3376QFSDeviceRetry:
3377 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3378 (void **) &pSMBr);
3379 if (rc)
3380 return rc;
3381
3382 params = 2; /* level */
3383 pSMB->TotalDataCount = 0;
3384 pSMB->MaxParameterCount = cpu_to_le16(2);
3385 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3386 pSMB->MaxSetupCount = 0;
3387 pSMB->Reserved = 0;
3388 pSMB->Flags = 0;
3389 pSMB->Timeout = 0;
3390 pSMB->Reserved2 = 0;
3391 byte_count = params + 1 /* pad */ ;
3392 pSMB->TotalParameterCount = cpu_to_le16(params);
3393 pSMB->ParameterCount = pSMB->TotalParameterCount;
3394 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3395 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3396
3397 pSMB->DataCount = 0;
3398 pSMB->DataOffset = 0;
3399 pSMB->SetupCount = 1;
3400 pSMB->Reserved3 = 0;
3401 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3402 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3403 pSMB->hdr.smb_buf_length += byte_count;
3404 pSMB->ByteCount = cpu_to_le16(byte_count);
3405
3406 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3407 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3408 if (rc) {
3409 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3410 } else { /* decode response */
3411 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3412
3413 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3414 rc = -EIO; /* bad smb */
3415 else {
3416 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3417 response_data =
Steve French737b7582005-04-28 22:41:06 -07003418 (FILE_SYSTEM_DEVICE_INFO *)
3419 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 data_offset);
3421 memcpy(&tcon->fsDevInfo, response_data,
3422 sizeof (FILE_SYSTEM_DEVICE_INFO));
3423 }
3424 }
3425 cifs_buf_release(pSMB);
3426
3427 if (rc == -EAGAIN)
3428 goto QFSDeviceRetry;
3429
3430 return rc;
3431}
3432
3433int
Steve French737b7582005-04-28 22:41:06 -07003434CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435{
3436/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3437 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3438 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3439 FILE_SYSTEM_UNIX_INFO *response_data;
3440 int rc = 0;
3441 int bytes_returned = 0;
3442 __u16 params, byte_count;
3443
3444 cFYI(1, ("In QFSUnixInfo"));
3445QFSUnixRetry:
3446 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3447 (void **) &pSMBr);
3448 if (rc)
3449 return rc;
3450
3451 params = 2; /* level */
3452 pSMB->TotalDataCount = 0;
3453 pSMB->DataCount = 0;
3454 pSMB->DataOffset = 0;
3455 pSMB->MaxParameterCount = cpu_to_le16(2);
3456 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3457 pSMB->MaxSetupCount = 0;
3458 pSMB->Reserved = 0;
3459 pSMB->Flags = 0;
3460 pSMB->Timeout = 0;
3461 pSMB->Reserved2 = 0;
3462 byte_count = params + 1 /* pad */ ;
3463 pSMB->ParameterCount = cpu_to_le16(params);
3464 pSMB->TotalParameterCount = pSMB->ParameterCount;
3465 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3466 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3467 pSMB->SetupCount = 1;
3468 pSMB->Reserved3 = 0;
3469 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3470 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3471 pSMB->hdr.smb_buf_length += byte_count;
3472 pSMB->ByteCount = cpu_to_le16(byte_count);
3473
3474 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3475 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3476 if (rc) {
3477 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3478 } else { /* decode response */
3479 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3480
3481 if (rc || (pSMBr->ByteCount < 13)) {
3482 rc = -EIO; /* bad smb */
3483 } else {
3484 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3485 response_data =
3486 (FILE_SYSTEM_UNIX_INFO
3487 *) (((char *) &pSMBr->hdr.Protocol) +
3488 data_offset);
3489 memcpy(&tcon->fsUnixInfo, response_data,
3490 sizeof (FILE_SYSTEM_UNIX_INFO));
3491 }
3492 }
3493 cifs_buf_release(pSMB);
3494
3495 if (rc == -EAGAIN)
3496 goto QFSUnixRetry;
3497
3498
3499 return rc;
3500}
3501
Jeremy Allisonac670552005-06-22 17:26:35 -07003502int
Steve French45abc6e2005-06-23 13:42:03 -05003503CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07003504{
3505/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3506 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3507 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3508 int rc = 0;
3509 int bytes_returned = 0;
3510 __u16 params, param_offset, offset, byte_count;
3511
3512 cFYI(1, ("In SETFSUnixInfo"));
3513SETFSUnixRetry:
3514 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3515 (void **) &pSMBr);
3516 if (rc)
3517 return rc;
3518
3519 params = 4; /* 2 bytes zero followed by info level. */
3520 pSMB->MaxSetupCount = 0;
3521 pSMB->Reserved = 0;
3522 pSMB->Flags = 0;
3523 pSMB->Timeout = 0;
3524 pSMB->Reserved2 = 0;
3525 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3526 offset = param_offset + params;
3527
3528 pSMB->MaxParameterCount = cpu_to_le16(4);
3529 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3530 pSMB->SetupCount = 1;
3531 pSMB->Reserved3 = 0;
3532 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3533 byte_count = 1 /* pad */ + params + 12;
3534
3535 pSMB->DataCount = cpu_to_le16(12);
3536 pSMB->ParameterCount = cpu_to_le16(params);
3537 pSMB->TotalDataCount = pSMB->DataCount;
3538 pSMB->TotalParameterCount = pSMB->ParameterCount;
3539 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3540 pSMB->DataOffset = cpu_to_le16(offset);
3541
3542 /* Params. */
3543 pSMB->FileNum = 0;
3544 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3545
3546 /* Data. */
3547 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3548 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3549 pSMB->ClientUnixCap = cpu_to_le64(cap);
3550
3551 pSMB->hdr.smb_buf_length += byte_count;
3552 pSMB->ByteCount = cpu_to_le16(byte_count);
3553
3554 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3555 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3556 if (rc) {
3557 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3558 } else { /* decode response */
3559 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3560 if (rc) {
3561 rc = -EIO; /* bad smb */
3562 }
3563 }
3564 cifs_buf_release(pSMB);
3565
3566 if (rc == -EAGAIN)
3567 goto SETFSUnixRetry;
3568
3569 return rc;
3570}
3571
3572
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573
3574int
3575CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003576 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577{
3578/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3579 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3580 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3581 FILE_SYSTEM_POSIX_INFO *response_data;
3582 int rc = 0;
3583 int bytes_returned = 0;
3584 __u16 params, byte_count;
3585
3586 cFYI(1, ("In QFSPosixInfo"));
3587QFSPosixRetry:
3588 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3589 (void **) &pSMBr);
3590 if (rc)
3591 return rc;
3592
3593 params = 2; /* level */
3594 pSMB->TotalDataCount = 0;
3595 pSMB->DataCount = 0;
3596 pSMB->DataOffset = 0;
3597 pSMB->MaxParameterCount = cpu_to_le16(2);
3598 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3599 pSMB->MaxSetupCount = 0;
3600 pSMB->Reserved = 0;
3601 pSMB->Flags = 0;
3602 pSMB->Timeout = 0;
3603 pSMB->Reserved2 = 0;
3604 byte_count = params + 1 /* pad */ ;
3605 pSMB->ParameterCount = cpu_to_le16(params);
3606 pSMB->TotalParameterCount = pSMB->ParameterCount;
3607 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3608 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3609 pSMB->SetupCount = 1;
3610 pSMB->Reserved3 = 0;
3611 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3612 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3613 pSMB->hdr.smb_buf_length += byte_count;
3614 pSMB->ByteCount = cpu_to_le16(byte_count);
3615
3616 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3617 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3618 if (rc) {
3619 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3620 } else { /* decode response */
3621 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3622
3623 if (rc || (pSMBr->ByteCount < 13)) {
3624 rc = -EIO; /* bad smb */
3625 } else {
3626 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3627 response_data =
3628 (FILE_SYSTEM_POSIX_INFO
3629 *) (((char *) &pSMBr->hdr.Protocol) +
3630 data_offset);
3631 FSData->f_bsize =
3632 le32_to_cpu(response_data->BlockSize);
3633 FSData->f_blocks =
3634 le64_to_cpu(response_data->TotalBlocks);
3635 FSData->f_bfree =
3636 le64_to_cpu(response_data->BlocksAvail);
3637 if(response_data->UserBlocksAvail == -1) {
3638 FSData->f_bavail = FSData->f_bfree;
3639 } else {
3640 FSData->f_bavail =
3641 le64_to_cpu(response_data->UserBlocksAvail);
3642 }
3643 if(response_data->TotalFileNodes != -1)
3644 FSData->f_files =
3645 le64_to_cpu(response_data->TotalFileNodes);
3646 if(response_data->FreeFileNodes != -1)
3647 FSData->f_ffree =
3648 le64_to_cpu(response_data->FreeFileNodes);
3649 }
3650 }
3651 cifs_buf_release(pSMB);
3652
3653 if (rc == -EAGAIN)
3654 goto QFSPosixRetry;
3655
3656 return rc;
3657}
3658
3659
3660/* We can not use write of zero bytes trick to
3661 set file size due to need for large file support. Also note that
3662 this SetPathInfo is preferred to SetFileInfo based method in next
3663 routine which is only needed to work around a sharing violation bug
3664 in Samba which this routine can run into */
3665
3666int
3667CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07003668 __u64 size, int SetAllocation,
3669 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670{
3671 struct smb_com_transaction2_spi_req *pSMB = NULL;
3672 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3673 struct file_end_of_file_info *parm_data;
3674 int name_len;
3675 int rc = 0;
3676 int bytes_returned = 0;
3677 __u16 params, byte_count, data_count, param_offset, offset;
3678
3679 cFYI(1, ("In SetEOF"));
3680SetEOFRetry:
3681 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3682 (void **) &pSMBr);
3683 if (rc)
3684 return rc;
3685
3686 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3687 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003688 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003689 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 name_len++; /* trailing null */
3691 name_len *= 2;
3692 } else { /* BB improve the check for buffer overruns BB */
3693 name_len = strnlen(fileName, PATH_MAX);
3694 name_len++; /* trailing null */
3695 strncpy(pSMB->FileName, fileName, name_len);
3696 }
3697 params = 6 + name_len;
3698 data_count = sizeof (struct file_end_of_file_info);
3699 pSMB->MaxParameterCount = cpu_to_le16(2);
3700 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
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_spi_req,
3707 InformationLevel) - 4;
3708 offset = param_offset + params;
3709 if(SetAllocation) {
3710 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3711 pSMB->InformationLevel =
3712 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3713 else
3714 pSMB->InformationLevel =
3715 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3716 } else /* Set File Size */ {
3717 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3718 pSMB->InformationLevel =
3719 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3720 else
3721 pSMB->InformationLevel =
3722 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3723 }
3724
3725 parm_data =
3726 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3727 offset);
3728 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3729 pSMB->DataOffset = cpu_to_le16(offset);
3730 pSMB->SetupCount = 1;
3731 pSMB->Reserved3 = 0;
3732 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3733 byte_count = 3 /* pad */ + params + data_count;
3734 pSMB->DataCount = cpu_to_le16(data_count);
3735 pSMB->TotalDataCount = pSMB->DataCount;
3736 pSMB->ParameterCount = cpu_to_le16(params);
3737 pSMB->TotalParameterCount = pSMB->ParameterCount;
3738 pSMB->Reserved4 = 0;
3739 pSMB->hdr.smb_buf_length += byte_count;
3740 parm_data->FileSize = cpu_to_le64(size);
3741 pSMB->ByteCount = cpu_to_le16(byte_count);
3742 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3743 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3744 if (rc) {
3745 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3746 }
3747
3748 cifs_buf_release(pSMB);
3749
3750 if (rc == -EAGAIN)
3751 goto SetEOFRetry;
3752
3753 return rc;
3754}
3755
3756int
3757CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
3758 __u16 fid, __u32 pid_of_opener, int SetAllocation)
3759{
3760 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3761 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3762 char *data_offset;
3763 struct file_end_of_file_info *parm_data;
3764 int rc = 0;
3765 int bytes_returned = 0;
3766 __u16 params, param_offset, offset, byte_count, count;
3767
3768 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3769 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07003770 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3771
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772 if (rc)
3773 return rc;
3774
Steve Frenchcd634992005-04-28 22:41:10 -07003775 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3776
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3778 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3779
3780 params = 6;
3781 pSMB->MaxSetupCount = 0;
3782 pSMB->Reserved = 0;
3783 pSMB->Flags = 0;
3784 pSMB->Timeout = 0;
3785 pSMB->Reserved2 = 0;
3786 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3787 offset = param_offset + params;
3788
3789 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3790
3791 count = sizeof(struct file_end_of_file_info);
3792 pSMB->MaxParameterCount = cpu_to_le16(2);
3793 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3794 pSMB->SetupCount = 1;
3795 pSMB->Reserved3 = 0;
3796 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3797 byte_count = 3 /* pad */ + params + count;
3798 pSMB->DataCount = cpu_to_le16(count);
3799 pSMB->ParameterCount = cpu_to_le16(params);
3800 pSMB->TotalDataCount = pSMB->DataCount;
3801 pSMB->TotalParameterCount = pSMB->ParameterCount;
3802 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3803 parm_data =
3804 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3805 offset);
3806 pSMB->DataOffset = cpu_to_le16(offset);
3807 parm_data->FileSize = cpu_to_le64(size);
3808 pSMB->Fid = fid;
3809 if(SetAllocation) {
3810 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3811 pSMB->InformationLevel =
3812 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3813 else
3814 pSMB->InformationLevel =
3815 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3816 } else /* Set File Size */ {
3817 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3818 pSMB->InformationLevel =
3819 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3820 else
3821 pSMB->InformationLevel =
3822 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3823 }
3824 pSMB->Reserved4 = 0;
3825 pSMB->hdr.smb_buf_length += byte_count;
3826 pSMB->ByteCount = cpu_to_le16(byte_count);
3827 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3828 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3829 if (rc) {
3830 cFYI(1,
3831 ("Send error in SetFileInfo (SetFileSize) = %d",
3832 rc));
3833 }
3834
3835 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07003836 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837
3838 /* Note: On -EAGAIN error only caller can retry on handle based calls
3839 since file handle passed in no longer valid */
3840
3841 return rc;
3842}
3843
3844/* Some legacy servers such as NT4 require that the file times be set on
3845 an open handle, rather than by pathname - this is awkward due to
3846 potential access conflicts on the open, but it is unavoidable for these
3847 old servers since the only other choice is to go from 100 nanosecond DCE
3848 time and resort to the original setpathinfo level which takes the ancient
3849 DOS time format with 2 second granularity */
3850int
3851CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
3852 __u16 fid)
3853{
3854 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3855 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3856 char *data_offset;
3857 int rc = 0;
3858 int bytes_returned = 0;
3859 __u16 params, param_offset, offset, byte_count, count;
3860
3861 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07003862 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3863
Linus Torvalds1da177e2005-04-16 15:20:36 -07003864 if (rc)
3865 return rc;
3866
Steve Frenchcd634992005-04-28 22:41:10 -07003867 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3868
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 /* At this point there is no need to override the current pid
3870 with the pid of the opener, but that could change if we someday
3871 use an existing handle (rather than opening one on the fly) */
3872 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3873 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3874
3875 params = 6;
3876 pSMB->MaxSetupCount = 0;
3877 pSMB->Reserved = 0;
3878 pSMB->Flags = 0;
3879 pSMB->Timeout = 0;
3880 pSMB->Reserved2 = 0;
3881 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3882 offset = param_offset + params;
3883
3884 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3885
3886 count = sizeof (FILE_BASIC_INFO);
3887 pSMB->MaxParameterCount = cpu_to_le16(2);
3888 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3889 pSMB->SetupCount = 1;
3890 pSMB->Reserved3 = 0;
3891 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3892 byte_count = 3 /* pad */ + params + count;
3893 pSMB->DataCount = cpu_to_le16(count);
3894 pSMB->ParameterCount = cpu_to_le16(params);
3895 pSMB->TotalDataCount = pSMB->DataCount;
3896 pSMB->TotalParameterCount = pSMB->ParameterCount;
3897 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3898 pSMB->DataOffset = cpu_to_le16(offset);
3899 pSMB->Fid = fid;
3900 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3901 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3902 else
3903 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3904 pSMB->Reserved4 = 0;
3905 pSMB->hdr.smb_buf_length += byte_count;
3906 pSMB->ByteCount = cpu_to_le16(byte_count);
3907 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
3908 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3909 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3910 if (rc) {
3911 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
3912 }
3913
Steve Frenchcd634992005-04-28 22:41:10 -07003914 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003915
3916 /* Note: On -EAGAIN error only caller can retry on handle based calls
3917 since file handle passed in no longer valid */
3918
3919 return rc;
3920}
3921
3922
3923int
3924CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3925 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07003926 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927{
3928 TRANSACTION2_SPI_REQ *pSMB = NULL;
3929 TRANSACTION2_SPI_RSP *pSMBr = NULL;
3930 int name_len;
3931 int rc = 0;
3932 int bytes_returned = 0;
3933 char *data_offset;
3934 __u16 params, param_offset, offset, byte_count, count;
3935
3936 cFYI(1, ("In SetTimes"));
3937
3938SetTimesRetry:
3939 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3940 (void **) &pSMBr);
3941 if (rc)
3942 return rc;
3943
3944 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3945 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003946 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003947 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948 name_len++; /* trailing null */
3949 name_len *= 2;
3950 } else { /* BB improve the check for buffer overruns BB */
3951 name_len = strnlen(fileName, PATH_MAX);
3952 name_len++; /* trailing null */
3953 strncpy(pSMB->FileName, fileName, name_len);
3954 }
3955
3956 params = 6 + name_len;
3957 count = sizeof (FILE_BASIC_INFO);
3958 pSMB->MaxParameterCount = cpu_to_le16(2);
3959 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3960 pSMB->MaxSetupCount = 0;
3961 pSMB->Reserved = 0;
3962 pSMB->Flags = 0;
3963 pSMB->Timeout = 0;
3964 pSMB->Reserved2 = 0;
3965 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3966 InformationLevel) - 4;
3967 offset = param_offset + params;
3968 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3969 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3970 pSMB->DataOffset = cpu_to_le16(offset);
3971 pSMB->SetupCount = 1;
3972 pSMB->Reserved3 = 0;
3973 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3974 byte_count = 3 /* pad */ + params + count;
3975
3976 pSMB->DataCount = cpu_to_le16(count);
3977 pSMB->ParameterCount = cpu_to_le16(params);
3978 pSMB->TotalDataCount = pSMB->DataCount;
3979 pSMB->TotalParameterCount = pSMB->ParameterCount;
3980 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3981 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3982 else
3983 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3984 pSMB->Reserved4 = 0;
3985 pSMB->hdr.smb_buf_length += byte_count;
3986 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
3987 pSMB->ByteCount = cpu_to_le16(byte_count);
3988 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3989 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3990 if (rc) {
3991 cFYI(1, ("SetPathInfo (times) returned %d", rc));
3992 }
3993
3994 cifs_buf_release(pSMB);
3995
3996 if (rc == -EAGAIN)
3997 goto SetTimesRetry;
3998
3999 return rc;
4000}
4001
4002/* Can not be used to set time stamps yet (due to old DOS time format) */
4003/* Can be used to set attributes */
4004#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4005 handling it anyway and NT4 was what we thought it would be needed for
4006 Do not delete it until we prove whether needed for Win9x though */
4007int
4008CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4009 __u16 dos_attrs, const struct nls_table *nls_codepage)
4010{
4011 SETATTR_REQ *pSMB = NULL;
4012 SETATTR_RSP *pSMBr = NULL;
4013 int rc = 0;
4014 int bytes_returned;
4015 int name_len;
4016
4017 cFYI(1, ("In SetAttrLegacy"));
4018
4019SetAttrLgcyRetry:
4020 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4021 (void **) &pSMBr);
4022 if (rc)
4023 return rc;
4024
4025 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4026 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004027 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 PATH_MAX, nls_codepage);
4029 name_len++; /* trailing null */
4030 name_len *= 2;
4031 } else { /* BB improve the check for buffer overruns BB */
4032 name_len = strnlen(fileName, PATH_MAX);
4033 name_len++; /* trailing null */
4034 strncpy(pSMB->fileName, fileName, name_len);
4035 }
4036 pSMB->attr = cpu_to_le16(dos_attrs);
4037 pSMB->BufferFormat = 0x04;
4038 pSMB->hdr.smb_buf_length += name_len + 1;
4039 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4040 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4041 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4042 if (rc) {
4043 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4044 }
4045
4046 cifs_buf_release(pSMB);
4047
4048 if (rc == -EAGAIN)
4049 goto SetAttrLgcyRetry;
4050
4051 return rc;
4052}
4053#endif /* temporarily unneeded SetAttr legacy function */
4054
4055int
4056CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004057 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4058 dev_t device, const struct nls_table *nls_codepage,
4059 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060{
4061 TRANSACTION2_SPI_REQ *pSMB = NULL;
4062 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4063 int name_len;
4064 int rc = 0;
4065 int bytes_returned = 0;
4066 FILE_UNIX_BASIC_INFO *data_offset;
4067 __u16 params, param_offset, offset, count, byte_count;
4068
4069 cFYI(1, ("In SetUID/GID/Mode"));
4070setPermsRetry:
4071 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4072 (void **) &pSMBr);
4073 if (rc)
4074 return rc;
4075
4076 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4077 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004078 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004079 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080 name_len++; /* trailing null */
4081 name_len *= 2;
4082 } else { /* BB improve the check for buffer overruns BB */
4083 name_len = strnlen(fileName, PATH_MAX);
4084 name_len++; /* trailing null */
4085 strncpy(pSMB->FileName, fileName, name_len);
4086 }
4087
4088 params = 6 + name_len;
4089 count = sizeof (FILE_UNIX_BASIC_INFO);
4090 pSMB->MaxParameterCount = cpu_to_le16(2);
4091 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4092 pSMB->MaxSetupCount = 0;
4093 pSMB->Reserved = 0;
4094 pSMB->Flags = 0;
4095 pSMB->Timeout = 0;
4096 pSMB->Reserved2 = 0;
4097 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4098 InformationLevel) - 4;
4099 offset = param_offset + params;
4100 data_offset =
4101 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4102 offset);
4103 memset(data_offset, 0, count);
4104 pSMB->DataOffset = cpu_to_le16(offset);
4105 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4106 pSMB->SetupCount = 1;
4107 pSMB->Reserved3 = 0;
4108 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4109 byte_count = 3 /* pad */ + params + count;
4110 pSMB->ParameterCount = cpu_to_le16(params);
4111 pSMB->DataCount = cpu_to_le16(count);
4112 pSMB->TotalParameterCount = pSMB->ParameterCount;
4113 pSMB->TotalDataCount = pSMB->DataCount;
4114 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4115 pSMB->Reserved4 = 0;
4116 pSMB->hdr.smb_buf_length += byte_count;
4117 data_offset->Uid = cpu_to_le64(uid);
4118 data_offset->Gid = cpu_to_le64(gid);
4119 /* better to leave device as zero when it is */
4120 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4121 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4122 data_offset->Permissions = cpu_to_le64(mode);
4123
4124 if(S_ISREG(mode))
4125 data_offset->Type = cpu_to_le32(UNIX_FILE);
4126 else if(S_ISDIR(mode))
4127 data_offset->Type = cpu_to_le32(UNIX_DIR);
4128 else if(S_ISLNK(mode))
4129 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4130 else if(S_ISCHR(mode))
4131 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4132 else if(S_ISBLK(mode))
4133 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4134 else if(S_ISFIFO(mode))
4135 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4136 else if(S_ISSOCK(mode))
4137 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4138
4139
4140 pSMB->ByteCount = cpu_to_le16(byte_count);
4141 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4142 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4143 if (rc) {
4144 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4145 }
4146
4147 if (pSMB)
4148 cifs_buf_release(pSMB);
4149 if (rc == -EAGAIN)
4150 goto setPermsRetry;
4151 return rc;
4152}
4153
4154int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004155 const int notify_subdirs, const __u16 netfid,
4156 __u32 filter, struct file * pfile, int multishot,
4157 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158{
4159 int rc = 0;
4160 struct smb_com_transaction_change_notify_req * pSMB = NULL;
4161 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004162 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 int bytes_returned;
4164
4165 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4166 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4167 (void **) &pSMBr);
4168 if (rc)
4169 return rc;
4170
4171 pSMB->TotalParameterCount = 0 ;
4172 pSMB->TotalDataCount = 0;
4173 pSMB->MaxParameterCount = cpu_to_le32(2);
4174 /* BB find exact data count max from sess structure BB */
4175 pSMB->MaxDataCount = 0; /* same in little endian or be */
4176 pSMB->MaxSetupCount = 4;
4177 pSMB->Reserved = 0;
4178 pSMB->ParameterOffset = 0;
4179 pSMB->DataCount = 0;
4180 pSMB->DataOffset = 0;
4181 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4182 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4183 pSMB->ParameterCount = pSMB->TotalParameterCount;
4184 if(notify_subdirs)
4185 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4186 pSMB->Reserved2 = 0;
4187 pSMB->CompletionFilter = cpu_to_le32(filter);
4188 pSMB->Fid = netfid; /* file handle always le */
4189 pSMB->ByteCount = 0;
4190
4191 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4192 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4193 if (rc) {
4194 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004195 } else {
4196 /* Add file to outstanding requests */
4197 dnotify_req = (struct dir_notify_req *) kmalloc(
4198 sizeof(struct dir_notify_req), GFP_KERNEL);
4199 dnotify_req->Pid = pSMB->hdr.Pid;
4200 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4201 dnotify_req->Mid = pSMB->hdr.Mid;
4202 dnotify_req->Tid = pSMB->hdr.Tid;
4203 dnotify_req->Uid = pSMB->hdr.Uid;
4204 dnotify_req->netfid = netfid;
Steve French167a2512005-08-24 20:03:11 -07004205 dnotify_req->pfile = pfile;
Steve Frenchff5dbd92005-08-24 17:10:36 -07004206 dnotify_req->filter = filter;
4207 dnotify_req->multishot = multishot;
4208 spin_lock(&GlobalMid_Lock);
4209 list_add_tail(&dnotify_req->lhead, &GlobalDnotifyReqList);
4210 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 }
4212 cifs_buf_release(pSMB);
4213 return rc;
4214}
4215#ifdef CONFIG_CIFS_XATTR
4216ssize_t
4217CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4218 const unsigned char *searchName,
4219 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004220 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221{
4222 /* BB assumes one setup word */
4223 TRANSACTION2_QPI_REQ *pSMB = NULL;
4224 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4225 int rc = 0;
4226 int bytes_returned;
4227 int name_len;
4228 struct fea * temp_fea;
4229 char * temp_ptr;
4230 __u16 params, byte_count;
4231
4232 cFYI(1, ("In Query All EAs path %s", searchName));
4233QAllEAsRetry:
4234 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4235 (void **) &pSMBr);
4236 if (rc)
4237 return rc;
4238
4239 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4240 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004241 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004242 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243 name_len++; /* trailing null */
4244 name_len *= 2;
4245 } else { /* BB improve the check for buffer overruns BB */
4246 name_len = strnlen(searchName, PATH_MAX);
4247 name_len++; /* trailing null */
4248 strncpy(pSMB->FileName, searchName, name_len);
4249 }
4250
4251 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4252 pSMB->TotalDataCount = 0;
4253 pSMB->MaxParameterCount = cpu_to_le16(2);
4254 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4255 pSMB->MaxSetupCount = 0;
4256 pSMB->Reserved = 0;
4257 pSMB->Flags = 0;
4258 pSMB->Timeout = 0;
4259 pSMB->Reserved2 = 0;
4260 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4261 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4262 pSMB->DataCount = 0;
4263 pSMB->DataOffset = 0;
4264 pSMB->SetupCount = 1;
4265 pSMB->Reserved3 = 0;
4266 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4267 byte_count = params + 1 /* pad */ ;
4268 pSMB->TotalParameterCount = cpu_to_le16(params);
4269 pSMB->ParameterCount = pSMB->TotalParameterCount;
4270 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4271 pSMB->Reserved4 = 0;
4272 pSMB->hdr.smb_buf_length += byte_count;
4273 pSMB->ByteCount = cpu_to_le16(byte_count);
4274
4275 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4276 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4277 if (rc) {
4278 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4279 } else { /* decode response */
4280 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4281
4282 /* BB also check enough total bytes returned */
4283 /* BB we need to improve the validity checking
4284 of these trans2 responses */
4285 if (rc || (pSMBr->ByteCount < 4))
4286 rc = -EIO; /* bad smb */
4287 /* else if (pFindData){
4288 memcpy((char *) pFindData,
4289 (char *) &pSMBr->hdr.Protocol +
4290 data_offset, kl);
4291 }*/ else {
4292 /* check that length of list is not more than bcc */
4293 /* check that each entry does not go beyond length
4294 of list */
4295 /* check that each element of each entry does not
4296 go beyond end of list */
4297 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4298 struct fealist * ea_response_data;
4299 rc = 0;
4300 /* validate_trans2_offsets() */
4301 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4302 ea_response_data = (struct fealist *)
4303 (((char *) &pSMBr->hdr.Protocol) +
4304 data_offset);
4305 name_len = le32_to_cpu(ea_response_data->list_len);
4306 cFYI(1,("ea length %d", name_len));
4307 if(name_len <= 8) {
4308 /* returned EA size zeroed at top of function */
4309 cFYI(1,("empty EA list returned from server"));
4310 } else {
4311 /* account for ea list len */
4312 name_len -= 4;
4313 temp_fea = ea_response_data->list;
4314 temp_ptr = (char *)temp_fea;
4315 while(name_len > 0) {
4316 __u16 value_len;
4317 name_len -= 4;
4318 temp_ptr += 4;
4319 rc += temp_fea->name_len;
4320 /* account for prefix user. and trailing null */
4321 rc = rc + 5 + 1;
4322 if(rc<(int)buf_size) {
4323 memcpy(EAData,"user.",5);
4324 EAData+=5;
4325 memcpy(EAData,temp_ptr,temp_fea->name_len);
4326 EAData+=temp_fea->name_len;
4327 /* null terminate name */
4328 *EAData = 0;
4329 EAData = EAData + 1;
4330 } else if(buf_size == 0) {
4331 /* skip copy - calc size only */
4332 } else {
4333 /* stop before overrun buffer */
4334 rc = -ERANGE;
4335 break;
4336 }
4337 name_len -= temp_fea->name_len;
4338 temp_ptr += temp_fea->name_len;
4339 /* account for trailing null */
4340 name_len--;
4341 temp_ptr++;
4342 value_len = le16_to_cpu(temp_fea->value_len);
4343 name_len -= value_len;
4344 temp_ptr += value_len;
4345 /* BB check that temp_ptr is still within smb BB*/
4346 /* no trailing null to account for in value len */
4347 /* go on to next EA */
4348 temp_fea = (struct fea *)temp_ptr;
4349 }
4350 }
4351 }
4352 }
4353 if (pSMB)
4354 cifs_buf_release(pSMB);
4355 if (rc == -EAGAIN)
4356 goto QAllEAsRetry;
4357
4358 return (ssize_t)rc;
4359}
4360
4361ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4362 const unsigned char * searchName,const unsigned char * ea_name,
4363 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004364 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365{
4366 TRANSACTION2_QPI_REQ *pSMB = NULL;
4367 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4368 int rc = 0;
4369 int bytes_returned;
4370 int name_len;
4371 struct fea * temp_fea;
4372 char * temp_ptr;
4373 __u16 params, byte_count;
4374
4375 cFYI(1, ("In Query EA path %s", searchName));
4376QEARetry:
4377 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4378 (void **) &pSMBr);
4379 if (rc)
4380 return rc;
4381
4382 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4383 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004384 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004385 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 name_len++; /* trailing null */
4387 name_len *= 2;
4388 } else { /* BB improve the check for buffer overruns BB */
4389 name_len = strnlen(searchName, PATH_MAX);
4390 name_len++; /* trailing null */
4391 strncpy(pSMB->FileName, searchName, name_len);
4392 }
4393
4394 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4395 pSMB->TotalDataCount = 0;
4396 pSMB->MaxParameterCount = cpu_to_le16(2);
4397 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4398 pSMB->MaxSetupCount = 0;
4399 pSMB->Reserved = 0;
4400 pSMB->Flags = 0;
4401 pSMB->Timeout = 0;
4402 pSMB->Reserved2 = 0;
4403 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4404 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4405 pSMB->DataCount = 0;
4406 pSMB->DataOffset = 0;
4407 pSMB->SetupCount = 1;
4408 pSMB->Reserved3 = 0;
4409 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4410 byte_count = params + 1 /* pad */ ;
4411 pSMB->TotalParameterCount = cpu_to_le16(params);
4412 pSMB->ParameterCount = pSMB->TotalParameterCount;
4413 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4414 pSMB->Reserved4 = 0;
4415 pSMB->hdr.smb_buf_length += byte_count;
4416 pSMB->ByteCount = cpu_to_le16(byte_count);
4417
4418 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4419 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4420 if (rc) {
4421 cFYI(1, ("Send error in Query EA = %d", rc));
4422 } else { /* decode response */
4423 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4424
4425 /* BB also check enough total bytes returned */
4426 /* BB we need to improve the validity checking
4427 of these trans2 responses */
4428 if (rc || (pSMBr->ByteCount < 4))
4429 rc = -EIO; /* bad smb */
4430 /* else if (pFindData){
4431 memcpy((char *) pFindData,
4432 (char *) &pSMBr->hdr.Protocol +
4433 data_offset, kl);
4434 }*/ else {
4435 /* check that length of list is not more than bcc */
4436 /* check that each entry does not go beyond length
4437 of list */
4438 /* check that each element of each entry does not
4439 go beyond end of list */
4440 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4441 struct fealist * ea_response_data;
4442 rc = -ENODATA;
4443 /* validate_trans2_offsets() */
4444 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4445 ea_response_data = (struct fealist *)
4446 (((char *) &pSMBr->hdr.Protocol) +
4447 data_offset);
4448 name_len = le32_to_cpu(ea_response_data->list_len);
4449 cFYI(1,("ea length %d", name_len));
4450 if(name_len <= 8) {
4451 /* returned EA size zeroed at top of function */
4452 cFYI(1,("empty EA list returned from server"));
4453 } else {
4454 /* account for ea list len */
4455 name_len -= 4;
4456 temp_fea = ea_response_data->list;
4457 temp_ptr = (char *)temp_fea;
4458 /* loop through checking if we have a matching
4459 name and then return the associated value */
4460 while(name_len > 0) {
4461 __u16 value_len;
4462 name_len -= 4;
4463 temp_ptr += 4;
4464 value_len = le16_to_cpu(temp_fea->value_len);
4465 /* BB validate that value_len falls within SMB,
4466 even though maximum for name_len is 255 */
4467 if(memcmp(temp_fea->name,ea_name,
4468 temp_fea->name_len) == 0) {
4469 /* found a match */
4470 rc = value_len;
4471 /* account for prefix user. and trailing null */
4472 if(rc<=(int)buf_size) {
4473 memcpy(ea_value,
4474 temp_fea->name+temp_fea->name_len+1,
4475 rc);
4476 /* ea values, unlike ea names,
4477 are not null terminated */
4478 } else if(buf_size == 0) {
4479 /* skip copy - calc size only */
4480 } else {
4481 /* stop before overrun buffer */
4482 rc = -ERANGE;
4483 }
4484 break;
4485 }
4486 name_len -= temp_fea->name_len;
4487 temp_ptr += temp_fea->name_len;
4488 /* account for trailing null */
4489 name_len--;
4490 temp_ptr++;
4491 name_len -= value_len;
4492 temp_ptr += value_len;
4493 /* no trailing null to account for in value len */
4494 /* go on to next EA */
4495 temp_fea = (struct fea *)temp_ptr;
4496 }
4497 }
4498 }
4499 }
4500 if (pSMB)
4501 cifs_buf_release(pSMB);
4502 if (rc == -EAGAIN)
4503 goto QEARetry;
4504
4505 return (ssize_t)rc;
4506}
4507
4508int
4509CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4510 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004511 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4512 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513{
4514 struct smb_com_transaction2_spi_req *pSMB = NULL;
4515 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4516 struct fealist *parm_data;
4517 int name_len;
4518 int rc = 0;
4519 int bytes_returned = 0;
4520 __u16 params, param_offset, byte_count, offset, count;
4521
4522 cFYI(1, ("In SetEA"));
4523SetEARetry:
4524 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4525 (void **) &pSMBr);
4526 if (rc)
4527 return rc;
4528
4529 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4530 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004531 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004532 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 name_len++; /* trailing null */
4534 name_len *= 2;
4535 } else { /* BB improve the check for buffer overruns BB */
4536 name_len = strnlen(fileName, PATH_MAX);
4537 name_len++; /* trailing null */
4538 strncpy(pSMB->FileName, fileName, name_len);
4539 }
4540
4541 params = 6 + name_len;
4542
4543 /* done calculating parms using name_len of file name,
4544 now use name_len to calculate length of ea name
4545 we are going to create in the inode xattrs */
4546 if(ea_name == NULL)
4547 name_len = 0;
4548 else
4549 name_len = strnlen(ea_name,255);
4550
4551 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4552 pSMB->MaxParameterCount = cpu_to_le16(2);
4553 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4554 pSMB->MaxSetupCount = 0;
4555 pSMB->Reserved = 0;
4556 pSMB->Flags = 0;
4557 pSMB->Timeout = 0;
4558 pSMB->Reserved2 = 0;
4559 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4560 InformationLevel) - 4;
4561 offset = param_offset + params;
4562 pSMB->InformationLevel =
4563 cpu_to_le16(SMB_SET_FILE_EA);
4564
4565 parm_data =
4566 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4567 offset);
4568 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4569 pSMB->DataOffset = cpu_to_le16(offset);
4570 pSMB->SetupCount = 1;
4571 pSMB->Reserved3 = 0;
4572 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4573 byte_count = 3 /* pad */ + params + count;
4574 pSMB->DataCount = cpu_to_le16(count);
4575 parm_data->list_len = cpu_to_le32(count);
4576 parm_data->list[0].EA_flags = 0;
4577 /* we checked above that name len is less than 255 */
4578 parm_data->list[0].name_len = (__u8)name_len;;
4579 /* EA names are always ASCII */
4580 if(ea_name)
4581 strncpy(parm_data->list[0].name,ea_name,name_len);
4582 parm_data->list[0].name[name_len] = 0;
4583 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4584 /* caller ensures that ea_value_len is less than 64K but
4585 we need to ensure that it fits within the smb */
4586
4587 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4588 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4589 if(ea_value_len)
4590 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4591
4592 pSMB->TotalDataCount = pSMB->DataCount;
4593 pSMB->ParameterCount = cpu_to_le16(params);
4594 pSMB->TotalParameterCount = pSMB->ParameterCount;
4595 pSMB->Reserved4 = 0;
4596 pSMB->hdr.smb_buf_length += byte_count;
4597 pSMB->ByteCount = cpu_to_le16(byte_count);
4598 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4599 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4600 if (rc) {
4601 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4602 }
4603
4604 cifs_buf_release(pSMB);
4605
4606 if (rc == -EAGAIN)
4607 goto SetEARetry;
4608
4609 return rc;
4610}
4611
4612#endif