blob: d179b0c3eee45e4bc01bd4c6e3242b38f5559a81 [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 French8cc64c62005-10-03 13:49:43 -07001142 int bytes_returned, wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001143 int smb_hdr_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
Steve Frenchff7feac2005-11-15 16:45:16 -08001145 /* BB removeme BB */
1146 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1147
Steve French8cc64c62005-10-03 13:49:43 -07001148 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1149 wct = 14;
1150 else
1151 wct = 12;
1152 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 if (rc)
1154 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 /* tcon and ses pointer are checked in smb_init */
1156 if (tcon->ses->server == NULL)
1157 return -ECONNABORTED;
1158
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001159 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 pSMB->Fid = netfid;
1161 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001162 if(wct == 14)
1163 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1164 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1165 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 pSMB->Reserved = 0xFFFFFFFF;
1167 pSMB->WriteMode = 0;
1168 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001169
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 pSMB->DataOffset =
1171 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1172
Steve French3e844692005-10-03 13:37:24 -07001173 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1174 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001175 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001176 if(wct == 14)
1177 pSMB->hdr.smb_buf_length += count+1;
1178 else /* wct == 12 */
1179 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1180 if(wct == 14)
1181 pSMB->ByteCount = cpu_to_le16(count + 1);
1182 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1183 struct smb_com_writex_req * pSMBW =
1184 (struct smb_com_writex_req *)pSMB;
1185 pSMBW->ByteCount = cpu_to_le16(count + 5);
1186 }
Steve French3e844692005-10-03 13:37:24 -07001187 iov[0].iov_base = pSMB;
1188 iov[0].iov_len = smb_hdr_len + 4;
1189
1190 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned,
1191 long_op);
Steve Frencha45443472005-08-24 13:59:35 -07001192 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001194 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001196 } else {
1197 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
1198 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1199 *nbytes = (*nbytes) << 16;
1200 *nbytes += le16_to_cpu(pSMBr->Count);
1201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202
1203 cifs_small_buf_release(pSMB);
1204
1205 /* Note: On -EAGAIN error only caller can retry on handle based calls
1206 since file handle passed in no longer valid */
1207
1208 return rc;
1209}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001210
1211
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212#endif /* CIFS_EXPERIMENTAL */
1213
1214int
1215CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1216 const __u16 smb_file_id, const __u64 len,
1217 const __u64 offset, const __u32 numUnlock,
1218 const __u32 numLock, const __u8 lockType, const int waitFlag)
1219{
1220 int rc = 0;
1221 LOCK_REQ *pSMB = NULL;
1222 LOCK_RSP *pSMBr = NULL;
1223 int bytes_returned;
1224 int timeout = 0;
1225 __u16 count;
1226
1227 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001228 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1229
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230 if (rc)
1231 return rc;
1232
Steve French46810cb2005-04-28 22:41:09 -07001233 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1234
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1236 timeout = -1; /* no response expected */
1237 pSMB->Timeout = 0;
1238 } else if (waitFlag == TRUE) {
1239 timeout = 3; /* blocking operation, no timeout */
1240 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1241 } else {
1242 pSMB->Timeout = 0;
1243 }
1244
1245 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1246 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1247 pSMB->LockType = lockType;
1248 pSMB->AndXCommand = 0xFF; /* none */
1249 pSMB->Fid = smb_file_id; /* netfid stays le */
1250
1251 if((numLock != 0) || (numUnlock != 0)) {
1252 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1253 /* BB where to store pid high? */
1254 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1255 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1256 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1257 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1258 count = sizeof(LOCKING_ANDX_RANGE);
1259 } else {
1260 /* oplock break */
1261 count = 0;
1262 }
1263 pSMB->hdr.smb_buf_length += count;
1264 pSMB->ByteCount = cpu_to_le16(count);
1265
1266 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1267 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha45443472005-08-24 13:59:35 -07001268 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 if (rc) {
1270 cFYI(1, ("Send error in Lock = %d", rc));
1271 }
Steve French46810cb2005-04-28 22:41:09 -07001272 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273
1274 /* Note: On -EAGAIN error only caller can retry on handle based calls
1275 since file handle passed in no longer valid */
1276 return rc;
1277}
1278
1279int
1280CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1281{
1282 int rc = 0;
1283 CLOSE_REQ *pSMB = NULL;
1284 CLOSE_RSP *pSMBr = NULL;
1285 int bytes_returned;
1286 cFYI(1, ("In CIFSSMBClose"));
1287
1288/* do not retry on dead session on close */
1289 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1290 if(rc == -EAGAIN)
1291 return 0;
1292 if (rc)
1293 return rc;
1294
1295 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1296
1297 pSMB->FileID = (__u16) smb_file_id;
1298 pSMB->LastWriteTime = 0;
1299 pSMB->ByteCount = 0;
1300 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1301 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001302 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 if (rc) {
1304 if(rc!=-EINTR) {
1305 /* EINTR is expected when user ctl-c to kill app */
1306 cERROR(1, ("Send error in Close = %d", rc));
1307 }
1308 }
1309
1310 cifs_small_buf_release(pSMB);
1311
1312 /* Since session is dead, file will be closed on server already */
1313 if(rc == -EAGAIN)
1314 rc = 0;
1315
1316 return rc;
1317}
1318
1319int
1320CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1321 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001322 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323{
1324 int rc = 0;
1325 RENAME_REQ *pSMB = NULL;
1326 RENAME_RSP *pSMBr = NULL;
1327 int bytes_returned;
1328 int name_len, name_len2;
1329 __u16 count;
1330
1331 cFYI(1, ("In CIFSSMBRename"));
1332renameRetry:
1333 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1334 (void **) &pSMBr);
1335 if (rc)
1336 return rc;
1337
1338 pSMB->BufferFormat = 0x04;
1339 pSMB->SearchAttributes =
1340 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1341 ATTR_DIRECTORY);
1342
1343 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1344 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001345 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001346 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 name_len++; /* trailing null */
1348 name_len *= 2;
1349 pSMB->OldFileName[name_len] = 0x04; /* pad */
1350 /* protocol requires ASCII signature byte on Unicode string */
1351 pSMB->OldFileName[name_len + 1] = 0x00;
1352 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001353 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001354 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1356 name_len2 *= 2; /* convert to bytes */
1357 } else { /* BB improve the check for buffer overruns BB */
1358 name_len = strnlen(fromName, PATH_MAX);
1359 name_len++; /* trailing null */
1360 strncpy(pSMB->OldFileName, fromName, name_len);
1361 name_len2 = strnlen(toName, PATH_MAX);
1362 name_len2++; /* trailing null */
1363 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1364 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1365 name_len2++; /* trailing null */
1366 name_len2++; /* signature byte */
1367 }
1368
1369 count = 1 /* 1st signature byte */ + name_len + name_len2;
1370 pSMB->hdr.smb_buf_length += count;
1371 pSMB->ByteCount = cpu_to_le16(count);
1372
1373 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1374 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001375 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 if (rc) {
1377 cFYI(1, ("Send error in rename = %d", rc));
1378 }
1379
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 cifs_buf_release(pSMB);
1381
1382 if (rc == -EAGAIN)
1383 goto renameRetry;
1384
1385 return rc;
1386}
1387
1388int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001389 int netfid, char * target_name,
1390 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391{
1392 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1393 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1394 struct set_file_rename * rename_info;
1395 char *data_offset;
1396 char dummy_string[30];
1397 int rc = 0;
1398 int bytes_returned = 0;
1399 int len_of_str;
1400 __u16 params, param_offset, offset, count, byte_count;
1401
1402 cFYI(1, ("Rename to File by handle"));
1403 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1404 (void **) &pSMBr);
1405 if (rc)
1406 return rc;
1407
1408 params = 6;
1409 pSMB->MaxSetupCount = 0;
1410 pSMB->Reserved = 0;
1411 pSMB->Flags = 0;
1412 pSMB->Timeout = 0;
1413 pSMB->Reserved2 = 0;
1414 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1415 offset = param_offset + params;
1416
1417 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1418 rename_info = (struct set_file_rename *) data_offset;
1419 pSMB->MaxParameterCount = cpu_to_le16(2);
1420 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1421 pSMB->SetupCount = 1;
1422 pSMB->Reserved3 = 0;
1423 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1424 byte_count = 3 /* pad */ + params;
1425 pSMB->ParameterCount = cpu_to_le16(params);
1426 pSMB->TotalParameterCount = pSMB->ParameterCount;
1427 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1428 pSMB->DataOffset = cpu_to_le16(offset);
1429 /* construct random name ".cifs_tmp<inodenum><mid>" */
1430 rename_info->overwrite = cpu_to_le32(1);
1431 rename_info->root_fid = 0;
1432 /* unicode only call */
1433 if(target_name == NULL) {
1434 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001435 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001436 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001437 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001438 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001439 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 }
1441 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1442 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1443 byte_count += count;
1444 pSMB->DataCount = cpu_to_le16(count);
1445 pSMB->TotalDataCount = pSMB->DataCount;
1446 pSMB->Fid = netfid;
1447 pSMB->InformationLevel =
1448 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1449 pSMB->Reserved4 = 0;
1450 pSMB->hdr.smb_buf_length += byte_count;
1451 pSMB->ByteCount = cpu_to_le16(byte_count);
1452 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1453 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001454 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 if (rc) {
1456 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1457 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001458
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 cifs_buf_release(pSMB);
1460
1461 /* Note: On -EAGAIN error only caller can retry on handle based calls
1462 since file handle passed in no longer valid */
1463
1464 return rc;
1465}
1466
1467int
1468CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1469 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001470 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471{
1472 int rc = 0;
1473 COPY_REQ *pSMB = NULL;
1474 COPY_RSP *pSMBr = NULL;
1475 int bytes_returned;
1476 int name_len, name_len2;
1477 __u16 count;
1478
1479 cFYI(1, ("In CIFSSMBCopy"));
1480copyRetry:
1481 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1482 (void **) &pSMBr);
1483 if (rc)
1484 return rc;
1485
1486 pSMB->BufferFormat = 0x04;
1487 pSMB->Tid2 = target_tid;
1488
1489 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1490
1491 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001492 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001493 fromName, PATH_MAX, nls_codepage,
1494 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 name_len++; /* trailing null */
1496 name_len *= 2;
1497 pSMB->OldFileName[name_len] = 0x04; /* pad */
1498 /* protocol requires ASCII signature byte on Unicode string */
1499 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001500 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001501 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1503 name_len2 *= 2; /* convert to bytes */
1504 } else { /* BB improve the check for buffer overruns BB */
1505 name_len = strnlen(fromName, PATH_MAX);
1506 name_len++; /* trailing null */
1507 strncpy(pSMB->OldFileName, fromName, name_len);
1508 name_len2 = strnlen(toName, PATH_MAX);
1509 name_len2++; /* trailing null */
1510 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1511 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1512 name_len2++; /* trailing null */
1513 name_len2++; /* signature byte */
1514 }
1515
1516 count = 1 /* 1st signature byte */ + name_len + name_len2;
1517 pSMB->hdr.smb_buf_length += count;
1518 pSMB->ByteCount = cpu_to_le16(count);
1519
1520 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1521 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1522 if (rc) {
1523 cFYI(1, ("Send error in copy = %d with %d files copied",
1524 rc, le16_to_cpu(pSMBr->CopyCount)));
1525 }
1526 if (pSMB)
1527 cifs_buf_release(pSMB);
1528
1529 if (rc == -EAGAIN)
1530 goto copyRetry;
1531
1532 return rc;
1533}
1534
1535int
1536CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1537 const char *fromName, const char *toName,
1538 const struct nls_table *nls_codepage)
1539{
1540 TRANSACTION2_SPI_REQ *pSMB = NULL;
1541 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1542 char *data_offset;
1543 int name_len;
1544 int name_len_target;
1545 int rc = 0;
1546 int bytes_returned = 0;
1547 __u16 params, param_offset, offset, byte_count;
1548
1549 cFYI(1, ("In Symlink Unix style"));
1550createSymLinkRetry:
1551 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1552 (void **) &pSMBr);
1553 if (rc)
1554 return rc;
1555
1556 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1557 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001558 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 /* find define for this maxpathcomponent */
1560 , nls_codepage);
1561 name_len++; /* trailing null */
1562 name_len *= 2;
1563
1564 } else { /* BB improve the check for buffer overruns BB */
1565 name_len = strnlen(fromName, PATH_MAX);
1566 name_len++; /* trailing null */
1567 strncpy(pSMB->FileName, fromName, name_len);
1568 }
1569 params = 6 + name_len;
1570 pSMB->MaxSetupCount = 0;
1571 pSMB->Reserved = 0;
1572 pSMB->Flags = 0;
1573 pSMB->Timeout = 0;
1574 pSMB->Reserved2 = 0;
1575 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1576 InformationLevel) - 4;
1577 offset = param_offset + params;
1578
1579 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1580 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1581 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001582 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 /* find define for this maxpathcomponent */
1584 , nls_codepage);
1585 name_len_target++; /* trailing null */
1586 name_len_target *= 2;
1587 } else { /* BB improve the check for buffer overruns BB */
1588 name_len_target = strnlen(toName, PATH_MAX);
1589 name_len_target++; /* trailing null */
1590 strncpy(data_offset, toName, name_len_target);
1591 }
1592
1593 pSMB->MaxParameterCount = cpu_to_le16(2);
1594 /* BB find exact max on data count below from sess */
1595 pSMB->MaxDataCount = cpu_to_le16(1000);
1596 pSMB->SetupCount = 1;
1597 pSMB->Reserved3 = 0;
1598 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1599 byte_count = 3 /* pad */ + params + name_len_target;
1600 pSMB->DataCount = cpu_to_le16(name_len_target);
1601 pSMB->ParameterCount = cpu_to_le16(params);
1602 pSMB->TotalDataCount = pSMB->DataCount;
1603 pSMB->TotalParameterCount = pSMB->ParameterCount;
1604 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1605 pSMB->DataOffset = cpu_to_le16(offset);
1606 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1607 pSMB->Reserved4 = 0;
1608 pSMB->hdr.smb_buf_length += byte_count;
1609 pSMB->ByteCount = cpu_to_le16(byte_count);
1610 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1611 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001612 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 if (rc) {
1614 cFYI(1,
1615 ("Send error in SetPathInfo (create symlink) = %d",
1616 rc));
1617 }
1618
1619 if (pSMB)
1620 cifs_buf_release(pSMB);
1621
1622 if (rc == -EAGAIN)
1623 goto createSymLinkRetry;
1624
1625 return rc;
1626}
1627
1628int
1629CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1630 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001631 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001632{
1633 TRANSACTION2_SPI_REQ *pSMB = NULL;
1634 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1635 char *data_offset;
1636 int name_len;
1637 int name_len_target;
1638 int rc = 0;
1639 int bytes_returned = 0;
1640 __u16 params, param_offset, offset, byte_count;
1641
1642 cFYI(1, ("In Create Hard link Unix style"));
1643createHardLinkRetry:
1644 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1645 (void **) &pSMBr);
1646 if (rc)
1647 return rc;
1648
1649 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001650 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001651 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 name_len++; /* trailing null */
1653 name_len *= 2;
1654
1655 } else { /* BB improve the check for buffer overruns BB */
1656 name_len = strnlen(toName, PATH_MAX);
1657 name_len++; /* trailing null */
1658 strncpy(pSMB->FileName, toName, name_len);
1659 }
1660 params = 6 + name_len;
1661 pSMB->MaxSetupCount = 0;
1662 pSMB->Reserved = 0;
1663 pSMB->Flags = 0;
1664 pSMB->Timeout = 0;
1665 pSMB->Reserved2 = 0;
1666 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1667 InformationLevel) - 4;
1668 offset = param_offset + params;
1669
1670 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1671 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1672 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001673 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001674 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675 name_len_target++; /* trailing null */
1676 name_len_target *= 2;
1677 } else { /* BB improve the check for buffer overruns BB */
1678 name_len_target = strnlen(fromName, PATH_MAX);
1679 name_len_target++; /* trailing null */
1680 strncpy(data_offset, fromName, name_len_target);
1681 }
1682
1683 pSMB->MaxParameterCount = cpu_to_le16(2);
1684 /* BB find exact max on data count below from sess*/
1685 pSMB->MaxDataCount = cpu_to_le16(1000);
1686 pSMB->SetupCount = 1;
1687 pSMB->Reserved3 = 0;
1688 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1689 byte_count = 3 /* pad */ + params + name_len_target;
1690 pSMB->ParameterCount = cpu_to_le16(params);
1691 pSMB->TotalParameterCount = pSMB->ParameterCount;
1692 pSMB->DataCount = cpu_to_le16(name_len_target);
1693 pSMB->TotalDataCount = pSMB->DataCount;
1694 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1695 pSMB->DataOffset = cpu_to_le16(offset);
1696 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1697 pSMB->Reserved4 = 0;
1698 pSMB->hdr.smb_buf_length += byte_count;
1699 pSMB->ByteCount = cpu_to_le16(byte_count);
1700 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1701 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001702 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 if (rc) {
1704 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1705 }
1706
1707 cifs_buf_release(pSMB);
1708 if (rc == -EAGAIN)
1709 goto createHardLinkRetry;
1710
1711 return rc;
1712}
1713
1714int
1715CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1716 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001717 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718{
1719 int rc = 0;
1720 NT_RENAME_REQ *pSMB = NULL;
1721 RENAME_RSP *pSMBr = NULL;
1722 int bytes_returned;
1723 int name_len, name_len2;
1724 __u16 count;
1725
1726 cFYI(1, ("In CIFSCreateHardLink"));
1727winCreateHardLinkRetry:
1728
1729 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1730 (void **) &pSMBr);
1731 if (rc)
1732 return rc;
1733
1734 pSMB->SearchAttributes =
1735 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1736 ATTR_DIRECTORY);
1737 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1738 pSMB->ClusterCount = 0;
1739
1740 pSMB->BufferFormat = 0x04;
1741
1742 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1743 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001744 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001745 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 name_len++; /* trailing null */
1747 name_len *= 2;
1748 pSMB->OldFileName[name_len] = 0; /* pad */
1749 pSMB->OldFileName[name_len + 1] = 0x04;
1750 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001751 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001752 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1754 name_len2 *= 2; /* convert to bytes */
1755 } else { /* BB improve the check for buffer overruns BB */
1756 name_len = strnlen(fromName, PATH_MAX);
1757 name_len++; /* trailing null */
1758 strncpy(pSMB->OldFileName, fromName, name_len);
1759 name_len2 = strnlen(toName, PATH_MAX);
1760 name_len2++; /* trailing null */
1761 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1762 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1763 name_len2++; /* trailing null */
1764 name_len2++; /* signature byte */
1765 }
1766
1767 count = 1 /* string type byte */ + name_len + name_len2;
1768 pSMB->hdr.smb_buf_length += count;
1769 pSMB->ByteCount = cpu_to_le16(count);
1770
1771 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1772 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07001773 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 if (rc) {
1775 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1776 }
1777 cifs_buf_release(pSMB);
1778 if (rc == -EAGAIN)
1779 goto winCreateHardLinkRetry;
1780
1781 return rc;
1782}
1783
1784int
1785CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1786 const unsigned char *searchName,
1787 char *symlinkinfo, const int buflen,
1788 const struct nls_table *nls_codepage)
1789{
1790/* SMB_QUERY_FILE_UNIX_LINK */
1791 TRANSACTION2_QPI_REQ *pSMB = NULL;
1792 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1793 int rc = 0;
1794 int bytes_returned;
1795 int name_len;
1796 __u16 params, byte_count;
1797
1798 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1799
1800querySymLinkRetry:
1801 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1802 (void **) &pSMBr);
1803 if (rc)
1804 return rc;
1805
1806 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1807 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001808 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809 /* find define for this maxpathcomponent */
1810 , nls_codepage);
1811 name_len++; /* trailing null */
1812 name_len *= 2;
1813 } else { /* BB improve the check for buffer overruns BB */
1814 name_len = strnlen(searchName, PATH_MAX);
1815 name_len++; /* trailing null */
1816 strncpy(pSMB->FileName, searchName, name_len);
1817 }
1818
1819 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1820 pSMB->TotalDataCount = 0;
1821 pSMB->MaxParameterCount = cpu_to_le16(2);
1822 /* BB find exact max data count below from sess structure BB */
1823 pSMB->MaxDataCount = cpu_to_le16(4000);
1824 pSMB->MaxSetupCount = 0;
1825 pSMB->Reserved = 0;
1826 pSMB->Flags = 0;
1827 pSMB->Timeout = 0;
1828 pSMB->Reserved2 = 0;
1829 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1830 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1831 pSMB->DataCount = 0;
1832 pSMB->DataOffset = 0;
1833 pSMB->SetupCount = 1;
1834 pSMB->Reserved3 = 0;
1835 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1836 byte_count = params + 1 /* pad */ ;
1837 pSMB->TotalParameterCount = cpu_to_le16(params);
1838 pSMB->ParameterCount = pSMB->TotalParameterCount;
1839 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1840 pSMB->Reserved4 = 0;
1841 pSMB->hdr.smb_buf_length += byte_count;
1842 pSMB->ByteCount = cpu_to_le16(byte_count);
1843
1844 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1845 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1846 if (rc) {
1847 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1848 } else {
1849 /* decode response */
1850
1851 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1852 if (rc || (pSMBr->ByteCount < 2))
1853 /* BB also check enough total bytes returned */
1854 rc = -EIO; /* bad smb */
1855 else {
1856 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1857 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1858
1859 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1860 name_len = UniStrnlen((wchar_t *) ((char *)
1861 &pSMBr->hdr.Protocol +data_offset),
1862 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07001863 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08001865 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001866 data_offset),
1867 name_len, nls_codepage);
1868 } else {
1869 strncpy(symlinkinfo,
1870 (char *) &pSMBr->hdr.Protocol +
1871 data_offset,
1872 min_t(const int, buflen, count));
1873 }
1874 symlinkinfo[buflen] = 0;
1875 /* just in case so calling code does not go off the end of buffer */
1876 }
1877 }
1878 cifs_buf_release(pSMB);
1879 if (rc == -EAGAIN)
1880 goto querySymLinkRetry;
1881 return rc;
1882}
1883
1884int
1885CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1886 const unsigned char *searchName,
1887 char *symlinkinfo, const int buflen,__u16 fid,
1888 const struct nls_table *nls_codepage)
1889{
1890 int rc = 0;
1891 int bytes_returned;
1892 int name_len;
1893 struct smb_com_transaction_ioctl_req * pSMB;
1894 struct smb_com_transaction_ioctl_rsp * pSMBr;
1895
1896 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1897 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1898 (void **) &pSMBr);
1899 if (rc)
1900 return rc;
1901
1902 pSMB->TotalParameterCount = 0 ;
1903 pSMB->TotalDataCount = 0;
1904 pSMB->MaxParameterCount = cpu_to_le32(2);
1905 /* BB find exact data count max from sess structure BB */
1906 pSMB->MaxDataCount = cpu_to_le32(4000);
1907 pSMB->MaxSetupCount = 4;
1908 pSMB->Reserved = 0;
1909 pSMB->ParameterOffset = 0;
1910 pSMB->DataCount = 0;
1911 pSMB->DataOffset = 0;
1912 pSMB->SetupCount = 4;
1913 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1914 pSMB->ParameterCount = pSMB->TotalParameterCount;
1915 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1916 pSMB->IsFsctl = 1; /* FSCTL */
1917 pSMB->IsRootFlag = 0;
1918 pSMB->Fid = fid; /* file handle always le */
1919 pSMB->ByteCount = 0;
1920
1921 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1922 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1923 if (rc) {
1924 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1925 } else { /* decode response */
1926 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1927 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1928 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1929 /* BB also check enough total bytes returned */
1930 rc = -EIO; /* bad smb */
1931 else {
1932 if(data_count && (data_count < 2048)) {
1933 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1934
1935 struct reparse_data * reparse_buf = (struct reparse_data *)
1936 ((char *)&pSMBr->hdr.Protocol + data_offset);
1937 if((char*)reparse_buf >= end_of_smb) {
1938 rc = -EIO;
1939 goto qreparse_out;
1940 }
1941 if((reparse_buf->LinkNamesBuf +
1942 reparse_buf->TargetNameOffset +
1943 reparse_buf->TargetNameLen) >
1944 end_of_smb) {
1945 cFYI(1,("reparse buf extended beyond SMB"));
1946 rc = -EIO;
1947 goto qreparse_out;
1948 }
1949
1950 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1951 name_len = UniStrnlen((wchar_t *)
1952 (reparse_buf->LinkNamesBuf +
1953 reparse_buf->TargetNameOffset),
1954 min(buflen/2, reparse_buf->TargetNameLen / 2));
1955 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08001956 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 reparse_buf->TargetNameOffset),
1958 name_len, nls_codepage);
1959 } else { /* ASCII names */
1960 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
1961 reparse_buf->TargetNameOffset,
1962 min_t(const int, buflen, reparse_buf->TargetNameLen));
1963 }
1964 } else {
1965 rc = -EIO;
1966 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1967 }
1968 symlinkinfo[buflen] = 0; /* just in case so the caller
1969 does not go off the end of the buffer */
1970 cFYI(1,("readlink result - %s ",symlinkinfo));
1971 }
1972 }
1973qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07001974 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975
1976 /* Note: On -EAGAIN error only caller can retry on handle based calls
1977 since file handle passed in no longer valid */
1978
1979 return rc;
1980}
1981
1982#ifdef CONFIG_CIFS_POSIX
1983
1984/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
1985static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
1986{
1987 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08001988 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
1989 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
1990 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
1992
1993 return;
1994}
1995
1996/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07001997static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
1998 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999{
2000 int size = 0;
2001 int i;
2002 __u16 count;
2003 struct cifs_posix_ace * pACE;
2004 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2005 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2006
2007 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2008 return -EOPNOTSUPP;
2009
2010 if(acl_type & ACL_TYPE_ACCESS) {
2011 count = le16_to_cpu(cifs_acl->access_entry_count);
2012 pACE = &cifs_acl->ace_array[0];
2013 size = sizeof(struct cifs_posix_acl);
2014 size += sizeof(struct cifs_posix_ace) * count;
2015 /* check if we would go beyond end of SMB */
2016 if(size_of_data_area < size) {
2017 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2018 return -EINVAL;
2019 }
2020 } else if(acl_type & ACL_TYPE_DEFAULT) {
2021 count = le16_to_cpu(cifs_acl->access_entry_count);
2022 size = sizeof(struct cifs_posix_acl);
2023 size += sizeof(struct cifs_posix_ace) * count;
2024/* skip past access ACEs to get to default ACEs */
2025 pACE = &cifs_acl->ace_array[count];
2026 count = le16_to_cpu(cifs_acl->default_entry_count);
2027 size += sizeof(struct cifs_posix_ace) * count;
2028 /* check if we would go beyond end of SMB */
2029 if(size_of_data_area < size)
2030 return -EINVAL;
2031 } else {
2032 /* illegal type */
2033 return -EINVAL;
2034 }
2035
2036 size = posix_acl_xattr_size(count);
2037 if((buflen == 0) || (local_acl == NULL)) {
2038 /* used to query ACL EA size */
2039 } else if(size > buflen) {
2040 return -ERANGE;
2041 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002042 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 for(i = 0;i < count ;i++) {
2044 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2045 pACE ++;
2046 }
2047 }
2048 return size;
2049}
2050
2051static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2052 const posix_acl_xattr_entry * local_ace)
2053{
2054 __u16 rc = 0; /* 0 = ACL converted ok */
2055
Steve Frenchff7feac2005-11-15 16:45:16 -08002056 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2057 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002059 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 /* Probably no need to le convert -1 on any arch but can not hurt */
2061 cifs_ace->cifs_uid = cpu_to_le64(-1);
2062 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002063 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2065 return rc;
2066}
2067
2068/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2069static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2070 const int acl_type)
2071{
2072 __u16 rc = 0;
2073 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2074 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2075 int count;
2076 int i;
2077
2078 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2079 return 0;
2080
2081 count = posix_acl_xattr_count((size_t)buflen);
2082 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002083 count, buflen, le32_to_cpu(local_acl->a_version)));
2084 if(le32_to_cpu(local_acl->a_version) != 2) {
2085 cFYI(1,("unknown POSIX ACL version %d",
2086 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087 return 0;
2088 }
2089 cifs_acl->version = cpu_to_le16(1);
2090 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002091 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002092 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002093 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 else {
2095 cFYI(1,("unknown ACL type %d",acl_type));
2096 return 0;
2097 }
2098 for(i=0;i<count;i++) {
2099 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2100 &local_acl->a_entries[i]);
2101 if(rc != 0) {
2102 /* ACE not converted */
2103 break;
2104 }
2105 }
2106 if(rc == 0) {
2107 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2108 rc += sizeof(struct cifs_posix_acl);
2109 /* BB add check to make sure ACL does not overflow SMB */
2110 }
2111 return rc;
2112}
2113
2114int
2115CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2116 const unsigned char *searchName,
2117 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002118 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119{
2120/* SMB_QUERY_POSIX_ACL */
2121 TRANSACTION2_QPI_REQ *pSMB = NULL;
2122 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2123 int rc = 0;
2124 int bytes_returned;
2125 int name_len;
2126 __u16 params, byte_count;
2127
2128 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2129
2130queryAclRetry:
2131 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2132 (void **) &pSMBr);
2133 if (rc)
2134 return rc;
2135
2136 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2137 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002138 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002139 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140 name_len++; /* trailing null */
2141 name_len *= 2;
2142 pSMB->FileName[name_len] = 0;
2143 pSMB->FileName[name_len+1] = 0;
2144 } else { /* BB improve the check for buffer overruns BB */
2145 name_len = strnlen(searchName, PATH_MAX);
2146 name_len++; /* trailing null */
2147 strncpy(pSMB->FileName, searchName, name_len);
2148 }
2149
2150 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2151 pSMB->TotalDataCount = 0;
2152 pSMB->MaxParameterCount = cpu_to_le16(2);
2153 /* BB find exact max data count below from sess structure BB */
2154 pSMB->MaxDataCount = cpu_to_le16(4000);
2155 pSMB->MaxSetupCount = 0;
2156 pSMB->Reserved = 0;
2157 pSMB->Flags = 0;
2158 pSMB->Timeout = 0;
2159 pSMB->Reserved2 = 0;
2160 pSMB->ParameterOffset = cpu_to_le16(
2161 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2162 pSMB->DataCount = 0;
2163 pSMB->DataOffset = 0;
2164 pSMB->SetupCount = 1;
2165 pSMB->Reserved3 = 0;
2166 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2167 byte_count = params + 1 /* pad */ ;
2168 pSMB->TotalParameterCount = cpu_to_le16(params);
2169 pSMB->ParameterCount = pSMB->TotalParameterCount;
2170 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2171 pSMB->Reserved4 = 0;
2172 pSMB->hdr.smb_buf_length += byte_count;
2173 pSMB->ByteCount = cpu_to_le16(byte_count);
2174
2175 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2176 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2177 if (rc) {
2178 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2179 } else {
2180 /* decode response */
2181
2182 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2183 if (rc || (pSMBr->ByteCount < 2))
2184 /* BB also check enough total bytes returned */
2185 rc = -EIO; /* bad smb */
2186 else {
2187 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2188 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2189 rc = cifs_copy_posix_acl(acl_inf,
2190 (char *)&pSMBr->hdr.Protocol+data_offset,
2191 buflen,acl_type,count);
2192 }
2193 }
2194 cifs_buf_release(pSMB);
2195 if (rc == -EAGAIN)
2196 goto queryAclRetry;
2197 return rc;
2198}
2199
2200int
2201CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2202 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002203 const char *local_acl, const int buflen,
2204 const int acl_type,
2205 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206{
2207 struct smb_com_transaction2_spi_req *pSMB = NULL;
2208 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2209 char *parm_data;
2210 int name_len;
2211 int rc = 0;
2212 int bytes_returned = 0;
2213 __u16 params, byte_count, data_count, param_offset, offset;
2214
2215 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2216setAclRetry:
2217 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2218 (void **) &pSMBr);
2219 if (rc)
2220 return rc;
2221 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2222 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002223 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002224 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 name_len++; /* trailing null */
2226 name_len *= 2;
2227 } else { /* BB improve the check for buffer overruns BB */
2228 name_len = strnlen(fileName, PATH_MAX);
2229 name_len++; /* trailing null */
2230 strncpy(pSMB->FileName, fileName, name_len);
2231 }
2232 params = 6 + name_len;
2233 pSMB->MaxParameterCount = cpu_to_le16(2);
2234 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2235 pSMB->MaxSetupCount = 0;
2236 pSMB->Reserved = 0;
2237 pSMB->Flags = 0;
2238 pSMB->Timeout = 0;
2239 pSMB->Reserved2 = 0;
2240 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2241 InformationLevel) - 4;
2242 offset = param_offset + params;
2243 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2244 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2245
2246 /* convert to on the wire format for POSIX ACL */
2247 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2248
2249 if(data_count == 0) {
2250 rc = -EOPNOTSUPP;
2251 goto setACLerrorExit;
2252 }
2253 pSMB->DataOffset = cpu_to_le16(offset);
2254 pSMB->SetupCount = 1;
2255 pSMB->Reserved3 = 0;
2256 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2257 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2258 byte_count = 3 /* pad */ + params + data_count;
2259 pSMB->DataCount = cpu_to_le16(data_count);
2260 pSMB->TotalDataCount = pSMB->DataCount;
2261 pSMB->ParameterCount = cpu_to_le16(params);
2262 pSMB->TotalParameterCount = pSMB->ParameterCount;
2263 pSMB->Reserved4 = 0;
2264 pSMB->hdr.smb_buf_length += byte_count;
2265 pSMB->ByteCount = cpu_to_le16(byte_count);
2266 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2267 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2268 if (rc) {
2269 cFYI(1, ("Set POSIX ACL returned %d", rc));
2270 }
2271
2272setACLerrorExit:
2273 cifs_buf_release(pSMB);
2274 if (rc == -EAGAIN)
2275 goto setAclRetry;
2276 return rc;
2277}
2278
Steve Frenchf654bac2005-04-28 22:41:04 -07002279/* BB fix tabs in this function FIXME BB */
2280int
2281CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2282 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2283{
2284 int rc = 0;
2285 struct smb_t2_qfi_req *pSMB = NULL;
2286 struct smb_t2_qfi_rsp *pSMBr = NULL;
2287 int bytes_returned;
2288 __u16 params, byte_count;
2289
2290 cFYI(1,("In GetExtAttr"));
2291 if(tcon == NULL)
2292 return -ENODEV;
2293
2294GetExtAttrRetry:
2295 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2296 (void **) &pSMBr);
2297 if (rc)
2298 return rc;
2299
Steve Frenchc67593a2005-04-28 22:41:04 -07002300 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002301 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002302 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002303 /* BB find exact max data count below from sess structure BB */
2304 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2305 pSMB->t2.MaxSetupCount = 0;
2306 pSMB->t2.Reserved = 0;
2307 pSMB->t2.Flags = 0;
2308 pSMB->t2.Timeout = 0;
2309 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002310 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2311 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002312 pSMB->t2.DataCount = 0;
2313 pSMB->t2.DataOffset = 0;
2314 pSMB->t2.SetupCount = 1;
2315 pSMB->t2.Reserved3 = 0;
2316 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002317 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002318 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2319 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2320 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002321 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002322 pSMB->Fid = netfid;
2323 pSMB->hdr.smb_buf_length += byte_count;
2324 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2325
2326 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2327 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2328 if (rc) {
2329 cFYI(1, ("error %d in GetExtAttr", rc));
2330 } else {
2331 /* decode response */
2332 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2333 if (rc || (pSMBr->ByteCount < 2))
2334 /* BB also check enough total bytes returned */
2335 /* If rc should we check for EOPNOSUPP and
2336 disable the srvino flag? or in caller? */
2337 rc = -EIO; /* bad smb */
2338 else {
2339 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2340 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2341 struct file_chattr_info * pfinfo;
2342 /* BB Do we need a cast or hash here ? */
2343 if(count != 16) {
2344 cFYI(1, ("Illegal size ret in GetExtAttr"));
2345 rc = -EIO;
2346 goto GetExtAttrOut;
2347 }
2348 pfinfo = (struct file_chattr_info *)
2349 (data_offset + (char *) &pSMBr->hdr.Protocol);
2350 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2351 *pMask = le64_to_cpu(pfinfo->mask);
2352 }
2353 }
2354GetExtAttrOut:
2355 cifs_buf_release(pSMB);
2356 if (rc == -EAGAIN)
2357 goto GetExtAttrRetry;
2358 return rc;
2359}
2360
2361
2362#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363
Steve French6b8edfe2005-08-23 20:26:03 -07002364/* Legacy Query Path Information call for lookup to old servers such
2365 as Win9x/WinME */
2366int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2367 const unsigned char *searchName,
2368 FILE_ALL_INFO * pFinfo,
2369 const struct nls_table *nls_codepage, int remap)
2370{
2371 QUERY_INFORMATION_REQ * pSMB;
2372 QUERY_INFORMATION_RSP * pSMBr;
2373 int rc = 0;
2374 int bytes_returned;
2375 int name_len;
2376
2377 cFYI(1, ("In SMBQPath path %s", searchName));
2378QInfRetry:
2379 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2380 (void **) &pSMBr);
2381 if (rc)
2382 return rc;
2383
2384 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2385 name_len =
2386 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2387 PATH_MAX, nls_codepage, remap);
2388 name_len++; /* trailing null */
2389 name_len *= 2;
2390 } else {
2391 name_len = strnlen(searchName, PATH_MAX);
2392 name_len++; /* trailing null */
2393 strncpy(pSMB->FileName, searchName, name_len);
2394 }
2395 pSMB->BufferFormat = 0x04;
2396 name_len++; /* account for buffer type byte */
2397 pSMB->hdr.smb_buf_length += (__u16) name_len;
2398 pSMB->ByteCount = cpu_to_le16(name_len);
2399
2400 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2401 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2402 if (rc) {
2403 cFYI(1, ("Send error in QueryInfo = %d", rc));
2404 } else if (pFinfo) { /* decode response */
2405 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002406 pFinfo->AllocationSize =
2407 cpu_to_le64(le32_to_cpu(pSMBr->size));
2408 pFinfo->EndOfFile = pFinfo->AllocationSize;
2409 pFinfo->Attributes =
2410 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002411 } else
2412 rc = -EIO; /* bad buffer passed in */
2413
2414 cifs_buf_release(pSMB);
2415
2416 if (rc == -EAGAIN)
2417 goto QInfRetry;
2418
2419 return rc;
2420}
2421
2422
2423
2424
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425int
2426CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2427 const unsigned char *searchName,
2428 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002429 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430{
2431/* level 263 SMB_QUERY_FILE_ALL_INFO */
2432 TRANSACTION2_QPI_REQ *pSMB = NULL;
2433 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2434 int rc = 0;
2435 int bytes_returned;
2436 int name_len;
2437 __u16 params, byte_count;
2438
2439/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2440QPathInfoRetry:
2441 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2442 (void **) &pSMBr);
2443 if (rc)
2444 return rc;
2445
2446 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2447 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002448 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002449 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 name_len++; /* trailing null */
2451 name_len *= 2;
2452 } else { /* BB improve the check for buffer overruns BB */
2453 name_len = strnlen(searchName, PATH_MAX);
2454 name_len++; /* trailing null */
2455 strncpy(pSMB->FileName, searchName, name_len);
2456 }
2457
2458 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2459 pSMB->TotalDataCount = 0;
2460 pSMB->MaxParameterCount = cpu_to_le16(2);
2461 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2462 pSMB->MaxSetupCount = 0;
2463 pSMB->Reserved = 0;
2464 pSMB->Flags = 0;
2465 pSMB->Timeout = 0;
2466 pSMB->Reserved2 = 0;
2467 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2468 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2469 pSMB->DataCount = 0;
2470 pSMB->DataOffset = 0;
2471 pSMB->SetupCount = 1;
2472 pSMB->Reserved3 = 0;
2473 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2474 byte_count = params + 1 /* pad */ ;
2475 pSMB->TotalParameterCount = cpu_to_le16(params);
2476 pSMB->ParameterCount = pSMB->TotalParameterCount;
2477 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2478 pSMB->Reserved4 = 0;
2479 pSMB->hdr.smb_buf_length += byte_count;
2480 pSMB->ByteCount = cpu_to_le16(byte_count);
2481
2482 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2483 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2484 if (rc) {
2485 cFYI(1, ("Send error in QPathInfo = %d", rc));
2486 } else { /* decode response */
2487 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2488
2489 if (rc || (pSMBr->ByteCount < 40))
2490 rc = -EIO; /* bad smb */
2491 else if (pFindData){
2492 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2493 memcpy((char *) pFindData,
2494 (char *) &pSMBr->hdr.Protocol +
2495 data_offset, sizeof (FILE_ALL_INFO));
2496 } else
2497 rc = -ENOMEM;
2498 }
2499 cifs_buf_release(pSMB);
2500 if (rc == -EAGAIN)
2501 goto QPathInfoRetry;
2502
2503 return rc;
2504}
2505
2506int
2507CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2508 const unsigned char *searchName,
2509 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002510 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511{
2512/* SMB_QUERY_FILE_UNIX_BASIC */
2513 TRANSACTION2_QPI_REQ *pSMB = NULL;
2514 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2515 int rc = 0;
2516 int bytes_returned = 0;
2517 int name_len;
2518 __u16 params, byte_count;
2519
2520 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2521UnixQPathInfoRetry:
2522 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2523 (void **) &pSMBr);
2524 if (rc)
2525 return rc;
2526
2527 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2528 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002529 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002530 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 name_len++; /* trailing null */
2532 name_len *= 2;
2533 } else { /* BB improve the check for buffer overruns BB */
2534 name_len = strnlen(searchName, PATH_MAX);
2535 name_len++; /* trailing null */
2536 strncpy(pSMB->FileName, searchName, name_len);
2537 }
2538
2539 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2540 pSMB->TotalDataCount = 0;
2541 pSMB->MaxParameterCount = cpu_to_le16(2);
2542 /* BB find exact max SMB PDU from sess structure BB */
2543 pSMB->MaxDataCount = cpu_to_le16(4000);
2544 pSMB->MaxSetupCount = 0;
2545 pSMB->Reserved = 0;
2546 pSMB->Flags = 0;
2547 pSMB->Timeout = 0;
2548 pSMB->Reserved2 = 0;
2549 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2550 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2551 pSMB->DataCount = 0;
2552 pSMB->DataOffset = 0;
2553 pSMB->SetupCount = 1;
2554 pSMB->Reserved3 = 0;
2555 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2556 byte_count = params + 1 /* pad */ ;
2557 pSMB->TotalParameterCount = cpu_to_le16(params);
2558 pSMB->ParameterCount = pSMB->TotalParameterCount;
2559 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2560 pSMB->Reserved4 = 0;
2561 pSMB->hdr.smb_buf_length += byte_count;
2562 pSMB->ByteCount = cpu_to_le16(byte_count);
2563
2564 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2565 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2566 if (rc) {
2567 cFYI(1, ("Send error in QPathInfo = %d", rc));
2568 } else { /* decode response */
2569 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2570
2571 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2572 rc = -EIO; /* bad smb */
2573 } else {
2574 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2575 memcpy((char *) pFindData,
2576 (char *) &pSMBr->hdr.Protocol +
2577 data_offset,
2578 sizeof (FILE_UNIX_BASIC_INFO));
2579 }
2580 }
2581 cifs_buf_release(pSMB);
2582 if (rc == -EAGAIN)
2583 goto UnixQPathInfoRetry;
2584
2585 return rc;
2586}
2587
2588#if 0 /* function unused at present */
2589int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2590 const char *searchName, FILE_ALL_INFO * findData,
2591 const struct nls_table *nls_codepage)
2592{
2593/* level 257 SMB_ */
2594 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2595 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2596 int rc = 0;
2597 int bytes_returned;
2598 int name_len;
2599 __u16 params, byte_count;
2600
2601 cFYI(1, ("In FindUnique"));
2602findUniqueRetry:
2603 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2604 (void **) &pSMBr);
2605 if (rc)
2606 return rc;
2607
2608 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2609 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002610 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 /* find define for this maxpathcomponent */
2612 , nls_codepage);
2613 name_len++; /* trailing null */
2614 name_len *= 2;
2615 } else { /* BB improve the check for buffer overruns BB */
2616 name_len = strnlen(searchName, PATH_MAX);
2617 name_len++; /* trailing null */
2618 strncpy(pSMB->FileName, searchName, name_len);
2619 }
2620
2621 params = 12 + name_len /* includes null */ ;
2622 pSMB->TotalDataCount = 0; /* no EAs */
2623 pSMB->MaxParameterCount = cpu_to_le16(2);
2624 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2625 pSMB->MaxSetupCount = 0;
2626 pSMB->Reserved = 0;
2627 pSMB->Flags = 0;
2628 pSMB->Timeout = 0;
2629 pSMB->Reserved2 = 0;
2630 pSMB->ParameterOffset = cpu_to_le16(
2631 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2632 pSMB->DataCount = 0;
2633 pSMB->DataOffset = 0;
2634 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2635 pSMB->Reserved3 = 0;
2636 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2637 byte_count = params + 1 /* pad */ ;
2638 pSMB->TotalParameterCount = cpu_to_le16(params);
2639 pSMB->ParameterCount = pSMB->TotalParameterCount;
2640 pSMB->SearchAttributes =
2641 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2642 ATTR_DIRECTORY);
2643 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2644 pSMB->SearchFlags = cpu_to_le16(1);
2645 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2646 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2647 pSMB->hdr.smb_buf_length += byte_count;
2648 pSMB->ByteCount = cpu_to_le16(byte_count);
2649
2650 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2651 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2652
2653 if (rc) {
2654 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2655 } else { /* decode response */
Steve Frencha45443472005-08-24 13:59:35 -07002656 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 /* BB fill in */
2658 }
2659
2660 cifs_buf_release(pSMB);
2661 if (rc == -EAGAIN)
2662 goto findUniqueRetry;
2663
2664 return rc;
2665}
2666#endif /* end unused (temporarily) function */
2667
2668/* xid, tcon, searchName and codepage are input parms, rest are returned */
2669int
2670CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2671 const char *searchName,
2672 const struct nls_table *nls_codepage,
2673 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07002674 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675{
2676/* level 257 SMB_ */
2677 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2678 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2679 T2_FFIRST_RSP_PARMS * parms;
2680 int rc = 0;
2681 int bytes_returned = 0;
2682 int name_len;
2683 __u16 params, byte_count;
2684
Steve French737b7582005-04-28 22:41:06 -07002685 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686
2687findFirstRetry:
2688 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2689 (void **) &pSMBr);
2690 if (rc)
2691 return rc;
2692
2693 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2694 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002695 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07002696 PATH_MAX, nls_codepage, remap);
2697 /* We can not add the asterik earlier in case
2698 it got remapped to 0xF03A as if it were part of the
2699 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07002701 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07002702 pSMB->FileName[name_len+1] = 0;
2703 pSMB->FileName[name_len+2] = '*';
2704 pSMB->FileName[name_len+3] = 0;
2705 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2707 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07002708 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 } else { /* BB add check for overrun of SMB buf BB */
2710 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711/* BB fix here and in unicode clause above ie
2712 if(name_len > buffersize-header)
2713 free buffer exit; BB */
2714 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07002715 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07002716 pSMB->FileName[name_len+1] = '*';
2717 pSMB->FileName[name_len+2] = 0;
2718 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 }
2720
2721 params = 12 + name_len /* includes null */ ;
2722 pSMB->TotalDataCount = 0; /* no EAs */
2723 pSMB->MaxParameterCount = cpu_to_le16(10);
2724 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2725 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2726 pSMB->MaxSetupCount = 0;
2727 pSMB->Reserved = 0;
2728 pSMB->Flags = 0;
2729 pSMB->Timeout = 0;
2730 pSMB->Reserved2 = 0;
2731 byte_count = params + 1 /* pad */ ;
2732 pSMB->TotalParameterCount = cpu_to_le16(params);
2733 pSMB->ParameterCount = pSMB->TotalParameterCount;
2734 pSMB->ParameterOffset = cpu_to_le16(
2735 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2736 pSMB->DataCount = 0;
2737 pSMB->DataOffset = 0;
2738 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2739 pSMB->Reserved3 = 0;
2740 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2741 pSMB->SearchAttributes =
2742 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2743 ATTR_DIRECTORY);
2744 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2745 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2746 CIFS_SEARCH_RETURN_RESUME);
2747 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2748
2749 /* BB what should we set StorageType to? Does it matter? BB */
2750 pSMB->SearchStorageType = 0;
2751 pSMB->hdr.smb_buf_length += byte_count;
2752 pSMB->ByteCount = cpu_to_le16(byte_count);
2753
2754 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2755 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002756 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757
Steve French1982c342005-08-17 12:38:22 -07002758 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 /* BB Add code to handle unsupported level rc */
2760 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07002761
2762 if (pSMB)
2763 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764
2765 /* BB eventually could optimize out free and realloc of buf */
2766 /* for this case */
2767 if (rc == -EAGAIN)
2768 goto findFirstRetry;
2769 } else { /* decode response */
2770 /* BB remember to free buffer if error BB */
2771 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2772 if(rc == 0) {
2773 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2774 psrch_inf->unicode = TRUE;
2775 else
2776 psrch_inf->unicode = FALSE;
2777
2778 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2779 psrch_inf->srch_entries_start =
2780 (char *) &pSMBr->hdr.Protocol +
2781 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2783 le16_to_cpu(pSMBr->t2.ParameterOffset));
2784
2785 if(parms->EndofSearch)
2786 psrch_inf->endOfSearch = TRUE;
2787 else
2788 psrch_inf->endOfSearch = FALSE;
2789
2790 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2791 psrch_inf->index_of_last_entry =
2792 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 *pnetfid = parms->SearchHandle;
2794 } else {
2795 cifs_buf_release(pSMB);
2796 }
2797 }
2798
2799 return rc;
2800}
2801
2802int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2803 __u16 searchHandle, struct cifs_search_info * psrch_inf)
2804{
2805 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2806 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2807 T2_FNEXT_RSP_PARMS * parms;
2808 char *response_data;
2809 int rc = 0;
2810 int bytes_returned, name_len;
2811 __u16 params, byte_count;
2812
2813 cFYI(1, ("In FindNext"));
2814
2815 if(psrch_inf->endOfSearch == TRUE)
2816 return -ENOENT;
2817
2818 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2819 (void **) &pSMBr);
2820 if (rc)
2821 return rc;
2822
2823 params = 14; /* includes 2 bytes of null string, converted to LE below */
2824 byte_count = 0;
2825 pSMB->TotalDataCount = 0; /* no EAs */
2826 pSMB->MaxParameterCount = cpu_to_le16(8);
2827 pSMB->MaxDataCount =
2828 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2829 pSMB->MaxSetupCount = 0;
2830 pSMB->Reserved = 0;
2831 pSMB->Flags = 0;
2832 pSMB->Timeout = 0;
2833 pSMB->Reserved2 = 0;
2834 pSMB->ParameterOffset = cpu_to_le16(
2835 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2836 pSMB->DataCount = 0;
2837 pSMB->DataOffset = 0;
2838 pSMB->SetupCount = 1;
2839 pSMB->Reserved3 = 0;
2840 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2841 pSMB->SearchHandle = searchHandle; /* always kept as le */
2842 pSMB->SearchCount =
2843 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2844 /* test for Unix extensions */
2845/* if (tcon->ses->capabilities & CAP_UNIX) {
2846 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2847 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2848 } else {
2849 pSMB->InformationLevel =
2850 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2851 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2852 } */
2853 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2854 pSMB->ResumeKey = psrch_inf->resume_key;
2855 pSMB->SearchFlags =
2856 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2857
2858 name_len = psrch_inf->resume_name_len;
2859 params += name_len;
2860 if(name_len < PATH_MAX) {
2861 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2862 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07002863 /* 14 byte parm len above enough for 2 byte null terminator */
2864 pSMB->ResumeFileName[name_len] = 0;
2865 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 } else {
2867 rc = -EINVAL;
2868 goto FNext2_err_exit;
2869 }
2870 byte_count = params + 1 /* pad */ ;
2871 pSMB->TotalParameterCount = cpu_to_le16(params);
2872 pSMB->ParameterCount = pSMB->TotalParameterCount;
2873 pSMB->hdr.smb_buf_length += byte_count;
2874 pSMB->ByteCount = cpu_to_le16(byte_count);
2875
2876 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2877 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha45443472005-08-24 13:59:35 -07002878 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 if (rc) {
2880 if (rc == -EBADF) {
2881 psrch_inf->endOfSearch = TRUE;
2882 rc = 0; /* search probably was closed at end of search above */
2883 } else
2884 cFYI(1, ("FindNext returned = %d", rc));
2885 } else { /* decode response */
2886 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2887
2888 if(rc == 0) {
2889 /* BB fixme add lock for file (srch_info) struct here */
2890 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2891 psrch_inf->unicode = TRUE;
2892 else
2893 psrch_inf->unicode = FALSE;
2894 response_data = (char *) &pSMBr->hdr.Protocol +
2895 le16_to_cpu(pSMBr->t2.ParameterOffset);
2896 parms = (T2_FNEXT_RSP_PARMS *)response_data;
2897 response_data = (char *)&pSMBr->hdr.Protocol +
2898 le16_to_cpu(pSMBr->t2.DataOffset);
2899 cifs_buf_release(psrch_inf->ntwrk_buf_start);
2900 psrch_inf->srch_entries_start = response_data;
2901 psrch_inf->ntwrk_buf_start = (char *)pSMB;
2902 if(parms->EndofSearch)
2903 psrch_inf->endOfSearch = TRUE;
2904 else
2905 psrch_inf->endOfSearch = FALSE;
2906
2907 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2908 psrch_inf->index_of_last_entry +=
2909 psrch_inf->entries_in_buffer;
2910/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2911
2912 /* BB fixme add unlock here */
2913 }
2914
2915 }
2916
2917 /* BB On error, should we leave previous search buf (and count and
2918 last entry fields) intact or free the previous one? */
2919
2920 /* Note: On -EAGAIN error only caller can retry on handle based calls
2921 since file handle passed in no longer valid */
2922FNext2_err_exit:
2923 if (rc != 0)
2924 cifs_buf_release(pSMB);
2925
2926 return rc;
2927}
2928
2929int
2930CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2931{
2932 int rc = 0;
2933 FINDCLOSE_REQ *pSMB = NULL;
2934 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2935 int bytes_returned;
2936
2937 cFYI(1, ("In CIFSSMBFindClose"));
2938 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2939
2940 /* no sense returning error if session restarted
2941 as file handle has been closed */
2942 if(rc == -EAGAIN)
2943 return 0;
2944 if (rc)
2945 return rc;
2946
2947 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
2948 pSMB->FileID = searchHandle;
2949 pSMB->ByteCount = 0;
2950 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2951 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2952 if (rc) {
2953 cERROR(1, ("Send error in FindClose = %d", rc));
2954 }
Steve Frencha45443472005-08-24 13:59:35 -07002955 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 cifs_small_buf_release(pSMB);
2957
2958 /* Since session is dead, search handle closed on server already */
2959 if (rc == -EAGAIN)
2960 rc = 0;
2961
2962 return rc;
2963}
2964
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965int
2966CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2967 const unsigned char *searchName,
2968 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07002969 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970{
2971 int rc = 0;
2972 TRANSACTION2_QPI_REQ *pSMB = NULL;
2973 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2974 int name_len, bytes_returned;
2975 __u16 params, byte_count;
2976
2977 cFYI(1,("In GetSrvInodeNum for %s",searchName));
2978 if(tcon == NULL)
2979 return -ENODEV;
2980
2981GetInodeNumberRetry:
2982 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2983 (void **) &pSMBr);
2984 if (rc)
2985 return rc;
2986
2987
2988 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2989 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002990 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002991 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992 name_len++; /* trailing null */
2993 name_len *= 2;
2994 } else { /* BB improve the check for buffer overruns BB */
2995 name_len = strnlen(searchName, PATH_MAX);
2996 name_len++; /* trailing null */
2997 strncpy(pSMB->FileName, searchName, name_len);
2998 }
2999
3000 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3001 pSMB->TotalDataCount = 0;
3002 pSMB->MaxParameterCount = cpu_to_le16(2);
3003 /* BB find exact max data count below from sess structure BB */
3004 pSMB->MaxDataCount = cpu_to_le16(4000);
3005 pSMB->MaxSetupCount = 0;
3006 pSMB->Reserved = 0;
3007 pSMB->Flags = 0;
3008 pSMB->Timeout = 0;
3009 pSMB->Reserved2 = 0;
3010 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3011 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3012 pSMB->DataCount = 0;
3013 pSMB->DataOffset = 0;
3014 pSMB->SetupCount = 1;
3015 pSMB->Reserved3 = 0;
3016 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3017 byte_count = params + 1 /* pad */ ;
3018 pSMB->TotalParameterCount = cpu_to_le16(params);
3019 pSMB->ParameterCount = pSMB->TotalParameterCount;
3020 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3021 pSMB->Reserved4 = 0;
3022 pSMB->hdr.smb_buf_length += byte_count;
3023 pSMB->ByteCount = cpu_to_le16(byte_count);
3024
3025 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3026 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3027 if (rc) {
3028 cFYI(1, ("error %d in QueryInternalInfo", rc));
3029 } else {
3030 /* decode response */
3031 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3032 if (rc || (pSMBr->ByteCount < 2))
3033 /* BB also check enough total bytes returned */
3034 /* If rc should we check for EOPNOSUPP and
3035 disable the srvino flag? or in caller? */
3036 rc = -EIO; /* bad smb */
3037 else {
3038 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3039 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3040 struct file_internal_info * pfinfo;
3041 /* BB Do we need a cast or hash here ? */
3042 if(count < 8) {
3043 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3044 rc = -EIO;
3045 goto GetInodeNumOut;
3046 }
3047 pfinfo = (struct file_internal_info *)
3048 (data_offset + (char *) &pSMBr->hdr.Protocol);
3049 *inode_number = pfinfo->UniqueId;
3050 }
3051 }
3052GetInodeNumOut:
3053 cifs_buf_release(pSMB);
3054 if (rc == -EAGAIN)
3055 goto GetInodeNumberRetry;
3056 return rc;
3057}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058
3059int
3060CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3061 const unsigned char *searchName,
3062 unsigned char **targetUNCs,
3063 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003064 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065{
3066/* TRANS2_GET_DFS_REFERRAL */
3067 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3068 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3069 struct dfs_referral_level_3 * referrals = NULL;
3070 int rc = 0;
3071 int bytes_returned;
3072 int name_len;
3073 unsigned int i;
3074 char * temp;
3075 __u16 params, byte_count;
3076 *number_of_UNC_in_array = 0;
3077 *targetUNCs = NULL;
3078
3079 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3080 if (ses == NULL)
3081 return -ENODEV;
3082getDFSRetry:
3083 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3084 (void **) &pSMBr);
3085 if (rc)
3086 return rc;
Steve French1982c342005-08-17 12:38:22 -07003087
3088 /* server pointer checked in called function,
3089 but should never be null here anyway */
3090 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003091 pSMB->hdr.Tid = ses->ipc_tid;
3092 pSMB->hdr.Uid = ses->Suid;
3093 if (ses->capabilities & CAP_STATUS32) {
3094 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3095 }
3096 if (ses->capabilities & CAP_DFS) {
3097 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3098 }
3099
3100 if (ses->capabilities & CAP_UNICODE) {
3101 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3102 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003103 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003104 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 name_len++; /* trailing null */
3106 name_len *= 2;
3107 } else { /* BB improve the check for buffer overruns BB */
3108 name_len = strnlen(searchName, PATH_MAX);
3109 name_len++; /* trailing null */
3110 strncpy(pSMB->RequestFileName, searchName, name_len);
3111 }
3112
3113 params = 2 /* level */ + name_len /*includes null */ ;
3114 pSMB->TotalDataCount = 0;
3115 pSMB->DataCount = 0;
3116 pSMB->DataOffset = 0;
3117 pSMB->MaxParameterCount = 0;
3118 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3119 pSMB->MaxSetupCount = 0;
3120 pSMB->Reserved = 0;
3121 pSMB->Flags = 0;
3122 pSMB->Timeout = 0;
3123 pSMB->Reserved2 = 0;
3124 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3125 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3126 pSMB->SetupCount = 1;
3127 pSMB->Reserved3 = 0;
3128 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3129 byte_count = params + 3 /* pad */ ;
3130 pSMB->ParameterCount = cpu_to_le16(params);
3131 pSMB->TotalParameterCount = pSMB->ParameterCount;
3132 pSMB->MaxReferralLevel = cpu_to_le16(3);
3133 pSMB->hdr.smb_buf_length += byte_count;
3134 pSMB->ByteCount = cpu_to_le16(byte_count);
3135
3136 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3137 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3138 if (rc) {
3139 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3140 } else { /* decode response */
3141/* BB Add logic to parse referrals here */
3142 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3143
3144 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3145 rc = -EIO; /* bad smb */
3146 else {
3147 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3148 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3149
3150 cFYI(1,
3151 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3152 pSMBr->ByteCount, data_offset));
3153 referrals =
3154 (struct dfs_referral_level_3 *)
3155 (8 /* sizeof start of data block */ +
3156 data_offset +
3157 (char *) &pSMBr->hdr.Protocol);
3158 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",
3159 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)));
3160 /* BB This field is actually two bytes in from start of
3161 data block so we could do safety check that DataBlock
3162 begins at address of pSMBr->NumberOfReferrals */
3163 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3164
3165 /* BB Fix below so can return more than one referral */
3166 if(*number_of_UNC_in_array > 1)
3167 *number_of_UNC_in_array = 1;
3168
3169 /* get the length of the strings describing refs */
3170 name_len = 0;
3171 for(i=0;i<*number_of_UNC_in_array;i++) {
3172 /* make sure that DfsPathOffset not past end */
3173 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3174 if (offset > data_count) {
3175 /* if invalid referral, stop here and do
3176 not try to copy any more */
3177 *number_of_UNC_in_array = i;
3178 break;
3179 }
3180 temp = ((char *)referrals) + offset;
3181
3182 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3183 name_len += UniStrnlen((wchar_t *)temp,data_count);
3184 } else {
3185 name_len += strnlen(temp,data_count);
3186 }
3187 referrals++;
3188 /* BB add check that referral pointer does not fall off end PDU */
3189
3190 }
3191 /* BB add check for name_len bigger than bcc */
3192 *targetUNCs =
3193 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3194 if(*targetUNCs == NULL) {
3195 rc = -ENOMEM;
3196 goto GetDFSRefExit;
3197 }
3198 /* copy the ref strings */
3199 referrals =
3200 (struct dfs_referral_level_3 *)
3201 (8 /* sizeof data hdr */ +
3202 data_offset +
3203 (char *) &pSMBr->hdr.Protocol);
3204
3205 for(i=0;i<*number_of_UNC_in_array;i++) {
3206 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3207 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3208 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003209 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 } else {
3211 strncpy(*targetUNCs,temp,name_len);
3212 }
3213 /* BB update target_uncs pointers */
3214 referrals++;
3215 }
3216 temp = *targetUNCs;
3217 temp[name_len] = 0;
3218 }
3219
3220 }
3221GetDFSRefExit:
3222 if (pSMB)
3223 cifs_buf_release(pSMB);
3224
3225 if (rc == -EAGAIN)
3226 goto getDFSRetry;
3227
3228 return rc;
3229}
3230
Steve French20962432005-09-21 22:05:57 -07003231/* Query File System Info such as free space to old servers such as Win 9x */
3232int
3233SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3234{
3235/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3236 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3237 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3238 FILE_SYSTEM_ALLOC_INFO *response_data;
3239 int rc = 0;
3240 int bytes_returned = 0;
3241 __u16 params, byte_count;
3242
3243 cFYI(1, ("OldQFSInfo"));
3244oldQFSInfoRetry:
3245 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3246 (void **) &pSMBr);
3247 if (rc)
3248 return rc;
3249 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3250 (void **) &pSMBr);
3251 if (rc)
3252 return rc;
3253
3254 params = 2; /* level */
3255 pSMB->TotalDataCount = 0;
3256 pSMB->MaxParameterCount = cpu_to_le16(2);
3257 pSMB->MaxDataCount = cpu_to_le16(1000);
3258 pSMB->MaxSetupCount = 0;
3259 pSMB->Reserved = 0;
3260 pSMB->Flags = 0;
3261 pSMB->Timeout = 0;
3262 pSMB->Reserved2 = 0;
3263 byte_count = params + 1 /* pad */ ;
3264 pSMB->TotalParameterCount = cpu_to_le16(params);
3265 pSMB->ParameterCount = pSMB->TotalParameterCount;
3266 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3267 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3268 pSMB->DataCount = 0;
3269 pSMB->DataOffset = 0;
3270 pSMB->SetupCount = 1;
3271 pSMB->Reserved3 = 0;
3272 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3273 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3274 pSMB->hdr.smb_buf_length += byte_count;
3275 pSMB->ByteCount = cpu_to_le16(byte_count);
3276
3277 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3278 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3279 if (rc) {
3280 cFYI(1, ("Send error in QFSInfo = %d", rc));
3281 } else { /* decode response */
3282 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3283
3284 if (rc || (pSMBr->ByteCount < 18))
3285 rc = -EIO; /* bad smb */
3286 else {
3287 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3288 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3289 pSMBr->ByteCount, data_offset));
3290
3291 response_data =
3292 (FILE_SYSTEM_ALLOC_INFO *)
3293 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3294 FSData->f_bsize =
3295 le16_to_cpu(response_data->BytesPerSector) *
3296 le32_to_cpu(response_data->
3297 SectorsPerAllocationUnit);
3298 FSData->f_blocks =
3299 le32_to_cpu(response_data->TotalAllocationUnits);
3300 FSData->f_bfree = FSData->f_bavail =
3301 le32_to_cpu(response_data->FreeAllocationUnits);
3302 cFYI(1,
3303 ("Blocks: %lld Free: %lld Block size %ld",
3304 (unsigned long long)FSData->f_blocks,
3305 (unsigned long long)FSData->f_bfree,
3306 FSData->f_bsize));
3307 }
3308 }
3309 cifs_buf_release(pSMB);
3310
3311 if (rc == -EAGAIN)
3312 goto oldQFSInfoRetry;
3313
3314 return rc;
3315}
3316
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317int
Steve French737b7582005-04-28 22:41:06 -07003318CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319{
3320/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3321 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3322 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3323 FILE_SYSTEM_INFO *response_data;
3324 int rc = 0;
3325 int bytes_returned = 0;
3326 __u16 params, byte_count;
3327
3328 cFYI(1, ("In QFSInfo"));
3329QFSInfoRetry:
3330 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3331 (void **) &pSMBr);
3332 if (rc)
3333 return rc;
3334
3335 params = 2; /* level */
3336 pSMB->TotalDataCount = 0;
3337 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003338 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 pSMB->MaxSetupCount = 0;
3340 pSMB->Reserved = 0;
3341 pSMB->Flags = 0;
3342 pSMB->Timeout = 0;
3343 pSMB->Reserved2 = 0;
3344 byte_count = params + 1 /* pad */ ;
3345 pSMB->TotalParameterCount = cpu_to_le16(params);
3346 pSMB->ParameterCount = pSMB->TotalParameterCount;
3347 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3348 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3349 pSMB->DataCount = 0;
3350 pSMB->DataOffset = 0;
3351 pSMB->SetupCount = 1;
3352 pSMB->Reserved3 = 0;
3353 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3354 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3355 pSMB->hdr.smb_buf_length += byte_count;
3356 pSMB->ByteCount = cpu_to_le16(byte_count);
3357
3358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3359 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3360 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003361 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003362 } else { /* decode response */
3363 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3364
Steve French20962432005-09-21 22:05:57 -07003365 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366 rc = -EIO; /* bad smb */
3367 else {
3368 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003369
3370 response_data =
3371 (FILE_SYSTEM_INFO
3372 *) (((char *) &pSMBr->hdr.Protocol) +
3373 data_offset);
3374 FSData->f_bsize =
3375 le32_to_cpu(response_data->BytesPerSector) *
3376 le32_to_cpu(response_data->
3377 SectorsPerAllocationUnit);
3378 FSData->f_blocks =
3379 le64_to_cpu(response_data->TotalAllocationUnits);
3380 FSData->f_bfree = FSData->f_bavail =
3381 le64_to_cpu(response_data->FreeAllocationUnits);
3382 cFYI(1,
3383 ("Blocks: %lld Free: %lld Block size %ld",
3384 (unsigned long long)FSData->f_blocks,
3385 (unsigned long long)FSData->f_bfree,
3386 FSData->f_bsize));
3387 }
3388 }
3389 cifs_buf_release(pSMB);
3390
3391 if (rc == -EAGAIN)
3392 goto QFSInfoRetry;
3393
3394 return rc;
3395}
3396
3397int
Steve French737b7582005-04-28 22:41:06 -07003398CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399{
3400/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3401 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3402 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3403 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3404 int rc = 0;
3405 int bytes_returned = 0;
3406 __u16 params, byte_count;
3407
3408 cFYI(1, ("In QFSAttributeInfo"));
3409QFSAttributeRetry:
3410 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3411 (void **) &pSMBr);
3412 if (rc)
3413 return rc;
3414
3415 params = 2; /* level */
3416 pSMB->TotalDataCount = 0;
3417 pSMB->MaxParameterCount = cpu_to_le16(2);
3418 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3419 pSMB->MaxSetupCount = 0;
3420 pSMB->Reserved = 0;
3421 pSMB->Flags = 0;
3422 pSMB->Timeout = 0;
3423 pSMB->Reserved2 = 0;
3424 byte_count = params + 1 /* pad */ ;
3425 pSMB->TotalParameterCount = cpu_to_le16(params);
3426 pSMB->ParameterCount = pSMB->TotalParameterCount;
3427 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3428 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3429 pSMB->DataCount = 0;
3430 pSMB->DataOffset = 0;
3431 pSMB->SetupCount = 1;
3432 pSMB->Reserved3 = 0;
3433 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3434 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3435 pSMB->hdr.smb_buf_length += byte_count;
3436 pSMB->ByteCount = cpu_to_le16(byte_count);
3437
3438 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3439 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3440 if (rc) {
3441 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3442 } else { /* decode response */
3443 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3444
3445 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3446 rc = -EIO; /* bad smb */
3447 } else {
3448 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3449 response_data =
3450 (FILE_SYSTEM_ATTRIBUTE_INFO
3451 *) (((char *) &pSMBr->hdr.Protocol) +
3452 data_offset);
3453 memcpy(&tcon->fsAttrInfo, response_data,
3454 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3455 }
3456 }
3457 cifs_buf_release(pSMB);
3458
3459 if (rc == -EAGAIN)
3460 goto QFSAttributeRetry;
3461
3462 return rc;
3463}
3464
3465int
Steve French737b7582005-04-28 22:41:06 -07003466CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467{
3468/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3469 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3470 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3471 FILE_SYSTEM_DEVICE_INFO *response_data;
3472 int rc = 0;
3473 int bytes_returned = 0;
3474 __u16 params, byte_count;
3475
3476 cFYI(1, ("In QFSDeviceInfo"));
3477QFSDeviceRetry:
3478 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3479 (void **) &pSMBr);
3480 if (rc)
3481 return rc;
3482
3483 params = 2; /* level */
3484 pSMB->TotalDataCount = 0;
3485 pSMB->MaxParameterCount = cpu_to_le16(2);
3486 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3487 pSMB->MaxSetupCount = 0;
3488 pSMB->Reserved = 0;
3489 pSMB->Flags = 0;
3490 pSMB->Timeout = 0;
3491 pSMB->Reserved2 = 0;
3492 byte_count = params + 1 /* pad */ ;
3493 pSMB->TotalParameterCount = cpu_to_le16(params);
3494 pSMB->ParameterCount = pSMB->TotalParameterCount;
3495 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3496 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3497
3498 pSMB->DataCount = 0;
3499 pSMB->DataOffset = 0;
3500 pSMB->SetupCount = 1;
3501 pSMB->Reserved3 = 0;
3502 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3503 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3504 pSMB->hdr.smb_buf_length += byte_count;
3505 pSMB->ByteCount = cpu_to_le16(byte_count);
3506
3507 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3508 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3509 if (rc) {
3510 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3511 } else { /* decode response */
3512 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3513
3514 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3515 rc = -EIO; /* bad smb */
3516 else {
3517 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3518 response_data =
Steve French737b7582005-04-28 22:41:06 -07003519 (FILE_SYSTEM_DEVICE_INFO *)
3520 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003521 data_offset);
3522 memcpy(&tcon->fsDevInfo, response_data,
3523 sizeof (FILE_SYSTEM_DEVICE_INFO));
3524 }
3525 }
3526 cifs_buf_release(pSMB);
3527
3528 if (rc == -EAGAIN)
3529 goto QFSDeviceRetry;
3530
3531 return rc;
3532}
3533
3534int
Steve French737b7582005-04-28 22:41:06 -07003535CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536{
3537/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3538 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3539 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3540 FILE_SYSTEM_UNIX_INFO *response_data;
3541 int rc = 0;
3542 int bytes_returned = 0;
3543 __u16 params, byte_count;
3544
3545 cFYI(1, ("In QFSUnixInfo"));
3546QFSUnixRetry:
3547 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3548 (void **) &pSMBr);
3549 if (rc)
3550 return rc;
3551
3552 params = 2; /* level */
3553 pSMB->TotalDataCount = 0;
3554 pSMB->DataCount = 0;
3555 pSMB->DataOffset = 0;
3556 pSMB->MaxParameterCount = cpu_to_le16(2);
3557 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3558 pSMB->MaxSetupCount = 0;
3559 pSMB->Reserved = 0;
3560 pSMB->Flags = 0;
3561 pSMB->Timeout = 0;
3562 pSMB->Reserved2 = 0;
3563 byte_count = params + 1 /* pad */ ;
3564 pSMB->ParameterCount = cpu_to_le16(params);
3565 pSMB->TotalParameterCount = pSMB->ParameterCount;
3566 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3567 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3568 pSMB->SetupCount = 1;
3569 pSMB->Reserved3 = 0;
3570 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3571 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3572 pSMB->hdr.smb_buf_length += byte_count;
3573 pSMB->ByteCount = cpu_to_le16(byte_count);
3574
3575 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3576 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3577 if (rc) {
3578 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3579 } else { /* decode response */
3580 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3581
3582 if (rc || (pSMBr->ByteCount < 13)) {
3583 rc = -EIO; /* bad smb */
3584 } else {
3585 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3586 response_data =
3587 (FILE_SYSTEM_UNIX_INFO
3588 *) (((char *) &pSMBr->hdr.Protocol) +
3589 data_offset);
3590 memcpy(&tcon->fsUnixInfo, response_data,
3591 sizeof (FILE_SYSTEM_UNIX_INFO));
3592 }
3593 }
3594 cifs_buf_release(pSMB);
3595
3596 if (rc == -EAGAIN)
3597 goto QFSUnixRetry;
3598
3599
3600 return rc;
3601}
3602
Jeremy Allisonac670552005-06-22 17:26:35 -07003603int
Steve French45abc6e2005-06-23 13:42:03 -05003604CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07003605{
3606/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3607 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3608 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3609 int rc = 0;
3610 int bytes_returned = 0;
3611 __u16 params, param_offset, offset, byte_count;
3612
3613 cFYI(1, ("In SETFSUnixInfo"));
3614SETFSUnixRetry:
3615 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3616 (void **) &pSMBr);
3617 if (rc)
3618 return rc;
3619
3620 params = 4; /* 2 bytes zero followed by info level. */
3621 pSMB->MaxSetupCount = 0;
3622 pSMB->Reserved = 0;
3623 pSMB->Flags = 0;
3624 pSMB->Timeout = 0;
3625 pSMB->Reserved2 = 0;
3626 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3627 offset = param_offset + params;
3628
3629 pSMB->MaxParameterCount = cpu_to_le16(4);
3630 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3631 pSMB->SetupCount = 1;
3632 pSMB->Reserved3 = 0;
3633 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3634 byte_count = 1 /* pad */ + params + 12;
3635
3636 pSMB->DataCount = cpu_to_le16(12);
3637 pSMB->ParameterCount = cpu_to_le16(params);
3638 pSMB->TotalDataCount = pSMB->DataCount;
3639 pSMB->TotalParameterCount = pSMB->ParameterCount;
3640 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3641 pSMB->DataOffset = cpu_to_le16(offset);
3642
3643 /* Params. */
3644 pSMB->FileNum = 0;
3645 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3646
3647 /* Data. */
3648 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3649 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3650 pSMB->ClientUnixCap = cpu_to_le64(cap);
3651
3652 pSMB->hdr.smb_buf_length += byte_count;
3653 pSMB->ByteCount = cpu_to_le16(byte_count);
3654
3655 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3656 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3657 if (rc) {
3658 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3659 } else { /* decode response */
3660 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3661 if (rc) {
3662 rc = -EIO; /* bad smb */
3663 }
3664 }
3665 cifs_buf_release(pSMB);
3666
3667 if (rc == -EAGAIN)
3668 goto SETFSUnixRetry;
3669
3670 return rc;
3671}
3672
3673
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674
3675int
3676CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003677 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678{
3679/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3680 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3681 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3682 FILE_SYSTEM_POSIX_INFO *response_data;
3683 int rc = 0;
3684 int bytes_returned = 0;
3685 __u16 params, byte_count;
3686
3687 cFYI(1, ("In QFSPosixInfo"));
3688QFSPosixRetry:
3689 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3690 (void **) &pSMBr);
3691 if (rc)
3692 return rc;
3693
3694 params = 2; /* level */
3695 pSMB->TotalDataCount = 0;
3696 pSMB->DataCount = 0;
3697 pSMB->DataOffset = 0;
3698 pSMB->MaxParameterCount = cpu_to_le16(2);
3699 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3700 pSMB->MaxSetupCount = 0;
3701 pSMB->Reserved = 0;
3702 pSMB->Flags = 0;
3703 pSMB->Timeout = 0;
3704 pSMB->Reserved2 = 0;
3705 byte_count = params + 1 /* pad */ ;
3706 pSMB->ParameterCount = cpu_to_le16(params);
3707 pSMB->TotalParameterCount = pSMB->ParameterCount;
3708 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3709 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3710 pSMB->SetupCount = 1;
3711 pSMB->Reserved3 = 0;
3712 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3713 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3714 pSMB->hdr.smb_buf_length += byte_count;
3715 pSMB->ByteCount = cpu_to_le16(byte_count);
3716
3717 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3718 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3719 if (rc) {
3720 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3721 } else { /* decode response */
3722 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3723
3724 if (rc || (pSMBr->ByteCount < 13)) {
3725 rc = -EIO; /* bad smb */
3726 } else {
3727 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3728 response_data =
3729 (FILE_SYSTEM_POSIX_INFO
3730 *) (((char *) &pSMBr->hdr.Protocol) +
3731 data_offset);
3732 FSData->f_bsize =
3733 le32_to_cpu(response_data->BlockSize);
3734 FSData->f_blocks =
3735 le64_to_cpu(response_data->TotalBlocks);
3736 FSData->f_bfree =
3737 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07003738 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 FSData->f_bavail = FSData->f_bfree;
3740 } else {
3741 FSData->f_bavail =
3742 le64_to_cpu(response_data->UserBlocksAvail);
3743 }
Steve French70ca7342005-09-22 16:32:06 -07003744 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745 FSData->f_files =
3746 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07003747 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003748 FSData->f_ffree =
3749 le64_to_cpu(response_data->FreeFileNodes);
3750 }
3751 }
3752 cifs_buf_release(pSMB);
3753
3754 if (rc == -EAGAIN)
3755 goto QFSPosixRetry;
3756
3757 return rc;
3758}
3759
3760
3761/* We can not use write of zero bytes trick to
3762 set file size due to need for large file support. Also note that
3763 this SetPathInfo is preferred to SetFileInfo based method in next
3764 routine which is only needed to work around a sharing violation bug
3765 in Samba which this routine can run into */
3766
3767int
3768CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07003769 __u64 size, int SetAllocation,
3770 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771{
3772 struct smb_com_transaction2_spi_req *pSMB = NULL;
3773 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3774 struct file_end_of_file_info *parm_data;
3775 int name_len;
3776 int rc = 0;
3777 int bytes_returned = 0;
3778 __u16 params, byte_count, data_count, param_offset, offset;
3779
3780 cFYI(1, ("In SetEOF"));
3781SetEOFRetry:
3782 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3783 (void **) &pSMBr);
3784 if (rc)
3785 return rc;
3786
3787 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3788 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003789 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003790 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 name_len++; /* trailing null */
3792 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07003793 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003794 name_len = strnlen(fileName, PATH_MAX);
3795 name_len++; /* trailing null */
3796 strncpy(pSMB->FileName, fileName, name_len);
3797 }
3798 params = 6 + name_len;
3799 data_count = sizeof (struct file_end_of_file_info);
3800 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07003801 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802 pSMB->MaxSetupCount = 0;
3803 pSMB->Reserved = 0;
3804 pSMB->Flags = 0;
3805 pSMB->Timeout = 0;
3806 pSMB->Reserved2 = 0;
3807 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3808 InformationLevel) - 4;
3809 offset = param_offset + params;
3810 if(SetAllocation) {
3811 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3812 pSMB->InformationLevel =
3813 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3814 else
3815 pSMB->InformationLevel =
3816 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3817 } else /* Set File Size */ {
3818 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3819 pSMB->InformationLevel =
3820 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3821 else
3822 pSMB->InformationLevel =
3823 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3824 }
3825
3826 parm_data =
3827 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3828 offset);
3829 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3830 pSMB->DataOffset = cpu_to_le16(offset);
3831 pSMB->SetupCount = 1;
3832 pSMB->Reserved3 = 0;
3833 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3834 byte_count = 3 /* pad */ + params + data_count;
3835 pSMB->DataCount = cpu_to_le16(data_count);
3836 pSMB->TotalDataCount = pSMB->DataCount;
3837 pSMB->ParameterCount = cpu_to_le16(params);
3838 pSMB->TotalParameterCount = pSMB->ParameterCount;
3839 pSMB->Reserved4 = 0;
3840 pSMB->hdr.smb_buf_length += byte_count;
3841 parm_data->FileSize = cpu_to_le64(size);
3842 pSMB->ByteCount = cpu_to_le16(byte_count);
3843 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3844 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3845 if (rc) {
3846 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3847 }
3848
3849 cifs_buf_release(pSMB);
3850
3851 if (rc == -EAGAIN)
3852 goto SetEOFRetry;
3853
3854 return rc;
3855}
3856
3857int
3858CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
3859 __u16 fid, __u32 pid_of_opener, int SetAllocation)
3860{
3861 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3862 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3863 char *data_offset;
3864 struct file_end_of_file_info *parm_data;
3865 int rc = 0;
3866 int bytes_returned = 0;
3867 __u16 params, param_offset, offset, byte_count, count;
3868
3869 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3870 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07003871 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3872
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 if (rc)
3874 return rc;
3875
Steve Frenchcd634992005-04-28 22:41:10 -07003876 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3877
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3879 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3880
3881 params = 6;
3882 pSMB->MaxSetupCount = 0;
3883 pSMB->Reserved = 0;
3884 pSMB->Flags = 0;
3885 pSMB->Timeout = 0;
3886 pSMB->Reserved2 = 0;
3887 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3888 offset = param_offset + params;
3889
3890 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3891
3892 count = sizeof(struct file_end_of_file_info);
3893 pSMB->MaxParameterCount = cpu_to_le16(2);
3894 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3895 pSMB->SetupCount = 1;
3896 pSMB->Reserved3 = 0;
3897 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3898 byte_count = 3 /* pad */ + params + count;
3899 pSMB->DataCount = cpu_to_le16(count);
3900 pSMB->ParameterCount = cpu_to_le16(params);
3901 pSMB->TotalDataCount = pSMB->DataCount;
3902 pSMB->TotalParameterCount = pSMB->ParameterCount;
3903 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3904 parm_data =
3905 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3906 offset);
3907 pSMB->DataOffset = cpu_to_le16(offset);
3908 parm_data->FileSize = cpu_to_le64(size);
3909 pSMB->Fid = fid;
3910 if(SetAllocation) {
3911 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3912 pSMB->InformationLevel =
3913 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3914 else
3915 pSMB->InformationLevel =
3916 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3917 } else /* Set File Size */ {
3918 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3919 pSMB->InformationLevel =
3920 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3921 else
3922 pSMB->InformationLevel =
3923 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3924 }
3925 pSMB->Reserved4 = 0;
3926 pSMB->hdr.smb_buf_length += byte_count;
3927 pSMB->ByteCount = cpu_to_le16(byte_count);
3928 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3929 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3930 if (rc) {
3931 cFYI(1,
3932 ("Send error in SetFileInfo (SetFileSize) = %d",
3933 rc));
3934 }
3935
3936 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07003937 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003938
3939 /* Note: On -EAGAIN error only caller can retry on handle based calls
3940 since file handle passed in no longer valid */
3941
3942 return rc;
3943}
3944
3945/* Some legacy servers such as NT4 require that the file times be set on
3946 an open handle, rather than by pathname - this is awkward due to
3947 potential access conflicts on the open, but it is unavoidable for these
3948 old servers since the only other choice is to go from 100 nanosecond DCE
3949 time and resort to the original setpathinfo level which takes the ancient
3950 DOS time format with 2 second granularity */
3951int
3952CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
3953 __u16 fid)
3954{
3955 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3956 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3957 char *data_offset;
3958 int rc = 0;
3959 int bytes_returned = 0;
3960 __u16 params, param_offset, offset, byte_count, count;
3961
3962 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07003963 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3964
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 if (rc)
3966 return rc;
3967
Steve Frenchcd634992005-04-28 22:41:10 -07003968 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3969
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 /* At this point there is no need to override the current pid
3971 with the pid of the opener, but that could change if we someday
3972 use an existing handle (rather than opening one on the fly) */
3973 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3974 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3975
3976 params = 6;
3977 pSMB->MaxSetupCount = 0;
3978 pSMB->Reserved = 0;
3979 pSMB->Flags = 0;
3980 pSMB->Timeout = 0;
3981 pSMB->Reserved2 = 0;
3982 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3983 offset = param_offset + params;
3984
3985 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3986
3987 count = sizeof (FILE_BASIC_INFO);
3988 pSMB->MaxParameterCount = cpu_to_le16(2);
3989 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3990 pSMB->SetupCount = 1;
3991 pSMB->Reserved3 = 0;
3992 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3993 byte_count = 3 /* pad */ + params + count;
3994 pSMB->DataCount = cpu_to_le16(count);
3995 pSMB->ParameterCount = cpu_to_le16(params);
3996 pSMB->TotalDataCount = pSMB->DataCount;
3997 pSMB->TotalParameterCount = pSMB->ParameterCount;
3998 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3999 pSMB->DataOffset = cpu_to_le16(offset);
4000 pSMB->Fid = fid;
4001 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4002 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4003 else
4004 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4005 pSMB->Reserved4 = 0;
4006 pSMB->hdr.smb_buf_length += byte_count;
4007 pSMB->ByteCount = cpu_to_le16(byte_count);
4008 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4009 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4010 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4011 if (rc) {
4012 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4013 }
4014
Steve Frenchcd634992005-04-28 22:41:10 -07004015 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016
4017 /* Note: On -EAGAIN error only caller can retry on handle based calls
4018 since file handle passed in no longer valid */
4019
4020 return rc;
4021}
4022
4023
4024int
4025CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4026 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004027 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028{
4029 TRANSACTION2_SPI_REQ *pSMB = NULL;
4030 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4031 int name_len;
4032 int rc = 0;
4033 int bytes_returned = 0;
4034 char *data_offset;
4035 __u16 params, param_offset, offset, byte_count, count;
4036
4037 cFYI(1, ("In SetTimes"));
4038
4039SetTimesRetry:
4040 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4041 (void **) &pSMBr);
4042 if (rc)
4043 return rc;
4044
4045 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4046 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004047 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004048 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049 name_len++; /* trailing null */
4050 name_len *= 2;
4051 } else { /* BB improve the check for buffer overruns BB */
4052 name_len = strnlen(fileName, PATH_MAX);
4053 name_len++; /* trailing null */
4054 strncpy(pSMB->FileName, fileName, name_len);
4055 }
4056
4057 params = 6 + name_len;
4058 count = sizeof (FILE_BASIC_INFO);
4059 pSMB->MaxParameterCount = cpu_to_le16(2);
4060 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4061 pSMB->MaxSetupCount = 0;
4062 pSMB->Reserved = 0;
4063 pSMB->Flags = 0;
4064 pSMB->Timeout = 0;
4065 pSMB->Reserved2 = 0;
4066 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4067 InformationLevel) - 4;
4068 offset = param_offset + params;
4069 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4070 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4071 pSMB->DataOffset = cpu_to_le16(offset);
4072 pSMB->SetupCount = 1;
4073 pSMB->Reserved3 = 0;
4074 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4075 byte_count = 3 /* pad */ + params + count;
4076
4077 pSMB->DataCount = cpu_to_le16(count);
4078 pSMB->ParameterCount = cpu_to_le16(params);
4079 pSMB->TotalDataCount = pSMB->DataCount;
4080 pSMB->TotalParameterCount = pSMB->ParameterCount;
4081 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4082 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4083 else
4084 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4085 pSMB->Reserved4 = 0;
4086 pSMB->hdr.smb_buf_length += byte_count;
4087 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4088 pSMB->ByteCount = cpu_to_le16(byte_count);
4089 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4090 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4091 if (rc) {
4092 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4093 }
4094
4095 cifs_buf_release(pSMB);
4096
4097 if (rc == -EAGAIN)
4098 goto SetTimesRetry;
4099
4100 return rc;
4101}
4102
4103/* Can not be used to set time stamps yet (due to old DOS time format) */
4104/* Can be used to set attributes */
4105#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4106 handling it anyway and NT4 was what we thought it would be needed for
4107 Do not delete it until we prove whether needed for Win9x though */
4108int
4109CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4110 __u16 dos_attrs, const struct nls_table *nls_codepage)
4111{
4112 SETATTR_REQ *pSMB = NULL;
4113 SETATTR_RSP *pSMBr = NULL;
4114 int rc = 0;
4115 int bytes_returned;
4116 int name_len;
4117
4118 cFYI(1, ("In SetAttrLegacy"));
4119
4120SetAttrLgcyRetry:
4121 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4122 (void **) &pSMBr);
4123 if (rc)
4124 return rc;
4125
4126 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4127 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004128 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004129 PATH_MAX, nls_codepage);
4130 name_len++; /* trailing null */
4131 name_len *= 2;
4132 } else { /* BB improve the check for buffer overruns BB */
4133 name_len = strnlen(fileName, PATH_MAX);
4134 name_len++; /* trailing null */
4135 strncpy(pSMB->fileName, fileName, name_len);
4136 }
4137 pSMB->attr = cpu_to_le16(dos_attrs);
4138 pSMB->BufferFormat = 0x04;
4139 pSMB->hdr.smb_buf_length += name_len + 1;
4140 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4141 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4142 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4143 if (rc) {
4144 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4145 }
4146
4147 cifs_buf_release(pSMB);
4148
4149 if (rc == -EAGAIN)
4150 goto SetAttrLgcyRetry;
4151
4152 return rc;
4153}
4154#endif /* temporarily unneeded SetAttr legacy function */
4155
4156int
4157CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004158 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4159 dev_t device, const struct nls_table *nls_codepage,
4160 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161{
4162 TRANSACTION2_SPI_REQ *pSMB = NULL;
4163 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4164 int name_len;
4165 int rc = 0;
4166 int bytes_returned = 0;
4167 FILE_UNIX_BASIC_INFO *data_offset;
4168 __u16 params, param_offset, offset, count, byte_count;
4169
4170 cFYI(1, ("In SetUID/GID/Mode"));
4171setPermsRetry:
4172 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4173 (void **) &pSMBr);
4174 if (rc)
4175 return rc;
4176
4177 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4178 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004179 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004180 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 name_len++; /* trailing null */
4182 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004183 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 name_len = strnlen(fileName, PATH_MAX);
4185 name_len++; /* trailing null */
4186 strncpy(pSMB->FileName, fileName, name_len);
4187 }
4188
4189 params = 6 + name_len;
4190 count = sizeof (FILE_UNIX_BASIC_INFO);
4191 pSMB->MaxParameterCount = cpu_to_le16(2);
4192 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4193 pSMB->MaxSetupCount = 0;
4194 pSMB->Reserved = 0;
4195 pSMB->Flags = 0;
4196 pSMB->Timeout = 0;
4197 pSMB->Reserved2 = 0;
4198 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4199 InformationLevel) - 4;
4200 offset = param_offset + params;
4201 data_offset =
4202 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4203 offset);
4204 memset(data_offset, 0, count);
4205 pSMB->DataOffset = cpu_to_le16(offset);
4206 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4207 pSMB->SetupCount = 1;
4208 pSMB->Reserved3 = 0;
4209 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4210 byte_count = 3 /* pad */ + params + count;
4211 pSMB->ParameterCount = cpu_to_le16(params);
4212 pSMB->DataCount = cpu_to_le16(count);
4213 pSMB->TotalParameterCount = pSMB->ParameterCount;
4214 pSMB->TotalDataCount = pSMB->DataCount;
4215 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4216 pSMB->Reserved4 = 0;
4217 pSMB->hdr.smb_buf_length += byte_count;
4218 data_offset->Uid = cpu_to_le64(uid);
4219 data_offset->Gid = cpu_to_le64(gid);
4220 /* better to leave device as zero when it is */
4221 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4222 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4223 data_offset->Permissions = cpu_to_le64(mode);
4224
4225 if(S_ISREG(mode))
4226 data_offset->Type = cpu_to_le32(UNIX_FILE);
4227 else if(S_ISDIR(mode))
4228 data_offset->Type = cpu_to_le32(UNIX_DIR);
4229 else if(S_ISLNK(mode))
4230 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4231 else if(S_ISCHR(mode))
4232 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4233 else if(S_ISBLK(mode))
4234 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4235 else if(S_ISFIFO(mode))
4236 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4237 else if(S_ISSOCK(mode))
4238 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4239
4240
4241 pSMB->ByteCount = cpu_to_le16(byte_count);
4242 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4243 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4244 if (rc) {
4245 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4246 }
4247
4248 if (pSMB)
4249 cifs_buf_release(pSMB);
4250 if (rc == -EAGAIN)
4251 goto setPermsRetry;
4252 return rc;
4253}
4254
4255int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004256 const int notify_subdirs, const __u16 netfid,
4257 __u32 filter, struct file * pfile, int multishot,
4258 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259{
4260 int rc = 0;
4261 struct smb_com_transaction_change_notify_req * pSMB = NULL;
4262 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004263 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264 int bytes_returned;
4265
4266 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4267 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4268 (void **) &pSMBr);
4269 if (rc)
4270 return rc;
4271
4272 pSMB->TotalParameterCount = 0 ;
4273 pSMB->TotalDataCount = 0;
4274 pSMB->MaxParameterCount = cpu_to_le32(2);
4275 /* BB find exact data count max from sess structure BB */
4276 pSMB->MaxDataCount = 0; /* same in little endian or be */
4277 pSMB->MaxSetupCount = 4;
4278 pSMB->Reserved = 0;
4279 pSMB->ParameterOffset = 0;
4280 pSMB->DataCount = 0;
4281 pSMB->DataOffset = 0;
4282 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4283 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4284 pSMB->ParameterCount = pSMB->TotalParameterCount;
4285 if(notify_subdirs)
4286 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4287 pSMB->Reserved2 = 0;
4288 pSMB->CompletionFilter = cpu_to_le32(filter);
4289 pSMB->Fid = netfid; /* file handle always le */
4290 pSMB->ByteCount = 0;
4291
4292 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4293 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4294 if (rc) {
4295 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004296 } else {
4297 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004298 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004299 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004300 sizeof(struct dir_notify_req),
4301 GFP_KERNEL);
4302 if(dnotify_req) {
4303 dnotify_req->Pid = pSMB->hdr.Pid;
4304 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4305 dnotify_req->Mid = pSMB->hdr.Mid;
4306 dnotify_req->Tid = pSMB->hdr.Tid;
4307 dnotify_req->Uid = pSMB->hdr.Uid;
4308 dnotify_req->netfid = netfid;
4309 dnotify_req->pfile = pfile;
4310 dnotify_req->filter = filter;
4311 dnotify_req->multishot = multishot;
4312 spin_lock(&GlobalMid_Lock);
4313 list_add_tail(&dnotify_req->lhead,
4314 &GlobalDnotifyReqList);
4315 spin_unlock(&GlobalMid_Lock);
4316 } else
4317 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318 }
4319 cifs_buf_release(pSMB);
4320 return rc;
4321}
4322#ifdef CONFIG_CIFS_XATTR
4323ssize_t
4324CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4325 const unsigned char *searchName,
4326 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004327 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328{
4329 /* BB assumes one setup word */
4330 TRANSACTION2_QPI_REQ *pSMB = NULL;
4331 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4332 int rc = 0;
4333 int bytes_returned;
4334 int name_len;
4335 struct fea * temp_fea;
4336 char * temp_ptr;
4337 __u16 params, byte_count;
4338
4339 cFYI(1, ("In Query All EAs path %s", searchName));
4340QAllEAsRetry:
4341 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4342 (void **) &pSMBr);
4343 if (rc)
4344 return rc;
4345
4346 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4347 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004348 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004349 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004350 name_len++; /* trailing null */
4351 name_len *= 2;
4352 } else { /* BB improve the check for buffer overruns BB */
4353 name_len = strnlen(searchName, PATH_MAX);
4354 name_len++; /* trailing null */
4355 strncpy(pSMB->FileName, searchName, name_len);
4356 }
4357
4358 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4359 pSMB->TotalDataCount = 0;
4360 pSMB->MaxParameterCount = cpu_to_le16(2);
4361 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4362 pSMB->MaxSetupCount = 0;
4363 pSMB->Reserved = 0;
4364 pSMB->Flags = 0;
4365 pSMB->Timeout = 0;
4366 pSMB->Reserved2 = 0;
4367 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4368 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4369 pSMB->DataCount = 0;
4370 pSMB->DataOffset = 0;
4371 pSMB->SetupCount = 1;
4372 pSMB->Reserved3 = 0;
4373 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4374 byte_count = params + 1 /* pad */ ;
4375 pSMB->TotalParameterCount = cpu_to_le16(params);
4376 pSMB->ParameterCount = pSMB->TotalParameterCount;
4377 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4378 pSMB->Reserved4 = 0;
4379 pSMB->hdr.smb_buf_length += byte_count;
4380 pSMB->ByteCount = cpu_to_le16(byte_count);
4381
4382 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4383 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4384 if (rc) {
4385 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4386 } else { /* decode response */
4387 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4388
4389 /* BB also check enough total bytes returned */
4390 /* BB we need to improve the validity checking
4391 of these trans2 responses */
4392 if (rc || (pSMBr->ByteCount < 4))
4393 rc = -EIO; /* bad smb */
4394 /* else if (pFindData){
4395 memcpy((char *) pFindData,
4396 (char *) &pSMBr->hdr.Protocol +
4397 data_offset, kl);
4398 }*/ else {
4399 /* check that length of list is not more than bcc */
4400 /* check that each entry does not go beyond length
4401 of list */
4402 /* check that each element of each entry does not
4403 go beyond end of list */
4404 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4405 struct fealist * ea_response_data;
4406 rc = 0;
4407 /* validate_trans2_offsets() */
4408 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4409 ea_response_data = (struct fealist *)
4410 (((char *) &pSMBr->hdr.Protocol) +
4411 data_offset);
4412 name_len = le32_to_cpu(ea_response_data->list_len);
4413 cFYI(1,("ea length %d", name_len));
4414 if(name_len <= 8) {
4415 /* returned EA size zeroed at top of function */
4416 cFYI(1,("empty EA list returned from server"));
4417 } else {
4418 /* account for ea list len */
4419 name_len -= 4;
4420 temp_fea = ea_response_data->list;
4421 temp_ptr = (char *)temp_fea;
4422 while(name_len > 0) {
4423 __u16 value_len;
4424 name_len -= 4;
4425 temp_ptr += 4;
4426 rc += temp_fea->name_len;
4427 /* account for prefix user. and trailing null */
4428 rc = rc + 5 + 1;
4429 if(rc<(int)buf_size) {
4430 memcpy(EAData,"user.",5);
4431 EAData+=5;
4432 memcpy(EAData,temp_ptr,temp_fea->name_len);
4433 EAData+=temp_fea->name_len;
4434 /* null terminate name */
4435 *EAData = 0;
4436 EAData = EAData + 1;
4437 } else if(buf_size == 0) {
4438 /* skip copy - calc size only */
4439 } else {
4440 /* stop before overrun buffer */
4441 rc = -ERANGE;
4442 break;
4443 }
4444 name_len -= temp_fea->name_len;
4445 temp_ptr += temp_fea->name_len;
4446 /* account for trailing null */
4447 name_len--;
4448 temp_ptr++;
4449 value_len = le16_to_cpu(temp_fea->value_len);
4450 name_len -= value_len;
4451 temp_ptr += value_len;
4452 /* BB check that temp_ptr is still within smb BB*/
4453 /* no trailing null to account for in value len */
4454 /* go on to next EA */
4455 temp_fea = (struct fea *)temp_ptr;
4456 }
4457 }
4458 }
4459 }
4460 if (pSMB)
4461 cifs_buf_release(pSMB);
4462 if (rc == -EAGAIN)
4463 goto QAllEAsRetry;
4464
4465 return (ssize_t)rc;
4466}
4467
4468ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4469 const unsigned char * searchName,const unsigned char * ea_name,
4470 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004471 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004472{
4473 TRANSACTION2_QPI_REQ *pSMB = NULL;
4474 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4475 int rc = 0;
4476 int bytes_returned;
4477 int name_len;
4478 struct fea * temp_fea;
4479 char * temp_ptr;
4480 __u16 params, byte_count;
4481
4482 cFYI(1, ("In Query EA path %s", searchName));
4483QEARetry:
4484 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4485 (void **) &pSMBr);
4486 if (rc)
4487 return rc;
4488
4489 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4490 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004491 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004492 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493 name_len++; /* trailing null */
4494 name_len *= 2;
4495 } else { /* BB improve the check for buffer overruns BB */
4496 name_len = strnlen(searchName, PATH_MAX);
4497 name_len++; /* trailing null */
4498 strncpy(pSMB->FileName, searchName, name_len);
4499 }
4500
4501 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4502 pSMB->TotalDataCount = 0;
4503 pSMB->MaxParameterCount = cpu_to_le16(2);
4504 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4505 pSMB->MaxSetupCount = 0;
4506 pSMB->Reserved = 0;
4507 pSMB->Flags = 0;
4508 pSMB->Timeout = 0;
4509 pSMB->Reserved2 = 0;
4510 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4511 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4512 pSMB->DataCount = 0;
4513 pSMB->DataOffset = 0;
4514 pSMB->SetupCount = 1;
4515 pSMB->Reserved3 = 0;
4516 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4517 byte_count = params + 1 /* pad */ ;
4518 pSMB->TotalParameterCount = cpu_to_le16(params);
4519 pSMB->ParameterCount = pSMB->TotalParameterCount;
4520 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4521 pSMB->Reserved4 = 0;
4522 pSMB->hdr.smb_buf_length += byte_count;
4523 pSMB->ByteCount = cpu_to_le16(byte_count);
4524
4525 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4526 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4527 if (rc) {
4528 cFYI(1, ("Send error in Query EA = %d", rc));
4529 } else { /* decode response */
4530 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4531
4532 /* BB also check enough total bytes returned */
4533 /* BB we need to improve the validity checking
4534 of these trans2 responses */
4535 if (rc || (pSMBr->ByteCount < 4))
4536 rc = -EIO; /* bad smb */
4537 /* else if (pFindData){
4538 memcpy((char *) pFindData,
4539 (char *) &pSMBr->hdr.Protocol +
4540 data_offset, kl);
4541 }*/ else {
4542 /* check that length of list is not more than bcc */
4543 /* check that each entry does not go beyond length
4544 of list */
4545 /* check that each element of each entry does not
4546 go beyond end of list */
4547 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4548 struct fealist * ea_response_data;
4549 rc = -ENODATA;
4550 /* validate_trans2_offsets() */
4551 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4552 ea_response_data = (struct fealist *)
4553 (((char *) &pSMBr->hdr.Protocol) +
4554 data_offset);
4555 name_len = le32_to_cpu(ea_response_data->list_len);
4556 cFYI(1,("ea length %d", name_len));
4557 if(name_len <= 8) {
4558 /* returned EA size zeroed at top of function */
4559 cFYI(1,("empty EA list returned from server"));
4560 } else {
4561 /* account for ea list len */
4562 name_len -= 4;
4563 temp_fea = ea_response_data->list;
4564 temp_ptr = (char *)temp_fea;
4565 /* loop through checking if we have a matching
4566 name and then return the associated value */
4567 while(name_len > 0) {
4568 __u16 value_len;
4569 name_len -= 4;
4570 temp_ptr += 4;
4571 value_len = le16_to_cpu(temp_fea->value_len);
4572 /* BB validate that value_len falls within SMB,
4573 even though maximum for name_len is 255 */
4574 if(memcmp(temp_fea->name,ea_name,
4575 temp_fea->name_len) == 0) {
4576 /* found a match */
4577 rc = value_len;
4578 /* account for prefix user. and trailing null */
4579 if(rc<=(int)buf_size) {
4580 memcpy(ea_value,
4581 temp_fea->name+temp_fea->name_len+1,
4582 rc);
4583 /* ea values, unlike ea names,
4584 are not null terminated */
4585 } else if(buf_size == 0) {
4586 /* skip copy - calc size only */
4587 } else {
4588 /* stop before overrun buffer */
4589 rc = -ERANGE;
4590 }
4591 break;
4592 }
4593 name_len -= temp_fea->name_len;
4594 temp_ptr += temp_fea->name_len;
4595 /* account for trailing null */
4596 name_len--;
4597 temp_ptr++;
4598 name_len -= value_len;
4599 temp_ptr += value_len;
4600 /* no trailing null to account for in value len */
4601 /* go on to next EA */
4602 temp_fea = (struct fea *)temp_ptr;
4603 }
4604 }
4605 }
4606 }
4607 if (pSMB)
4608 cifs_buf_release(pSMB);
4609 if (rc == -EAGAIN)
4610 goto QEARetry;
4611
4612 return (ssize_t)rc;
4613}
4614
4615int
4616CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4617 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004618 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4619 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620{
4621 struct smb_com_transaction2_spi_req *pSMB = NULL;
4622 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4623 struct fealist *parm_data;
4624 int name_len;
4625 int rc = 0;
4626 int bytes_returned = 0;
4627 __u16 params, param_offset, byte_count, offset, count;
4628
4629 cFYI(1, ("In SetEA"));
4630SetEARetry:
4631 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4632 (void **) &pSMBr);
4633 if (rc)
4634 return rc;
4635
4636 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4637 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004638 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004639 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 name_len++; /* trailing null */
4641 name_len *= 2;
4642 } else { /* BB improve the check for buffer overruns BB */
4643 name_len = strnlen(fileName, PATH_MAX);
4644 name_len++; /* trailing null */
4645 strncpy(pSMB->FileName, fileName, name_len);
4646 }
4647
4648 params = 6 + name_len;
4649
4650 /* done calculating parms using name_len of file name,
4651 now use name_len to calculate length of ea name
4652 we are going to create in the inode xattrs */
4653 if(ea_name == NULL)
4654 name_len = 0;
4655 else
4656 name_len = strnlen(ea_name,255);
4657
4658 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4659 pSMB->MaxParameterCount = cpu_to_le16(2);
4660 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4661 pSMB->MaxSetupCount = 0;
4662 pSMB->Reserved = 0;
4663 pSMB->Flags = 0;
4664 pSMB->Timeout = 0;
4665 pSMB->Reserved2 = 0;
4666 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4667 InformationLevel) - 4;
4668 offset = param_offset + params;
4669 pSMB->InformationLevel =
4670 cpu_to_le16(SMB_SET_FILE_EA);
4671
4672 parm_data =
4673 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4674 offset);
4675 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4676 pSMB->DataOffset = cpu_to_le16(offset);
4677 pSMB->SetupCount = 1;
4678 pSMB->Reserved3 = 0;
4679 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4680 byte_count = 3 /* pad */ + params + count;
4681 pSMB->DataCount = cpu_to_le16(count);
4682 parm_data->list_len = cpu_to_le32(count);
4683 parm_data->list[0].EA_flags = 0;
4684 /* we checked above that name len is less than 255 */
4685 parm_data->list[0].name_len = (__u8)name_len;;
4686 /* EA names are always ASCII */
4687 if(ea_name)
4688 strncpy(parm_data->list[0].name,ea_name,name_len);
4689 parm_data->list[0].name[name_len] = 0;
4690 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4691 /* caller ensures that ea_value_len is less than 64K but
4692 we need to ensure that it fits within the smb */
4693
4694 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4695 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4696 if(ea_value_len)
4697 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4698
4699 pSMB->TotalDataCount = pSMB->DataCount;
4700 pSMB->ParameterCount = cpu_to_le16(params);
4701 pSMB->TotalParameterCount = pSMB->ParameterCount;
4702 pSMB->Reserved4 = 0;
4703 pSMB->hdr.smb_buf_length += byte_count;
4704 pSMB->ByteCount = cpu_to_le16(byte_count);
4705 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4706 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4707 if (rc) {
4708 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4709 }
4710
4711 cifs_buf_release(pSMB);
4712
4713 if (rc == -EAGAIN)
4714 goto SetEARetry;
4715
4716 return rc;
4717}
4718
4719#endif