blob: 365949c1464691bd32d2d10207073cd0d642c1f8 [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);
Steve French3e844692005-10-03 13:37:24 -0700128 /* BB FIXME add code to check if wsize needs
129 update due to negotiated smb buffer size
130 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 if(rc == 0)
132 atomic_inc(&tconInfoReconnectCount);
133
134 cFYI(1, ("reconnect tcon rc = %d", rc));
135 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700136 it is safer (and faster) to reopen files
137 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
139 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700140 know whether we can continue or not without
141 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 switch(smb_command) {
143 case SMB_COM_READ_ANDX:
144 case SMB_COM_WRITE_ANDX:
145 case SMB_COM_CLOSE:
146 case SMB_COM_FIND_CLOSE2:
147 case SMB_COM_LOCKING_ANDX: {
148 unload_nls(nls_codepage);
149 return -EAGAIN;
150 }
151 }
152 } else {
153 up(&tcon->ses->sesSem);
154 }
155 unload_nls(nls_codepage);
156
157 } else {
158 return -EIO;
159 }
160 }
161 if(rc)
162 return rc;
163
164 *request_buf = cifs_small_buf_get();
165 if (*request_buf == NULL) {
166 /* BB should we add a retry in here if not a writepage? */
167 return -ENOMEM;
168 }
169
170 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
171
Steve Frencha45443472005-08-24 13:59:35 -0700172 if(tcon != NULL)
173 cifs_stats_inc(&tcon->num_smbs_sent);
174
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 return rc;
176}
177
178/* If the return code is zero, this function must fill in request_buf pointer */
179static int
180smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
181 void **request_buf /* returned */ ,
182 void **response_buf /* returned */ )
183{
184 int rc = 0;
185
186 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
187 check for tcp and smb session status done differently
188 for those three - in the calling routine */
189 if(tcon) {
Steve French31ca3bc2005-04-28 22:41:11 -0700190 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
191 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700193 /* Give Demultiplex thread up to 10 seconds to
194 reconnect, should be greater than cifs socket
195 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
197 wait_event_interruptible_timeout(tcon->ses->server->response_q,
198 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
Steve French09d1db52005-04-28 22:41:08 -0700199 if(tcon->ses->server->tcpStatus ==
200 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 /* on "soft" mounts we wait once */
202 if((tcon->retry == FALSE) ||
203 (tcon->ses->status == CifsExiting)) {
204 cFYI(1,("gave up waiting on reconnect in smb_init"));
205 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700206 } /* else "hard" mount - keep retrying
207 until process is killed or server
208 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 } else /* TCP session is reestablished now */
210 break;
211
212 }
213
214 nls_codepage = load_nls_default();
215 /* need to prevent multiple threads trying to
216 simultaneously reconnect the same SMB session */
217 down(&tcon->ses->sesSem);
218 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700219 rc = cifs_setup_session(0, tcon->ses,
220 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
222 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700223 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
224 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700226 /* BB FIXME add code to check if wsize needs
227 update due to negotiated smb buffer size
228 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 if(rc == 0)
230 atomic_inc(&tconInfoReconnectCount);
231
232 cFYI(1, ("reconnect tcon rc = %d", rc));
233 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700234 it is safer (and faster) to reopen files
235 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
237 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700238 know whether we can continue or not without
239 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240 switch(smb_command) {
241 case SMB_COM_READ_ANDX:
242 case SMB_COM_WRITE_ANDX:
243 case SMB_COM_CLOSE:
244 case SMB_COM_FIND_CLOSE2:
245 case SMB_COM_LOCKING_ANDX: {
246 unload_nls(nls_codepage);
247 return -EAGAIN;
248 }
249 }
250 } else {
251 up(&tcon->ses->sesSem);
252 }
253 unload_nls(nls_codepage);
254
255 } else {
256 return -EIO;
257 }
258 }
259 if(rc)
260 return rc;
261
262 *request_buf = cifs_buf_get();
263 if (*request_buf == NULL) {
264 /* BB should we add a retry in here if not a writepage? */
265 return -ENOMEM;
266 }
267 /* Although the original thought was we needed the response buf for */
268 /* potential retries of smb operations it turns out we can determine */
269 /* from the mid flags when the request buffer can be resent without */
270 /* having to use a second distinct buffer for the response */
271 *response_buf = *request_buf;
272
273 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
274 wct /*wct */ );
275
Steve Frencha45443472005-08-24 13:59:35 -0700276 if(tcon != NULL)
277 cifs_stats_inc(&tcon->num_smbs_sent);
278
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 return rc;
280}
281
282static int validate_t2(struct smb_t2_rsp * pSMB)
283{
284 int rc = -EINVAL;
285 int total_size;
286 char * pBCC;
287
288 /* check for plausible wct, bcc and t2 data and parm sizes */
289 /* check for parm and data offset going beyond end of smb */
290 if(pSMB->hdr.WordCount >= 10) {
291 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
292 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
293 /* check that bcc is at least as big as parms + data */
294 /* check that bcc is less than negotiated smb buffer */
295 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
296 if(total_size < 512) {
297 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
298 /* BCC le converted in SendReceive */
Steve French09d1db52005-04-28 22:41:08 -0700299 pBCC = (pSMB->hdr.WordCount * 2) +
300 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 (char *)pSMB;
302 if((total_size <= (*(u16 *)pBCC)) &&
303 (total_size <
304 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
305 return 0;
306 }
307
308 }
309 }
310 }
311 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
312 sizeof(struct smb_t2_rsp) + 16);
313 return rc;
314}
315int
316CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
317{
318 NEGOTIATE_REQ *pSMB;
319 NEGOTIATE_RSP *pSMBr;
320 int rc = 0;
321 int bytes_returned;
322 struct TCP_Server_Info * server;
323 u16 count;
324
325 if(ses->server)
326 server = ses->server;
327 else {
328 rc = -EIO;
329 return rc;
330 }
331 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
332 (void **) &pSMB, (void **) &pSMBr);
333 if (rc)
334 return rc;
Steve French1982c342005-08-17 12:38:22 -0700335 pSMB->hdr.Mid = GetNextMid(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
337 if (extended_security)
338 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
339
340 count = strlen(protocols[0].name) + 1;
341 strncpy(pSMB->DialectsArray, protocols[0].name, 30);
342 /* null guaranteed to be at end of source and target buffers anyway */
343
344 pSMB->hdr.smb_buf_length += count;
345 pSMB->ByteCount = cpu_to_le16(count);
346
347 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
348 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
349 if (rc == 0) {
350 server->secMode = pSMBr->SecurityMode;
Steve French09d1db52005-04-28 22:41:08 -0700351 server->secType = NTLM; /* BB override default for
352 NTLMv2 or kerberos v5 */
353 /* one byte - no need to convert this or EncryptionKeyLen
354 from little endian */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
356 /* probably no need to store and check maxvcs */
357 server->maxBuf =
358 min(le32_to_cpu(pSMBr->MaxBufferSize),
359 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
360 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
361 cFYI(0, ("Max buf = %d ", ses->server->maxBuf));
362 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
363 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
364 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
365 /* BB with UTC do we ever need to be using srvr timezone? */
366 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
367 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
368 CIFS_CRYPTO_KEY_SIZE);
369 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
370 && (pSMBr->EncryptionKeyLength == 0)) {
371 /* decode security blob */
372 } else
373 rc = -EIO;
374
375 /* BB might be helpful to save off the domain of server here */
376
377 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
378 (server->capabilities & CAP_EXTENDED_SECURITY)) {
379 count = pSMBr->ByteCount;
380 if (count < 16)
381 rc = -EIO;
382 else if (count == 16) {
383 server->secType = RawNTLMSSP;
384 if (server->socketUseCount.counter > 1) {
385 if (memcmp
386 (server->server_GUID,
387 pSMBr->u.extended_response.
388 GUID, 16) != 0) {
389 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700390 ("UID of server does not match previous connection to same ip address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 memcpy(server->
392 server_GUID,
393 pSMBr->u.
394 extended_response.
395 GUID, 16);
396 }
397 } else
398 memcpy(server->server_GUID,
399 pSMBr->u.extended_response.
400 GUID, 16);
401 } else {
402 rc = decode_negTokenInit(pSMBr->u.
403 extended_response.
404 SecurityBlob,
405 count - 16,
406 &server->secType);
407 if(rc == 1) {
408 /* BB Need to fill struct for sessetup here */
409 rc = -EOPNOTSUPP;
410 } else {
411 rc = -EINVAL;
412 }
413 }
414 } else
415 server->capabilities &= ~CAP_EXTENDED_SECURITY;
416 if(sign_CIFS_PDUs == FALSE) {
417 if(server->secMode & SECMODE_SIGN_REQUIRED)
418 cERROR(1,
419 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
Steve French1982c342005-08-17 12:38:22 -0700420 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 } else if(sign_CIFS_PDUs == 1) {
422 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French1982c342005-08-17 12:38:22 -0700423 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 }
425
426 }
Steve French1982c342005-08-17 12:38:22 -0700427
Steve French4a6d87f2005-08-13 08:15:54 -0700428 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 return rc;
430}
431
432int
433CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
434{
435 struct smb_hdr *smb_buffer;
436 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
437 int rc = 0;
438 int length;
439
440 cFYI(1, ("In tree disconnect"));
441 /*
442 * If last user of the connection and
443 * connection alive - disconnect it
444 * If this is the last connection on the server session disconnect it
445 * (and inside session disconnect we should check if tcp socket needs
446 * to be freed and kernel thread woken up).
447 */
448 if (tcon)
449 down(&tcon->tconSem);
450 else
451 return -EIO;
452
453 atomic_dec(&tcon->useCount);
454 if (atomic_read(&tcon->useCount) > 0) {
455 up(&tcon->tconSem);
456 return -EBUSY;
457 }
458
459 /* No need to return error on this operation if tid invalidated and
460 closed on server already e.g. due to tcp session crashing */
461 if(tcon->tidStatus == CifsNeedReconnect) {
462 up(&tcon->tconSem);
463 return 0;
464 }
465
466 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
467 up(&tcon->tconSem);
468 return -EIO;
469 }
Steve French09d1db52005-04-28 22:41:08 -0700470 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
471 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 if (rc) {
473 up(&tcon->tconSem);
474 return rc;
475 } else {
476 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
479 &length, 0);
480 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700481 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
483 if (smb_buffer)
484 cifs_small_buf_release(smb_buffer);
485 up(&tcon->tconSem);
486
487 /* No need to return error on this operation if tid invalidated and
488 closed on server already e.g. due to tcp session crashing */
489 if (rc == -EAGAIN)
490 rc = 0;
491
492 return rc;
493}
494
495int
496CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
497{
498 struct smb_hdr *smb_buffer_response;
499 LOGOFF_ANDX_REQ *pSMB;
500 int rc = 0;
501 int length;
502
503 cFYI(1, ("In SMBLogoff for session disconnect"));
504 if (ses)
505 down(&ses->sesSem);
506 else
507 return -EIO;
508
509 atomic_dec(&ses->inUse);
510 if (atomic_read(&ses->inUse) > 0) {
511 up(&ses->sesSem);
512 return -EBUSY;
513 }
514 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
515 if (rc) {
516 up(&ses->sesSem);
517 return rc;
518 }
519
520 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
521
522 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700523 pSMB->hdr.Mid = GetNextMid(ses->server);
524
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 if(ses->server->secMode &
526 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
527 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
528 }
529
530 pSMB->hdr.Uid = ses->Suid;
531
532 pSMB->AndXCommand = 0xFF;
533 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
534 smb_buffer_response, &length, 0);
535 if (ses->server) {
536 atomic_dec(&ses->server->socketUseCount);
537 if (atomic_read(&ses->server->socketUseCount) == 0) {
538 spin_lock(&GlobalMid_Lock);
539 ses->server->tcpStatus = CifsExiting;
540 spin_unlock(&GlobalMid_Lock);
541 rc = -ESHUTDOWN;
542 }
543 }
Steve Frencha59c6582005-08-17 12:12:19 -0700544 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700545 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
547 /* if session dead then we do not need to do ulogoff,
548 since server closed smb session, no sense reporting
549 error */
550 if (rc == -EAGAIN)
551 rc = 0;
552 return rc;
553}
554
555int
Steve French737b7582005-04-28 22:41:06 -0700556CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
557 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558{
559 DELETE_FILE_REQ *pSMB = NULL;
560 DELETE_FILE_RSP *pSMBr = NULL;
561 int rc = 0;
562 int bytes_returned;
563 int name_len;
564
565DelFileRetry:
566 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
567 (void **) &pSMBr);
568 if (rc)
569 return rc;
570
571 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
572 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500573 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700574 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 name_len++; /* trailing null */
576 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700577 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 name_len = strnlen(fileName, PATH_MAX);
579 name_len++; /* trailing null */
580 strncpy(pSMB->fileName, fileName, name_len);
581 }
582 pSMB->SearchAttributes =
583 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
584 pSMB->BufferFormat = 0x04;
585 pSMB->hdr.smb_buf_length += name_len + 1;
586 pSMB->ByteCount = cpu_to_le16(name_len + 1);
587 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
588 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700589 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 if (rc) {
591 cFYI(1, ("Error in RMFile = %d", rc));
592 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593
594 cifs_buf_release(pSMB);
595 if (rc == -EAGAIN)
596 goto DelFileRetry;
597
598 return rc;
599}
600
601int
Steve French737b7582005-04-28 22:41:06 -0700602CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
603 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604{
605 DELETE_DIRECTORY_REQ *pSMB = NULL;
606 DELETE_DIRECTORY_RSP *pSMBr = NULL;
607 int rc = 0;
608 int bytes_returned;
609 int name_len;
610
611 cFYI(1, ("In CIFSSMBRmDir"));
612RmDirRetry:
613 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
614 (void **) &pSMBr);
615 if (rc)
616 return rc;
617
618 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700619 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
620 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 name_len++; /* trailing null */
622 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700623 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 name_len = strnlen(dirName, PATH_MAX);
625 name_len++; /* trailing null */
626 strncpy(pSMB->DirName, dirName, name_len);
627 }
628
629 pSMB->BufferFormat = 0x04;
630 pSMB->hdr.smb_buf_length += name_len + 1;
631 pSMB->ByteCount = cpu_to_le16(name_len + 1);
632 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
633 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700634 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 if (rc) {
636 cFYI(1, ("Error in RMDir = %d", rc));
637 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
639 cifs_buf_release(pSMB);
640 if (rc == -EAGAIN)
641 goto RmDirRetry;
642 return rc;
643}
644
645int
646CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700647 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648{
649 int rc = 0;
650 CREATE_DIRECTORY_REQ *pSMB = NULL;
651 CREATE_DIRECTORY_RSP *pSMBr = NULL;
652 int bytes_returned;
653 int name_len;
654
655 cFYI(1, ("In CIFSSMBMkDir"));
656MkDirRetry:
657 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
658 (void **) &pSMBr);
659 if (rc)
660 return rc;
661
662 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500663 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700664 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 name_len++; /* trailing null */
666 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700667 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 name_len = strnlen(name, PATH_MAX);
669 name_len++; /* trailing null */
670 strncpy(pSMB->DirName, name, name_len);
671 }
672
673 pSMB->BufferFormat = 0x04;
674 pSMB->hdr.smb_buf_length += name_len + 1;
675 pSMB->ByteCount = cpu_to_le16(name_len + 1);
676 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
677 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700678 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 if (rc) {
680 cFYI(1, ("Error in Mkdir = %d", rc));
681 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700682
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 cifs_buf_release(pSMB);
684 if (rc == -EAGAIN)
685 goto MkDirRetry;
686 return rc;
687}
688
Steve Frencha9d02ad2005-08-24 23:06:05 -0700689static __u16 convert_disposition(int disposition)
690{
691 __u16 ofun = 0;
692
693 switch (disposition) {
694 case FILE_SUPERSEDE:
695 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
696 break;
697 case FILE_OPEN:
698 ofun = SMBOPEN_OAPPEND;
699 break;
700 case FILE_CREATE:
701 ofun = SMBOPEN_OCREATE;
702 break;
703 case FILE_OPEN_IF:
704 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
705 break;
706 case FILE_OVERWRITE:
707 ofun = SMBOPEN_OTRUNC;
708 break;
709 case FILE_OVERWRITE_IF:
710 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
711 break;
712 default:
713 cFYI(1,("unknown disposition %d",disposition));
714 ofun = SMBOPEN_OAPPEND; /* regular open */
715 }
716 return ofun;
717}
718
719int
720SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
721 const char *fileName, const int openDisposition,
722 const int access_flags, const int create_options, __u16 * netfid,
723 int *pOplock, FILE_ALL_INFO * pfile_info,
724 const struct nls_table *nls_codepage, int remap)
725{
726 int rc = -EACCES;
727 OPENX_REQ *pSMB = NULL;
728 OPENX_RSP *pSMBr = NULL;
729 int bytes_returned;
730 int name_len;
731 __u16 count;
732
733OldOpenRetry:
734 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
735 (void **) &pSMBr);
736 if (rc)
737 return rc;
738
739 pSMB->AndXCommand = 0xFF; /* none */
740
741 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
742 count = 1; /* account for one byte pad to word boundary */
743 name_len =
744 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
745 fileName, PATH_MAX, nls_codepage, remap);
746 name_len++; /* trailing null */
747 name_len *= 2;
748 } else { /* BB improve check for buffer overruns BB */
749 count = 0; /* no pad */
750 name_len = strnlen(fileName, PATH_MAX);
751 name_len++; /* trailing null */
752 strncpy(pSMB->fileName, fileName, name_len);
753 }
754 if (*pOplock & REQ_OPLOCK)
755 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
756 else if (*pOplock & REQ_BATCHOPLOCK) {
757 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
758 }
759 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
760 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
761 /* 0 = read
762 1 = write
763 2 = rw
764 3 = execute
765 */
766 pSMB->Mode = cpu_to_le16(2);
767 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
768 /* set file as system file if special file such
769 as fifo and server expecting SFU style and
770 no Unix extensions */
771
772 if(create_options & CREATE_OPTION_SPECIAL)
773 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
774 else
Steve French3e87d802005-09-18 20:49:21 -0700775 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700776
777 /* if ((omode & S_IWUGO) == 0)
778 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
779 /* Above line causes problems due to vfs splitting create into two
780 pieces - need to set mode after file created not while it is
781 being created */
782
783 /* BB FIXME BB */
784/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
785 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700786
787 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700788 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700789 count += name_len;
790 pSMB->hdr.smb_buf_length += count;
791
792 pSMB->ByteCount = cpu_to_le16(count);
793 /* long_op set to 1 to allow for oplock break timeouts */
794 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
795 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
796 cifs_stats_inc(&tcon->num_opens);
797 if (rc) {
798 cFYI(1, ("Error in Open = %d", rc));
799 } else {
800 /* BB verify if wct == 15 */
801
802/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
803
804 *netfid = pSMBr->Fid; /* cifs fid stays in le */
805 /* Let caller know file was created so we can set the mode. */
806 /* Do we care about the CreateAction in any other cases? */
807 /* BB FIXME BB */
808/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
809 *pOplock |= CIFS_CREATE_ACTION; */
810 /* BB FIXME END */
811
812 if(pfile_info) {
813 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
814 pfile_info->LastAccessTime = 0; /* BB fixme */
815 pfile_info->LastWriteTime = 0; /* BB fixme */
816 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -0700817 pfile_info->Attributes =
818 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700819 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -0700820 pfile_info->AllocationSize =
821 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
822 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -0700823 pfile_info->NumberOfLinks = cpu_to_le32(1);
824 }
825 }
826
827 cifs_buf_release(pSMB);
828 if (rc == -EAGAIN)
829 goto OldOpenRetry;
830 return rc;
831}
832
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833int
834CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
835 const char *fileName, const int openDisposition,
836 const int access_flags, const int create_options, __u16 * netfid,
837 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -0700838 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839{
840 int rc = -EACCES;
841 OPEN_REQ *pSMB = NULL;
842 OPEN_RSP *pSMBr = NULL;
843 int bytes_returned;
844 int name_len;
845 __u16 count;
846
847openRetry:
848 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
849 (void **) &pSMBr);
850 if (rc)
851 return rc;
852
853 pSMB->AndXCommand = 0xFF; /* none */
854
855 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
856 count = 1; /* account for one byte pad to word boundary */
857 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500858 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -0700859 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 name_len++; /* trailing null */
861 name_len *= 2;
862 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -0700863 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 count = 0; /* no pad */
865 name_len = strnlen(fileName, PATH_MAX);
866 name_len++; /* trailing null */
867 pSMB->NameLength = cpu_to_le16(name_len);
868 strncpy(pSMB->fileName, fileName, name_len);
869 }
870 if (*pOplock & REQ_OPLOCK)
871 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
872 else if (*pOplock & REQ_BATCHOPLOCK) {
873 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
874 }
875 pSMB->DesiredAccess = cpu_to_le32(access_flags);
876 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -0700877 /* set file as system file if special file such
878 as fifo and server expecting SFU style and
879 no Unix extensions */
880 if(create_options & CREATE_OPTION_SPECIAL)
881 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
882 else
883 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 /* XP does not handle ATTR_POSIX_SEMANTICS */
885 /* but it helps speed up case sensitive checks for other
886 servers such as Samba */
887 if (tcon->ses->capabilities & CAP_UNIX)
888 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
889
890 /* if ((omode & S_IWUGO) == 0)
891 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
892 /* Above line causes problems due to vfs splitting create into two
893 pieces - need to set mode after file created not while it is
894 being created */
895 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
896 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -0700897 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -0700898 /* BB Expirement with various impersonation levels and verify */
899 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 pSMB->SecurityFlags =
901 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
902
903 count += name_len;
904 pSMB->hdr.smb_buf_length += count;
905
906 pSMB->ByteCount = cpu_to_le16(count);
907 /* long_op set to 1 to allow for oplock break timeouts */
908 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
909 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha45443472005-08-24 13:59:35 -0700910 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 if (rc) {
912 cFYI(1, ("Error in Open = %d", rc));
913 } else {
Steve French09d1db52005-04-28 22:41:08 -0700914 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 *netfid = pSMBr->Fid; /* cifs fid stays in le */
916 /* Let caller know file was created so we can set the mode. */
917 /* Do we care about the CreateAction in any other cases? */
918 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
919 *pOplock |= CIFS_CREATE_ACTION;
920 if(pfile_info) {
921 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
922 36 /* CreationTime to Attributes */);
923 /* the file_info buf is endian converted by caller */
924 pfile_info->AllocationSize = pSMBr->AllocationSize;
925 pfile_info->EndOfFile = pSMBr->EndOfFile;
926 pfile_info->NumberOfLinks = cpu_to_le32(1);
927 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700929
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 cifs_buf_release(pSMB);
931 if (rc == -EAGAIN)
932 goto openRetry;
933 return rc;
934}
935
936/* If no buffer passed in, then caller wants to do the copy
937 as in the case of readpages so the SMB buffer must be
938 freed by the caller */
939
940int
941CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
942 const int netfid, const unsigned int count,
943 const __u64 lseek, unsigned int *nbytes, char **buf)
944{
945 int rc = -EACCES;
946 READ_REQ *pSMB = NULL;
947 READ_RSP *pSMBr = NULL;
948 char *pReadData = NULL;
949 int bytes_returned;
Steve Frenchbfa0d752005-08-31 21:50:37 -0700950 int wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951
952 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -0700953 if(tcon->ses->capabilities & CAP_LARGE_FILES)
954 wct = 12;
955 else
956 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
958 *nbytes = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -0700959 rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 (void **) &pSMBr);
961 if (rc)
962 return rc;
963
964 /* tcon and ses pointer are checked in smb_init */
965 if (tcon->ses->server == NULL)
966 return -ECONNABORTED;
967
968 pSMB->AndXCommand = 0xFF; /* none */
969 pSMB->Fid = netfid;
970 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -0700971 if(wct == 12)
972 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
973 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
974 return -EIO;
975
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 pSMB->Remaining = 0;
977 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
978 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -0700979 if(wct == 12)
980 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
981 else {
982 /* old style read */
983 struct smb_com_readx_req * pSMBW =
984 (struct smb_com_readx_req *)pSMB;
985 pSMBW->ByteCount = 0;
986 }
987
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
989 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -0700990 cifs_stats_inc(&tcon->num_reads);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 if (rc) {
992 cERROR(1, ("Send error in read = %d", rc));
993 } else {
994 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
995 data_length = data_length << 16;
996 data_length += le16_to_cpu(pSMBr->DataLength);
997 *nbytes = data_length;
998
999 /*check that DataLength would not go beyond end of SMB */
1000 if ((data_length > CIFSMaxBufSize)
1001 || (data_length > count)) {
1002 cFYI(1,("bad length %d for count %d",data_length,count));
1003 rc = -EIO;
1004 *nbytes = 0;
1005 } else {
1006 pReadData =
1007 (char *) (&pSMBr->hdr.Protocol) +
1008 le16_to_cpu(pSMBr->DataOffset);
1009/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1010 cERROR(1,("Faulting on read rc = %d",rc));
1011 rc = -EFAULT;
1012 }*/ /* can not use copy_to_user when using page cache*/
1013 if(*buf)
1014 memcpy(*buf,pReadData,data_length);
1015 }
1016 }
1017 if(*buf)
1018 cifs_buf_release(pSMB);
1019 else
1020 *buf = (char *)pSMB;
1021
1022 /* Note: On -EAGAIN error only caller can retry on handle based calls
1023 since file handle passed in no longer valid */
1024 return rc;
1025}
1026
1027int
1028CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1029 const int netfid, const unsigned int count,
1030 const __u64 offset, unsigned int *nbytes, const char *buf,
1031 const char __user * ubuf, const int long_op)
1032{
1033 int rc = -EACCES;
1034 WRITE_REQ *pSMB = NULL;
1035 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001036 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 __u32 bytes_sent;
1038 __u16 byte_count;
1039
1040 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001041 if(tcon->ses == NULL)
1042 return -ECONNABORTED;
1043
1044 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1045 wct = 14;
1046 else
1047 wct = 12;
1048
1049 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 (void **) &pSMBr);
1051 if (rc)
1052 return rc;
1053 /* tcon and ses pointer are checked in smb_init */
1054 if (tcon->ses->server == NULL)
1055 return -ECONNABORTED;
1056
1057 pSMB->AndXCommand = 0xFF; /* none */
1058 pSMB->Fid = netfid;
1059 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001060 if(wct == 14)
1061 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1062 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1063 return -EIO;
1064
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 pSMB->Reserved = 0xFFFFFFFF;
1066 pSMB->WriteMode = 0;
1067 pSMB->Remaining = 0;
1068
1069 /* Can increase buffer size if buffer is big enough in some cases - ie we
1070 can send more if LARGE_WRITE_X capability returned by the server and if
1071 our buffer is big enough or if we convert to iovecs on socket writes
1072 and eliminate the copy to the CIFS buffer */
1073 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1074 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1075 } else {
1076 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1077 & ~0xFF;
1078 }
1079
1080 if (bytes_sent > count)
1081 bytes_sent = count;
1082 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001083 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 if(buf)
1085 memcpy(pSMB->Data,buf,bytes_sent);
1086 else if(ubuf) {
1087 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1088 cifs_buf_release(pSMB);
1089 return -EFAULT;
1090 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001091 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 /* No buffer */
1093 cifs_buf_release(pSMB);
1094 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001095 } /* else setting file size with write of zero bytes */
1096 if(wct == 14)
1097 byte_count = bytes_sent + 1; /* pad */
1098 else /* wct == 12 */ {
1099 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1102 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001103 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001104
1105 if(wct == 14)
1106 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001107 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001108 struct smb_com_writex_req * pSMBW =
1109 (struct smb_com_writex_req *)pSMB;
1110 pSMBW->ByteCount = cpu_to_le16(byte_count);
1111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112
1113 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1114 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001115 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 if (rc) {
1117 cFYI(1, ("Send error in write = %d", rc));
1118 *nbytes = 0;
1119 } else {
1120 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1121 *nbytes = (*nbytes) << 16;
1122 *nbytes += le16_to_cpu(pSMBr->Count);
1123 }
1124
1125 cifs_buf_release(pSMB);
1126
1127 /* Note: On -EAGAIN error only caller can retry on handle based calls
1128 since file handle passed in no longer valid */
1129
1130 return rc;
1131}
1132
1133#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001134int
1135CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001137 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1138 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139{
1140 int rc = -EACCES;
1141 WRITE_REQ *pSMB = NULL;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001142 int bytes_returned;
1143 int smb_hdr_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
Steve French0c0ff092005-06-23 19:31:17 -05001145 cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 if (rc)
1148 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 /* tcon and ses pointer are checked in smb_init */
1150 if (tcon->ses->server == NULL)
1151 return -ECONNABORTED;
1152
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001153 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 pSMB->Fid = netfid;
1155 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1156 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1157 pSMB->Reserved = 0xFFFFFFFF;
1158 pSMB->WriteMode = 0;
1159 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001160
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 pSMB->DataOffset =
1162 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1163
Steve French3e844692005-10-03 13:37:24 -07001164 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1165 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001166 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French3e844692005-10-03 13:37:24 -07001167 pSMB->hdr.smb_buf_length += count+1;
1168 pSMB->ByteCount = cpu_to_le16(count + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
Steve French3e844692005-10-03 13:37:24 -07001170 iov[0].iov_base = pSMB;
1171 iov[0].iov_len = smb_hdr_len + 4;
1172
1173 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned,
1174 long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001175 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 if (rc) {
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001177 cFYI(1, ("Send error in write = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001179 } else {
1180 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
1181 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1182 *nbytes = (*nbytes) << 16;
1183 *nbytes += le16_to_cpu(pSMBr->Count);
1184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185
1186 cifs_small_buf_release(pSMB);
1187
1188 /* Note: On -EAGAIN error only caller can retry on handle based calls
1189 since file handle passed in no longer valid */
1190
1191 return rc;
1192}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001193
1194
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195#endif /* CIFS_EXPERIMENTAL */
1196
1197int
1198CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1199 const __u16 smb_file_id, const __u64 len,
1200 const __u64 offset, const __u32 numUnlock,
1201 const __u32 numLock, const __u8 lockType, const int waitFlag)
1202{
1203 int rc = 0;
1204 LOCK_REQ *pSMB = NULL;
1205 LOCK_RSP *pSMBr = NULL;
1206 int bytes_returned;
1207 int timeout = 0;
1208 __u16 count;
1209
1210 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001211 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1212
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 if (rc)
1214 return rc;
1215
Steve French46810cb2005-04-28 22:41:09 -07001216 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1217
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1219 timeout = -1; /* no response expected */
1220 pSMB->Timeout = 0;
1221 } else if (waitFlag == TRUE) {
1222 timeout = 3; /* blocking operation, no timeout */
1223 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1224 } else {
1225 pSMB->Timeout = 0;
1226 }
1227
1228 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1229 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1230 pSMB->LockType = lockType;
1231 pSMB->AndXCommand = 0xFF; /* none */
1232 pSMB->Fid = smb_file_id; /* netfid stays le */
1233
1234 if((numLock != 0) || (numUnlock != 0)) {
1235 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1236 /* BB where to store pid high? */
1237 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1238 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1239 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1240 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1241 count = sizeof(LOCKING_ANDX_RANGE);
1242 } else {
1243 /* oplock break */
1244 count = 0;
1245 }
1246 pSMB->hdr.smb_buf_length += count;
1247 pSMB->ByteCount = cpu_to_le16(count);
1248
1249 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1250 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha45443472005-08-24 13:59:35 -07001251 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 if (rc) {
1253 cFYI(1, ("Send error in Lock = %d", rc));
1254 }
Steve French46810cb2005-04-28 22:41:09 -07001255 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256
1257 /* Note: On -EAGAIN error only caller can retry on handle based calls
1258 since file handle passed in no longer valid */
1259 return rc;
1260}
1261
1262int
1263CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1264{
1265 int rc = 0;
1266 CLOSE_REQ *pSMB = NULL;
1267 CLOSE_RSP *pSMBr = NULL;
1268 int bytes_returned;
1269 cFYI(1, ("In CIFSSMBClose"));
1270
1271/* do not retry on dead session on close */
1272 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1273 if(rc == -EAGAIN)
1274 return 0;
1275 if (rc)
1276 return rc;
1277
1278 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1279
1280 pSMB->FileID = (__u16) smb_file_id;
1281 pSMB->LastWriteTime = 0;
1282 pSMB->ByteCount = 0;
1283 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1284 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001285 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 if (rc) {
1287 if(rc!=-EINTR) {
1288 /* EINTR is expected when user ctl-c to kill app */
1289 cERROR(1, ("Send error in Close = %d", rc));
1290 }
1291 }
1292
1293 cifs_small_buf_release(pSMB);
1294
1295 /* Since session is dead, file will be closed on server already */
1296 if(rc == -EAGAIN)
1297 rc = 0;
1298
1299 return rc;
1300}
1301
1302int
1303CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1304 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001305 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306{
1307 int rc = 0;
1308 RENAME_REQ *pSMB = NULL;
1309 RENAME_RSP *pSMBr = NULL;
1310 int bytes_returned;
1311 int name_len, name_len2;
1312 __u16 count;
1313
1314 cFYI(1, ("In CIFSSMBRename"));
1315renameRetry:
1316 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1317 (void **) &pSMBr);
1318 if (rc)
1319 return rc;
1320
1321 pSMB->BufferFormat = 0x04;
1322 pSMB->SearchAttributes =
1323 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1324 ATTR_DIRECTORY);
1325
1326 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1327 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001328 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001329 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 name_len++; /* trailing null */
1331 name_len *= 2;
1332 pSMB->OldFileName[name_len] = 0x04; /* pad */
1333 /* protocol requires ASCII signature byte on Unicode string */
1334 pSMB->OldFileName[name_len + 1] = 0x00;
1335 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001336 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001337 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1339 name_len2 *= 2; /* convert to bytes */
1340 } else { /* BB improve the check for buffer overruns BB */
1341 name_len = strnlen(fromName, PATH_MAX);
1342 name_len++; /* trailing null */
1343 strncpy(pSMB->OldFileName, fromName, name_len);
1344 name_len2 = strnlen(toName, PATH_MAX);
1345 name_len2++; /* trailing null */
1346 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1347 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1348 name_len2++; /* trailing null */
1349 name_len2++; /* signature byte */
1350 }
1351
1352 count = 1 /* 1st signature byte */ + name_len + name_len2;
1353 pSMB->hdr.smb_buf_length += count;
1354 pSMB->ByteCount = cpu_to_le16(count);
1355
1356 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1357 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001358 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001359 if (rc) {
1360 cFYI(1, ("Send error in rename = %d", rc));
1361 }
1362
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 cifs_buf_release(pSMB);
1364
1365 if (rc == -EAGAIN)
1366 goto renameRetry;
1367
1368 return rc;
1369}
1370
1371int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001372 int netfid, char * target_name,
1373 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374{
1375 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1376 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1377 struct set_file_rename * rename_info;
1378 char *data_offset;
1379 char dummy_string[30];
1380 int rc = 0;
1381 int bytes_returned = 0;
1382 int len_of_str;
1383 __u16 params, param_offset, offset, count, byte_count;
1384
1385 cFYI(1, ("Rename to File by handle"));
1386 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1387 (void **) &pSMBr);
1388 if (rc)
1389 return rc;
1390
1391 params = 6;
1392 pSMB->MaxSetupCount = 0;
1393 pSMB->Reserved = 0;
1394 pSMB->Flags = 0;
1395 pSMB->Timeout = 0;
1396 pSMB->Reserved2 = 0;
1397 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1398 offset = param_offset + params;
1399
1400 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1401 rename_info = (struct set_file_rename *) data_offset;
1402 pSMB->MaxParameterCount = cpu_to_le16(2);
1403 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1404 pSMB->SetupCount = 1;
1405 pSMB->Reserved3 = 0;
1406 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1407 byte_count = 3 /* pad */ + params;
1408 pSMB->ParameterCount = cpu_to_le16(params);
1409 pSMB->TotalParameterCount = pSMB->ParameterCount;
1410 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1411 pSMB->DataOffset = cpu_to_le16(offset);
1412 /* construct random name ".cifs_tmp<inodenum><mid>" */
1413 rename_info->overwrite = cpu_to_le32(1);
1414 rename_info->root_fid = 0;
1415 /* unicode only call */
1416 if(target_name == NULL) {
1417 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001418 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001419 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001421 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001422 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423 }
1424 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1425 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1426 byte_count += count;
1427 pSMB->DataCount = cpu_to_le16(count);
1428 pSMB->TotalDataCount = pSMB->DataCount;
1429 pSMB->Fid = netfid;
1430 pSMB->InformationLevel =
1431 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1432 pSMB->Reserved4 = 0;
1433 pSMB->hdr.smb_buf_length += byte_count;
1434 pSMB->ByteCount = cpu_to_le16(byte_count);
1435 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1436 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001437 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 if (rc) {
1439 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1440 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001441
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 cifs_buf_release(pSMB);
1443
1444 /* Note: On -EAGAIN error only caller can retry on handle based calls
1445 since file handle passed in no longer valid */
1446
1447 return rc;
1448}
1449
1450int
1451CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1452 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001453 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454{
1455 int rc = 0;
1456 COPY_REQ *pSMB = NULL;
1457 COPY_RSP *pSMBr = NULL;
1458 int bytes_returned;
1459 int name_len, name_len2;
1460 __u16 count;
1461
1462 cFYI(1, ("In CIFSSMBCopy"));
1463copyRetry:
1464 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1465 (void **) &pSMBr);
1466 if (rc)
1467 return rc;
1468
1469 pSMB->BufferFormat = 0x04;
1470 pSMB->Tid2 = target_tid;
1471
1472 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1473
1474 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001475 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001476 fromName, PATH_MAX, nls_codepage,
1477 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478 name_len++; /* trailing null */
1479 name_len *= 2;
1480 pSMB->OldFileName[name_len] = 0x04; /* pad */
1481 /* protocol requires ASCII signature byte on Unicode string */
1482 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001483 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001484 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1486 name_len2 *= 2; /* convert to bytes */
1487 } else { /* BB improve the check for buffer overruns BB */
1488 name_len = strnlen(fromName, PATH_MAX);
1489 name_len++; /* trailing null */
1490 strncpy(pSMB->OldFileName, fromName, name_len);
1491 name_len2 = strnlen(toName, PATH_MAX);
1492 name_len2++; /* trailing null */
1493 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1494 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1495 name_len2++; /* trailing null */
1496 name_len2++; /* signature byte */
1497 }
1498
1499 count = 1 /* 1st signature byte */ + name_len + name_len2;
1500 pSMB->hdr.smb_buf_length += count;
1501 pSMB->ByteCount = cpu_to_le16(count);
1502
1503 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1504 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1505 if (rc) {
1506 cFYI(1, ("Send error in copy = %d with %d files copied",
1507 rc, le16_to_cpu(pSMBr->CopyCount)));
1508 }
1509 if (pSMB)
1510 cifs_buf_release(pSMB);
1511
1512 if (rc == -EAGAIN)
1513 goto copyRetry;
1514
1515 return rc;
1516}
1517
1518int
1519CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1520 const char *fromName, const char *toName,
1521 const struct nls_table *nls_codepage)
1522{
1523 TRANSACTION2_SPI_REQ *pSMB = NULL;
1524 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1525 char *data_offset;
1526 int name_len;
1527 int name_len_target;
1528 int rc = 0;
1529 int bytes_returned = 0;
1530 __u16 params, param_offset, offset, byte_count;
1531
1532 cFYI(1, ("In Symlink Unix style"));
1533createSymLinkRetry:
1534 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1535 (void **) &pSMBr);
1536 if (rc)
1537 return rc;
1538
1539 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1540 name_len =
1541 cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
1542 /* find define for this maxpathcomponent */
1543 , nls_codepage);
1544 name_len++; /* trailing null */
1545 name_len *= 2;
1546
1547 } else { /* BB improve the check for buffer overruns BB */
1548 name_len = strnlen(fromName, PATH_MAX);
1549 name_len++; /* trailing null */
1550 strncpy(pSMB->FileName, fromName, name_len);
1551 }
1552 params = 6 + name_len;
1553 pSMB->MaxSetupCount = 0;
1554 pSMB->Reserved = 0;
1555 pSMB->Flags = 0;
1556 pSMB->Timeout = 0;
1557 pSMB->Reserved2 = 0;
1558 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1559 InformationLevel) - 4;
1560 offset = param_offset + params;
1561
1562 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1563 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1564 name_len_target =
1565 cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
1566 /* find define for this maxpathcomponent */
1567 , nls_codepage);
1568 name_len_target++; /* trailing null */
1569 name_len_target *= 2;
1570 } else { /* BB improve the check for buffer overruns BB */
1571 name_len_target = strnlen(toName, PATH_MAX);
1572 name_len_target++; /* trailing null */
1573 strncpy(data_offset, toName, name_len_target);
1574 }
1575
1576 pSMB->MaxParameterCount = cpu_to_le16(2);
1577 /* BB find exact max on data count below from sess */
1578 pSMB->MaxDataCount = cpu_to_le16(1000);
1579 pSMB->SetupCount = 1;
1580 pSMB->Reserved3 = 0;
1581 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1582 byte_count = 3 /* pad */ + params + name_len_target;
1583 pSMB->DataCount = cpu_to_le16(name_len_target);
1584 pSMB->ParameterCount = cpu_to_le16(params);
1585 pSMB->TotalDataCount = pSMB->DataCount;
1586 pSMB->TotalParameterCount = pSMB->ParameterCount;
1587 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1588 pSMB->DataOffset = cpu_to_le16(offset);
1589 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1590 pSMB->Reserved4 = 0;
1591 pSMB->hdr.smb_buf_length += byte_count;
1592 pSMB->ByteCount = cpu_to_le16(byte_count);
1593 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1594 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001595 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 if (rc) {
1597 cFYI(1,
1598 ("Send error in SetPathInfo (create symlink) = %d",
1599 rc));
1600 }
1601
1602 if (pSMB)
1603 cifs_buf_release(pSMB);
1604
1605 if (rc == -EAGAIN)
1606 goto createSymLinkRetry;
1607
1608 return rc;
1609}
1610
1611int
1612CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1613 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001614 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615{
1616 TRANSACTION2_SPI_REQ *pSMB = NULL;
1617 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1618 char *data_offset;
1619 int name_len;
1620 int name_len_target;
1621 int rc = 0;
1622 int bytes_returned = 0;
1623 __u16 params, param_offset, offset, byte_count;
1624
1625 cFYI(1, ("In Create Hard link Unix style"));
1626createHardLinkRetry:
1627 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1628 (void **) &pSMBr);
1629 if (rc)
1630 return rc;
1631
1632 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001633 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001634 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 name_len++; /* trailing null */
1636 name_len *= 2;
1637
1638 } else { /* BB improve the check for buffer overruns BB */
1639 name_len = strnlen(toName, PATH_MAX);
1640 name_len++; /* trailing null */
1641 strncpy(pSMB->FileName, toName, name_len);
1642 }
1643 params = 6 + name_len;
1644 pSMB->MaxSetupCount = 0;
1645 pSMB->Reserved = 0;
1646 pSMB->Flags = 0;
1647 pSMB->Timeout = 0;
1648 pSMB->Reserved2 = 0;
1649 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1650 InformationLevel) - 4;
1651 offset = param_offset + params;
1652
1653 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1654 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1655 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001656 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001657 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 name_len_target++; /* trailing null */
1659 name_len_target *= 2;
1660 } else { /* BB improve the check for buffer overruns BB */
1661 name_len_target = strnlen(fromName, PATH_MAX);
1662 name_len_target++; /* trailing null */
1663 strncpy(data_offset, fromName, name_len_target);
1664 }
1665
1666 pSMB->MaxParameterCount = cpu_to_le16(2);
1667 /* BB find exact max on data count below from sess*/
1668 pSMB->MaxDataCount = cpu_to_le16(1000);
1669 pSMB->SetupCount = 1;
1670 pSMB->Reserved3 = 0;
1671 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1672 byte_count = 3 /* pad */ + params + name_len_target;
1673 pSMB->ParameterCount = cpu_to_le16(params);
1674 pSMB->TotalParameterCount = pSMB->ParameterCount;
1675 pSMB->DataCount = cpu_to_le16(name_len_target);
1676 pSMB->TotalDataCount = pSMB->DataCount;
1677 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1678 pSMB->DataOffset = cpu_to_le16(offset);
1679 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1680 pSMB->Reserved4 = 0;
1681 pSMB->hdr.smb_buf_length += byte_count;
1682 pSMB->ByteCount = cpu_to_le16(byte_count);
1683 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1684 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001685 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 if (rc) {
1687 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1688 }
1689
1690 cifs_buf_release(pSMB);
1691 if (rc == -EAGAIN)
1692 goto createHardLinkRetry;
1693
1694 return rc;
1695}
1696
1697int
1698CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1699 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001700 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701{
1702 int rc = 0;
1703 NT_RENAME_REQ *pSMB = NULL;
1704 RENAME_RSP *pSMBr = NULL;
1705 int bytes_returned;
1706 int name_len, name_len2;
1707 __u16 count;
1708
1709 cFYI(1, ("In CIFSCreateHardLink"));
1710winCreateHardLinkRetry:
1711
1712 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1713 (void **) &pSMBr);
1714 if (rc)
1715 return rc;
1716
1717 pSMB->SearchAttributes =
1718 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1719 ATTR_DIRECTORY);
1720 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1721 pSMB->ClusterCount = 0;
1722
1723 pSMB->BufferFormat = 0x04;
1724
1725 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1726 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001727 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001728 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 name_len++; /* trailing null */
1730 name_len *= 2;
1731 pSMB->OldFileName[name_len] = 0; /* pad */
1732 pSMB->OldFileName[name_len + 1] = 0x04;
1733 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001734 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001735 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1737 name_len2 *= 2; /* convert to bytes */
1738 } else { /* BB improve the check for buffer overruns BB */
1739 name_len = strnlen(fromName, PATH_MAX);
1740 name_len++; /* trailing null */
1741 strncpy(pSMB->OldFileName, fromName, name_len);
1742 name_len2 = strnlen(toName, PATH_MAX);
1743 name_len2++; /* trailing null */
1744 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1745 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1746 name_len2++; /* trailing null */
1747 name_len2++; /* signature byte */
1748 }
1749
1750 count = 1 /* string type byte */ + name_len + name_len2;
1751 pSMB->hdr.smb_buf_length += count;
1752 pSMB->ByteCount = cpu_to_le16(count);
1753
1754 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1755 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001756 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 if (rc) {
1758 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1759 }
1760 cifs_buf_release(pSMB);
1761 if (rc == -EAGAIN)
1762 goto winCreateHardLinkRetry;
1763
1764 return rc;
1765}
1766
1767int
1768CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1769 const unsigned char *searchName,
1770 char *symlinkinfo, const int buflen,
1771 const struct nls_table *nls_codepage)
1772{
1773/* SMB_QUERY_FILE_UNIX_LINK */
1774 TRANSACTION2_QPI_REQ *pSMB = NULL;
1775 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1776 int rc = 0;
1777 int bytes_returned;
1778 int name_len;
1779 __u16 params, byte_count;
1780
1781 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1782
1783querySymLinkRetry:
1784 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1785 (void **) &pSMBr);
1786 if (rc)
1787 return rc;
1788
1789 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1790 name_len =
1791 cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1792 /* find define for this maxpathcomponent */
1793 , nls_codepage);
1794 name_len++; /* trailing null */
1795 name_len *= 2;
1796 } else { /* BB improve the check for buffer overruns BB */
1797 name_len = strnlen(searchName, PATH_MAX);
1798 name_len++; /* trailing null */
1799 strncpy(pSMB->FileName, searchName, name_len);
1800 }
1801
1802 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1803 pSMB->TotalDataCount = 0;
1804 pSMB->MaxParameterCount = cpu_to_le16(2);
1805 /* BB find exact max data count below from sess structure BB */
1806 pSMB->MaxDataCount = cpu_to_le16(4000);
1807 pSMB->MaxSetupCount = 0;
1808 pSMB->Reserved = 0;
1809 pSMB->Flags = 0;
1810 pSMB->Timeout = 0;
1811 pSMB->Reserved2 = 0;
1812 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1813 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1814 pSMB->DataCount = 0;
1815 pSMB->DataOffset = 0;
1816 pSMB->SetupCount = 1;
1817 pSMB->Reserved3 = 0;
1818 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1819 byte_count = params + 1 /* pad */ ;
1820 pSMB->TotalParameterCount = cpu_to_le16(params);
1821 pSMB->ParameterCount = pSMB->TotalParameterCount;
1822 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1823 pSMB->Reserved4 = 0;
1824 pSMB->hdr.smb_buf_length += byte_count;
1825 pSMB->ByteCount = cpu_to_le16(byte_count);
1826
1827 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1828 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1829 if (rc) {
1830 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1831 } else {
1832 /* decode response */
1833
1834 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1835 if (rc || (pSMBr->ByteCount < 2))
1836 /* BB also check enough total bytes returned */
1837 rc = -EIO; /* bad smb */
1838 else {
1839 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1840 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1841
1842 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1843 name_len = UniStrnlen((wchar_t *) ((char *)
1844 &pSMBr->hdr.Protocol +data_offset),
1845 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07001846 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 cifs_strfromUCS_le(symlinkinfo,
1848 (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1849 data_offset),
1850 name_len, nls_codepage);
1851 } else {
1852 strncpy(symlinkinfo,
1853 (char *) &pSMBr->hdr.Protocol +
1854 data_offset,
1855 min_t(const int, buflen, count));
1856 }
1857 symlinkinfo[buflen] = 0;
1858 /* just in case so calling code does not go off the end of buffer */
1859 }
1860 }
1861 cifs_buf_release(pSMB);
1862 if (rc == -EAGAIN)
1863 goto querySymLinkRetry;
1864 return rc;
1865}
1866
1867int
1868CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1869 const unsigned char *searchName,
1870 char *symlinkinfo, const int buflen,__u16 fid,
1871 const struct nls_table *nls_codepage)
1872{
1873 int rc = 0;
1874 int bytes_returned;
1875 int name_len;
1876 struct smb_com_transaction_ioctl_req * pSMB;
1877 struct smb_com_transaction_ioctl_rsp * pSMBr;
1878
1879 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1880 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1881 (void **) &pSMBr);
1882 if (rc)
1883 return rc;
1884
1885 pSMB->TotalParameterCount = 0 ;
1886 pSMB->TotalDataCount = 0;
1887 pSMB->MaxParameterCount = cpu_to_le32(2);
1888 /* BB find exact data count max from sess structure BB */
1889 pSMB->MaxDataCount = cpu_to_le32(4000);
1890 pSMB->MaxSetupCount = 4;
1891 pSMB->Reserved = 0;
1892 pSMB->ParameterOffset = 0;
1893 pSMB->DataCount = 0;
1894 pSMB->DataOffset = 0;
1895 pSMB->SetupCount = 4;
1896 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1897 pSMB->ParameterCount = pSMB->TotalParameterCount;
1898 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1899 pSMB->IsFsctl = 1; /* FSCTL */
1900 pSMB->IsRootFlag = 0;
1901 pSMB->Fid = fid; /* file handle always le */
1902 pSMB->ByteCount = 0;
1903
1904 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1905 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1906 if (rc) {
1907 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1908 } else { /* decode response */
1909 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1910 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1911 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1912 /* BB also check enough total bytes returned */
1913 rc = -EIO; /* bad smb */
1914 else {
1915 if(data_count && (data_count < 2048)) {
1916 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1917
1918 struct reparse_data * reparse_buf = (struct reparse_data *)
1919 ((char *)&pSMBr->hdr.Protocol + data_offset);
1920 if((char*)reparse_buf >= end_of_smb) {
1921 rc = -EIO;
1922 goto qreparse_out;
1923 }
1924 if((reparse_buf->LinkNamesBuf +
1925 reparse_buf->TargetNameOffset +
1926 reparse_buf->TargetNameLen) >
1927 end_of_smb) {
1928 cFYI(1,("reparse buf extended beyond SMB"));
1929 rc = -EIO;
1930 goto qreparse_out;
1931 }
1932
1933 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1934 name_len = UniStrnlen((wchar_t *)
1935 (reparse_buf->LinkNamesBuf +
1936 reparse_buf->TargetNameOffset),
1937 min(buflen/2, reparse_buf->TargetNameLen / 2));
1938 cifs_strfromUCS_le(symlinkinfo,
1939 (wchar_t *) (reparse_buf->LinkNamesBuf +
1940 reparse_buf->TargetNameOffset),
1941 name_len, nls_codepage);
1942 } else { /* ASCII names */
1943 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
1944 reparse_buf->TargetNameOffset,
1945 min_t(const int, buflen, reparse_buf->TargetNameLen));
1946 }
1947 } else {
1948 rc = -EIO;
1949 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1950 }
1951 symlinkinfo[buflen] = 0; /* just in case so the caller
1952 does not go off the end of the buffer */
1953 cFYI(1,("readlink result - %s ",symlinkinfo));
1954 }
1955 }
1956qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07001957 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958
1959 /* Note: On -EAGAIN error only caller can retry on handle based calls
1960 since file handle passed in no longer valid */
1961
1962 return rc;
1963}
1964
1965#ifdef CONFIG_CIFS_POSIX
1966
1967/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
1968static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
1969{
1970 /* u8 cifs fields do not need le conversion */
1971 ace->e_perm = (__u16)cifs_ace->cifs_e_perm;
1972 ace->e_tag = (__u16)cifs_ace->cifs_e_tag;
1973 ace->e_id = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
1974 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
1975
1976 return;
1977}
1978
1979/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07001980static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
1981 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982{
1983 int size = 0;
1984 int i;
1985 __u16 count;
1986 struct cifs_posix_ace * pACE;
1987 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
1988 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
1989
1990 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
1991 return -EOPNOTSUPP;
1992
1993 if(acl_type & ACL_TYPE_ACCESS) {
1994 count = le16_to_cpu(cifs_acl->access_entry_count);
1995 pACE = &cifs_acl->ace_array[0];
1996 size = sizeof(struct cifs_posix_acl);
1997 size += sizeof(struct cifs_posix_ace) * count;
1998 /* check if we would go beyond end of SMB */
1999 if(size_of_data_area < size) {
2000 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2001 return -EINVAL;
2002 }
2003 } else if(acl_type & ACL_TYPE_DEFAULT) {
2004 count = le16_to_cpu(cifs_acl->access_entry_count);
2005 size = sizeof(struct cifs_posix_acl);
2006 size += sizeof(struct cifs_posix_ace) * count;
2007/* skip past access ACEs to get to default ACEs */
2008 pACE = &cifs_acl->ace_array[count];
2009 count = le16_to_cpu(cifs_acl->default_entry_count);
2010 size += sizeof(struct cifs_posix_ace) * count;
2011 /* check if we would go beyond end of SMB */
2012 if(size_of_data_area < size)
2013 return -EINVAL;
2014 } else {
2015 /* illegal type */
2016 return -EINVAL;
2017 }
2018
2019 size = posix_acl_xattr_size(count);
2020 if((buflen == 0) || (local_acl == NULL)) {
2021 /* used to query ACL EA size */
2022 } else if(size > buflen) {
2023 return -ERANGE;
2024 } else /* buffer big enough */ {
2025 local_acl->a_version = POSIX_ACL_XATTR_VERSION;
2026 for(i = 0;i < count ;i++) {
2027 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2028 pACE ++;
2029 }
2030 }
2031 return size;
2032}
2033
2034static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2035 const posix_acl_xattr_entry * local_ace)
2036{
2037 __u16 rc = 0; /* 0 = ACL converted ok */
2038
2039 cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
2040 cifs_ace->cifs_e_tag = (__u8)cpu_to_le16(local_ace->e_tag);
2041 /* BB is there a better way to handle the large uid? */
2042 if(local_ace->e_id == -1) {
2043 /* Probably no need to le convert -1 on any arch but can not hurt */
2044 cifs_ace->cifs_uid = cpu_to_le64(-1);
2045 } else
2046 cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
2047 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2048 return rc;
2049}
2050
2051/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2052static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2053 const int acl_type)
2054{
2055 __u16 rc = 0;
2056 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2057 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2058 int count;
2059 int i;
2060
2061 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2062 return 0;
2063
2064 count = posix_acl_xattr_count((size_t)buflen);
2065 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2066 count,buflen,local_acl->a_version));
2067 if(local_acl->a_version != 2) {
2068 cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
2069 return 0;
2070 }
2071 cifs_acl->version = cpu_to_le16(1);
2072 if(acl_type == ACL_TYPE_ACCESS)
2073 cifs_acl->access_entry_count = count;
2074 else if(acl_type == ACL_TYPE_DEFAULT)
2075 cifs_acl->default_entry_count = count;
2076 else {
2077 cFYI(1,("unknown ACL type %d",acl_type));
2078 return 0;
2079 }
2080 for(i=0;i<count;i++) {
2081 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2082 &local_acl->a_entries[i]);
2083 if(rc != 0) {
2084 /* ACE not converted */
2085 break;
2086 }
2087 }
2088 if(rc == 0) {
2089 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2090 rc += sizeof(struct cifs_posix_acl);
2091 /* BB add check to make sure ACL does not overflow SMB */
2092 }
2093 return rc;
2094}
2095
2096int
2097CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2098 const unsigned char *searchName,
2099 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002100 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101{
2102/* SMB_QUERY_POSIX_ACL */
2103 TRANSACTION2_QPI_REQ *pSMB = NULL;
2104 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2105 int rc = 0;
2106 int bytes_returned;
2107 int name_len;
2108 __u16 params, byte_count;
2109
2110 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2111
2112queryAclRetry:
2113 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2114 (void **) &pSMBr);
2115 if (rc)
2116 return rc;
2117
2118 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2119 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002120 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002121 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 name_len++; /* trailing null */
2123 name_len *= 2;
2124 pSMB->FileName[name_len] = 0;
2125 pSMB->FileName[name_len+1] = 0;
2126 } else { /* BB improve the check for buffer overruns BB */
2127 name_len = strnlen(searchName, PATH_MAX);
2128 name_len++; /* trailing null */
2129 strncpy(pSMB->FileName, searchName, name_len);
2130 }
2131
2132 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2133 pSMB->TotalDataCount = 0;
2134 pSMB->MaxParameterCount = cpu_to_le16(2);
2135 /* BB find exact max data count below from sess structure BB */
2136 pSMB->MaxDataCount = cpu_to_le16(4000);
2137 pSMB->MaxSetupCount = 0;
2138 pSMB->Reserved = 0;
2139 pSMB->Flags = 0;
2140 pSMB->Timeout = 0;
2141 pSMB->Reserved2 = 0;
2142 pSMB->ParameterOffset = cpu_to_le16(
2143 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2144 pSMB->DataCount = 0;
2145 pSMB->DataOffset = 0;
2146 pSMB->SetupCount = 1;
2147 pSMB->Reserved3 = 0;
2148 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2149 byte_count = params + 1 /* pad */ ;
2150 pSMB->TotalParameterCount = cpu_to_le16(params);
2151 pSMB->ParameterCount = pSMB->TotalParameterCount;
2152 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2153 pSMB->Reserved4 = 0;
2154 pSMB->hdr.smb_buf_length += byte_count;
2155 pSMB->ByteCount = cpu_to_le16(byte_count);
2156
2157 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2158 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2159 if (rc) {
2160 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2161 } else {
2162 /* decode response */
2163
2164 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2165 if (rc || (pSMBr->ByteCount < 2))
2166 /* BB also check enough total bytes returned */
2167 rc = -EIO; /* bad smb */
2168 else {
2169 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2170 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2171 rc = cifs_copy_posix_acl(acl_inf,
2172 (char *)&pSMBr->hdr.Protocol+data_offset,
2173 buflen,acl_type,count);
2174 }
2175 }
2176 cifs_buf_release(pSMB);
2177 if (rc == -EAGAIN)
2178 goto queryAclRetry;
2179 return rc;
2180}
2181
2182int
2183CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2184 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002185 const char *local_acl, const int buflen,
2186 const int acl_type,
2187 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002188{
2189 struct smb_com_transaction2_spi_req *pSMB = NULL;
2190 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2191 char *parm_data;
2192 int name_len;
2193 int rc = 0;
2194 int bytes_returned = 0;
2195 __u16 params, byte_count, data_count, param_offset, offset;
2196
2197 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2198setAclRetry:
2199 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2200 (void **) &pSMBr);
2201 if (rc)
2202 return rc;
2203 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2204 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002205 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002206 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 name_len++; /* trailing null */
2208 name_len *= 2;
2209 } else { /* BB improve the check for buffer overruns BB */
2210 name_len = strnlen(fileName, PATH_MAX);
2211 name_len++; /* trailing null */
2212 strncpy(pSMB->FileName, fileName, name_len);
2213 }
2214 params = 6 + name_len;
2215 pSMB->MaxParameterCount = cpu_to_le16(2);
2216 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2217 pSMB->MaxSetupCount = 0;
2218 pSMB->Reserved = 0;
2219 pSMB->Flags = 0;
2220 pSMB->Timeout = 0;
2221 pSMB->Reserved2 = 0;
2222 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2223 InformationLevel) - 4;
2224 offset = param_offset + params;
2225 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2226 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2227
2228 /* convert to on the wire format for POSIX ACL */
2229 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2230
2231 if(data_count == 0) {
2232 rc = -EOPNOTSUPP;
2233 goto setACLerrorExit;
2234 }
2235 pSMB->DataOffset = cpu_to_le16(offset);
2236 pSMB->SetupCount = 1;
2237 pSMB->Reserved3 = 0;
2238 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2239 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2240 byte_count = 3 /* pad */ + params + data_count;
2241 pSMB->DataCount = cpu_to_le16(data_count);
2242 pSMB->TotalDataCount = pSMB->DataCount;
2243 pSMB->ParameterCount = cpu_to_le16(params);
2244 pSMB->TotalParameterCount = pSMB->ParameterCount;
2245 pSMB->Reserved4 = 0;
2246 pSMB->hdr.smb_buf_length += byte_count;
2247 pSMB->ByteCount = cpu_to_le16(byte_count);
2248 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2249 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2250 if (rc) {
2251 cFYI(1, ("Set POSIX ACL returned %d", rc));
2252 }
2253
2254setACLerrorExit:
2255 cifs_buf_release(pSMB);
2256 if (rc == -EAGAIN)
2257 goto setAclRetry;
2258 return rc;
2259}
2260
Steve Frenchf654bac2005-04-28 22:41:04 -07002261/* BB fix tabs in this function FIXME BB */
2262int
2263CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2264 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2265{
2266 int rc = 0;
2267 struct smb_t2_qfi_req *pSMB = NULL;
2268 struct smb_t2_qfi_rsp *pSMBr = NULL;
2269 int bytes_returned;
2270 __u16 params, byte_count;
2271
2272 cFYI(1,("In GetExtAttr"));
2273 if(tcon == NULL)
2274 return -ENODEV;
2275
2276GetExtAttrRetry:
2277 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2278 (void **) &pSMBr);
2279 if (rc)
2280 return rc;
2281
Steve Frenchc67593a2005-04-28 22:41:04 -07002282 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002283 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002284 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002285 /* BB find exact max data count below from sess structure BB */
2286 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2287 pSMB->t2.MaxSetupCount = 0;
2288 pSMB->t2.Reserved = 0;
2289 pSMB->t2.Flags = 0;
2290 pSMB->t2.Timeout = 0;
2291 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002292 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2293 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002294 pSMB->t2.DataCount = 0;
2295 pSMB->t2.DataOffset = 0;
2296 pSMB->t2.SetupCount = 1;
2297 pSMB->t2.Reserved3 = 0;
2298 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002299 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002300 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2301 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2302 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002303 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002304 pSMB->Fid = netfid;
2305 pSMB->hdr.smb_buf_length += byte_count;
2306 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2307
2308 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2309 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2310 if (rc) {
2311 cFYI(1, ("error %d in GetExtAttr", rc));
2312 } else {
2313 /* decode response */
2314 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2315 if (rc || (pSMBr->ByteCount < 2))
2316 /* BB also check enough total bytes returned */
2317 /* If rc should we check for EOPNOSUPP and
2318 disable the srvino flag? or in caller? */
2319 rc = -EIO; /* bad smb */
2320 else {
2321 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2322 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2323 struct file_chattr_info * pfinfo;
2324 /* BB Do we need a cast or hash here ? */
2325 if(count != 16) {
2326 cFYI(1, ("Illegal size ret in GetExtAttr"));
2327 rc = -EIO;
2328 goto GetExtAttrOut;
2329 }
2330 pfinfo = (struct file_chattr_info *)
2331 (data_offset + (char *) &pSMBr->hdr.Protocol);
2332 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2333 *pMask = le64_to_cpu(pfinfo->mask);
2334 }
2335 }
2336GetExtAttrOut:
2337 cifs_buf_release(pSMB);
2338 if (rc == -EAGAIN)
2339 goto GetExtAttrRetry;
2340 return rc;
2341}
2342
2343
2344#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345
Steve French6b8edfe2005-08-23 20:26:03 -07002346/* Legacy Query Path Information call for lookup to old servers such
2347 as Win9x/WinME */
2348int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2349 const unsigned char *searchName,
2350 FILE_ALL_INFO * pFinfo,
2351 const struct nls_table *nls_codepage, int remap)
2352{
2353 QUERY_INFORMATION_REQ * pSMB;
2354 QUERY_INFORMATION_RSP * pSMBr;
2355 int rc = 0;
2356 int bytes_returned;
2357 int name_len;
2358
2359 cFYI(1, ("In SMBQPath path %s", searchName));
2360QInfRetry:
2361 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2362 (void **) &pSMBr);
2363 if (rc)
2364 return rc;
2365
2366 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2367 name_len =
2368 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2369 PATH_MAX, nls_codepage, remap);
2370 name_len++; /* trailing null */
2371 name_len *= 2;
2372 } else {
2373 name_len = strnlen(searchName, PATH_MAX);
2374 name_len++; /* trailing null */
2375 strncpy(pSMB->FileName, searchName, name_len);
2376 }
2377 pSMB->BufferFormat = 0x04;
2378 name_len++; /* account for buffer type byte */
2379 pSMB->hdr.smb_buf_length += (__u16) name_len;
2380 pSMB->ByteCount = cpu_to_le16(name_len);
2381
2382 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2383 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2384 if (rc) {
2385 cFYI(1, ("Send error in QueryInfo = %d", rc));
2386 } else if (pFinfo) { /* decode response */
2387 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002388 pFinfo->AllocationSize =
2389 cpu_to_le64(le32_to_cpu(pSMBr->size));
2390 pFinfo->EndOfFile = pFinfo->AllocationSize;
2391 pFinfo->Attributes =
2392 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002393 } 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 Frencha45443472005-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 Frencha45443472005-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 Frencha45443472005-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 Frencha45443472005-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
Steve French20962432005-09-21 22:05:57 -07003215/* Query File System Info such as free space to old servers such as Win 9x */
3216int
3217SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3218{
3219/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3220 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3221 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3222 FILE_SYSTEM_ALLOC_INFO *response_data;
3223 int rc = 0;
3224 int bytes_returned = 0;
3225 __u16 params, byte_count;
3226
3227 cFYI(1, ("OldQFSInfo"));
3228oldQFSInfoRetry:
3229 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3230 (void **) &pSMBr);
3231 if (rc)
3232 return rc;
3233 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3234 (void **) &pSMBr);
3235 if (rc)
3236 return rc;
3237
3238 params = 2; /* level */
3239 pSMB->TotalDataCount = 0;
3240 pSMB->MaxParameterCount = cpu_to_le16(2);
3241 pSMB->MaxDataCount = cpu_to_le16(1000);
3242 pSMB->MaxSetupCount = 0;
3243 pSMB->Reserved = 0;
3244 pSMB->Flags = 0;
3245 pSMB->Timeout = 0;
3246 pSMB->Reserved2 = 0;
3247 byte_count = params + 1 /* pad */ ;
3248 pSMB->TotalParameterCount = cpu_to_le16(params);
3249 pSMB->ParameterCount = pSMB->TotalParameterCount;
3250 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3251 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3252 pSMB->DataCount = 0;
3253 pSMB->DataOffset = 0;
3254 pSMB->SetupCount = 1;
3255 pSMB->Reserved3 = 0;
3256 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3257 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3258 pSMB->hdr.smb_buf_length += byte_count;
3259 pSMB->ByteCount = cpu_to_le16(byte_count);
3260
3261 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3262 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3263 if (rc) {
3264 cFYI(1, ("Send error in QFSInfo = %d", rc));
3265 } else { /* decode response */
3266 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3267
3268 if (rc || (pSMBr->ByteCount < 18))
3269 rc = -EIO; /* bad smb */
3270 else {
3271 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3272 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3273 pSMBr->ByteCount, data_offset));
3274
3275 response_data =
3276 (FILE_SYSTEM_ALLOC_INFO *)
3277 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3278 FSData->f_bsize =
3279 le16_to_cpu(response_data->BytesPerSector) *
3280 le32_to_cpu(response_data->
3281 SectorsPerAllocationUnit);
3282 FSData->f_blocks =
3283 le32_to_cpu(response_data->TotalAllocationUnits);
3284 FSData->f_bfree = FSData->f_bavail =
3285 le32_to_cpu(response_data->FreeAllocationUnits);
3286 cFYI(1,
3287 ("Blocks: %lld Free: %lld Block size %ld",
3288 (unsigned long long)FSData->f_blocks,
3289 (unsigned long long)FSData->f_bfree,
3290 FSData->f_bsize));
3291 }
3292 }
3293 cifs_buf_release(pSMB);
3294
3295 if (rc == -EAGAIN)
3296 goto oldQFSInfoRetry;
3297
3298 return rc;
3299}
3300
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301int
Steve French737b7582005-04-28 22:41:06 -07003302CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003303{
3304/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3305 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3306 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3307 FILE_SYSTEM_INFO *response_data;
3308 int rc = 0;
3309 int bytes_returned = 0;
3310 __u16 params, byte_count;
3311
3312 cFYI(1, ("In QFSInfo"));
3313QFSInfoRetry:
3314 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3315 (void **) &pSMBr);
3316 if (rc)
3317 return rc;
3318
3319 params = 2; /* level */
3320 pSMB->TotalDataCount = 0;
3321 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003322 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 pSMB->MaxSetupCount = 0;
3324 pSMB->Reserved = 0;
3325 pSMB->Flags = 0;
3326 pSMB->Timeout = 0;
3327 pSMB->Reserved2 = 0;
3328 byte_count = params + 1 /* pad */ ;
3329 pSMB->TotalParameterCount = cpu_to_le16(params);
3330 pSMB->ParameterCount = pSMB->TotalParameterCount;
3331 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3332 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3333 pSMB->DataCount = 0;
3334 pSMB->DataOffset = 0;
3335 pSMB->SetupCount = 1;
3336 pSMB->Reserved3 = 0;
3337 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3338 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3339 pSMB->hdr.smb_buf_length += byte_count;
3340 pSMB->ByteCount = cpu_to_le16(byte_count);
3341
3342 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3343 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3344 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003345 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 } else { /* decode response */
3347 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3348
Steve French20962432005-09-21 22:05:57 -07003349 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 rc = -EIO; /* bad smb */
3351 else {
3352 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353
3354 response_data =
3355 (FILE_SYSTEM_INFO
3356 *) (((char *) &pSMBr->hdr.Protocol) +
3357 data_offset);
3358 FSData->f_bsize =
3359 le32_to_cpu(response_data->BytesPerSector) *
3360 le32_to_cpu(response_data->
3361 SectorsPerAllocationUnit);
3362 FSData->f_blocks =
3363 le64_to_cpu(response_data->TotalAllocationUnits);
3364 FSData->f_bfree = FSData->f_bavail =
3365 le64_to_cpu(response_data->FreeAllocationUnits);
3366 cFYI(1,
3367 ("Blocks: %lld Free: %lld Block size %ld",
3368 (unsigned long long)FSData->f_blocks,
3369 (unsigned long long)FSData->f_bfree,
3370 FSData->f_bsize));
3371 }
3372 }
3373 cifs_buf_release(pSMB);
3374
3375 if (rc == -EAGAIN)
3376 goto QFSInfoRetry;
3377
3378 return rc;
3379}
3380
3381int
Steve French737b7582005-04-28 22:41:06 -07003382CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383{
3384/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3385 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3386 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3387 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3388 int rc = 0;
3389 int bytes_returned = 0;
3390 __u16 params, byte_count;
3391
3392 cFYI(1, ("In QFSAttributeInfo"));
3393QFSAttributeRetry:
3394 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3395 (void **) &pSMBr);
3396 if (rc)
3397 return rc;
3398
3399 params = 2; /* level */
3400 pSMB->TotalDataCount = 0;
3401 pSMB->MaxParameterCount = cpu_to_le16(2);
3402 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3403 pSMB->MaxSetupCount = 0;
3404 pSMB->Reserved = 0;
3405 pSMB->Flags = 0;
3406 pSMB->Timeout = 0;
3407 pSMB->Reserved2 = 0;
3408 byte_count = params + 1 /* pad */ ;
3409 pSMB->TotalParameterCount = cpu_to_le16(params);
3410 pSMB->ParameterCount = pSMB->TotalParameterCount;
3411 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3412 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3413 pSMB->DataCount = 0;
3414 pSMB->DataOffset = 0;
3415 pSMB->SetupCount = 1;
3416 pSMB->Reserved3 = 0;
3417 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3418 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3419 pSMB->hdr.smb_buf_length += byte_count;
3420 pSMB->ByteCount = cpu_to_le16(byte_count);
3421
3422 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3423 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3424 if (rc) {
3425 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3426 } else { /* decode response */
3427 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3428
3429 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3430 rc = -EIO; /* bad smb */
3431 } else {
3432 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3433 response_data =
3434 (FILE_SYSTEM_ATTRIBUTE_INFO
3435 *) (((char *) &pSMBr->hdr.Protocol) +
3436 data_offset);
3437 memcpy(&tcon->fsAttrInfo, response_data,
3438 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3439 }
3440 }
3441 cifs_buf_release(pSMB);
3442
3443 if (rc == -EAGAIN)
3444 goto QFSAttributeRetry;
3445
3446 return rc;
3447}
3448
3449int
Steve French737b7582005-04-28 22:41:06 -07003450CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003451{
3452/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3453 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3454 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3455 FILE_SYSTEM_DEVICE_INFO *response_data;
3456 int rc = 0;
3457 int bytes_returned = 0;
3458 __u16 params, byte_count;
3459
3460 cFYI(1, ("In QFSDeviceInfo"));
3461QFSDeviceRetry:
3462 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3463 (void **) &pSMBr);
3464 if (rc)
3465 return rc;
3466
3467 params = 2; /* level */
3468 pSMB->TotalDataCount = 0;
3469 pSMB->MaxParameterCount = cpu_to_le16(2);
3470 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3471 pSMB->MaxSetupCount = 0;
3472 pSMB->Reserved = 0;
3473 pSMB->Flags = 0;
3474 pSMB->Timeout = 0;
3475 pSMB->Reserved2 = 0;
3476 byte_count = params + 1 /* pad */ ;
3477 pSMB->TotalParameterCount = cpu_to_le16(params);
3478 pSMB->ParameterCount = pSMB->TotalParameterCount;
3479 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3480 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3481
3482 pSMB->DataCount = 0;
3483 pSMB->DataOffset = 0;
3484 pSMB->SetupCount = 1;
3485 pSMB->Reserved3 = 0;
3486 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3487 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3488 pSMB->hdr.smb_buf_length += byte_count;
3489 pSMB->ByteCount = cpu_to_le16(byte_count);
3490
3491 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3492 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3493 if (rc) {
3494 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3495 } else { /* decode response */
3496 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3497
3498 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3499 rc = -EIO; /* bad smb */
3500 else {
3501 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3502 response_data =
Steve French737b7582005-04-28 22:41:06 -07003503 (FILE_SYSTEM_DEVICE_INFO *)
3504 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505 data_offset);
3506 memcpy(&tcon->fsDevInfo, response_data,
3507 sizeof (FILE_SYSTEM_DEVICE_INFO));
3508 }
3509 }
3510 cifs_buf_release(pSMB);
3511
3512 if (rc == -EAGAIN)
3513 goto QFSDeviceRetry;
3514
3515 return rc;
3516}
3517
3518int
Steve French737b7582005-04-28 22:41:06 -07003519CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520{
3521/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3522 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3523 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3524 FILE_SYSTEM_UNIX_INFO *response_data;
3525 int rc = 0;
3526 int bytes_returned = 0;
3527 __u16 params, byte_count;
3528
3529 cFYI(1, ("In QFSUnixInfo"));
3530QFSUnixRetry:
3531 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3532 (void **) &pSMBr);
3533 if (rc)
3534 return rc;
3535
3536 params = 2; /* level */
3537 pSMB->TotalDataCount = 0;
3538 pSMB->DataCount = 0;
3539 pSMB->DataOffset = 0;
3540 pSMB->MaxParameterCount = cpu_to_le16(2);
3541 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3542 pSMB->MaxSetupCount = 0;
3543 pSMB->Reserved = 0;
3544 pSMB->Flags = 0;
3545 pSMB->Timeout = 0;
3546 pSMB->Reserved2 = 0;
3547 byte_count = params + 1 /* pad */ ;
3548 pSMB->ParameterCount = cpu_to_le16(params);
3549 pSMB->TotalParameterCount = pSMB->ParameterCount;
3550 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3551 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3552 pSMB->SetupCount = 1;
3553 pSMB->Reserved3 = 0;
3554 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3555 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3556 pSMB->hdr.smb_buf_length += byte_count;
3557 pSMB->ByteCount = cpu_to_le16(byte_count);
3558
3559 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3560 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3561 if (rc) {
3562 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3563 } else { /* decode response */
3564 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3565
3566 if (rc || (pSMBr->ByteCount < 13)) {
3567 rc = -EIO; /* bad smb */
3568 } else {
3569 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3570 response_data =
3571 (FILE_SYSTEM_UNIX_INFO
3572 *) (((char *) &pSMBr->hdr.Protocol) +
3573 data_offset);
3574 memcpy(&tcon->fsUnixInfo, response_data,
3575 sizeof (FILE_SYSTEM_UNIX_INFO));
3576 }
3577 }
3578 cifs_buf_release(pSMB);
3579
3580 if (rc == -EAGAIN)
3581 goto QFSUnixRetry;
3582
3583
3584 return rc;
3585}
3586
Jeremy Allisonac670552005-06-22 17:26:35 -07003587int
Steve French45abc6e2005-06-23 13:42:03 -05003588CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07003589{
3590/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3591 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3592 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3593 int rc = 0;
3594 int bytes_returned = 0;
3595 __u16 params, param_offset, offset, byte_count;
3596
3597 cFYI(1, ("In SETFSUnixInfo"));
3598SETFSUnixRetry:
3599 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3600 (void **) &pSMBr);
3601 if (rc)
3602 return rc;
3603
3604 params = 4; /* 2 bytes zero followed by info level. */
3605 pSMB->MaxSetupCount = 0;
3606 pSMB->Reserved = 0;
3607 pSMB->Flags = 0;
3608 pSMB->Timeout = 0;
3609 pSMB->Reserved2 = 0;
3610 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3611 offset = param_offset + params;
3612
3613 pSMB->MaxParameterCount = cpu_to_le16(4);
3614 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3615 pSMB->SetupCount = 1;
3616 pSMB->Reserved3 = 0;
3617 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3618 byte_count = 1 /* pad */ + params + 12;
3619
3620 pSMB->DataCount = cpu_to_le16(12);
3621 pSMB->ParameterCount = cpu_to_le16(params);
3622 pSMB->TotalDataCount = pSMB->DataCount;
3623 pSMB->TotalParameterCount = pSMB->ParameterCount;
3624 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3625 pSMB->DataOffset = cpu_to_le16(offset);
3626
3627 /* Params. */
3628 pSMB->FileNum = 0;
3629 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3630
3631 /* Data. */
3632 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3633 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3634 pSMB->ClientUnixCap = cpu_to_le64(cap);
3635
3636 pSMB->hdr.smb_buf_length += byte_count;
3637 pSMB->ByteCount = cpu_to_le16(byte_count);
3638
3639 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3640 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3641 if (rc) {
3642 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3643 } else { /* decode response */
3644 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3645 if (rc) {
3646 rc = -EIO; /* bad smb */
3647 }
3648 }
3649 cifs_buf_release(pSMB);
3650
3651 if (rc == -EAGAIN)
3652 goto SETFSUnixRetry;
3653
3654 return rc;
3655}
3656
3657
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658
3659int
3660CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003661 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003662{
3663/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3664 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3665 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3666 FILE_SYSTEM_POSIX_INFO *response_data;
3667 int rc = 0;
3668 int bytes_returned = 0;
3669 __u16 params, byte_count;
3670
3671 cFYI(1, ("In QFSPosixInfo"));
3672QFSPosixRetry:
3673 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3674 (void **) &pSMBr);
3675 if (rc)
3676 return rc;
3677
3678 params = 2; /* level */
3679 pSMB->TotalDataCount = 0;
3680 pSMB->DataCount = 0;
3681 pSMB->DataOffset = 0;
3682 pSMB->MaxParameterCount = cpu_to_le16(2);
3683 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3684 pSMB->MaxSetupCount = 0;
3685 pSMB->Reserved = 0;
3686 pSMB->Flags = 0;
3687 pSMB->Timeout = 0;
3688 pSMB->Reserved2 = 0;
3689 byte_count = params + 1 /* pad */ ;
3690 pSMB->ParameterCount = cpu_to_le16(params);
3691 pSMB->TotalParameterCount = pSMB->ParameterCount;
3692 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3693 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3694 pSMB->SetupCount = 1;
3695 pSMB->Reserved3 = 0;
3696 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3697 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3698 pSMB->hdr.smb_buf_length += byte_count;
3699 pSMB->ByteCount = cpu_to_le16(byte_count);
3700
3701 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3702 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3703 if (rc) {
3704 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3705 } else { /* decode response */
3706 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3707
3708 if (rc || (pSMBr->ByteCount < 13)) {
3709 rc = -EIO; /* bad smb */
3710 } else {
3711 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3712 response_data =
3713 (FILE_SYSTEM_POSIX_INFO
3714 *) (((char *) &pSMBr->hdr.Protocol) +
3715 data_offset);
3716 FSData->f_bsize =
3717 le32_to_cpu(response_data->BlockSize);
3718 FSData->f_blocks =
3719 le64_to_cpu(response_data->TotalBlocks);
3720 FSData->f_bfree =
3721 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07003722 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 FSData->f_bavail = FSData->f_bfree;
3724 } else {
3725 FSData->f_bavail =
3726 le64_to_cpu(response_data->UserBlocksAvail);
3727 }
Steve French70ca7342005-09-22 16:32:06 -07003728 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729 FSData->f_files =
3730 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07003731 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 FSData->f_ffree =
3733 le64_to_cpu(response_data->FreeFileNodes);
3734 }
3735 }
3736 cifs_buf_release(pSMB);
3737
3738 if (rc == -EAGAIN)
3739 goto QFSPosixRetry;
3740
3741 return rc;
3742}
3743
3744
3745/* We can not use write of zero bytes trick to
3746 set file size due to need for large file support. Also note that
3747 this SetPathInfo is preferred to SetFileInfo based method in next
3748 routine which is only needed to work around a sharing violation bug
3749 in Samba which this routine can run into */
3750
3751int
3752CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07003753 __u64 size, int SetAllocation,
3754 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755{
3756 struct smb_com_transaction2_spi_req *pSMB = NULL;
3757 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3758 struct file_end_of_file_info *parm_data;
3759 int name_len;
3760 int rc = 0;
3761 int bytes_returned = 0;
3762 __u16 params, byte_count, data_count, param_offset, offset;
3763
3764 cFYI(1, ("In SetEOF"));
3765SetEOFRetry:
3766 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3767 (void **) &pSMBr);
3768 if (rc)
3769 return rc;
3770
3771 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3772 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003773 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003774 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 name_len++; /* trailing null */
3776 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07003777 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778 name_len = strnlen(fileName, PATH_MAX);
3779 name_len++; /* trailing null */
3780 strncpy(pSMB->FileName, fileName, name_len);
3781 }
3782 params = 6 + name_len;
3783 data_count = sizeof (struct file_end_of_file_info);
3784 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07003785 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786 pSMB->MaxSetupCount = 0;
3787 pSMB->Reserved = 0;
3788 pSMB->Flags = 0;
3789 pSMB->Timeout = 0;
3790 pSMB->Reserved2 = 0;
3791 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3792 InformationLevel) - 4;
3793 offset = param_offset + params;
3794 if(SetAllocation) {
3795 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3796 pSMB->InformationLevel =
3797 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3798 else
3799 pSMB->InformationLevel =
3800 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3801 } else /* Set File Size */ {
3802 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3803 pSMB->InformationLevel =
3804 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3805 else
3806 pSMB->InformationLevel =
3807 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3808 }
3809
3810 parm_data =
3811 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3812 offset);
3813 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3814 pSMB->DataOffset = cpu_to_le16(offset);
3815 pSMB->SetupCount = 1;
3816 pSMB->Reserved3 = 0;
3817 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3818 byte_count = 3 /* pad */ + params + data_count;
3819 pSMB->DataCount = cpu_to_le16(data_count);
3820 pSMB->TotalDataCount = pSMB->DataCount;
3821 pSMB->ParameterCount = cpu_to_le16(params);
3822 pSMB->TotalParameterCount = pSMB->ParameterCount;
3823 pSMB->Reserved4 = 0;
3824 pSMB->hdr.smb_buf_length += byte_count;
3825 parm_data->FileSize = cpu_to_le64(size);
3826 pSMB->ByteCount = cpu_to_le16(byte_count);
3827 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3828 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3829 if (rc) {
3830 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3831 }
3832
3833 cifs_buf_release(pSMB);
3834
3835 if (rc == -EAGAIN)
3836 goto SetEOFRetry;
3837
3838 return rc;
3839}
3840
3841int
3842CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
3843 __u16 fid, __u32 pid_of_opener, int SetAllocation)
3844{
3845 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3846 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3847 char *data_offset;
3848 struct file_end_of_file_info *parm_data;
3849 int rc = 0;
3850 int bytes_returned = 0;
3851 __u16 params, param_offset, offset, byte_count, count;
3852
3853 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3854 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07003855 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3856
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 if (rc)
3858 return rc;
3859
Steve Frenchcd634992005-04-28 22:41:10 -07003860 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3861
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3863 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3864
3865 params = 6;
3866 pSMB->MaxSetupCount = 0;
3867 pSMB->Reserved = 0;
3868 pSMB->Flags = 0;
3869 pSMB->Timeout = 0;
3870 pSMB->Reserved2 = 0;
3871 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3872 offset = param_offset + params;
3873
3874 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3875
3876 count = sizeof(struct file_end_of_file_info);
3877 pSMB->MaxParameterCount = cpu_to_le16(2);
3878 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3879 pSMB->SetupCount = 1;
3880 pSMB->Reserved3 = 0;
3881 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3882 byte_count = 3 /* pad */ + params + count;
3883 pSMB->DataCount = cpu_to_le16(count);
3884 pSMB->ParameterCount = cpu_to_le16(params);
3885 pSMB->TotalDataCount = pSMB->DataCount;
3886 pSMB->TotalParameterCount = pSMB->ParameterCount;
3887 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3888 parm_data =
3889 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3890 offset);
3891 pSMB->DataOffset = cpu_to_le16(offset);
3892 parm_data->FileSize = cpu_to_le64(size);
3893 pSMB->Fid = fid;
3894 if(SetAllocation) {
3895 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3896 pSMB->InformationLevel =
3897 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3898 else
3899 pSMB->InformationLevel =
3900 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3901 } else /* Set File Size */ {
3902 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3903 pSMB->InformationLevel =
3904 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3905 else
3906 pSMB->InformationLevel =
3907 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3908 }
3909 pSMB->Reserved4 = 0;
3910 pSMB->hdr.smb_buf_length += byte_count;
3911 pSMB->ByteCount = cpu_to_le16(byte_count);
3912 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3913 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3914 if (rc) {
3915 cFYI(1,
3916 ("Send error in SetFileInfo (SetFileSize) = %d",
3917 rc));
3918 }
3919
3920 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07003921 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922
3923 /* Note: On -EAGAIN error only caller can retry on handle based calls
3924 since file handle passed in no longer valid */
3925
3926 return rc;
3927}
3928
3929/* Some legacy servers such as NT4 require that the file times be set on
3930 an open handle, rather than by pathname - this is awkward due to
3931 potential access conflicts on the open, but it is unavoidable for these
3932 old servers since the only other choice is to go from 100 nanosecond DCE
3933 time and resort to the original setpathinfo level which takes the ancient
3934 DOS time format with 2 second granularity */
3935int
3936CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
3937 __u16 fid)
3938{
3939 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3940 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3941 char *data_offset;
3942 int rc = 0;
3943 int bytes_returned = 0;
3944 __u16 params, param_offset, offset, byte_count, count;
3945
3946 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07003947 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3948
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 if (rc)
3950 return rc;
3951
Steve Frenchcd634992005-04-28 22:41:10 -07003952 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3953
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 /* At this point there is no need to override the current pid
3955 with the pid of the opener, but that could change if we someday
3956 use an existing handle (rather than opening one on the fly) */
3957 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3958 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3959
3960 params = 6;
3961 pSMB->MaxSetupCount = 0;
3962 pSMB->Reserved = 0;
3963 pSMB->Flags = 0;
3964 pSMB->Timeout = 0;
3965 pSMB->Reserved2 = 0;
3966 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3967 offset = param_offset + params;
3968
3969 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3970
3971 count = sizeof (FILE_BASIC_INFO);
3972 pSMB->MaxParameterCount = cpu_to_le16(2);
3973 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3974 pSMB->SetupCount = 1;
3975 pSMB->Reserved3 = 0;
3976 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3977 byte_count = 3 /* pad */ + params + count;
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 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3983 pSMB->DataOffset = cpu_to_le16(offset);
3984 pSMB->Fid = fid;
3985 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3986 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3987 else
3988 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3989 pSMB->Reserved4 = 0;
3990 pSMB->hdr.smb_buf_length += byte_count;
3991 pSMB->ByteCount = cpu_to_le16(byte_count);
3992 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
3993 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3994 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3995 if (rc) {
3996 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
3997 }
3998
Steve Frenchcd634992005-04-28 22:41:10 -07003999 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000
4001 /* Note: On -EAGAIN error only caller can retry on handle based calls
4002 since file handle passed in no longer valid */
4003
4004 return rc;
4005}
4006
4007
4008int
4009CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4010 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004011 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012{
4013 TRANSACTION2_SPI_REQ *pSMB = NULL;
4014 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4015 int name_len;
4016 int rc = 0;
4017 int bytes_returned = 0;
4018 char *data_offset;
4019 __u16 params, param_offset, offset, byte_count, count;
4020
4021 cFYI(1, ("In SetTimes"));
4022
4023SetTimesRetry:
4024 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4025 (void **) &pSMBr);
4026 if (rc)
4027 return rc;
4028
4029 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4030 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004031 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004032 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 name_len++; /* trailing null */
4034 name_len *= 2;
4035 } else { /* BB improve the check for buffer overruns BB */
4036 name_len = strnlen(fileName, PATH_MAX);
4037 name_len++; /* trailing null */
4038 strncpy(pSMB->FileName, fileName, name_len);
4039 }
4040
4041 params = 6 + name_len;
4042 count = sizeof (FILE_BASIC_INFO);
4043 pSMB->MaxParameterCount = cpu_to_le16(2);
4044 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4045 pSMB->MaxSetupCount = 0;
4046 pSMB->Reserved = 0;
4047 pSMB->Flags = 0;
4048 pSMB->Timeout = 0;
4049 pSMB->Reserved2 = 0;
4050 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4051 InformationLevel) - 4;
4052 offset = param_offset + params;
4053 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4054 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4055 pSMB->DataOffset = cpu_to_le16(offset);
4056 pSMB->SetupCount = 1;
4057 pSMB->Reserved3 = 0;
4058 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4059 byte_count = 3 /* pad */ + params + count;
4060
4061 pSMB->DataCount = cpu_to_le16(count);
4062 pSMB->ParameterCount = cpu_to_le16(params);
4063 pSMB->TotalDataCount = pSMB->DataCount;
4064 pSMB->TotalParameterCount = pSMB->ParameterCount;
4065 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4066 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4067 else
4068 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4069 pSMB->Reserved4 = 0;
4070 pSMB->hdr.smb_buf_length += byte_count;
4071 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4072 pSMB->ByteCount = cpu_to_le16(byte_count);
4073 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4074 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4075 if (rc) {
4076 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4077 }
4078
4079 cifs_buf_release(pSMB);
4080
4081 if (rc == -EAGAIN)
4082 goto SetTimesRetry;
4083
4084 return rc;
4085}
4086
4087/* Can not be used to set time stamps yet (due to old DOS time format) */
4088/* Can be used to set attributes */
4089#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4090 handling it anyway and NT4 was what we thought it would be needed for
4091 Do not delete it until we prove whether needed for Win9x though */
4092int
4093CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4094 __u16 dos_attrs, const struct nls_table *nls_codepage)
4095{
4096 SETATTR_REQ *pSMB = NULL;
4097 SETATTR_RSP *pSMBr = NULL;
4098 int rc = 0;
4099 int bytes_returned;
4100 int name_len;
4101
4102 cFYI(1, ("In SetAttrLegacy"));
4103
4104SetAttrLgcyRetry:
4105 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4106 (void **) &pSMBr);
4107 if (rc)
4108 return rc;
4109
4110 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4111 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004112 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004113 PATH_MAX, nls_codepage);
4114 name_len++; /* trailing null */
4115 name_len *= 2;
4116 } else { /* BB improve the check for buffer overruns BB */
4117 name_len = strnlen(fileName, PATH_MAX);
4118 name_len++; /* trailing null */
4119 strncpy(pSMB->fileName, fileName, name_len);
4120 }
4121 pSMB->attr = cpu_to_le16(dos_attrs);
4122 pSMB->BufferFormat = 0x04;
4123 pSMB->hdr.smb_buf_length += name_len + 1;
4124 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4125 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4126 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4127 if (rc) {
4128 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4129 }
4130
4131 cifs_buf_release(pSMB);
4132
4133 if (rc == -EAGAIN)
4134 goto SetAttrLgcyRetry;
4135
4136 return rc;
4137}
4138#endif /* temporarily unneeded SetAttr legacy function */
4139
4140int
4141CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004142 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4143 dev_t device, const struct nls_table *nls_codepage,
4144 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004145{
4146 TRANSACTION2_SPI_REQ *pSMB = NULL;
4147 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4148 int name_len;
4149 int rc = 0;
4150 int bytes_returned = 0;
4151 FILE_UNIX_BASIC_INFO *data_offset;
4152 __u16 params, param_offset, offset, count, byte_count;
4153
4154 cFYI(1, ("In SetUID/GID/Mode"));
4155setPermsRetry:
4156 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4157 (void **) &pSMBr);
4158 if (rc)
4159 return rc;
4160
4161 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4162 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004163 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004164 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165 name_len++; /* trailing null */
4166 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004167 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 name_len = strnlen(fileName, PATH_MAX);
4169 name_len++; /* trailing null */
4170 strncpy(pSMB->FileName, fileName, name_len);
4171 }
4172
4173 params = 6 + name_len;
4174 count = sizeof (FILE_UNIX_BASIC_INFO);
4175 pSMB->MaxParameterCount = cpu_to_le16(2);
4176 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4177 pSMB->MaxSetupCount = 0;
4178 pSMB->Reserved = 0;
4179 pSMB->Flags = 0;
4180 pSMB->Timeout = 0;
4181 pSMB->Reserved2 = 0;
4182 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4183 InformationLevel) - 4;
4184 offset = param_offset + params;
4185 data_offset =
4186 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4187 offset);
4188 memset(data_offset, 0, count);
4189 pSMB->DataOffset = cpu_to_le16(offset);
4190 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4191 pSMB->SetupCount = 1;
4192 pSMB->Reserved3 = 0;
4193 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4194 byte_count = 3 /* pad */ + params + count;
4195 pSMB->ParameterCount = cpu_to_le16(params);
4196 pSMB->DataCount = cpu_to_le16(count);
4197 pSMB->TotalParameterCount = pSMB->ParameterCount;
4198 pSMB->TotalDataCount = pSMB->DataCount;
4199 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4200 pSMB->Reserved4 = 0;
4201 pSMB->hdr.smb_buf_length += byte_count;
4202 data_offset->Uid = cpu_to_le64(uid);
4203 data_offset->Gid = cpu_to_le64(gid);
4204 /* better to leave device as zero when it is */
4205 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4206 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4207 data_offset->Permissions = cpu_to_le64(mode);
4208
4209 if(S_ISREG(mode))
4210 data_offset->Type = cpu_to_le32(UNIX_FILE);
4211 else if(S_ISDIR(mode))
4212 data_offset->Type = cpu_to_le32(UNIX_DIR);
4213 else if(S_ISLNK(mode))
4214 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4215 else if(S_ISCHR(mode))
4216 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4217 else if(S_ISBLK(mode))
4218 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4219 else if(S_ISFIFO(mode))
4220 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4221 else if(S_ISSOCK(mode))
4222 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4223
4224
4225 pSMB->ByteCount = cpu_to_le16(byte_count);
4226 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4227 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4228 if (rc) {
4229 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4230 }
4231
4232 if (pSMB)
4233 cifs_buf_release(pSMB);
4234 if (rc == -EAGAIN)
4235 goto setPermsRetry;
4236 return rc;
4237}
4238
4239int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004240 const int notify_subdirs, const __u16 netfid,
4241 __u32 filter, struct file * pfile, int multishot,
4242 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243{
4244 int rc = 0;
4245 struct smb_com_transaction_change_notify_req * pSMB = NULL;
4246 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004247 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248 int bytes_returned;
4249
4250 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4251 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4252 (void **) &pSMBr);
4253 if (rc)
4254 return rc;
4255
4256 pSMB->TotalParameterCount = 0 ;
4257 pSMB->TotalDataCount = 0;
4258 pSMB->MaxParameterCount = cpu_to_le32(2);
4259 /* BB find exact data count max from sess structure BB */
4260 pSMB->MaxDataCount = 0; /* same in little endian or be */
4261 pSMB->MaxSetupCount = 4;
4262 pSMB->Reserved = 0;
4263 pSMB->ParameterOffset = 0;
4264 pSMB->DataCount = 0;
4265 pSMB->DataOffset = 0;
4266 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4267 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4268 pSMB->ParameterCount = pSMB->TotalParameterCount;
4269 if(notify_subdirs)
4270 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4271 pSMB->Reserved2 = 0;
4272 pSMB->CompletionFilter = cpu_to_le32(filter);
4273 pSMB->Fid = netfid; /* file handle always le */
4274 pSMB->ByteCount = 0;
4275
4276 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4277 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4278 if (rc) {
4279 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004280 } else {
4281 /* Add file to outstanding requests */
4282 dnotify_req = (struct dir_notify_req *) kmalloc(
4283 sizeof(struct dir_notify_req), GFP_KERNEL);
4284 dnotify_req->Pid = pSMB->hdr.Pid;
4285 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4286 dnotify_req->Mid = pSMB->hdr.Mid;
4287 dnotify_req->Tid = pSMB->hdr.Tid;
4288 dnotify_req->Uid = pSMB->hdr.Uid;
4289 dnotify_req->netfid = netfid;
Steve French167a2512005-08-24 20:03:11 -07004290 dnotify_req->pfile = pfile;
Steve Frenchff5dbd92005-08-24 17:10:36 -07004291 dnotify_req->filter = filter;
4292 dnotify_req->multishot = multishot;
4293 spin_lock(&GlobalMid_Lock);
4294 list_add_tail(&dnotify_req->lhead, &GlobalDnotifyReqList);
4295 spin_unlock(&GlobalMid_Lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 }
4297 cifs_buf_release(pSMB);
4298 return rc;
4299}
4300#ifdef CONFIG_CIFS_XATTR
4301ssize_t
4302CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4303 const unsigned char *searchName,
4304 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004305 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306{
4307 /* BB assumes one setup word */
4308 TRANSACTION2_QPI_REQ *pSMB = NULL;
4309 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4310 int rc = 0;
4311 int bytes_returned;
4312 int name_len;
4313 struct fea * temp_fea;
4314 char * temp_ptr;
4315 __u16 params, byte_count;
4316
4317 cFYI(1, ("In Query All EAs path %s", searchName));
4318QAllEAsRetry:
4319 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4320 (void **) &pSMBr);
4321 if (rc)
4322 return rc;
4323
4324 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4325 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004326 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004327 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 name_len++; /* trailing null */
4329 name_len *= 2;
4330 } else { /* BB improve the check for buffer overruns BB */
4331 name_len = strnlen(searchName, PATH_MAX);
4332 name_len++; /* trailing null */
4333 strncpy(pSMB->FileName, searchName, name_len);
4334 }
4335
4336 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4337 pSMB->TotalDataCount = 0;
4338 pSMB->MaxParameterCount = cpu_to_le16(2);
4339 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4340 pSMB->MaxSetupCount = 0;
4341 pSMB->Reserved = 0;
4342 pSMB->Flags = 0;
4343 pSMB->Timeout = 0;
4344 pSMB->Reserved2 = 0;
4345 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4346 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4347 pSMB->DataCount = 0;
4348 pSMB->DataOffset = 0;
4349 pSMB->SetupCount = 1;
4350 pSMB->Reserved3 = 0;
4351 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4352 byte_count = params + 1 /* pad */ ;
4353 pSMB->TotalParameterCount = cpu_to_le16(params);
4354 pSMB->ParameterCount = pSMB->TotalParameterCount;
4355 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4356 pSMB->Reserved4 = 0;
4357 pSMB->hdr.smb_buf_length += byte_count;
4358 pSMB->ByteCount = cpu_to_le16(byte_count);
4359
4360 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4361 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4362 if (rc) {
4363 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4364 } else { /* decode response */
4365 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4366
4367 /* BB also check enough total bytes returned */
4368 /* BB we need to improve the validity checking
4369 of these trans2 responses */
4370 if (rc || (pSMBr->ByteCount < 4))
4371 rc = -EIO; /* bad smb */
4372 /* else if (pFindData){
4373 memcpy((char *) pFindData,
4374 (char *) &pSMBr->hdr.Protocol +
4375 data_offset, kl);
4376 }*/ else {
4377 /* check that length of list is not more than bcc */
4378 /* check that each entry does not go beyond length
4379 of list */
4380 /* check that each element of each entry does not
4381 go beyond end of list */
4382 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4383 struct fealist * ea_response_data;
4384 rc = 0;
4385 /* validate_trans2_offsets() */
4386 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4387 ea_response_data = (struct fealist *)
4388 (((char *) &pSMBr->hdr.Protocol) +
4389 data_offset);
4390 name_len = le32_to_cpu(ea_response_data->list_len);
4391 cFYI(1,("ea length %d", name_len));
4392 if(name_len <= 8) {
4393 /* returned EA size zeroed at top of function */
4394 cFYI(1,("empty EA list returned from server"));
4395 } else {
4396 /* account for ea list len */
4397 name_len -= 4;
4398 temp_fea = ea_response_data->list;
4399 temp_ptr = (char *)temp_fea;
4400 while(name_len > 0) {
4401 __u16 value_len;
4402 name_len -= 4;
4403 temp_ptr += 4;
4404 rc += temp_fea->name_len;
4405 /* account for prefix user. and trailing null */
4406 rc = rc + 5 + 1;
4407 if(rc<(int)buf_size) {
4408 memcpy(EAData,"user.",5);
4409 EAData+=5;
4410 memcpy(EAData,temp_ptr,temp_fea->name_len);
4411 EAData+=temp_fea->name_len;
4412 /* null terminate name */
4413 *EAData = 0;
4414 EAData = EAData + 1;
4415 } else if(buf_size == 0) {
4416 /* skip copy - calc size only */
4417 } else {
4418 /* stop before overrun buffer */
4419 rc = -ERANGE;
4420 break;
4421 }
4422 name_len -= temp_fea->name_len;
4423 temp_ptr += temp_fea->name_len;
4424 /* account for trailing null */
4425 name_len--;
4426 temp_ptr++;
4427 value_len = le16_to_cpu(temp_fea->value_len);
4428 name_len -= value_len;
4429 temp_ptr += value_len;
4430 /* BB check that temp_ptr is still within smb BB*/
4431 /* no trailing null to account for in value len */
4432 /* go on to next EA */
4433 temp_fea = (struct fea *)temp_ptr;
4434 }
4435 }
4436 }
4437 }
4438 if (pSMB)
4439 cifs_buf_release(pSMB);
4440 if (rc == -EAGAIN)
4441 goto QAllEAsRetry;
4442
4443 return (ssize_t)rc;
4444}
4445
4446ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4447 const unsigned char * searchName,const unsigned char * ea_name,
4448 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004449 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450{
4451 TRANSACTION2_QPI_REQ *pSMB = NULL;
4452 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4453 int rc = 0;
4454 int bytes_returned;
4455 int name_len;
4456 struct fea * temp_fea;
4457 char * temp_ptr;
4458 __u16 params, byte_count;
4459
4460 cFYI(1, ("In Query EA path %s", searchName));
4461QEARetry:
4462 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4463 (void **) &pSMBr);
4464 if (rc)
4465 return rc;
4466
4467 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4468 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004469 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004470 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 name_len++; /* trailing null */
4472 name_len *= 2;
4473 } else { /* BB improve the check for buffer overruns BB */
4474 name_len = strnlen(searchName, PATH_MAX);
4475 name_len++; /* trailing null */
4476 strncpy(pSMB->FileName, searchName, name_len);
4477 }
4478
4479 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4480 pSMB->TotalDataCount = 0;
4481 pSMB->MaxParameterCount = cpu_to_le16(2);
4482 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4483 pSMB->MaxSetupCount = 0;
4484 pSMB->Reserved = 0;
4485 pSMB->Flags = 0;
4486 pSMB->Timeout = 0;
4487 pSMB->Reserved2 = 0;
4488 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4489 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4490 pSMB->DataCount = 0;
4491 pSMB->DataOffset = 0;
4492 pSMB->SetupCount = 1;
4493 pSMB->Reserved3 = 0;
4494 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4495 byte_count = params + 1 /* pad */ ;
4496 pSMB->TotalParameterCount = cpu_to_le16(params);
4497 pSMB->ParameterCount = pSMB->TotalParameterCount;
4498 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4499 pSMB->Reserved4 = 0;
4500 pSMB->hdr.smb_buf_length += byte_count;
4501 pSMB->ByteCount = cpu_to_le16(byte_count);
4502
4503 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4504 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4505 if (rc) {
4506 cFYI(1, ("Send error in Query EA = %d", rc));
4507 } else { /* decode response */
4508 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4509
4510 /* BB also check enough total bytes returned */
4511 /* BB we need to improve the validity checking
4512 of these trans2 responses */
4513 if (rc || (pSMBr->ByteCount < 4))
4514 rc = -EIO; /* bad smb */
4515 /* else if (pFindData){
4516 memcpy((char *) pFindData,
4517 (char *) &pSMBr->hdr.Protocol +
4518 data_offset, kl);
4519 }*/ else {
4520 /* check that length of list is not more than bcc */
4521 /* check that each entry does not go beyond length
4522 of list */
4523 /* check that each element of each entry does not
4524 go beyond end of list */
4525 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4526 struct fealist * ea_response_data;
4527 rc = -ENODATA;
4528 /* validate_trans2_offsets() */
4529 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4530 ea_response_data = (struct fealist *)
4531 (((char *) &pSMBr->hdr.Protocol) +
4532 data_offset);
4533 name_len = le32_to_cpu(ea_response_data->list_len);
4534 cFYI(1,("ea length %d", name_len));
4535 if(name_len <= 8) {
4536 /* returned EA size zeroed at top of function */
4537 cFYI(1,("empty EA list returned from server"));
4538 } else {
4539 /* account for ea list len */
4540 name_len -= 4;
4541 temp_fea = ea_response_data->list;
4542 temp_ptr = (char *)temp_fea;
4543 /* loop through checking if we have a matching
4544 name and then return the associated value */
4545 while(name_len > 0) {
4546 __u16 value_len;
4547 name_len -= 4;
4548 temp_ptr += 4;
4549 value_len = le16_to_cpu(temp_fea->value_len);
4550 /* BB validate that value_len falls within SMB,
4551 even though maximum for name_len is 255 */
4552 if(memcmp(temp_fea->name,ea_name,
4553 temp_fea->name_len) == 0) {
4554 /* found a match */
4555 rc = value_len;
4556 /* account for prefix user. and trailing null */
4557 if(rc<=(int)buf_size) {
4558 memcpy(ea_value,
4559 temp_fea->name+temp_fea->name_len+1,
4560 rc);
4561 /* ea values, unlike ea names,
4562 are not null terminated */
4563 } else if(buf_size == 0) {
4564 /* skip copy - calc size only */
4565 } else {
4566 /* stop before overrun buffer */
4567 rc = -ERANGE;
4568 }
4569 break;
4570 }
4571 name_len -= temp_fea->name_len;
4572 temp_ptr += temp_fea->name_len;
4573 /* account for trailing null */
4574 name_len--;
4575 temp_ptr++;
4576 name_len -= value_len;
4577 temp_ptr += value_len;
4578 /* no trailing null to account for in value len */
4579 /* go on to next EA */
4580 temp_fea = (struct fea *)temp_ptr;
4581 }
4582 }
4583 }
4584 }
4585 if (pSMB)
4586 cifs_buf_release(pSMB);
4587 if (rc == -EAGAIN)
4588 goto QEARetry;
4589
4590 return (ssize_t)rc;
4591}
4592
4593int
4594CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4595 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004596 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4597 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598{
4599 struct smb_com_transaction2_spi_req *pSMB = NULL;
4600 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4601 struct fealist *parm_data;
4602 int name_len;
4603 int rc = 0;
4604 int bytes_returned = 0;
4605 __u16 params, param_offset, byte_count, offset, count;
4606
4607 cFYI(1, ("In SetEA"));
4608SetEARetry:
4609 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4610 (void **) &pSMBr);
4611 if (rc)
4612 return rc;
4613
4614 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4615 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004616 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004617 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 name_len++; /* trailing null */
4619 name_len *= 2;
4620 } else { /* BB improve the check for buffer overruns BB */
4621 name_len = strnlen(fileName, PATH_MAX);
4622 name_len++; /* trailing null */
4623 strncpy(pSMB->FileName, fileName, name_len);
4624 }
4625
4626 params = 6 + name_len;
4627
4628 /* done calculating parms using name_len of file name,
4629 now use name_len to calculate length of ea name
4630 we are going to create in the inode xattrs */
4631 if(ea_name == NULL)
4632 name_len = 0;
4633 else
4634 name_len = strnlen(ea_name,255);
4635
4636 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4637 pSMB->MaxParameterCount = cpu_to_le16(2);
4638 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4639 pSMB->MaxSetupCount = 0;
4640 pSMB->Reserved = 0;
4641 pSMB->Flags = 0;
4642 pSMB->Timeout = 0;
4643 pSMB->Reserved2 = 0;
4644 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4645 InformationLevel) - 4;
4646 offset = param_offset + params;
4647 pSMB->InformationLevel =
4648 cpu_to_le16(SMB_SET_FILE_EA);
4649
4650 parm_data =
4651 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4652 offset);
4653 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4654 pSMB->DataOffset = cpu_to_le16(offset);
4655 pSMB->SetupCount = 1;
4656 pSMB->Reserved3 = 0;
4657 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4658 byte_count = 3 /* pad */ + params + count;
4659 pSMB->DataCount = cpu_to_le16(count);
4660 parm_data->list_len = cpu_to_le32(count);
4661 parm_data->list[0].EA_flags = 0;
4662 /* we checked above that name len is less than 255 */
4663 parm_data->list[0].name_len = (__u8)name_len;;
4664 /* EA names are always ASCII */
4665 if(ea_name)
4666 strncpy(parm_data->list[0].name,ea_name,name_len);
4667 parm_data->list[0].name[name_len] = 0;
4668 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4669 /* caller ensures that ea_value_len is less than 64K but
4670 we need to ensure that it fits within the smb */
4671
4672 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4673 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4674 if(ea_value_len)
4675 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4676
4677 pSMB->TotalDataCount = pSMB->DataCount;
4678 pSMB->ParameterCount = cpu_to_le16(params);
4679 pSMB->TotalParameterCount = pSMB->ParameterCount;
4680 pSMB->Reserved4 = 0;
4681 pSMB->hdr.smb_buf_length += byte_count;
4682 pSMB->ByteCount = cpu_to_le16(byte_count);
4683 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4684 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4685 if (rc) {
4686 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4687 }
4688
4689 cifs_buf_release(pSMB);
4690
4691 if (rc == -EAGAIN)
4692 goto SetEARetry;
4693
4694 return rc;
4695}
4696
4697#endif