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