blob: 52caac063a7750622050697c81eb06b96e404319 [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 Frencha4544342005-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 Frencha4544342005-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 Frencha4544342005-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 Frencha4544342005-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 Frencha4544342005-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
Steve French3e87d802005-09-18 20:49:21 -0700769 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700770
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 */
Steve French3e87d802005-09-18 20:49:21 -0700780
781 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700782 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700783 count += name_len;
784 pSMB->hdr.smb_buf_length += count;
785
786 pSMB->ByteCount = cpu_to_le16(count);
787 /* long_op set to 1 to allow for oplock break timeouts */
788 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
789 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
790 cifs_stats_inc(&tcon->num_opens);
791 if (rc) {
792 cFYI(1, ("Error in Open = %d", rc));
793 } else {
794 /* BB verify if wct == 15 */
795
796/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
797
798 *netfid = pSMBr->Fid; /* cifs fid stays in le */
799 /* Let caller know file was created so we can set the mode. */
800 /* Do we care about the CreateAction in any other cases? */
801 /* BB FIXME BB */
802/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
803 *pOplock |= CIFS_CREATE_ACTION; */
804 /* BB FIXME END */
805
806 if(pfile_info) {
807 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
808 pfile_info->LastAccessTime = 0; /* BB fixme */
809 pfile_info->LastWriteTime = 0; /* BB fixme */
810 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -0700811 pfile_info->Attributes =
812 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700813 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -0700814 pfile_info->AllocationSize =
815 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
816 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -0700817 pfile_info->NumberOfLinks = cpu_to_le32(1);
818 }
819 }
820
821 cifs_buf_release(pSMB);
822 if (rc == -EAGAIN)
823 goto OldOpenRetry;
824 return rc;
825}
826
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827int
828CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
829 const char *fileName, const int openDisposition,
830 const int access_flags, const int create_options, __u16 * netfid,
831 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -0700832 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833{
834 int rc = -EACCES;
835 OPEN_REQ *pSMB = NULL;
836 OPEN_RSP *pSMBr = NULL;
837 int bytes_returned;
838 int name_len;
839 __u16 count;
840
841openRetry:
842 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
843 (void **) &pSMBr);
844 if (rc)
845 return rc;
846
847 pSMB->AndXCommand = 0xFF; /* none */
848
849 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
850 count = 1; /* account for one byte pad to word boundary */
851 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500852 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -0700853 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 name_len++; /* trailing null */
855 name_len *= 2;
856 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -0700857 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 count = 0; /* no pad */
859 name_len = strnlen(fileName, PATH_MAX);
860 name_len++; /* trailing null */
861 pSMB->NameLength = cpu_to_le16(name_len);
862 strncpy(pSMB->fileName, fileName, name_len);
863 }
864 if (*pOplock & REQ_OPLOCK)
865 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
866 else if (*pOplock & REQ_BATCHOPLOCK) {
867 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
868 }
869 pSMB->DesiredAccess = cpu_to_le32(access_flags);
870 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -0700871 /* set file as system file if special file such
872 as fifo and server expecting SFU style and
873 no Unix extensions */
874 if(create_options & CREATE_OPTION_SPECIAL)
875 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
876 else
877 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 /* XP does not handle ATTR_POSIX_SEMANTICS */
879 /* but it helps speed up case sensitive checks for other
880 servers such as Samba */
881 if (tcon->ses->capabilities & CAP_UNIX)
882 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
883
884 /* if ((omode & S_IWUGO) == 0)
885 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
886 /* Above line causes problems due to vfs splitting create into two
887 pieces - need to set mode after file created not while it is
888 being created */
889 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
890 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -0700891 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -0700892 /* BB Expirement with various impersonation levels and verify */
893 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 pSMB->SecurityFlags =
895 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
896
897 count += name_len;
898 pSMB->hdr.smb_buf_length += count;
899
900 pSMB->ByteCount = cpu_to_le16(count);
901 /* long_op set to 1 to allow for oplock break timeouts */
902 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
903 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -0700904 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 if (rc) {
906 cFYI(1, ("Error in Open = %d", rc));
907 } else {
Steve French09d1db52005-04-28 22:41:08 -0700908 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 *netfid = pSMBr->Fid; /* cifs fid stays in le */
910 /* Let caller know file was created so we can set the mode. */
911 /* Do we care about the CreateAction in any other cases? */
912 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
913 *pOplock |= CIFS_CREATE_ACTION;
914 if(pfile_info) {
915 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
916 36 /* CreationTime to Attributes */);
917 /* the file_info buf is endian converted by caller */
918 pfile_info->AllocationSize = pSMBr->AllocationSize;
919 pfile_info->EndOfFile = pSMBr->EndOfFile;
920 pfile_info->NumberOfLinks = cpu_to_le32(1);
921 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700923
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 cifs_buf_release(pSMB);
925 if (rc == -EAGAIN)
926 goto openRetry;
927 return rc;
928}
929
930/* If no buffer passed in, then caller wants to do the copy
931 as in the case of readpages so the SMB buffer must be
932 freed by the caller */
933
934int
935CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
936 const int netfid, const unsigned int count,
937 const __u64 lseek, unsigned int *nbytes, char **buf)
938{
939 int rc = -EACCES;
940 READ_REQ *pSMB = NULL;
941 READ_RSP *pSMBr = NULL;
942 char *pReadData = NULL;
943 int bytes_returned;
Steve Frenchbfa0d752005-08-31 21:50:37 -0700944 int wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -0700947 if(tcon->ses->capabilities & CAP_LARGE_FILES)
948 wct = 12;
949 else
950 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
952 *nbytes = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -0700953 rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 (void **) &pSMBr);
955 if (rc)
956 return rc;
957
958 /* tcon and ses pointer are checked in smb_init */
959 if (tcon->ses->server == NULL)
960 return -ECONNABORTED;
961
962 pSMB->AndXCommand = 0xFF; /* none */
963 pSMB->Fid = netfid;
964 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -0700965 if(wct == 12)
966 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
967 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
968 return -EIO;
969
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 pSMB->Remaining = 0;
971 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
972 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -0700973 if(wct == 12)
974 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
975 else {
976 /* old style read */
977 struct smb_com_readx_req * pSMBW =
978 (struct smb_com_readx_req *)pSMB;
979 pSMBW->ByteCount = 0;
980 }
981
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
983 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700984 cifs_stats_inc(&tcon->num_reads);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 if (rc) {
986 cERROR(1, ("Send error in read = %d", rc));
987 } else {
988 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
989 data_length = data_length << 16;
990 data_length += le16_to_cpu(pSMBr->DataLength);
991 *nbytes = data_length;
992
993 /*check that DataLength would not go beyond end of SMB */
994 if ((data_length > CIFSMaxBufSize)
995 || (data_length > count)) {
996 cFYI(1,("bad length %d for count %d",data_length,count));
997 rc = -EIO;
998 *nbytes = 0;
999 } else {
1000 pReadData =
1001 (char *) (&pSMBr->hdr.Protocol) +
1002 le16_to_cpu(pSMBr->DataOffset);
1003/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1004 cERROR(1,("Faulting on read rc = %d",rc));
1005 rc = -EFAULT;
1006 }*/ /* can not use copy_to_user when using page cache*/
1007 if(*buf)
1008 memcpy(*buf,pReadData,data_length);
1009 }
1010 }
1011 if(*buf)
1012 cifs_buf_release(pSMB);
1013 else
1014 *buf = (char *)pSMB;
1015
1016 /* Note: On -EAGAIN error only caller can retry on handle based calls
1017 since file handle passed in no longer valid */
1018 return rc;
1019}
1020
1021int
1022CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1023 const int netfid, const unsigned int count,
1024 const __u64 offset, unsigned int *nbytes, const char *buf,
1025 const char __user * ubuf, const int long_op)
1026{
1027 int rc = -EACCES;
1028 WRITE_REQ *pSMB = NULL;
1029 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001030 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 __u32 bytes_sent;
1032 __u16 byte_count;
1033
1034 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001035 if(tcon->ses == NULL)
1036 return -ECONNABORTED;
1037
1038 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1039 wct = 14;
1040 else
1041 wct = 12;
1042
1043 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 (void **) &pSMBr);
1045 if (rc)
1046 return rc;
1047 /* tcon and ses pointer are checked in smb_init */
1048 if (tcon->ses->server == NULL)
1049 return -ECONNABORTED;
1050
1051 pSMB->AndXCommand = 0xFF; /* none */
1052 pSMB->Fid = netfid;
1053 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001054 if(wct == 14)
1055 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1056 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1057 return -EIO;
1058
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 pSMB->Reserved = 0xFFFFFFFF;
1060 pSMB->WriteMode = 0;
1061 pSMB->Remaining = 0;
1062
1063 /* Can increase buffer size if buffer is big enough in some cases - ie we
1064 can send more if LARGE_WRITE_X capability returned by the server and if
1065 our buffer is big enough or if we convert to iovecs on socket writes
1066 and eliminate the copy to the CIFS buffer */
1067 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1068 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1069 } else {
1070 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1071 & ~0xFF;
1072 }
1073
1074 if (bytes_sent > count)
1075 bytes_sent = count;
1076 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001077 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 if(buf)
1079 memcpy(pSMB->Data,buf,bytes_sent);
1080 else if(ubuf) {
1081 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1082 cifs_buf_release(pSMB);
1083 return -EFAULT;
1084 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001085 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 /* No buffer */
1087 cifs_buf_release(pSMB);
1088 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001089 } /* else setting file size with write of zero bytes */
1090 if(wct == 14)
1091 byte_count = bytes_sent + 1; /* pad */
1092 else /* wct == 12 */ {
1093 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1096 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001097 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001098
1099 if(wct == 14)
1100 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001101 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001102 struct smb_com_writex_req * pSMBW =
1103 (struct smb_com_writex_req *)pSMB;
1104 pSMBW->ByteCount = cpu_to_le16(byte_count);
1105 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
1107 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1108 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001109 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 if (rc) {
1111 cFYI(1, ("Send error in write = %d", rc));
1112 *nbytes = 0;
1113 } else {
1114 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1115 *nbytes = (*nbytes) << 16;
1116 *nbytes += le16_to_cpu(pSMBr->Count);
1117 }
1118
1119 cifs_buf_release(pSMB);
1120
1121 /* Note: On -EAGAIN error only caller can retry on handle based calls
1122 since file handle passed in no longer valid */
1123
1124 return rc;
1125}
1126
1127#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001128int
1129CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 const int netfid, const unsigned int count,
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001131 const __u64 offset, unsigned int *nbytes, const char *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 const int long_op)
1133{
1134 int rc = -EACCES;
1135 WRITE_REQ *pSMB = NULL;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001136 int bytes_returned;
1137 int smb_hdr_len;
1138 __u32 bytes_sent;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 __u16 byte_count;
1140
Steve French0c0ff092005-06-23 19:31:17 -05001141 cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 if (rc)
1144 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 /* tcon and ses pointer are checked in smb_init */
1146 if (tcon->ses->server == NULL)
1147 return -ECONNABORTED;
1148
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001149 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 pSMB->Fid = netfid;
1151 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1152 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1153 pSMB->Reserved = 0xFFFFFFFF;
1154 pSMB->WriteMode = 0;
1155 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001156
1157 /* Can increase buffer size if buffer is big enough in some cases - ie
1158 can send more if LARGE_WRITE_X capability returned by the server and if
1159 our buffer is big enough or if we convert to iovecs on socket writes
1160 and eliminate the copy to the CIFS buffer */
1161 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1162 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1163 } else {
1164 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1165 & ~0xFF;
1166 }
1167
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 if (bytes_sent > count)
1169 bytes_sent = count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 pSMB->DataOffset =
1171 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1172
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001173 byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
1174 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1175 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1176 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1177 pSMB->hdr.smb_buf_length += bytes_sent+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 pSMB->ByteCount = cpu_to_le16(byte_count);
1179
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001180 rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
1181 buf, bytes_sent, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001182 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 if (rc) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001184 cFYI(1, ("Send error in write = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001186 } else {
1187 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
1188 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1189 *nbytes = (*nbytes) << 16;
1190 *nbytes += le16_to_cpu(pSMBr->Count);
1191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
1193 cifs_small_buf_release(pSMB);
1194
1195 /* Note: On -EAGAIN error only caller can retry on handle based calls
1196 since file handle passed in no longer valid */
1197
1198 return rc;
1199}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001200
1201
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202#endif /* CIFS_EXPERIMENTAL */
1203
1204int
1205CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1206 const __u16 smb_file_id, const __u64 len,
1207 const __u64 offset, const __u32 numUnlock,
1208 const __u32 numLock, const __u8 lockType, const int waitFlag)
1209{
1210 int rc = 0;
1211 LOCK_REQ *pSMB = NULL;
1212 LOCK_RSP *pSMBr = NULL;
1213 int bytes_returned;
1214 int timeout = 0;
1215 __u16 count;
1216
1217 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001218 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1219
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 if (rc)
1221 return rc;
1222
Steve French46810cb2005-04-28 22:41:09 -07001223 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1224
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1226 timeout = -1; /* no response expected */
1227 pSMB->Timeout = 0;
1228 } else if (waitFlag == TRUE) {
1229 timeout = 3; /* blocking operation, no timeout */
1230 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1231 } else {
1232 pSMB->Timeout = 0;
1233 }
1234
1235 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1236 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1237 pSMB->LockType = lockType;
1238 pSMB->AndXCommand = 0xFF; /* none */
1239 pSMB->Fid = smb_file_id; /* netfid stays le */
1240
1241 if((numLock != 0) || (numUnlock != 0)) {
1242 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1243 /* BB where to store pid high? */
1244 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1245 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1246 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1247 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1248 count = sizeof(LOCKING_ANDX_RANGE);
1249 } else {
1250 /* oplock break */
1251 count = 0;
1252 }
1253 pSMB->hdr.smb_buf_length += count;
1254 pSMB->ByteCount = cpu_to_le16(count);
1255
1256 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1257 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha4544342005-08-24 13:59:35 -07001258 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 if (rc) {
1260 cFYI(1, ("Send error in Lock = %d", rc));
1261 }
Steve French46810cb2005-04-28 22:41:09 -07001262 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263
1264 /* Note: On -EAGAIN error only caller can retry on handle based calls
1265 since file handle passed in no longer valid */
1266 return rc;
1267}
1268
1269int
1270CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1271{
1272 int rc = 0;
1273 CLOSE_REQ *pSMB = NULL;
1274 CLOSE_RSP *pSMBr = NULL;
1275 int bytes_returned;
1276 cFYI(1, ("In CIFSSMBClose"));
1277
1278/* do not retry on dead session on close */
1279 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1280 if(rc == -EAGAIN)
1281 return 0;
1282 if (rc)
1283 return rc;
1284
1285 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1286
1287 pSMB->FileID = (__u16) smb_file_id;
1288 pSMB->LastWriteTime = 0;
1289 pSMB->ByteCount = 0;
1290 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1291 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001292 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293 if (rc) {
1294 if(rc!=-EINTR) {
1295 /* EINTR is expected when user ctl-c to kill app */
1296 cERROR(1, ("Send error in Close = %d", rc));
1297 }
1298 }
1299
1300 cifs_small_buf_release(pSMB);
1301
1302 /* Since session is dead, file will be closed on server already */
1303 if(rc == -EAGAIN)
1304 rc = 0;
1305
1306 return rc;
1307}
1308
1309int
1310CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1311 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001312 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001313{
1314 int rc = 0;
1315 RENAME_REQ *pSMB = NULL;
1316 RENAME_RSP *pSMBr = NULL;
1317 int bytes_returned;
1318 int name_len, name_len2;
1319 __u16 count;
1320
1321 cFYI(1, ("In CIFSSMBRename"));
1322renameRetry:
1323 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1324 (void **) &pSMBr);
1325 if (rc)
1326 return rc;
1327
1328 pSMB->BufferFormat = 0x04;
1329 pSMB->SearchAttributes =
1330 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1331 ATTR_DIRECTORY);
1332
1333 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1334 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001335 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001336 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 name_len++; /* trailing null */
1338 name_len *= 2;
1339 pSMB->OldFileName[name_len] = 0x04; /* pad */
1340 /* protocol requires ASCII signature byte on Unicode string */
1341 pSMB->OldFileName[name_len + 1] = 0x00;
1342 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001343 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001344 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1346 name_len2 *= 2; /* convert to bytes */
1347 } else { /* BB improve the check for buffer overruns BB */
1348 name_len = strnlen(fromName, PATH_MAX);
1349 name_len++; /* trailing null */
1350 strncpy(pSMB->OldFileName, fromName, name_len);
1351 name_len2 = strnlen(toName, PATH_MAX);
1352 name_len2++; /* trailing null */
1353 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1354 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1355 name_len2++; /* trailing null */
1356 name_len2++; /* signature byte */
1357 }
1358
1359 count = 1 /* 1st signature byte */ + name_len + name_len2;
1360 pSMB->hdr.smb_buf_length += count;
1361 pSMB->ByteCount = cpu_to_le16(count);
1362
1363 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1364 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001365 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 if (rc) {
1367 cFYI(1, ("Send error in rename = %d", rc));
1368 }
1369
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 cifs_buf_release(pSMB);
1371
1372 if (rc == -EAGAIN)
1373 goto renameRetry;
1374
1375 return rc;
1376}
1377
1378int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001379 int netfid, char * target_name,
1380 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381{
1382 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1383 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1384 struct set_file_rename * rename_info;
1385 char *data_offset;
1386 char dummy_string[30];
1387 int rc = 0;
1388 int bytes_returned = 0;
1389 int len_of_str;
1390 __u16 params, param_offset, offset, count, byte_count;
1391
1392 cFYI(1, ("Rename to File by handle"));
1393 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1394 (void **) &pSMBr);
1395 if (rc)
1396 return rc;
1397
1398 params = 6;
1399 pSMB->MaxSetupCount = 0;
1400 pSMB->Reserved = 0;
1401 pSMB->Flags = 0;
1402 pSMB->Timeout = 0;
1403 pSMB->Reserved2 = 0;
1404 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1405 offset = param_offset + params;
1406
1407 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1408 rename_info = (struct set_file_rename *) data_offset;
1409 pSMB->MaxParameterCount = cpu_to_le16(2);
1410 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1411 pSMB->SetupCount = 1;
1412 pSMB->Reserved3 = 0;
1413 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1414 byte_count = 3 /* pad */ + params;
1415 pSMB->ParameterCount = cpu_to_le16(params);
1416 pSMB->TotalParameterCount = pSMB->ParameterCount;
1417 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1418 pSMB->DataOffset = cpu_to_le16(offset);
1419 /* construct random name ".cifs_tmp<inodenum><mid>" */
1420 rename_info->overwrite = cpu_to_le32(1);
1421 rename_info->root_fid = 0;
1422 /* unicode only call */
1423 if(target_name == NULL) {
1424 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001425 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001426 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001428 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001429 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 }
1431 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1432 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1433 byte_count += count;
1434 pSMB->DataCount = cpu_to_le16(count);
1435 pSMB->TotalDataCount = pSMB->DataCount;
1436 pSMB->Fid = netfid;
1437 pSMB->InformationLevel =
1438 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1439 pSMB->Reserved4 = 0;
1440 pSMB->hdr.smb_buf_length += byte_count;
1441 pSMB->ByteCount = cpu_to_le16(byte_count);
1442 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1443 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001444 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001445 if (rc) {
1446 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1447 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001448
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 cifs_buf_release(pSMB);
1450
1451 /* Note: On -EAGAIN error only caller can retry on handle based calls
1452 since file handle passed in no longer valid */
1453
1454 return rc;
1455}
1456
1457int
1458CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1459 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001460 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461{
1462 int rc = 0;
1463 COPY_REQ *pSMB = NULL;
1464 COPY_RSP *pSMBr = NULL;
1465 int bytes_returned;
1466 int name_len, name_len2;
1467 __u16 count;
1468
1469 cFYI(1, ("In CIFSSMBCopy"));
1470copyRetry:
1471 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1472 (void **) &pSMBr);
1473 if (rc)
1474 return rc;
1475
1476 pSMB->BufferFormat = 0x04;
1477 pSMB->Tid2 = target_tid;
1478
1479 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1480
1481 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001482 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001483 fromName, PATH_MAX, nls_codepage,
1484 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 name_len++; /* trailing null */
1486 name_len *= 2;
1487 pSMB->OldFileName[name_len] = 0x04; /* pad */
1488 /* protocol requires ASCII signature byte on Unicode string */
1489 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001490 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001491 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1493 name_len2 *= 2; /* convert to bytes */
1494 } else { /* BB improve the check for buffer overruns BB */
1495 name_len = strnlen(fromName, PATH_MAX);
1496 name_len++; /* trailing null */
1497 strncpy(pSMB->OldFileName, fromName, name_len);
1498 name_len2 = strnlen(toName, PATH_MAX);
1499 name_len2++; /* trailing null */
1500 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1501 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1502 name_len2++; /* trailing null */
1503 name_len2++; /* signature byte */
1504 }
1505
1506 count = 1 /* 1st signature byte */ + name_len + name_len2;
1507 pSMB->hdr.smb_buf_length += count;
1508 pSMB->ByteCount = cpu_to_le16(count);
1509
1510 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1511 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1512 if (rc) {
1513 cFYI(1, ("Send error in copy = %d with %d files copied",
1514 rc, le16_to_cpu(pSMBr->CopyCount)));
1515 }
1516 if (pSMB)
1517 cifs_buf_release(pSMB);
1518
1519 if (rc == -EAGAIN)
1520 goto copyRetry;
1521
1522 return rc;
1523}
1524
1525int
1526CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1527 const char *fromName, const char *toName,
1528 const struct nls_table *nls_codepage)
1529{
1530 TRANSACTION2_SPI_REQ *pSMB = NULL;
1531 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1532 char *data_offset;
1533 int name_len;
1534 int name_len_target;
1535 int rc = 0;
1536 int bytes_returned = 0;
1537 __u16 params, param_offset, offset, byte_count;
1538
1539 cFYI(1, ("In Symlink Unix style"));
1540createSymLinkRetry:
1541 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1542 (void **) &pSMBr);
1543 if (rc)
1544 return rc;
1545
1546 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1547 name_len =
1548 cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
1549 /* find define for this maxpathcomponent */
1550 , nls_codepage);
1551 name_len++; /* trailing null */
1552 name_len *= 2;
1553
1554 } else { /* BB improve the check for buffer overruns BB */
1555 name_len = strnlen(fromName, PATH_MAX);
1556 name_len++; /* trailing null */
1557 strncpy(pSMB->FileName, fromName, name_len);
1558 }
1559 params = 6 + name_len;
1560 pSMB->MaxSetupCount = 0;
1561 pSMB->Reserved = 0;
1562 pSMB->Flags = 0;
1563 pSMB->Timeout = 0;
1564 pSMB->Reserved2 = 0;
1565 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1566 InformationLevel) - 4;
1567 offset = param_offset + params;
1568
1569 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1570 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1571 name_len_target =
1572 cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
1573 /* find define for this maxpathcomponent */
1574 , nls_codepage);
1575 name_len_target++; /* trailing null */
1576 name_len_target *= 2;
1577 } else { /* BB improve the check for buffer overruns BB */
1578 name_len_target = strnlen(toName, PATH_MAX);
1579 name_len_target++; /* trailing null */
1580 strncpy(data_offset, toName, name_len_target);
1581 }
1582
1583 pSMB->MaxParameterCount = cpu_to_le16(2);
1584 /* BB find exact max on data count below from sess */
1585 pSMB->MaxDataCount = cpu_to_le16(1000);
1586 pSMB->SetupCount = 1;
1587 pSMB->Reserved3 = 0;
1588 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1589 byte_count = 3 /* pad */ + params + name_len_target;
1590 pSMB->DataCount = cpu_to_le16(name_len_target);
1591 pSMB->ParameterCount = cpu_to_le16(params);
1592 pSMB->TotalDataCount = pSMB->DataCount;
1593 pSMB->TotalParameterCount = pSMB->ParameterCount;
1594 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1595 pSMB->DataOffset = cpu_to_le16(offset);
1596 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1597 pSMB->Reserved4 = 0;
1598 pSMB->hdr.smb_buf_length += byte_count;
1599 pSMB->ByteCount = cpu_to_le16(byte_count);
1600 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1601 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001602 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 if (rc) {
1604 cFYI(1,
1605 ("Send error in SetPathInfo (create symlink) = %d",
1606 rc));
1607 }
1608
1609 if (pSMB)
1610 cifs_buf_release(pSMB);
1611
1612 if (rc == -EAGAIN)
1613 goto createSymLinkRetry;
1614
1615 return rc;
1616}
1617
1618int
1619CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1620 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001621 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622{
1623 TRANSACTION2_SPI_REQ *pSMB = NULL;
1624 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1625 char *data_offset;
1626 int name_len;
1627 int name_len_target;
1628 int rc = 0;
1629 int bytes_returned = 0;
1630 __u16 params, param_offset, offset, byte_count;
1631
1632 cFYI(1, ("In Create Hard link Unix style"));
1633createHardLinkRetry:
1634 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1635 (void **) &pSMBr);
1636 if (rc)
1637 return rc;
1638
1639 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001640 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001641 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642 name_len++; /* trailing null */
1643 name_len *= 2;
1644
1645 } else { /* BB improve the check for buffer overruns BB */
1646 name_len = strnlen(toName, PATH_MAX);
1647 name_len++; /* trailing null */
1648 strncpy(pSMB->FileName, toName, name_len);
1649 }
1650 params = 6 + name_len;
1651 pSMB->MaxSetupCount = 0;
1652 pSMB->Reserved = 0;
1653 pSMB->Flags = 0;
1654 pSMB->Timeout = 0;
1655 pSMB->Reserved2 = 0;
1656 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1657 InformationLevel) - 4;
1658 offset = param_offset + params;
1659
1660 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1661 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1662 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001663 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001664 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 name_len_target++; /* trailing null */
1666 name_len_target *= 2;
1667 } else { /* BB improve the check for buffer overruns BB */
1668 name_len_target = strnlen(fromName, PATH_MAX);
1669 name_len_target++; /* trailing null */
1670 strncpy(data_offset, fromName, name_len_target);
1671 }
1672
1673 pSMB->MaxParameterCount = cpu_to_le16(2);
1674 /* BB find exact max on data count below from sess*/
1675 pSMB->MaxDataCount = cpu_to_le16(1000);
1676 pSMB->SetupCount = 1;
1677 pSMB->Reserved3 = 0;
1678 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1679 byte_count = 3 /* pad */ + params + name_len_target;
1680 pSMB->ParameterCount = cpu_to_le16(params);
1681 pSMB->TotalParameterCount = pSMB->ParameterCount;
1682 pSMB->DataCount = cpu_to_le16(name_len_target);
1683 pSMB->TotalDataCount = pSMB->DataCount;
1684 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1685 pSMB->DataOffset = cpu_to_le16(offset);
1686 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1687 pSMB->Reserved4 = 0;
1688 pSMB->hdr.smb_buf_length += byte_count;
1689 pSMB->ByteCount = cpu_to_le16(byte_count);
1690 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1691 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001692 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 if (rc) {
1694 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1695 }
1696
1697 cifs_buf_release(pSMB);
1698 if (rc == -EAGAIN)
1699 goto createHardLinkRetry;
1700
1701 return rc;
1702}
1703
1704int
1705CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1706 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001707 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708{
1709 int rc = 0;
1710 NT_RENAME_REQ *pSMB = NULL;
1711 RENAME_RSP *pSMBr = NULL;
1712 int bytes_returned;
1713 int name_len, name_len2;
1714 __u16 count;
1715
1716 cFYI(1, ("In CIFSCreateHardLink"));
1717winCreateHardLinkRetry:
1718
1719 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1720 (void **) &pSMBr);
1721 if (rc)
1722 return rc;
1723
1724 pSMB->SearchAttributes =
1725 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1726 ATTR_DIRECTORY);
1727 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1728 pSMB->ClusterCount = 0;
1729
1730 pSMB->BufferFormat = 0x04;
1731
1732 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1733 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001734 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001735 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 name_len++; /* trailing null */
1737 name_len *= 2;
1738 pSMB->OldFileName[name_len] = 0; /* pad */
1739 pSMB->OldFileName[name_len + 1] = 0x04;
1740 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001741 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001742 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1744 name_len2 *= 2; /* convert to bytes */
1745 } else { /* BB improve the check for buffer overruns BB */
1746 name_len = strnlen(fromName, PATH_MAX);
1747 name_len++; /* trailing null */
1748 strncpy(pSMB->OldFileName, fromName, name_len);
1749 name_len2 = strnlen(toName, PATH_MAX);
1750 name_len2++; /* trailing null */
1751 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1752 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1753 name_len2++; /* trailing null */
1754 name_len2++; /* signature byte */
1755 }
1756
1757 count = 1 /* string type byte */ + name_len + name_len2;
1758 pSMB->hdr.smb_buf_length += count;
1759 pSMB->ByteCount = cpu_to_le16(count);
1760
1761 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1762 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001763 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 if (rc) {
1765 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1766 }
1767 cifs_buf_release(pSMB);
1768 if (rc == -EAGAIN)
1769 goto winCreateHardLinkRetry;
1770
1771 return rc;
1772}
1773
1774int
1775CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1776 const unsigned char *searchName,
1777 char *symlinkinfo, const int buflen,
1778 const struct nls_table *nls_codepage)
1779{
1780/* SMB_QUERY_FILE_UNIX_LINK */
1781 TRANSACTION2_QPI_REQ *pSMB = NULL;
1782 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1783 int rc = 0;
1784 int bytes_returned;
1785 int name_len;
1786 __u16 params, byte_count;
1787
1788 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1789
1790querySymLinkRetry:
1791 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1792 (void **) &pSMBr);
1793 if (rc)
1794 return rc;
1795
1796 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1797 name_len =
1798 cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1799 /* find define for this maxpathcomponent */
1800 , nls_codepage);
1801 name_len++; /* trailing null */
1802 name_len *= 2;
1803 } else { /* BB improve the check for buffer overruns BB */
1804 name_len = strnlen(searchName, PATH_MAX);
1805 name_len++; /* trailing null */
1806 strncpy(pSMB->FileName, searchName, name_len);
1807 }
1808
1809 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1810 pSMB->TotalDataCount = 0;
1811 pSMB->MaxParameterCount = cpu_to_le16(2);
1812 /* BB find exact max data count below from sess structure BB */
1813 pSMB->MaxDataCount = cpu_to_le16(4000);
1814 pSMB->MaxSetupCount = 0;
1815 pSMB->Reserved = 0;
1816 pSMB->Flags = 0;
1817 pSMB->Timeout = 0;
1818 pSMB->Reserved2 = 0;
1819 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1820 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1821 pSMB->DataCount = 0;
1822 pSMB->DataOffset = 0;
1823 pSMB->SetupCount = 1;
1824 pSMB->Reserved3 = 0;
1825 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1826 byte_count = params + 1 /* pad */ ;
1827 pSMB->TotalParameterCount = cpu_to_le16(params);
1828 pSMB->ParameterCount = pSMB->TotalParameterCount;
1829 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1830 pSMB->Reserved4 = 0;
1831 pSMB->hdr.smb_buf_length += byte_count;
1832 pSMB->ByteCount = cpu_to_le16(byte_count);
1833
1834 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1835 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1836 if (rc) {
1837 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1838 } else {
1839 /* decode response */
1840
1841 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1842 if (rc || (pSMBr->ByteCount < 2))
1843 /* BB also check enough total bytes returned */
1844 rc = -EIO; /* bad smb */
1845 else {
1846 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1847 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1848
1849 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1850 name_len = UniStrnlen((wchar_t *) ((char *)
1851 &pSMBr->hdr.Protocol +data_offset),
1852 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07001853 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 cifs_strfromUCS_le(symlinkinfo,
1855 (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1856 data_offset),
1857 name_len, nls_codepage);
1858 } else {
1859 strncpy(symlinkinfo,
1860 (char *) &pSMBr->hdr.Protocol +
1861 data_offset,
1862 min_t(const int, buflen, count));
1863 }
1864 symlinkinfo[buflen] = 0;
1865 /* just in case so calling code does not go off the end of buffer */
1866 }
1867 }
1868 cifs_buf_release(pSMB);
1869 if (rc == -EAGAIN)
1870 goto querySymLinkRetry;
1871 return rc;
1872}
1873
1874int
1875CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1876 const unsigned char *searchName,
1877 char *symlinkinfo, const int buflen,__u16 fid,
1878 const struct nls_table *nls_codepage)
1879{
1880 int rc = 0;
1881 int bytes_returned;
1882 int name_len;
1883 struct smb_com_transaction_ioctl_req * pSMB;
1884 struct smb_com_transaction_ioctl_rsp * pSMBr;
1885
1886 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1887 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1888 (void **) &pSMBr);
1889 if (rc)
1890 return rc;
1891
1892 pSMB->TotalParameterCount = 0 ;
1893 pSMB->TotalDataCount = 0;
1894 pSMB->MaxParameterCount = cpu_to_le32(2);
1895 /* BB find exact data count max from sess structure BB */
1896 pSMB->MaxDataCount = cpu_to_le32(4000);
1897 pSMB->MaxSetupCount = 4;
1898 pSMB->Reserved = 0;
1899 pSMB->ParameterOffset = 0;
1900 pSMB->DataCount = 0;
1901 pSMB->DataOffset = 0;
1902 pSMB->SetupCount = 4;
1903 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1904 pSMB->ParameterCount = pSMB->TotalParameterCount;
1905 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1906 pSMB->IsFsctl = 1; /* FSCTL */
1907 pSMB->IsRootFlag = 0;
1908 pSMB->Fid = fid; /* file handle always le */
1909 pSMB->ByteCount = 0;
1910
1911 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1912 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1913 if (rc) {
1914 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1915 } else { /* decode response */
1916 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1917 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1918 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1919 /* BB also check enough total bytes returned */
1920 rc = -EIO; /* bad smb */
1921 else {
1922 if(data_count && (data_count < 2048)) {
1923 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1924
1925 struct reparse_data * reparse_buf = (struct reparse_data *)
1926 ((char *)&pSMBr->hdr.Protocol + data_offset);
1927 if((char*)reparse_buf >= end_of_smb) {
1928 rc = -EIO;
1929 goto qreparse_out;
1930 }
1931 if((reparse_buf->LinkNamesBuf +
1932 reparse_buf->TargetNameOffset +
1933 reparse_buf->TargetNameLen) >
1934 end_of_smb) {
1935 cFYI(1,("reparse buf extended beyond SMB"));
1936 rc = -EIO;
1937 goto qreparse_out;
1938 }
1939
1940 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1941 name_len = UniStrnlen((wchar_t *)
1942 (reparse_buf->LinkNamesBuf +
1943 reparse_buf->TargetNameOffset),
1944 min(buflen/2, reparse_buf->TargetNameLen / 2));
1945 cifs_strfromUCS_le(symlinkinfo,
1946 (wchar_t *) (reparse_buf->LinkNamesBuf +
1947 reparse_buf->TargetNameOffset),
1948 name_len, nls_codepage);
1949 } else { /* ASCII names */
1950 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
1951 reparse_buf->TargetNameOffset,
1952 min_t(const int, buflen, reparse_buf->TargetNameLen));
1953 }
1954 } else {
1955 rc = -EIO;
1956 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1957 }
1958 symlinkinfo[buflen] = 0; /* just in case so the caller
1959 does not go off the end of the buffer */
1960 cFYI(1,("readlink result - %s ",symlinkinfo));
1961 }
1962 }
1963qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07001964 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965
1966 /* Note: On -EAGAIN error only caller can retry on handle based calls
1967 since file handle passed in no longer valid */
1968
1969 return rc;
1970}
1971
1972#ifdef CONFIG_CIFS_POSIX
1973
1974/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
1975static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
1976{
1977 /* u8 cifs fields do not need le conversion */
1978 ace->e_perm = (__u16)cifs_ace->cifs_e_perm;
1979 ace->e_tag = (__u16)cifs_ace->cifs_e_tag;
1980 ace->e_id = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
1981 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
1982
1983 return;
1984}
1985
1986/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07001987static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
1988 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989{
1990 int size = 0;
1991 int i;
1992 __u16 count;
1993 struct cifs_posix_ace * pACE;
1994 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
1995 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
1996
1997 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
1998 return -EOPNOTSUPP;
1999
2000 if(acl_type & ACL_TYPE_ACCESS) {
2001 count = le16_to_cpu(cifs_acl->access_entry_count);
2002 pACE = &cifs_acl->ace_array[0];
2003 size = sizeof(struct cifs_posix_acl);
2004 size += sizeof(struct cifs_posix_ace) * count;
2005 /* check if we would go beyond end of SMB */
2006 if(size_of_data_area < size) {
2007 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2008 return -EINVAL;
2009 }
2010 } else if(acl_type & ACL_TYPE_DEFAULT) {
2011 count = le16_to_cpu(cifs_acl->access_entry_count);
2012 size = sizeof(struct cifs_posix_acl);
2013 size += sizeof(struct cifs_posix_ace) * count;
2014/* skip past access ACEs to get to default ACEs */
2015 pACE = &cifs_acl->ace_array[count];
2016 count = le16_to_cpu(cifs_acl->default_entry_count);
2017 size += sizeof(struct cifs_posix_ace) * count;
2018 /* check if we would go beyond end of SMB */
2019 if(size_of_data_area < size)
2020 return -EINVAL;
2021 } else {
2022 /* illegal type */
2023 return -EINVAL;
2024 }
2025
2026 size = posix_acl_xattr_size(count);
2027 if((buflen == 0) || (local_acl == NULL)) {
2028 /* used to query ACL EA size */
2029 } else if(size > buflen) {
2030 return -ERANGE;
2031 } else /* buffer big enough */ {
2032 local_acl->a_version = POSIX_ACL_XATTR_VERSION;
2033 for(i = 0;i < count ;i++) {
2034 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2035 pACE ++;
2036 }
2037 }
2038 return size;
2039}
2040
2041static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2042 const posix_acl_xattr_entry * local_ace)
2043{
2044 __u16 rc = 0; /* 0 = ACL converted ok */
2045
2046 cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
2047 cifs_ace->cifs_e_tag = (__u8)cpu_to_le16(local_ace->e_tag);
2048 /* BB is there a better way to handle the large uid? */
2049 if(local_ace->e_id == -1) {
2050 /* Probably no need to le convert -1 on any arch but can not hurt */
2051 cifs_ace->cifs_uid = cpu_to_le64(-1);
2052 } else
2053 cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
2054 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2055 return rc;
2056}
2057
2058/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2059static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2060 const int acl_type)
2061{
2062 __u16 rc = 0;
2063 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2064 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2065 int count;
2066 int i;
2067
2068 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2069 return 0;
2070
2071 count = posix_acl_xattr_count((size_t)buflen);
2072 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2073 count,buflen,local_acl->a_version));
2074 if(local_acl->a_version != 2) {
2075 cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
2076 return 0;
2077 }
2078 cifs_acl->version = cpu_to_le16(1);
2079 if(acl_type == ACL_TYPE_ACCESS)
2080 cifs_acl->access_entry_count = count;
2081 else if(acl_type == ACL_TYPE_DEFAULT)
2082 cifs_acl->default_entry_count = count;
2083 else {
2084 cFYI(1,("unknown ACL type %d",acl_type));
2085 return 0;
2086 }
2087 for(i=0;i<count;i++) {
2088 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2089 &local_acl->a_entries[i]);
2090 if(rc != 0) {
2091 /* ACE not converted */
2092 break;
2093 }
2094 }
2095 if(rc == 0) {
2096 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2097 rc += sizeof(struct cifs_posix_acl);
2098 /* BB add check to make sure ACL does not overflow SMB */
2099 }
2100 return rc;
2101}
2102
2103int
2104CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2105 const unsigned char *searchName,
2106 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002107 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108{
2109/* SMB_QUERY_POSIX_ACL */
2110 TRANSACTION2_QPI_REQ *pSMB = NULL;
2111 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2112 int rc = 0;
2113 int bytes_returned;
2114 int name_len;
2115 __u16 params, byte_count;
2116
2117 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2118
2119queryAclRetry:
2120 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2121 (void **) &pSMBr);
2122 if (rc)
2123 return rc;
2124
2125 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2126 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002127 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002128 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 name_len++; /* trailing null */
2130 name_len *= 2;
2131 pSMB->FileName[name_len] = 0;
2132 pSMB->FileName[name_len+1] = 0;
2133 } else { /* BB improve the check for buffer overruns BB */
2134 name_len = strnlen(searchName, PATH_MAX);
2135 name_len++; /* trailing null */
2136 strncpy(pSMB->FileName, searchName, name_len);
2137 }
2138
2139 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2140 pSMB->TotalDataCount = 0;
2141 pSMB->MaxParameterCount = cpu_to_le16(2);
2142 /* BB find exact max data count below from sess structure BB */
2143 pSMB->MaxDataCount = cpu_to_le16(4000);
2144 pSMB->MaxSetupCount = 0;
2145 pSMB->Reserved = 0;
2146 pSMB->Flags = 0;
2147 pSMB->Timeout = 0;
2148 pSMB->Reserved2 = 0;
2149 pSMB->ParameterOffset = cpu_to_le16(
2150 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2151 pSMB->DataCount = 0;
2152 pSMB->DataOffset = 0;
2153 pSMB->SetupCount = 1;
2154 pSMB->Reserved3 = 0;
2155 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2156 byte_count = params + 1 /* pad */ ;
2157 pSMB->TotalParameterCount = cpu_to_le16(params);
2158 pSMB->ParameterCount = pSMB->TotalParameterCount;
2159 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2160 pSMB->Reserved4 = 0;
2161 pSMB->hdr.smb_buf_length += byte_count;
2162 pSMB->ByteCount = cpu_to_le16(byte_count);
2163
2164 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2165 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2166 if (rc) {
2167 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2168 } else {
2169 /* decode response */
2170
2171 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2172 if (rc || (pSMBr->ByteCount < 2))
2173 /* BB also check enough total bytes returned */
2174 rc = -EIO; /* bad smb */
2175 else {
2176 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2177 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2178 rc = cifs_copy_posix_acl(acl_inf,
2179 (char *)&pSMBr->hdr.Protocol+data_offset,
2180 buflen,acl_type,count);
2181 }
2182 }
2183 cifs_buf_release(pSMB);
2184 if (rc == -EAGAIN)
2185 goto queryAclRetry;
2186 return rc;
2187}
2188
2189int
2190CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2191 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002192 const char *local_acl, const int buflen,
2193 const int acl_type,
2194 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195{
2196 struct smb_com_transaction2_spi_req *pSMB = NULL;
2197 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2198 char *parm_data;
2199 int name_len;
2200 int rc = 0;
2201 int bytes_returned = 0;
2202 __u16 params, byte_count, data_count, param_offset, offset;
2203
2204 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2205setAclRetry:
2206 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2207 (void **) &pSMBr);
2208 if (rc)
2209 return rc;
2210 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2211 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002212 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002213 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 name_len++; /* trailing null */
2215 name_len *= 2;
2216 } else { /* BB improve the check for buffer overruns BB */
2217 name_len = strnlen(fileName, PATH_MAX);
2218 name_len++; /* trailing null */
2219 strncpy(pSMB->FileName, fileName, name_len);
2220 }
2221 params = 6 + name_len;
2222 pSMB->MaxParameterCount = cpu_to_le16(2);
2223 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2224 pSMB->MaxSetupCount = 0;
2225 pSMB->Reserved = 0;
2226 pSMB->Flags = 0;
2227 pSMB->Timeout = 0;
2228 pSMB->Reserved2 = 0;
2229 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2230 InformationLevel) - 4;
2231 offset = param_offset + params;
2232 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2233 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2234
2235 /* convert to on the wire format for POSIX ACL */
2236 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2237
2238 if(data_count == 0) {
2239 rc = -EOPNOTSUPP;
2240 goto setACLerrorExit;
2241 }
2242 pSMB->DataOffset = cpu_to_le16(offset);
2243 pSMB->SetupCount = 1;
2244 pSMB->Reserved3 = 0;
2245 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2246 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2247 byte_count = 3 /* pad */ + params + data_count;
2248 pSMB->DataCount = cpu_to_le16(data_count);
2249 pSMB->TotalDataCount = pSMB->DataCount;
2250 pSMB->ParameterCount = cpu_to_le16(params);
2251 pSMB->TotalParameterCount = pSMB->ParameterCount;
2252 pSMB->Reserved4 = 0;
2253 pSMB->hdr.smb_buf_length += byte_count;
2254 pSMB->ByteCount = cpu_to_le16(byte_count);
2255 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2256 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2257 if (rc) {
2258 cFYI(1, ("Set POSIX ACL returned %d", rc));
2259 }
2260
2261setACLerrorExit:
2262 cifs_buf_release(pSMB);
2263 if (rc == -EAGAIN)
2264 goto setAclRetry;
2265 return rc;
2266}
2267
Steve Frenchf654bac2005-04-28 22:41:04 -07002268/* BB fix tabs in this function FIXME BB */
2269int
2270CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2271 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2272{
2273 int rc = 0;
2274 struct smb_t2_qfi_req *pSMB = NULL;
2275 struct smb_t2_qfi_rsp *pSMBr = NULL;
2276 int bytes_returned;
2277 __u16 params, byte_count;
2278
2279 cFYI(1,("In GetExtAttr"));
2280 if(tcon == NULL)
2281 return -ENODEV;
2282
2283GetExtAttrRetry:
2284 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2285 (void **) &pSMBr);
2286 if (rc)
2287 return rc;
2288
Steve Frenchc67593a2005-04-28 22:41:04 -07002289 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002290 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002291 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002292 /* BB find exact max data count below from sess structure BB */
2293 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2294 pSMB->t2.MaxSetupCount = 0;
2295 pSMB->t2.Reserved = 0;
2296 pSMB->t2.Flags = 0;
2297 pSMB->t2.Timeout = 0;
2298 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002299 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2300 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002301 pSMB->t2.DataCount = 0;
2302 pSMB->t2.DataOffset = 0;
2303 pSMB->t2.SetupCount = 1;
2304 pSMB->t2.Reserved3 = 0;
2305 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002306 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002307 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2308 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2309 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002310 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002311 pSMB->Fid = netfid;
2312 pSMB->hdr.smb_buf_length += byte_count;
2313 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2314
2315 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2316 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2317 if (rc) {
2318 cFYI(1, ("error %d in GetExtAttr", rc));
2319 } else {
2320 /* decode response */
2321 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2322 if (rc || (pSMBr->ByteCount < 2))
2323 /* BB also check enough total bytes returned */
2324 /* If rc should we check for EOPNOSUPP and
2325 disable the srvino flag? or in caller? */
2326 rc = -EIO; /* bad smb */
2327 else {
2328 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2329 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2330 struct file_chattr_info * pfinfo;
2331 /* BB Do we need a cast or hash here ? */
2332 if(count != 16) {
2333 cFYI(1, ("Illegal size ret in GetExtAttr"));
2334 rc = -EIO;
2335 goto GetExtAttrOut;
2336 }
2337 pfinfo = (struct file_chattr_info *)
2338 (data_offset + (char *) &pSMBr->hdr.Protocol);
2339 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2340 *pMask = le64_to_cpu(pfinfo->mask);
2341 }
2342 }
2343GetExtAttrOut:
2344 cifs_buf_release(pSMB);
2345 if (rc == -EAGAIN)
2346 goto GetExtAttrRetry;
2347 return rc;
2348}
2349
2350
2351#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352
Steve French6b8edfe2005-08-23 20:26:03 -07002353/* Legacy Query Path Information call for lookup to old servers such
2354 as Win9x/WinME */
2355int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2356 const unsigned char *searchName,
2357 FILE_ALL_INFO * pFinfo,
2358 const struct nls_table *nls_codepage, int remap)
2359{
2360 QUERY_INFORMATION_REQ * pSMB;
2361 QUERY_INFORMATION_RSP * pSMBr;
2362 int rc = 0;
2363 int bytes_returned;
2364 int name_len;
2365
2366 cFYI(1, ("In SMBQPath path %s", searchName));
2367QInfRetry:
2368 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2369 (void **) &pSMBr);
2370 if (rc)
2371 return rc;
2372
2373 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2374 name_len =
2375 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2376 PATH_MAX, nls_codepage, remap);
2377 name_len++; /* trailing null */
2378 name_len *= 2;
2379 } else {
2380 name_len = strnlen(searchName, PATH_MAX);
2381 name_len++; /* trailing null */
2382 strncpy(pSMB->FileName, searchName, name_len);
2383 }
2384 pSMB->BufferFormat = 0x04;
2385 name_len++; /* account for buffer type byte */
2386 pSMB->hdr.smb_buf_length += (__u16) name_len;
2387 pSMB->ByteCount = cpu_to_le16(name_len);
2388
2389 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2390 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2391 if (rc) {
2392 cFYI(1, ("Send error in QueryInfo = %d", rc));
2393 } else if (pFinfo) { /* decode response */
2394 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002395 pFinfo->AllocationSize =
2396 cpu_to_le64(le32_to_cpu(pSMBr->size));
2397 pFinfo->EndOfFile = pFinfo->AllocationSize;
2398 pFinfo->Attributes =
2399 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002400 } else
2401 rc = -EIO; /* bad buffer passed in */
2402
2403 cifs_buf_release(pSMB);
2404
2405 if (rc == -EAGAIN)
2406 goto QInfRetry;
2407
2408 return rc;
2409}
2410
2411
2412
2413
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414int
2415CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2416 const unsigned char *searchName,
2417 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002418 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419{
2420/* level 263 SMB_QUERY_FILE_ALL_INFO */
2421 TRANSACTION2_QPI_REQ *pSMB = NULL;
2422 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2423 int rc = 0;
2424 int bytes_returned;
2425 int name_len;
2426 __u16 params, byte_count;
2427
2428/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2429QPathInfoRetry:
2430 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2431 (void **) &pSMBr);
2432 if (rc)
2433 return rc;
2434
2435 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2436 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002437 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002438 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439 name_len++; /* trailing null */
2440 name_len *= 2;
2441 } else { /* BB improve the check for buffer overruns BB */
2442 name_len = strnlen(searchName, PATH_MAX);
2443 name_len++; /* trailing null */
2444 strncpy(pSMB->FileName, searchName, name_len);
2445 }
2446
2447 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2448 pSMB->TotalDataCount = 0;
2449 pSMB->MaxParameterCount = cpu_to_le16(2);
2450 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2451 pSMB->MaxSetupCount = 0;
2452 pSMB->Reserved = 0;
2453 pSMB->Flags = 0;
2454 pSMB->Timeout = 0;
2455 pSMB->Reserved2 = 0;
2456 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2457 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2458 pSMB->DataCount = 0;
2459 pSMB->DataOffset = 0;
2460 pSMB->SetupCount = 1;
2461 pSMB->Reserved3 = 0;
2462 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2463 byte_count = params + 1 /* pad */ ;
2464 pSMB->TotalParameterCount = cpu_to_le16(params);
2465 pSMB->ParameterCount = pSMB->TotalParameterCount;
2466 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2467 pSMB->Reserved4 = 0;
2468 pSMB->hdr.smb_buf_length += byte_count;
2469 pSMB->ByteCount = cpu_to_le16(byte_count);
2470
2471 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2472 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2473 if (rc) {
2474 cFYI(1, ("Send error in QPathInfo = %d", rc));
2475 } else { /* decode response */
2476 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2477
2478 if (rc || (pSMBr->ByteCount < 40))
2479 rc = -EIO; /* bad smb */
2480 else if (pFindData){
2481 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2482 memcpy((char *) pFindData,
2483 (char *) &pSMBr->hdr.Protocol +
2484 data_offset, sizeof (FILE_ALL_INFO));
2485 } else
2486 rc = -ENOMEM;
2487 }
2488 cifs_buf_release(pSMB);
2489 if (rc == -EAGAIN)
2490 goto QPathInfoRetry;
2491
2492 return rc;
2493}
2494
2495int
2496CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2497 const unsigned char *searchName,
2498 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002499 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500{
2501/* SMB_QUERY_FILE_UNIX_BASIC */
2502 TRANSACTION2_QPI_REQ *pSMB = NULL;
2503 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2504 int rc = 0;
2505 int bytes_returned = 0;
2506 int name_len;
2507 __u16 params, byte_count;
2508
2509 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2510UnixQPathInfoRetry:
2511 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2512 (void **) &pSMBr);
2513 if (rc)
2514 return rc;
2515
2516 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2517 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002518 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002519 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002520 name_len++; /* trailing null */
2521 name_len *= 2;
2522 } else { /* BB improve the check for buffer overruns BB */
2523 name_len = strnlen(searchName, PATH_MAX);
2524 name_len++; /* trailing null */
2525 strncpy(pSMB->FileName, searchName, name_len);
2526 }
2527
2528 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2529 pSMB->TotalDataCount = 0;
2530 pSMB->MaxParameterCount = cpu_to_le16(2);
2531 /* BB find exact max SMB PDU from sess structure BB */
2532 pSMB->MaxDataCount = cpu_to_le16(4000);
2533 pSMB->MaxSetupCount = 0;
2534 pSMB->Reserved = 0;
2535 pSMB->Flags = 0;
2536 pSMB->Timeout = 0;
2537 pSMB->Reserved2 = 0;
2538 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2539 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2540 pSMB->DataCount = 0;
2541 pSMB->DataOffset = 0;
2542 pSMB->SetupCount = 1;
2543 pSMB->Reserved3 = 0;
2544 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2545 byte_count = params + 1 /* pad */ ;
2546 pSMB->TotalParameterCount = cpu_to_le16(params);
2547 pSMB->ParameterCount = pSMB->TotalParameterCount;
2548 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2549 pSMB->Reserved4 = 0;
2550 pSMB->hdr.smb_buf_length += byte_count;
2551 pSMB->ByteCount = cpu_to_le16(byte_count);
2552
2553 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2554 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2555 if (rc) {
2556 cFYI(1, ("Send error in QPathInfo = %d", rc));
2557 } else { /* decode response */
2558 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2559
2560 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2561 rc = -EIO; /* bad smb */
2562 } else {
2563 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2564 memcpy((char *) pFindData,
2565 (char *) &pSMBr->hdr.Protocol +
2566 data_offset,
2567 sizeof (FILE_UNIX_BASIC_INFO));
2568 }
2569 }
2570 cifs_buf_release(pSMB);
2571 if (rc == -EAGAIN)
2572 goto UnixQPathInfoRetry;
2573
2574 return rc;
2575}
2576
2577#if 0 /* function unused at present */
2578int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2579 const char *searchName, FILE_ALL_INFO * findData,
2580 const struct nls_table *nls_codepage)
2581{
2582/* level 257 SMB_ */
2583 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2584 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2585 int rc = 0;
2586 int bytes_returned;
2587 int name_len;
2588 __u16 params, byte_count;
2589
2590 cFYI(1, ("In FindUnique"));
2591findUniqueRetry:
2592 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2593 (void **) &pSMBr);
2594 if (rc)
2595 return rc;
2596
2597 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2598 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002599 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 /* find define for this maxpathcomponent */
2601 , nls_codepage);
2602 name_len++; /* trailing null */
2603 name_len *= 2;
2604 } else { /* BB improve the check for buffer overruns BB */
2605 name_len = strnlen(searchName, PATH_MAX);
2606 name_len++; /* trailing null */
2607 strncpy(pSMB->FileName, searchName, name_len);
2608 }
2609
2610 params = 12 + name_len /* includes null */ ;
2611 pSMB->TotalDataCount = 0; /* no EAs */
2612 pSMB->MaxParameterCount = cpu_to_le16(2);
2613 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2614 pSMB->MaxSetupCount = 0;
2615 pSMB->Reserved = 0;
2616 pSMB->Flags = 0;
2617 pSMB->Timeout = 0;
2618 pSMB->Reserved2 = 0;
2619 pSMB->ParameterOffset = cpu_to_le16(
2620 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2621 pSMB->DataCount = 0;
2622 pSMB->DataOffset = 0;
2623 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2624 pSMB->Reserved3 = 0;
2625 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2626 byte_count = params + 1 /* pad */ ;
2627 pSMB->TotalParameterCount = cpu_to_le16(params);
2628 pSMB->ParameterCount = pSMB->TotalParameterCount;
2629 pSMB->SearchAttributes =
2630 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2631 ATTR_DIRECTORY);
2632 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2633 pSMB->SearchFlags = cpu_to_le16(1);
2634 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2635 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2636 pSMB->hdr.smb_buf_length += byte_count;
2637 pSMB->ByteCount = cpu_to_le16(byte_count);
2638
2639 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2640 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2641
2642 if (rc) {
2643 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2644 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07002645 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 /* BB fill in */
2647 }
2648
2649 cifs_buf_release(pSMB);
2650 if (rc == -EAGAIN)
2651 goto findUniqueRetry;
2652
2653 return rc;
2654}
2655#endif /* end unused (temporarily) function */
2656
2657/* xid, tcon, searchName and codepage are input parms, rest are returned */
2658int
2659CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2660 const char *searchName,
2661 const struct nls_table *nls_codepage,
2662 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07002663 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664{
2665/* level 257 SMB_ */
2666 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2667 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2668 T2_FFIRST_RSP_PARMS * parms;
2669 int rc = 0;
2670 int bytes_returned = 0;
2671 int name_len;
2672 __u16 params, byte_count;
2673
Steve French737b7582005-04-28 22:41:06 -07002674 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675
2676findFirstRetry:
2677 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2678 (void **) &pSMBr);
2679 if (rc)
2680 return rc;
2681
2682 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2683 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002684 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07002685 PATH_MAX, nls_codepage, remap);
2686 /* We can not add the asterik earlier in case
2687 it got remapped to 0xF03A as if it were part of the
2688 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07002690 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07002691 pSMB->FileName[name_len+1] = 0;
2692 pSMB->FileName[name_len+2] = '*';
2693 pSMB->FileName[name_len+3] = 0;
2694 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2696 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07002697 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 } else { /* BB add check for overrun of SMB buf BB */
2699 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700/* BB fix here and in unicode clause above ie
2701 if(name_len > buffersize-header)
2702 free buffer exit; BB */
2703 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07002704 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07002705 pSMB->FileName[name_len+1] = '*';
2706 pSMB->FileName[name_len+2] = 0;
2707 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 }
2709
2710 params = 12 + name_len /* includes null */ ;
2711 pSMB->TotalDataCount = 0; /* no EAs */
2712 pSMB->MaxParameterCount = cpu_to_le16(10);
2713 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2714 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2715 pSMB->MaxSetupCount = 0;
2716 pSMB->Reserved = 0;
2717 pSMB->Flags = 0;
2718 pSMB->Timeout = 0;
2719 pSMB->Reserved2 = 0;
2720 byte_count = params + 1 /* pad */ ;
2721 pSMB->TotalParameterCount = cpu_to_le16(params);
2722 pSMB->ParameterCount = pSMB->TotalParameterCount;
2723 pSMB->ParameterOffset = cpu_to_le16(
2724 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2725 pSMB->DataCount = 0;
2726 pSMB->DataOffset = 0;
2727 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2728 pSMB->Reserved3 = 0;
2729 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2730 pSMB->SearchAttributes =
2731 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2732 ATTR_DIRECTORY);
2733 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2734 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2735 CIFS_SEARCH_RETURN_RESUME);
2736 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2737
2738 /* BB what should we set StorageType to? Does it matter? BB */
2739 pSMB->SearchStorageType = 0;
2740 pSMB->hdr.smb_buf_length += byte_count;
2741 pSMB->ByteCount = cpu_to_le16(byte_count);
2742
2743 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2744 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002745 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746
Steve French1982c342005-08-17 12:38:22 -07002747 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 /* BB Add code to handle unsupported level rc */
2749 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07002750
2751 if (pSMB)
2752 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753
2754 /* BB eventually could optimize out free and realloc of buf */
2755 /* for this case */
2756 if (rc == -EAGAIN)
2757 goto findFirstRetry;
2758 } else { /* decode response */
2759 /* BB remember to free buffer if error BB */
2760 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2761 if(rc == 0) {
2762 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2763 psrch_inf->unicode = TRUE;
2764 else
2765 psrch_inf->unicode = FALSE;
2766
2767 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2768 psrch_inf->srch_entries_start =
2769 (char *) &pSMBr->hdr.Protocol +
2770 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2772 le16_to_cpu(pSMBr->t2.ParameterOffset));
2773
2774 if(parms->EndofSearch)
2775 psrch_inf->endOfSearch = TRUE;
2776 else
2777 psrch_inf->endOfSearch = FALSE;
2778
2779 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2780 psrch_inf->index_of_last_entry =
2781 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 *pnetfid = parms->SearchHandle;
2783 } else {
2784 cifs_buf_release(pSMB);
2785 }
2786 }
2787
2788 return rc;
2789}
2790
2791int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2792 __u16 searchHandle, struct cifs_search_info * psrch_inf)
2793{
2794 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2795 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2796 T2_FNEXT_RSP_PARMS * parms;
2797 char *response_data;
2798 int rc = 0;
2799 int bytes_returned, name_len;
2800 __u16 params, byte_count;
2801
2802 cFYI(1, ("In FindNext"));
2803
2804 if(psrch_inf->endOfSearch == TRUE)
2805 return -ENOENT;
2806
2807 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2808 (void **) &pSMBr);
2809 if (rc)
2810 return rc;
2811
2812 params = 14; /* includes 2 bytes of null string, converted to LE below */
2813 byte_count = 0;
2814 pSMB->TotalDataCount = 0; /* no EAs */
2815 pSMB->MaxParameterCount = cpu_to_le16(8);
2816 pSMB->MaxDataCount =
2817 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2818 pSMB->MaxSetupCount = 0;
2819 pSMB->Reserved = 0;
2820 pSMB->Flags = 0;
2821 pSMB->Timeout = 0;
2822 pSMB->Reserved2 = 0;
2823 pSMB->ParameterOffset = cpu_to_le16(
2824 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2825 pSMB->DataCount = 0;
2826 pSMB->DataOffset = 0;
2827 pSMB->SetupCount = 1;
2828 pSMB->Reserved3 = 0;
2829 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2830 pSMB->SearchHandle = searchHandle; /* always kept as le */
2831 pSMB->SearchCount =
2832 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2833 /* test for Unix extensions */
2834/* if (tcon->ses->capabilities & CAP_UNIX) {
2835 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2836 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2837 } else {
2838 pSMB->InformationLevel =
2839 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2840 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2841 } */
2842 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2843 pSMB->ResumeKey = psrch_inf->resume_key;
2844 pSMB->SearchFlags =
2845 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2846
2847 name_len = psrch_inf->resume_name_len;
2848 params += name_len;
2849 if(name_len < PATH_MAX) {
2850 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2851 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07002852 /* 14 byte parm len above enough for 2 byte null terminator */
2853 pSMB->ResumeFileName[name_len] = 0;
2854 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 } else {
2856 rc = -EINVAL;
2857 goto FNext2_err_exit;
2858 }
2859 byte_count = params + 1 /* pad */ ;
2860 pSMB->TotalParameterCount = cpu_to_le16(params);
2861 pSMB->ParameterCount = pSMB->TotalParameterCount;
2862 pSMB->hdr.smb_buf_length += byte_count;
2863 pSMB->ByteCount = cpu_to_le16(byte_count);
2864
2865 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2866 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002867 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 if (rc) {
2869 if (rc == -EBADF) {
2870 psrch_inf->endOfSearch = TRUE;
2871 rc = 0; /* search probably was closed at end of search above */
2872 } else
2873 cFYI(1, ("FindNext returned = %d", rc));
2874 } else { /* decode response */
2875 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2876
2877 if(rc == 0) {
2878 /* BB fixme add lock for file (srch_info) struct here */
2879 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2880 psrch_inf->unicode = TRUE;
2881 else
2882 psrch_inf->unicode = FALSE;
2883 response_data = (char *) &pSMBr->hdr.Protocol +
2884 le16_to_cpu(pSMBr->t2.ParameterOffset);
2885 parms = (T2_FNEXT_RSP_PARMS *)response_data;
2886 response_data = (char *)&pSMBr->hdr.Protocol +
2887 le16_to_cpu(pSMBr->t2.DataOffset);
2888 cifs_buf_release(psrch_inf->ntwrk_buf_start);
2889 psrch_inf->srch_entries_start = response_data;
2890 psrch_inf->ntwrk_buf_start = (char *)pSMB;
2891 if(parms->EndofSearch)
2892 psrch_inf->endOfSearch = TRUE;
2893 else
2894 psrch_inf->endOfSearch = FALSE;
2895
2896 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2897 psrch_inf->index_of_last_entry +=
2898 psrch_inf->entries_in_buffer;
2899/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2900
2901 /* BB fixme add unlock here */
2902 }
2903
2904 }
2905
2906 /* BB On error, should we leave previous search buf (and count and
2907 last entry fields) intact or free the previous one? */
2908
2909 /* Note: On -EAGAIN error only caller can retry on handle based calls
2910 since file handle passed in no longer valid */
2911FNext2_err_exit:
2912 if (rc != 0)
2913 cifs_buf_release(pSMB);
2914
2915 return rc;
2916}
2917
2918int
2919CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2920{
2921 int rc = 0;
2922 FINDCLOSE_REQ *pSMB = NULL;
2923 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2924 int bytes_returned;
2925
2926 cFYI(1, ("In CIFSSMBFindClose"));
2927 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2928
2929 /* no sense returning error if session restarted
2930 as file handle has been closed */
2931 if(rc == -EAGAIN)
2932 return 0;
2933 if (rc)
2934 return rc;
2935
2936 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
2937 pSMB->FileID = searchHandle;
2938 pSMB->ByteCount = 0;
2939 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2940 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2941 if (rc) {
2942 cERROR(1, ("Send error in FindClose = %d", rc));
2943 }
Steve Frencha4544342005-08-24 13:59:35 -07002944 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 cifs_small_buf_release(pSMB);
2946
2947 /* Since session is dead, search handle closed on server already */
2948 if (rc == -EAGAIN)
2949 rc = 0;
2950
2951 return rc;
2952}
2953
2954#ifdef CONFIG_CIFS_EXPERIMENTAL
2955int
2956CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2957 const unsigned char *searchName,
2958 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07002959 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960{
2961 int rc = 0;
2962 TRANSACTION2_QPI_REQ *pSMB = NULL;
2963 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2964 int name_len, bytes_returned;
2965 __u16 params, byte_count;
2966
2967 cFYI(1,("In GetSrvInodeNum for %s",searchName));
2968 if(tcon == NULL)
2969 return -ENODEV;
2970
2971GetInodeNumberRetry:
2972 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2973 (void **) &pSMBr);
2974 if (rc)
2975 return rc;
2976
2977
2978 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2979 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002980 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002981 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002982 name_len++; /* trailing null */
2983 name_len *= 2;
2984 } else { /* BB improve the check for buffer overruns BB */
2985 name_len = strnlen(searchName, PATH_MAX);
2986 name_len++; /* trailing null */
2987 strncpy(pSMB->FileName, searchName, name_len);
2988 }
2989
2990 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2991 pSMB->TotalDataCount = 0;
2992 pSMB->MaxParameterCount = cpu_to_le16(2);
2993 /* BB find exact max data count below from sess structure BB */
2994 pSMB->MaxDataCount = cpu_to_le16(4000);
2995 pSMB->MaxSetupCount = 0;
2996 pSMB->Reserved = 0;
2997 pSMB->Flags = 0;
2998 pSMB->Timeout = 0;
2999 pSMB->Reserved2 = 0;
3000 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3001 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3002 pSMB->DataCount = 0;
3003 pSMB->DataOffset = 0;
3004 pSMB->SetupCount = 1;
3005 pSMB->Reserved3 = 0;
3006 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3007 byte_count = params + 1 /* pad */ ;
3008 pSMB->TotalParameterCount = cpu_to_le16(params);
3009 pSMB->ParameterCount = pSMB->TotalParameterCount;
3010 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3011 pSMB->Reserved4 = 0;
3012 pSMB->hdr.smb_buf_length += byte_count;
3013 pSMB->ByteCount = cpu_to_le16(byte_count);
3014
3015 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3016 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3017 if (rc) {
3018 cFYI(1, ("error %d in QueryInternalInfo", rc));
3019 } else {
3020 /* decode response */
3021 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3022 if (rc || (pSMBr->ByteCount < 2))
3023 /* BB also check enough total bytes returned */
3024 /* If rc should we check for EOPNOSUPP and
3025 disable the srvino flag? or in caller? */
3026 rc = -EIO; /* bad smb */
3027 else {
3028 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3029 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3030 struct file_internal_info * pfinfo;
3031 /* BB Do we need a cast or hash here ? */
3032 if(count < 8) {
3033 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3034 rc = -EIO;
3035 goto GetInodeNumOut;
3036 }
3037 pfinfo = (struct file_internal_info *)
3038 (data_offset + (char *) &pSMBr->hdr.Protocol);
3039 *inode_number = pfinfo->UniqueId;
3040 }
3041 }
3042GetInodeNumOut:
3043 cifs_buf_release(pSMB);
3044 if (rc == -EAGAIN)
3045 goto GetInodeNumberRetry;
3046 return rc;
3047}
3048#endif /* CIFS_EXPERIMENTAL */
3049
3050int
3051CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3052 const unsigned char *searchName,
3053 unsigned char **targetUNCs,
3054 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003055 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056{
3057/* TRANS2_GET_DFS_REFERRAL */
3058 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3059 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3060 struct dfs_referral_level_3 * referrals = NULL;
3061 int rc = 0;
3062 int bytes_returned;
3063 int name_len;
3064 unsigned int i;
3065 char * temp;
3066 __u16 params, byte_count;
3067 *number_of_UNC_in_array = 0;
3068 *targetUNCs = NULL;
3069
3070 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3071 if (ses == NULL)
3072 return -ENODEV;
3073getDFSRetry:
3074 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3075 (void **) &pSMBr);
3076 if (rc)
3077 return rc;
Steve French1982c342005-08-17 12:38:22 -07003078
3079 /* server pointer checked in called function,
3080 but should never be null here anyway */
3081 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003082 pSMB->hdr.Tid = ses->ipc_tid;
3083 pSMB->hdr.Uid = ses->Suid;
3084 if (ses->capabilities & CAP_STATUS32) {
3085 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3086 }
3087 if (ses->capabilities & CAP_DFS) {
3088 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3089 }
3090
3091 if (ses->capabilities & CAP_UNICODE) {
3092 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3093 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003094 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003095 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003096 name_len++; /* trailing null */
3097 name_len *= 2;
3098 } else { /* BB improve the check for buffer overruns BB */
3099 name_len = strnlen(searchName, PATH_MAX);
3100 name_len++; /* trailing null */
3101 strncpy(pSMB->RequestFileName, searchName, name_len);
3102 }
3103
3104 params = 2 /* level */ + name_len /*includes null */ ;
3105 pSMB->TotalDataCount = 0;
3106 pSMB->DataCount = 0;
3107 pSMB->DataOffset = 0;
3108 pSMB->MaxParameterCount = 0;
3109 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3110 pSMB->MaxSetupCount = 0;
3111 pSMB->Reserved = 0;
3112 pSMB->Flags = 0;
3113 pSMB->Timeout = 0;
3114 pSMB->Reserved2 = 0;
3115 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3116 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3117 pSMB->SetupCount = 1;
3118 pSMB->Reserved3 = 0;
3119 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3120 byte_count = params + 3 /* pad */ ;
3121 pSMB->ParameterCount = cpu_to_le16(params);
3122 pSMB->TotalParameterCount = pSMB->ParameterCount;
3123 pSMB->MaxReferralLevel = cpu_to_le16(3);
3124 pSMB->hdr.smb_buf_length += byte_count;
3125 pSMB->ByteCount = cpu_to_le16(byte_count);
3126
3127 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3128 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3129 if (rc) {
3130 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3131 } else { /* decode response */
3132/* BB Add logic to parse referrals here */
3133 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3134
3135 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3136 rc = -EIO; /* bad smb */
3137 else {
3138 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3139 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3140
3141 cFYI(1,
3142 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3143 pSMBr->ByteCount, data_offset));
3144 referrals =
3145 (struct dfs_referral_level_3 *)
3146 (8 /* sizeof start of data block */ +
3147 data_offset +
3148 (char *) &pSMBr->hdr.Protocol);
3149 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",
3150 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)));
3151 /* BB This field is actually two bytes in from start of
3152 data block so we could do safety check that DataBlock
3153 begins at address of pSMBr->NumberOfReferrals */
3154 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3155
3156 /* BB Fix below so can return more than one referral */
3157 if(*number_of_UNC_in_array > 1)
3158 *number_of_UNC_in_array = 1;
3159
3160 /* get the length of the strings describing refs */
3161 name_len = 0;
3162 for(i=0;i<*number_of_UNC_in_array;i++) {
3163 /* make sure that DfsPathOffset not past end */
3164 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3165 if (offset > data_count) {
3166 /* if invalid referral, stop here and do
3167 not try to copy any more */
3168 *number_of_UNC_in_array = i;
3169 break;
3170 }
3171 temp = ((char *)referrals) + offset;
3172
3173 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3174 name_len += UniStrnlen((wchar_t *)temp,data_count);
3175 } else {
3176 name_len += strnlen(temp,data_count);
3177 }
3178 referrals++;
3179 /* BB add check that referral pointer does not fall off end PDU */
3180
3181 }
3182 /* BB add check for name_len bigger than bcc */
3183 *targetUNCs =
3184 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3185 if(*targetUNCs == NULL) {
3186 rc = -ENOMEM;
3187 goto GetDFSRefExit;
3188 }
3189 /* copy the ref strings */
3190 referrals =
3191 (struct dfs_referral_level_3 *)
3192 (8 /* sizeof data hdr */ +
3193 data_offset +
3194 (char *) &pSMBr->hdr.Protocol);
3195
3196 for(i=0;i<*number_of_UNC_in_array;i++) {
3197 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3198 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3199 cifs_strfromUCS_le(*targetUNCs,
3200 (wchar_t *) temp, name_len, nls_codepage);
3201 } else {
3202 strncpy(*targetUNCs,temp,name_len);
3203 }
3204 /* BB update target_uncs pointers */
3205 referrals++;
3206 }
3207 temp = *targetUNCs;
3208 temp[name_len] = 0;
3209 }
3210
3211 }
3212GetDFSRefExit:
3213 if (pSMB)
3214 cifs_buf_release(pSMB);
3215
3216 if (rc == -EAGAIN)
3217 goto getDFSRetry;
3218
3219 return rc;
3220}
3221
Steve French20962432005-09-21 22:05:57 -07003222/* Query File System Info such as free space to old servers such as Win 9x */
3223int
3224SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3225{
3226/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3227 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3228 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3229 FILE_SYSTEM_ALLOC_INFO *response_data;
3230 int rc = 0;
3231 int bytes_returned = 0;
3232 __u16 params, byte_count;
3233
3234 cFYI(1, ("OldQFSInfo"));
3235oldQFSInfoRetry:
3236 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3237 (void **) &pSMBr);
3238 if (rc)
3239 return rc;
3240 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3241 (void **) &pSMBr);
3242 if (rc)
3243 return rc;
3244
3245 params = 2; /* level */
3246 pSMB->TotalDataCount = 0;
3247 pSMB->MaxParameterCount = cpu_to_le16(2);
3248 pSMB->MaxDataCount = cpu_to_le16(1000);
3249 pSMB->MaxSetupCount = 0;
3250 pSMB->Reserved = 0;
3251 pSMB->Flags = 0;
3252 pSMB->Timeout = 0;
3253 pSMB->Reserved2 = 0;
3254 byte_count = params + 1 /* pad */ ;
3255 pSMB->TotalParameterCount = cpu_to_le16(params);
3256 pSMB->ParameterCount = pSMB->TotalParameterCount;
3257 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3258 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3259 pSMB->DataCount = 0;
3260 pSMB->DataOffset = 0;
3261 pSMB->SetupCount = 1;
3262 pSMB->Reserved3 = 0;
3263 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3264 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3265 pSMB->hdr.smb_buf_length += byte_count;
3266 pSMB->ByteCount = cpu_to_le16(byte_count);
3267
3268 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3269 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3270 if (rc) {
3271 cFYI(1, ("Send error in QFSInfo = %d", rc));
3272 } else { /* decode response */
3273 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3274
3275 if (rc || (pSMBr->ByteCount < 18))
3276 rc = -EIO; /* bad smb */
3277 else {
3278 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3279 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3280 pSMBr->ByteCount, data_offset));
3281
3282 response_data =
3283 (FILE_SYSTEM_ALLOC_INFO *)
3284 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3285 FSData->f_bsize =
3286 le16_to_cpu(response_data->BytesPerSector) *
3287 le32_to_cpu(response_data->
3288 SectorsPerAllocationUnit);
3289 FSData->f_blocks =
3290 le32_to_cpu(response_data->TotalAllocationUnits);
3291 FSData->f_bfree = FSData->f_bavail =
3292 le32_to_cpu(response_data->FreeAllocationUnits);
3293 cFYI(1,
3294 ("Blocks: %lld Free: %lld Block size %ld",
3295 (unsigned long long)FSData->f_blocks,
3296 (unsigned long long)FSData->f_bfree,
3297 FSData->f_bsize));
3298 }
3299 }
3300 cifs_buf_release(pSMB);
3301
3302 if (rc == -EAGAIN)
3303 goto oldQFSInfoRetry;
3304
3305 return rc;
3306}
3307
Linus Torvalds1da177e2005-04-16 15:20:36 -07003308int
Steve French737b7582005-04-28 22:41:06 -07003309CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003310{
3311/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3312 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3313 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3314 FILE_SYSTEM_INFO *response_data;
3315 int rc = 0;
3316 int bytes_returned = 0;
3317 __u16 params, byte_count;
3318
3319 cFYI(1, ("In QFSInfo"));
3320QFSInfoRetry:
3321 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3322 (void **) &pSMBr);
3323 if (rc)
3324 return rc;
3325
3326 params = 2; /* level */
3327 pSMB->TotalDataCount = 0;
3328 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003329 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330 pSMB->MaxSetupCount = 0;
3331 pSMB->Reserved = 0;
3332 pSMB->Flags = 0;
3333 pSMB->Timeout = 0;
3334 pSMB->Reserved2 = 0;
3335 byte_count = params + 1 /* pad */ ;
3336 pSMB->TotalParameterCount = cpu_to_le16(params);
3337 pSMB->ParameterCount = pSMB->TotalParameterCount;
3338 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3339 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3340 pSMB->DataCount = 0;
3341 pSMB->DataOffset = 0;
3342 pSMB->SetupCount = 1;
3343 pSMB->Reserved3 = 0;
3344 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3345 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3346 pSMB->hdr.smb_buf_length += byte_count;
3347 pSMB->ByteCount = cpu_to_le16(byte_count);
3348
3349 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3350 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3351 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003352 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 } else { /* decode response */
3354 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3355
Steve French20962432005-09-21 22:05:57 -07003356 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003357 rc = -EIO; /* bad smb */
3358 else {
3359 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003360
3361 response_data =
3362 (FILE_SYSTEM_INFO
3363 *) (((char *) &pSMBr->hdr.Protocol) +
3364 data_offset);
3365 FSData->f_bsize =
3366 le32_to_cpu(response_data->BytesPerSector) *
3367 le32_to_cpu(response_data->
3368 SectorsPerAllocationUnit);
3369 FSData->f_blocks =
3370 le64_to_cpu(response_data->TotalAllocationUnits);
3371 FSData->f_bfree = FSData->f_bavail =
3372 le64_to_cpu(response_data->FreeAllocationUnits);
3373 cFYI(1,
3374 ("Blocks: %lld Free: %lld Block size %ld",
3375 (unsigned long long)FSData->f_blocks,
3376 (unsigned long long)FSData->f_bfree,
3377 FSData->f_bsize));
3378 }
3379 }
3380 cifs_buf_release(pSMB);
3381
3382 if (rc == -EAGAIN)
3383 goto QFSInfoRetry;
3384
3385 return rc;
3386}
3387
3388int
Steve French737b7582005-04-28 22:41:06 -07003389CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390{
3391/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3392 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3393 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3394 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3395 int rc = 0;
3396 int bytes_returned = 0;
3397 __u16 params, byte_count;
3398
3399 cFYI(1, ("In QFSAttributeInfo"));
3400QFSAttributeRetry:
3401 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3402 (void **) &pSMBr);
3403 if (rc)
3404 return rc;
3405
3406 params = 2; /* level */
3407 pSMB->TotalDataCount = 0;
3408 pSMB->MaxParameterCount = cpu_to_le16(2);
3409 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3410 pSMB->MaxSetupCount = 0;
3411 pSMB->Reserved = 0;
3412 pSMB->Flags = 0;
3413 pSMB->Timeout = 0;
3414 pSMB->Reserved2 = 0;
3415 byte_count = params + 1 /* pad */ ;
3416 pSMB->TotalParameterCount = cpu_to_le16(params);
3417 pSMB->ParameterCount = pSMB->TotalParameterCount;
3418 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3419 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3420 pSMB->DataCount = 0;
3421 pSMB->DataOffset = 0;
3422 pSMB->SetupCount = 1;
3423 pSMB->Reserved3 = 0;
3424 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3425 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3426 pSMB->hdr.smb_buf_length += byte_count;
3427 pSMB->ByteCount = cpu_to_le16(byte_count);
3428
3429 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3430 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3431 if (rc) {
3432 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3433 } else { /* decode response */
3434 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3435
3436 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3437 rc = -EIO; /* bad smb */
3438 } else {
3439 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3440 response_data =
3441 (FILE_SYSTEM_ATTRIBUTE_INFO
3442 *) (((char *) &pSMBr->hdr.Protocol) +
3443 data_offset);
3444 memcpy(&tcon->fsAttrInfo, response_data,
3445 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3446 }
3447 }
3448 cifs_buf_release(pSMB);
3449
3450 if (rc == -EAGAIN)
3451 goto QFSAttributeRetry;
3452
3453 return rc;
3454}
3455
3456int
Steve French737b7582005-04-28 22:41:06 -07003457CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458{
3459/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3460 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3461 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3462 FILE_SYSTEM_DEVICE_INFO *response_data;
3463 int rc = 0;
3464 int bytes_returned = 0;
3465 __u16 params, byte_count;
3466
3467 cFYI(1, ("In QFSDeviceInfo"));
3468QFSDeviceRetry:
3469 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3470 (void **) &pSMBr);
3471 if (rc)
3472 return rc;
3473
3474 params = 2; /* level */
3475 pSMB->TotalDataCount = 0;
3476 pSMB->MaxParameterCount = cpu_to_le16(2);
3477 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3478 pSMB->MaxSetupCount = 0;
3479 pSMB->Reserved = 0;
3480 pSMB->Flags = 0;
3481 pSMB->Timeout = 0;
3482 pSMB->Reserved2 = 0;
3483 byte_count = params + 1 /* pad */ ;
3484 pSMB->TotalParameterCount = cpu_to_le16(params);
3485 pSMB->ParameterCount = pSMB->TotalParameterCount;
3486 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3487 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3488
3489 pSMB->DataCount = 0;
3490 pSMB->DataOffset = 0;
3491 pSMB->SetupCount = 1;
3492 pSMB->Reserved3 = 0;
3493 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3494 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3495 pSMB->hdr.smb_buf_length += byte_count;
3496 pSMB->ByteCount = cpu_to_le16(byte_count);
3497
3498 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3499 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3500 if (rc) {
3501 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3502 } else { /* decode response */
3503 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3504
3505 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3506 rc = -EIO; /* bad smb */
3507 else {
3508 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3509 response_data =
Steve French737b7582005-04-28 22:41:06 -07003510 (FILE_SYSTEM_DEVICE_INFO *)
3511 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 data_offset);
3513 memcpy(&tcon->fsDevInfo, response_data,
3514 sizeof (FILE_SYSTEM_DEVICE_INFO));
3515 }
3516 }
3517 cifs_buf_release(pSMB);
3518
3519 if (rc == -EAGAIN)
3520 goto QFSDeviceRetry;
3521
3522 return rc;
3523}
3524
3525int
Steve French737b7582005-04-28 22:41:06 -07003526CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527{
3528/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3529 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3530 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3531 FILE_SYSTEM_UNIX_INFO *response_data;
3532 int rc = 0;
3533 int bytes_returned = 0;
3534 __u16 params, byte_count;
3535
3536 cFYI(1, ("In QFSUnixInfo"));
3537QFSUnixRetry:
3538 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3539 (void **) &pSMBr);
3540 if (rc)
3541 return rc;
3542
3543 params = 2; /* level */
3544 pSMB->TotalDataCount = 0;
3545 pSMB->DataCount = 0;
3546 pSMB->DataOffset = 0;
3547 pSMB->MaxParameterCount = cpu_to_le16(2);
3548 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3549 pSMB->MaxSetupCount = 0;
3550 pSMB->Reserved = 0;
3551 pSMB->Flags = 0;
3552 pSMB->Timeout = 0;
3553 pSMB->Reserved2 = 0;
3554 byte_count = params + 1 /* pad */ ;
3555 pSMB->ParameterCount = cpu_to_le16(params);
3556 pSMB->TotalParameterCount = pSMB->ParameterCount;
3557 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3558 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3559 pSMB->SetupCount = 1;
3560 pSMB->Reserved3 = 0;
3561 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3562 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3563 pSMB->hdr.smb_buf_length += byte_count;
3564 pSMB->ByteCount = cpu_to_le16(byte_count);
3565
3566 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3567 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3568 if (rc) {
3569 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3570 } else { /* decode response */
3571 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3572
3573 if (rc || (pSMBr->ByteCount < 13)) {
3574 rc = -EIO; /* bad smb */
3575 } else {
3576 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3577 response_data =
3578 (FILE_SYSTEM_UNIX_INFO
3579 *) (((char *) &pSMBr->hdr.Protocol) +
3580 data_offset);
3581 memcpy(&tcon->fsUnixInfo, response_data,
3582 sizeof (FILE_SYSTEM_UNIX_INFO));
3583 }
3584 }
3585 cifs_buf_release(pSMB);
3586
3587 if (rc == -EAGAIN)
3588 goto QFSUnixRetry;
3589
3590
3591 return rc;
3592}
3593
Jeremy Allisonac670552005-06-22 17:26:35 -07003594int
Steve French45abc6e2005-06-23 13:42:03 -05003595CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07003596{
3597/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3598 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3599 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3600 int rc = 0;
3601 int bytes_returned = 0;
3602 __u16 params, param_offset, offset, byte_count;
3603
3604 cFYI(1, ("In SETFSUnixInfo"));
3605SETFSUnixRetry:
3606 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3607 (void **) &pSMBr);
3608 if (rc)
3609 return rc;
3610
3611 params = 4; /* 2 bytes zero followed by info level. */
3612 pSMB->MaxSetupCount = 0;
3613 pSMB->Reserved = 0;
3614 pSMB->Flags = 0;
3615 pSMB->Timeout = 0;
3616 pSMB->Reserved2 = 0;
3617 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3618 offset = param_offset + params;
3619
3620 pSMB->MaxParameterCount = cpu_to_le16(4);
3621 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3622 pSMB->SetupCount = 1;
3623 pSMB->Reserved3 = 0;
3624 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3625 byte_count = 1 /* pad */ + params + 12;
3626
3627 pSMB->DataCount = cpu_to_le16(12);
3628 pSMB->ParameterCount = cpu_to_le16(params);
3629 pSMB->TotalDataCount = pSMB->DataCount;
3630 pSMB->TotalParameterCount = pSMB->ParameterCount;
3631 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3632 pSMB->DataOffset = cpu_to_le16(offset);
3633
3634 /* Params. */
3635 pSMB->FileNum = 0;
3636 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3637
3638 /* Data. */
3639 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3640 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3641 pSMB->ClientUnixCap = cpu_to_le64(cap);
3642
3643 pSMB->hdr.smb_buf_length += byte_count;
3644 pSMB->ByteCount = cpu_to_le16(byte_count);
3645
3646 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3647 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3648 if (rc) {
3649 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3650 } else { /* decode response */
3651 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3652 if (rc) {
3653 rc = -EIO; /* bad smb */
3654 }
3655 }
3656 cifs_buf_release(pSMB);
3657
3658 if (rc == -EAGAIN)
3659 goto SETFSUnixRetry;
3660
3661 return rc;
3662}
3663
3664
Linus Torvalds1da177e2005-04-16 15:20:36 -07003665
3666int
3667CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003668 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669{
3670/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3671 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3672 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3673 FILE_SYSTEM_POSIX_INFO *response_data;
3674 int rc = 0;
3675 int bytes_returned = 0;
3676 __u16 params, byte_count;
3677
3678 cFYI(1, ("In QFSPosixInfo"));
3679QFSPosixRetry:
3680 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3681 (void **) &pSMBr);
3682 if (rc)
3683 return rc;
3684
3685 params = 2; /* level */
3686 pSMB->TotalDataCount = 0;
3687 pSMB->DataCount = 0;
3688 pSMB->DataOffset = 0;
3689 pSMB->MaxParameterCount = cpu_to_le16(2);
3690 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3691 pSMB->MaxSetupCount = 0;
3692 pSMB->Reserved = 0;
3693 pSMB->Flags = 0;
3694 pSMB->Timeout = 0;
3695 pSMB->Reserved2 = 0;
3696 byte_count = params + 1 /* pad */ ;
3697 pSMB->ParameterCount = cpu_to_le16(params);
3698 pSMB->TotalParameterCount = pSMB->ParameterCount;
3699 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3700 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3701 pSMB->SetupCount = 1;
3702 pSMB->Reserved3 = 0;
3703 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3704 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3705 pSMB->hdr.smb_buf_length += byte_count;
3706 pSMB->ByteCount = cpu_to_le16(byte_count);
3707
3708 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3709 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3710 if (rc) {
3711 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3712 } else { /* decode response */
3713 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3714
3715 if (rc || (pSMBr->ByteCount < 13)) {
3716 rc = -EIO; /* bad smb */
3717 } else {
3718 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3719 response_data =
3720 (FILE_SYSTEM_POSIX_INFO
3721 *) (((char *) &pSMBr->hdr.Protocol) +
3722 data_offset);
3723 FSData->f_bsize =
3724 le32_to_cpu(response_data->BlockSize);
3725 FSData->f_blocks =
3726 le64_to_cpu(response_data->TotalBlocks);
3727 FSData->f_bfree =
3728 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07003729 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730 FSData->f_bavail = FSData->f_bfree;
3731 } else {
3732 FSData->f_bavail =
3733 le64_to_cpu(response_data->UserBlocksAvail);
3734 }
Steve French70ca7342005-09-22 16:32:06 -07003735 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736 FSData->f_files =
3737 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07003738 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 FSData->f_ffree =
3740 le64_to_cpu(response_data->FreeFileNodes);
3741 }
3742 }
3743 cifs_buf_release(pSMB);
3744
3745 if (rc == -EAGAIN)
3746 goto QFSPosixRetry;
3747
3748 return rc;
3749}
3750
3751
3752/* We can not use write of zero bytes trick to
3753 set file size due to need for large file support. Also note that
3754 this SetPathInfo is preferred to SetFileInfo based method in next
3755 routine which is only needed to work around a sharing violation bug
3756 in Samba which this routine can run into */
3757
3758int
3759CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07003760 __u64 size, int SetAllocation,
3761 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762{
3763 struct smb_com_transaction2_spi_req *pSMB = NULL;
3764 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3765 struct file_end_of_file_info *parm_data;
3766 int name_len;
3767 int rc = 0;
3768 int bytes_returned = 0;
3769 __u16 params, byte_count, data_count, param_offset, offset;
3770
3771 cFYI(1, ("In SetEOF"));
3772SetEOFRetry:
3773 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3774 (void **) &pSMBr);
3775 if (rc)
3776 return rc;
3777
3778 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3779 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003780 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003781 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 name_len++; /* trailing null */
3783 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07003784 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 name_len = strnlen(fileName, PATH_MAX);
3786 name_len++; /* trailing null */
3787 strncpy(pSMB->FileName, fileName, name_len);
3788 }
3789 params = 6 + name_len;
3790 data_count = sizeof (struct file_end_of_file_info);
3791 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07003792 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 pSMB->MaxSetupCount = 0;
3794 pSMB->Reserved = 0;
3795 pSMB->Flags = 0;
3796 pSMB->Timeout = 0;
3797 pSMB->Reserved2 = 0;
3798 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3799 InformationLevel) - 4;
3800 offset = param_offset + params;
3801 if(SetAllocation) {
3802 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3803 pSMB->InformationLevel =
3804 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3805 else
3806 pSMB->InformationLevel =
3807 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3808 } else /* Set File Size */ {
3809 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3810 pSMB->InformationLevel =
3811 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3812 else
3813 pSMB->InformationLevel =
3814 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3815 }
3816
3817 parm_data =
3818 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3819 offset);
3820 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3821 pSMB->DataOffset = cpu_to_le16(offset);
3822 pSMB->SetupCount = 1;
3823 pSMB->Reserved3 = 0;
3824 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3825 byte_count = 3 /* pad */ + params + data_count;
3826 pSMB->DataCount = cpu_to_le16(data_count);
3827 pSMB->TotalDataCount = pSMB->DataCount;
3828 pSMB->ParameterCount = cpu_to_le16(params);
3829 pSMB->TotalParameterCount = pSMB->ParameterCount;
3830 pSMB->Reserved4 = 0;
3831 pSMB->hdr.smb_buf_length += byte_count;
3832 parm_data->FileSize = cpu_to_le64(size);
3833 pSMB->ByteCount = cpu_to_le16(byte_count);
3834 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3835 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3836 if (rc) {
3837 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3838 }
3839
3840 cifs_buf_release(pSMB);
3841
3842 if (rc == -EAGAIN)
3843 goto SetEOFRetry;
3844
3845 return rc;
3846}
3847
3848int
3849CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
3850 __u16 fid, __u32 pid_of_opener, int SetAllocation)
3851{
3852 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3853 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3854 char *data_offset;
3855 struct file_end_of_file_info *parm_data;
3856 int rc = 0;
3857 int bytes_returned = 0;
3858 __u16 params, param_offset, offset, byte_count, count;
3859
3860 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3861 (long long)size));
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 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3870 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3871
3872 params = 6;
3873 pSMB->MaxSetupCount = 0;
3874 pSMB->Reserved = 0;
3875 pSMB->Flags = 0;
3876 pSMB->Timeout = 0;
3877 pSMB->Reserved2 = 0;
3878 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3879 offset = param_offset + params;
3880
3881 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3882
3883 count = sizeof(struct file_end_of_file_info);
3884 pSMB->MaxParameterCount = cpu_to_le16(2);
3885 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3886 pSMB->SetupCount = 1;
3887 pSMB->Reserved3 = 0;
3888 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3889 byte_count = 3 /* pad */ + params + count;
3890 pSMB->DataCount = cpu_to_le16(count);
3891 pSMB->ParameterCount = cpu_to_le16(params);
3892 pSMB->TotalDataCount = pSMB->DataCount;
3893 pSMB->TotalParameterCount = pSMB->ParameterCount;
3894 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3895 parm_data =
3896 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3897 offset);
3898 pSMB->DataOffset = cpu_to_le16(offset);
3899 parm_data->FileSize = cpu_to_le64(size);
3900 pSMB->Fid = fid;
3901 if(SetAllocation) {
3902 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3903 pSMB->InformationLevel =
3904 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3905 else
3906 pSMB->InformationLevel =
3907 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3908 } else /* Set File Size */ {
3909 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3910 pSMB->InformationLevel =
3911 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3912 else
3913 pSMB->InformationLevel =
3914 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3915 }
3916 pSMB->Reserved4 = 0;
3917 pSMB->hdr.smb_buf_length += byte_count;
3918 pSMB->ByteCount = cpu_to_le16(byte_count);
3919 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3920 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3921 if (rc) {
3922 cFYI(1,
3923 ("Send error in SetFileInfo (SetFileSize) = %d",
3924 rc));
3925 }
3926
3927 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07003928 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929
3930 /* Note: On -EAGAIN error only caller can retry on handle based calls
3931 since file handle passed in no longer valid */
3932
3933 return rc;
3934}
3935
3936/* Some legacy servers such as NT4 require that the file times be set on
3937 an open handle, rather than by pathname - this is awkward due to
3938 potential access conflicts on the open, but it is unavoidable for these
3939 old servers since the only other choice is to go from 100 nanosecond DCE
3940 time and resort to the original setpathinfo level which takes the ancient
3941 DOS time format with 2 second granularity */
3942int
3943CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
3944 __u16 fid)
3945{
3946 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3947 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3948 char *data_offset;
3949 int rc = 0;
3950 int bytes_returned = 0;
3951 __u16 params, param_offset, offset, byte_count, count;
3952
3953 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07003954 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3955
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 if (rc)
3957 return rc;
3958
Steve Frenchcd634992005-04-28 22:41:10 -07003959 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3960
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 /* At this point there is no need to override the current pid
3962 with the pid of the opener, but that could change if we someday
3963 use an existing handle (rather than opening one on the fly) */
3964 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3965 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3966
3967 params = 6;
3968 pSMB->MaxSetupCount = 0;
3969 pSMB->Reserved = 0;
3970 pSMB->Flags = 0;
3971 pSMB->Timeout = 0;
3972 pSMB->Reserved2 = 0;
3973 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3974 offset = param_offset + params;
3975
3976 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3977
3978 count = sizeof (FILE_BASIC_INFO);
3979 pSMB->MaxParameterCount = cpu_to_le16(2);
3980 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3981 pSMB->SetupCount = 1;
3982 pSMB->Reserved3 = 0;
3983 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3984 byte_count = 3 /* pad */ + params + count;
3985 pSMB->DataCount = cpu_to_le16(count);
3986 pSMB->ParameterCount = cpu_to_le16(params);
3987 pSMB->TotalDataCount = pSMB->DataCount;
3988 pSMB->TotalParameterCount = pSMB->ParameterCount;
3989 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3990 pSMB->DataOffset = cpu_to_le16(offset);
3991 pSMB->Fid = fid;
3992 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3993 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3994 else
3995 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3996 pSMB->Reserved4 = 0;
3997 pSMB->hdr.smb_buf_length += byte_count;
3998 pSMB->ByteCount = cpu_to_le16(byte_count);
3999 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4000 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4001 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4002 if (rc) {
4003 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4004 }
4005
Steve Frenchcd634992005-04-28 22:41:10 -07004006 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007
4008 /* Note: On -EAGAIN error only caller can retry on handle based calls
4009 since file handle passed in no longer valid */
4010
4011 return rc;
4012}
4013
4014
4015int
4016CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4017 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004018 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019{
4020 TRANSACTION2_SPI_REQ *pSMB = NULL;
4021 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4022 int name_len;
4023 int rc = 0;
4024 int bytes_returned = 0;
4025 char *data_offset;
4026 __u16 params, param_offset, offset, byte_count, count;
4027
4028 cFYI(1, ("In SetTimes"));
4029
4030SetTimesRetry:
4031 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4032 (void **) &pSMBr);
4033 if (rc)
4034 return rc;
4035
4036 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4037 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004038 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004039 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 name_len++; /* trailing null */
4041 name_len *= 2;
4042 } else { /* BB improve the check for buffer overruns BB */
4043 name_len = strnlen(fileName, PATH_MAX);
4044 name_len++; /* trailing null */
4045 strncpy(pSMB->FileName, fileName, name_len);
4046 }
4047
4048 params = 6 + name_len;
4049 count = sizeof (FILE_BASIC_INFO);
4050 pSMB->MaxParameterCount = cpu_to_le16(2);
4051 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4052 pSMB->MaxSetupCount = 0;
4053 pSMB->Reserved = 0;
4054 pSMB->Flags = 0;
4055 pSMB->Timeout = 0;
4056 pSMB->Reserved2 = 0;
4057 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4058 InformationLevel) - 4;
4059 offset = param_offset + params;
4060 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4061 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4062 pSMB->DataOffset = cpu_to_le16(offset);
4063 pSMB->SetupCount = 1;
4064 pSMB->Reserved3 = 0;
4065 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4066 byte_count = 3 /* pad */ + params + count;
4067
4068 pSMB->DataCount = cpu_to_le16(count);
4069 pSMB->ParameterCount = cpu_to_le16(params);
4070 pSMB->TotalDataCount = pSMB->DataCount;
4071 pSMB->TotalParameterCount = pSMB->ParameterCount;
4072 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4073 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4074 else
4075 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4076 pSMB->Reserved4 = 0;
4077 pSMB->hdr.smb_buf_length += byte_count;
4078 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4079 pSMB->ByteCount = cpu_to_le16(byte_count);
4080 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4081 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4082 if (rc) {
4083 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4084 }
4085
4086 cifs_buf_release(pSMB);
4087
4088 if (rc == -EAGAIN)
4089 goto SetTimesRetry;
4090
4091 return rc;
4092}
4093
4094/* Can not be used to set time stamps yet (due to old DOS time format) */
4095/* Can be used to set attributes */
4096#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4097 handling it anyway and NT4 was what we thought it would be needed for
4098 Do not delete it until we prove whether needed for Win9x though */
4099int
4100CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4101 __u16 dos_attrs, const struct nls_table *nls_codepage)
4102{
4103 SETATTR_REQ *pSMB = NULL;
4104 SETATTR_RSP *pSMBr = NULL;
4105 int rc = 0;
4106 int bytes_returned;
4107 int name_len;
4108
4109 cFYI(1, ("In SetAttrLegacy"));
4110
4111SetAttrLgcyRetry:
4112 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4113 (void **) &pSMBr);
4114 if (rc)
4115 return rc;
4116
4117 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4118 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004119 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120 PATH_MAX, nls_codepage);
4121 name_len++; /* trailing null */
4122 name_len *= 2;
4123 } else { /* BB improve the check for buffer overruns BB */
4124 name_len = strnlen(fileName, PATH_MAX);
4125 name_len++; /* trailing null */
4126 strncpy(pSMB->fileName, fileName, name_len);
4127 }
4128 pSMB->attr = cpu_to_le16(dos_attrs);
4129 pSMB->BufferFormat = 0x04;
4130 pSMB->hdr.smb_buf_length += name_len + 1;
4131 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4132 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4133 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4134 if (rc) {
4135 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4136 }
4137
4138 cifs_buf_release(pSMB);
4139
4140 if (rc == -EAGAIN)
4141 goto SetAttrLgcyRetry;
4142
4143 return rc;
4144}
4145#endif /* temporarily unneeded SetAttr legacy function */
4146
4147int
4148CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004149 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4150 dev_t device, const struct nls_table *nls_codepage,
4151 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152{
4153 TRANSACTION2_SPI_REQ *pSMB = NULL;
4154 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4155 int name_len;
4156 int rc = 0;
4157 int bytes_returned = 0;
4158 FILE_UNIX_BASIC_INFO *data_offset;
4159 __u16 params, param_offset, offset, count, byte_count;
4160
4161 cFYI(1, ("In SetUID/GID/Mode"));
4162setPermsRetry:
4163 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4164 (void **) &pSMBr);
4165 if (rc)
4166 return rc;
4167
4168 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4169 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004170 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004171 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004172 name_len++; /* trailing null */
4173 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004174 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 name_len = strnlen(fileName, PATH_MAX);
4176 name_len++; /* trailing null */
4177 strncpy(pSMB->FileName, fileName, name_len);
4178 }
4179
4180 params = 6 + name_len;
4181 count = sizeof (FILE_UNIX_BASIC_INFO);
4182 pSMB->MaxParameterCount = cpu_to_le16(2);
4183 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4184 pSMB->MaxSetupCount = 0;
4185 pSMB->Reserved = 0;
4186 pSMB->Flags = 0;
4187 pSMB->Timeout = 0;
4188 pSMB->Reserved2 = 0;
4189 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4190 InformationLevel) - 4;
4191 offset = param_offset + params;
4192 data_offset =
4193 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4194 offset);
4195 memset(data_offset, 0, count);
4196 pSMB->DataOffset = cpu_to_le16(offset);
4197 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4198 pSMB->SetupCount = 1;
4199 pSMB->Reserved3 = 0;
4200 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4201 byte_count = 3 /* pad */ + params + count;
4202 pSMB->ParameterCount = cpu_to_le16(params);
4203 pSMB->DataCount = cpu_to_le16(count);
4204 pSMB->TotalParameterCount = pSMB->ParameterCount;
4205 pSMB->TotalDataCount = pSMB->DataCount;
4206 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4207 pSMB->Reserved4 = 0;
4208 pSMB->hdr.smb_buf_length += byte_count;
4209 data_offset->Uid = cpu_to_le64(uid);
4210 data_offset->Gid = cpu_to_le64(gid);
4211 /* better to leave device as zero when it is */
4212 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4213 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4214 data_offset->Permissions = cpu_to_le64(mode);
4215
4216 if(S_ISREG(mode))
4217 data_offset->Type = cpu_to_le32(UNIX_FILE);
4218 else if(S_ISDIR(mode))
4219 data_offset->Type = cpu_to_le32(UNIX_DIR);
4220 else if(S_ISLNK(mode))
4221 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4222 else if(S_ISCHR(mode))
4223 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4224 else if(S_ISBLK(mode))
4225 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4226 else if(S_ISFIFO(mode))
4227 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4228 else if(S_ISSOCK(mode))
4229 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4230
4231
4232 pSMB->ByteCount = cpu_to_le16(byte_count);
4233 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4234 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4235 if (rc) {
4236 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4237 }
4238
4239 if (pSMB)
4240 cifs_buf_release(pSMB);
4241 if (rc == -EAGAIN)
4242 goto setPermsRetry;
4243 return rc;
4244}
4245
4246int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004247 const int notify_subdirs, const __u16 netfid,
4248 __u32 filter, struct file * pfile, int multishot,
4249 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250{
4251 int rc = 0;
4252 struct smb_com_transaction_change_notify_req * pSMB = NULL;
4253 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004254 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004255 int bytes_returned;
4256
4257 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4258 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4259 (void **) &pSMBr);
4260 if (rc)
4261 return rc;
4262
4263 pSMB->TotalParameterCount = 0 ;
4264 pSMB->TotalDataCount = 0;
4265 pSMB->MaxParameterCount = cpu_to_le32(2);
4266 /* BB find exact data count max from sess structure BB */
4267 pSMB->MaxDataCount = 0; /* same in little endian or be */
4268 pSMB->MaxSetupCount = 4;
4269 pSMB->Reserved = 0;
4270 pSMB->ParameterOffset = 0;
4271 pSMB->DataCount = 0;
4272 pSMB->DataOffset = 0;
4273 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4274 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4275 pSMB->ParameterCount = pSMB->TotalParameterCount;
4276 if(notify_subdirs)
4277 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4278 pSMB->Reserved2 = 0;
4279 pSMB->CompletionFilter = cpu_to_le32(filter);
4280 pSMB->Fid = netfid; /* file handle always le */
4281 pSMB->ByteCount = 0;
4282
4283 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4284 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4285 if (rc) {
4286 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004287 } else {
4288 /* Add file to outstanding requests */
4289 dnotify_req = (struct dir_notify_req *) kmalloc(
4290 sizeof(struct dir_notify_req), GFP_KERNEL);
4291 dnotify_req->Pid = pSMB->hdr.Pid;
4292 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4293 dnotify_req->Mid = pSMB->hdr.Mid;
4294 dnotify_req->Tid = pSMB->hdr.Tid;
4295 dnotify_req->Uid = pSMB->hdr.Uid;
4296 dnotify_req->netfid = netfid;
Steve French167a2512005-08-24 20:03:11 -07004297 dnotify_req->pfile = pfile;
Steve Frenchff5dbd92005-08-24 17:10:36 -07004298 dnotify_req->filter = filter;
4299 dnotify_req->multishot = multishot;
4300 spin_lock(&GlobalMid_Lock);
4301 list_add_tail(&dnotify_req->lhead, &GlobalDnotifyReqList);
4302 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303 }
4304 cifs_buf_release(pSMB);
4305 return rc;
4306}
4307#ifdef CONFIG_CIFS_XATTR
4308ssize_t
4309CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4310 const unsigned char *searchName,
4311 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004312 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313{
4314 /* BB assumes one setup word */
4315 TRANSACTION2_QPI_REQ *pSMB = NULL;
4316 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4317 int rc = 0;
4318 int bytes_returned;
4319 int name_len;
4320 struct fea * temp_fea;
4321 char * temp_ptr;
4322 __u16 params, byte_count;
4323
4324 cFYI(1, ("In Query All EAs path %s", searchName));
4325QAllEAsRetry:
4326 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4327 (void **) &pSMBr);
4328 if (rc)
4329 return rc;
4330
4331 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4332 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004333 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004334 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335 name_len++; /* trailing null */
4336 name_len *= 2;
4337 } else { /* BB improve the check for buffer overruns BB */
4338 name_len = strnlen(searchName, PATH_MAX);
4339 name_len++; /* trailing null */
4340 strncpy(pSMB->FileName, searchName, name_len);
4341 }
4342
4343 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4344 pSMB->TotalDataCount = 0;
4345 pSMB->MaxParameterCount = cpu_to_le16(2);
4346 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4347 pSMB->MaxSetupCount = 0;
4348 pSMB->Reserved = 0;
4349 pSMB->Flags = 0;
4350 pSMB->Timeout = 0;
4351 pSMB->Reserved2 = 0;
4352 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4353 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4354 pSMB->DataCount = 0;
4355 pSMB->DataOffset = 0;
4356 pSMB->SetupCount = 1;
4357 pSMB->Reserved3 = 0;
4358 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4359 byte_count = params + 1 /* pad */ ;
4360 pSMB->TotalParameterCount = cpu_to_le16(params);
4361 pSMB->ParameterCount = pSMB->TotalParameterCount;
4362 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4363 pSMB->Reserved4 = 0;
4364 pSMB->hdr.smb_buf_length += byte_count;
4365 pSMB->ByteCount = cpu_to_le16(byte_count);
4366
4367 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4368 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4369 if (rc) {
4370 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4371 } else { /* decode response */
4372 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4373
4374 /* BB also check enough total bytes returned */
4375 /* BB we need to improve the validity checking
4376 of these trans2 responses */
4377 if (rc || (pSMBr->ByteCount < 4))
4378 rc = -EIO; /* bad smb */
4379 /* else if (pFindData){
4380 memcpy((char *) pFindData,
4381 (char *) &pSMBr->hdr.Protocol +
4382 data_offset, kl);
4383 }*/ else {
4384 /* check that length of list is not more than bcc */
4385 /* check that each entry does not go beyond length
4386 of list */
4387 /* check that each element of each entry does not
4388 go beyond end of list */
4389 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4390 struct fealist * ea_response_data;
4391 rc = 0;
4392 /* validate_trans2_offsets() */
4393 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4394 ea_response_data = (struct fealist *)
4395 (((char *) &pSMBr->hdr.Protocol) +
4396 data_offset);
4397 name_len = le32_to_cpu(ea_response_data->list_len);
4398 cFYI(1,("ea length %d", name_len));
4399 if(name_len <= 8) {
4400 /* returned EA size zeroed at top of function */
4401 cFYI(1,("empty EA list returned from server"));
4402 } else {
4403 /* account for ea list len */
4404 name_len -= 4;
4405 temp_fea = ea_response_data->list;
4406 temp_ptr = (char *)temp_fea;
4407 while(name_len > 0) {
4408 __u16 value_len;
4409 name_len -= 4;
4410 temp_ptr += 4;
4411 rc += temp_fea->name_len;
4412 /* account for prefix user. and trailing null */
4413 rc = rc + 5 + 1;
4414 if(rc<(int)buf_size) {
4415 memcpy(EAData,"user.",5);
4416 EAData+=5;
4417 memcpy(EAData,temp_ptr,temp_fea->name_len);
4418 EAData+=temp_fea->name_len;
4419 /* null terminate name */
4420 *EAData = 0;
4421 EAData = EAData + 1;
4422 } else if(buf_size == 0) {
4423 /* skip copy - calc size only */
4424 } else {
4425 /* stop before overrun buffer */
4426 rc = -ERANGE;
4427 break;
4428 }
4429 name_len -= temp_fea->name_len;
4430 temp_ptr += temp_fea->name_len;
4431 /* account for trailing null */
4432 name_len--;
4433 temp_ptr++;
4434 value_len = le16_to_cpu(temp_fea->value_len);
4435 name_len -= value_len;
4436 temp_ptr += value_len;
4437 /* BB check that temp_ptr is still within smb BB*/
4438 /* no trailing null to account for in value len */
4439 /* go on to next EA */
4440 temp_fea = (struct fea *)temp_ptr;
4441 }
4442 }
4443 }
4444 }
4445 if (pSMB)
4446 cifs_buf_release(pSMB);
4447 if (rc == -EAGAIN)
4448 goto QAllEAsRetry;
4449
4450 return (ssize_t)rc;
4451}
4452
4453ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4454 const unsigned char * searchName,const unsigned char * ea_name,
4455 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004456 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004457{
4458 TRANSACTION2_QPI_REQ *pSMB = NULL;
4459 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4460 int rc = 0;
4461 int bytes_returned;
4462 int name_len;
4463 struct fea * temp_fea;
4464 char * temp_ptr;
4465 __u16 params, byte_count;
4466
4467 cFYI(1, ("In Query EA path %s", searchName));
4468QEARetry:
4469 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4470 (void **) &pSMBr);
4471 if (rc)
4472 return rc;
4473
4474 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4475 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004476 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004477 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004478 name_len++; /* trailing null */
4479 name_len *= 2;
4480 } else { /* BB improve the check for buffer overruns BB */
4481 name_len = strnlen(searchName, PATH_MAX);
4482 name_len++; /* trailing null */
4483 strncpy(pSMB->FileName, searchName, name_len);
4484 }
4485
4486 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4487 pSMB->TotalDataCount = 0;
4488 pSMB->MaxParameterCount = cpu_to_le16(2);
4489 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4490 pSMB->MaxSetupCount = 0;
4491 pSMB->Reserved = 0;
4492 pSMB->Flags = 0;
4493 pSMB->Timeout = 0;
4494 pSMB->Reserved2 = 0;
4495 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4496 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4497 pSMB->DataCount = 0;
4498 pSMB->DataOffset = 0;
4499 pSMB->SetupCount = 1;
4500 pSMB->Reserved3 = 0;
4501 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4502 byte_count = params + 1 /* pad */ ;
4503 pSMB->TotalParameterCount = cpu_to_le16(params);
4504 pSMB->ParameterCount = pSMB->TotalParameterCount;
4505 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4506 pSMB->Reserved4 = 0;
4507 pSMB->hdr.smb_buf_length += byte_count;
4508 pSMB->ByteCount = cpu_to_le16(byte_count);
4509
4510 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4511 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4512 if (rc) {
4513 cFYI(1, ("Send error in Query EA = %d", rc));
4514 } else { /* decode response */
4515 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4516
4517 /* BB also check enough total bytes returned */
4518 /* BB we need to improve the validity checking
4519 of these trans2 responses */
4520 if (rc || (pSMBr->ByteCount < 4))
4521 rc = -EIO; /* bad smb */
4522 /* else if (pFindData){
4523 memcpy((char *) pFindData,
4524 (char *) &pSMBr->hdr.Protocol +
4525 data_offset, kl);
4526 }*/ else {
4527 /* check that length of list is not more than bcc */
4528 /* check that each entry does not go beyond length
4529 of list */
4530 /* check that each element of each entry does not
4531 go beyond end of list */
4532 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4533 struct fealist * ea_response_data;
4534 rc = -ENODATA;
4535 /* validate_trans2_offsets() */
4536 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4537 ea_response_data = (struct fealist *)
4538 (((char *) &pSMBr->hdr.Protocol) +
4539 data_offset);
4540 name_len = le32_to_cpu(ea_response_data->list_len);
4541 cFYI(1,("ea length %d", name_len));
4542 if(name_len <= 8) {
4543 /* returned EA size zeroed at top of function */
4544 cFYI(1,("empty EA list returned from server"));
4545 } else {
4546 /* account for ea list len */
4547 name_len -= 4;
4548 temp_fea = ea_response_data->list;
4549 temp_ptr = (char *)temp_fea;
4550 /* loop through checking if we have a matching
4551 name and then return the associated value */
4552 while(name_len > 0) {
4553 __u16 value_len;
4554 name_len -= 4;
4555 temp_ptr += 4;
4556 value_len = le16_to_cpu(temp_fea->value_len);
4557 /* BB validate that value_len falls within SMB,
4558 even though maximum for name_len is 255 */
4559 if(memcmp(temp_fea->name,ea_name,
4560 temp_fea->name_len) == 0) {
4561 /* found a match */
4562 rc = value_len;
4563 /* account for prefix user. and trailing null */
4564 if(rc<=(int)buf_size) {
4565 memcpy(ea_value,
4566 temp_fea->name+temp_fea->name_len+1,
4567 rc);
4568 /* ea values, unlike ea names,
4569 are not null terminated */
4570 } else if(buf_size == 0) {
4571 /* skip copy - calc size only */
4572 } else {
4573 /* stop before overrun buffer */
4574 rc = -ERANGE;
4575 }
4576 break;
4577 }
4578 name_len -= temp_fea->name_len;
4579 temp_ptr += temp_fea->name_len;
4580 /* account for trailing null */
4581 name_len--;
4582 temp_ptr++;
4583 name_len -= value_len;
4584 temp_ptr += value_len;
4585 /* no trailing null to account for in value len */
4586 /* go on to next EA */
4587 temp_fea = (struct fea *)temp_ptr;
4588 }
4589 }
4590 }
4591 }
4592 if (pSMB)
4593 cifs_buf_release(pSMB);
4594 if (rc == -EAGAIN)
4595 goto QEARetry;
4596
4597 return (ssize_t)rc;
4598}
4599
4600int
4601CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4602 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004603 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4604 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605{
4606 struct smb_com_transaction2_spi_req *pSMB = NULL;
4607 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4608 struct fealist *parm_data;
4609 int name_len;
4610 int rc = 0;
4611 int bytes_returned = 0;
4612 __u16 params, param_offset, byte_count, offset, count;
4613
4614 cFYI(1, ("In SetEA"));
4615SetEARetry:
4616 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4617 (void **) &pSMBr);
4618 if (rc)
4619 return rc;
4620
4621 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4622 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004623 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004624 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 name_len++; /* trailing null */
4626 name_len *= 2;
4627 } else { /* BB improve the check for buffer overruns BB */
4628 name_len = strnlen(fileName, PATH_MAX);
4629 name_len++; /* trailing null */
4630 strncpy(pSMB->FileName, fileName, name_len);
4631 }
4632
4633 params = 6 + name_len;
4634
4635 /* done calculating parms using name_len of file name,
4636 now use name_len to calculate length of ea name
4637 we are going to create in the inode xattrs */
4638 if(ea_name == NULL)
4639 name_len = 0;
4640 else
4641 name_len = strnlen(ea_name,255);
4642
4643 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4644 pSMB->MaxParameterCount = cpu_to_le16(2);
4645 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4646 pSMB->MaxSetupCount = 0;
4647 pSMB->Reserved = 0;
4648 pSMB->Flags = 0;
4649 pSMB->Timeout = 0;
4650 pSMB->Reserved2 = 0;
4651 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4652 InformationLevel) - 4;
4653 offset = param_offset + params;
4654 pSMB->InformationLevel =
4655 cpu_to_le16(SMB_SET_FILE_EA);
4656
4657 parm_data =
4658 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4659 offset);
4660 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4661 pSMB->DataOffset = cpu_to_le16(offset);
4662 pSMB->SetupCount = 1;
4663 pSMB->Reserved3 = 0;
4664 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4665 byte_count = 3 /* pad */ + params + count;
4666 pSMB->DataCount = cpu_to_le16(count);
4667 parm_data->list_len = cpu_to_le32(count);
4668 parm_data->list[0].EA_flags = 0;
4669 /* we checked above that name len is less than 255 */
4670 parm_data->list[0].name_len = (__u8)name_len;;
4671 /* EA names are always ASCII */
4672 if(ea_name)
4673 strncpy(parm_data->list[0].name,ea_name,name_len);
4674 parm_data->list[0].name[name_len] = 0;
4675 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4676 /* caller ensures that ea_value_len is less than 64K but
4677 we need to ensure that it fits within the smb */
4678
4679 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4680 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4681 if(ea_value_len)
4682 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4683
4684 pSMB->TotalDataCount = pSMB->DataCount;
4685 pSMB->ParameterCount = cpu_to_le16(params);
4686 pSMB->TotalParameterCount = pSMB->ParameterCount;
4687 pSMB->Reserved4 = 0;
4688 pSMB->hdr.smb_buf_length += byte_count;
4689 pSMB->ByteCount = cpu_to_le16(byte_count);
4690 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4691 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4692 if (rc) {
4693 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4694 }
4695
4696 cifs_buf_release(pSMB);
4697
4698 if (rc == -EAGAIN)
4699 goto SetEARetry;
4700
4701 return rc;
4702}
4703
4704#endif