blob: 6867e556d37e51485a4e9d35fb7ea332fc971b6d [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 French6ab16d22005-11-29 20:55:11 -080093 if(tcon->tidStatus == CifsExiting) {
94 /* only tree disconnect, open, and write,
95 (and ulogoff which does not have tcon)
96 are allowed as we start force umount */
97 if((smb_command != SMB_COM_WRITE_ANDX) &&
98 (smb_command != SMB_COM_OPEN_ANDX) &&
99 (smb_command != SMB_COM_TREE_DISCONNECT)) {
100 cFYI(1,("can not send cmd %d while umounting",
101 smb_command));
102 return -ENODEV;
103 }
104 }
Steve French31ca3bc2005-04-28 22:41:11 -0700105 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
106 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 struct nls_table *nls_codepage;
108 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700109 reconnect, should be greater than cifs socket
110 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
112 wait_event_interruptible_timeout(tcon->ses->server->response_q,
113 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
114 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
115 /* on "soft" mounts we wait once */
116 if((tcon->retry == FALSE) ||
117 (tcon->ses->status == CifsExiting)) {
118 cFYI(1,("gave up waiting on reconnect in smb_init"));
119 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700120 } /* else "hard" mount - keep retrying
121 until process is killed or server
122 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 } else /* TCP session is reestablished now */
124 break;
125
126 }
127
128 nls_codepage = load_nls_default();
129 /* need to prevent multiple threads trying to
130 simultaneously reconnect the same SMB session */
131 down(&tcon->ses->sesSem);
132 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700133 rc = cifs_setup_session(0, tcon->ses,
134 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
136 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700137 rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon
138 , nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700140 /* BB FIXME add code to check if wsize needs
141 update due to negotiated smb buffer size
142 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 if(rc == 0)
144 atomic_inc(&tconInfoReconnectCount);
145
146 cFYI(1, ("reconnect tcon rc = %d", rc));
147 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700148 it is safer (and faster) to reopen files
149 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
151 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700152 know whether we can continue or not without
153 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 switch(smb_command) {
155 case SMB_COM_READ_ANDX:
156 case SMB_COM_WRITE_ANDX:
157 case SMB_COM_CLOSE:
158 case SMB_COM_FIND_CLOSE2:
159 case SMB_COM_LOCKING_ANDX: {
160 unload_nls(nls_codepage);
161 return -EAGAIN;
162 }
163 }
164 } else {
165 up(&tcon->ses->sesSem);
166 }
167 unload_nls(nls_codepage);
168
169 } else {
170 return -EIO;
171 }
172 }
173 if(rc)
174 return rc;
175
176 *request_buf = cifs_small_buf_get();
177 if (*request_buf == NULL) {
178 /* BB should we add a retry in here if not a writepage? */
179 return -ENOMEM;
180 }
181
182 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
183
Steve Frencha4544342005-08-24 13:59:35 -0700184 if(tcon != NULL)
185 cifs_stats_inc(&tcon->num_smbs_sent);
186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 return rc;
188}
189
190/* If the return code is zero, this function must fill in request_buf pointer */
191static int
192smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
193 void **request_buf /* returned */ ,
194 void **response_buf /* returned */ )
195{
196 int rc = 0;
197
198 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
199 check for tcp and smb session status done differently
200 for those three - in the calling routine */
201 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800202 if(tcon->tidStatus == CifsExiting) {
203 /* only tree disconnect, open, and write,
204 (and ulogoff which does not have tcon)
205 are allowed as we start force umount */
206 if((smb_command != SMB_COM_WRITE_ANDX) &&
207 (smb_command != SMB_COM_OPEN_ANDX) &&
208 (smb_command != SMB_COM_TREE_DISCONNECT)) {
209 cFYI(1,("can not send cmd %d while umounting",
210 smb_command));
211 return -ENODEV;
212 }
213 }
214
Steve French31ca3bc2005-04-28 22:41:11 -0700215 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
216 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700218 /* Give Demultiplex thread up to 10 seconds to
219 reconnect, should be greater than cifs socket
220 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
222 wait_event_interruptible_timeout(tcon->ses->server->response_q,
223 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
Steve French09d1db52005-04-28 22:41:08 -0700224 if(tcon->ses->server->tcpStatus ==
225 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 /* on "soft" mounts we wait once */
227 if((tcon->retry == FALSE) ||
228 (tcon->ses->status == CifsExiting)) {
229 cFYI(1,("gave up waiting on reconnect in smb_init"));
230 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700231 } /* else "hard" mount - keep retrying
232 until process is killed or server
233 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 } else /* TCP session is reestablished now */
235 break;
236
237 }
238
239 nls_codepage = load_nls_default();
240 /* need to prevent multiple threads trying to
241 simultaneously reconnect the same SMB session */
242 down(&tcon->ses->sesSem);
243 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700244 rc = cifs_setup_session(0, tcon->ses,
245 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
247 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700248 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
249 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 up(&tcon->ses->sesSem);
Steve French3e844692005-10-03 13:37:24 -0700251 /* BB FIXME add code to check if wsize needs
252 update due to negotiated smb buffer size
253 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 if(rc == 0)
255 atomic_inc(&tconInfoReconnectCount);
256
257 cFYI(1, ("reconnect tcon rc = %d", rc));
258 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700259 it is safer (and faster) to reopen files
260 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
262 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700263 know whether we can continue or not without
264 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 switch(smb_command) {
266 case SMB_COM_READ_ANDX:
267 case SMB_COM_WRITE_ANDX:
268 case SMB_COM_CLOSE:
269 case SMB_COM_FIND_CLOSE2:
270 case SMB_COM_LOCKING_ANDX: {
271 unload_nls(nls_codepage);
272 return -EAGAIN;
273 }
274 }
275 } else {
276 up(&tcon->ses->sesSem);
277 }
278 unload_nls(nls_codepage);
279
280 } else {
281 return -EIO;
282 }
283 }
284 if(rc)
285 return rc;
286
287 *request_buf = cifs_buf_get();
288 if (*request_buf == NULL) {
289 /* BB should we add a retry in here if not a writepage? */
290 return -ENOMEM;
291 }
292 /* Although the original thought was we needed the response buf for */
293 /* potential retries of smb operations it turns out we can determine */
294 /* from the mid flags when the request buffer can be resent without */
295 /* having to use a second distinct buffer for the response */
296 *response_buf = *request_buf;
297
298 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
299 wct /*wct */ );
300
Steve Frencha4544342005-08-24 13:59:35 -0700301 if(tcon != NULL)
302 cifs_stats_inc(&tcon->num_smbs_sent);
303
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 return rc;
305}
306
307static int validate_t2(struct smb_t2_rsp * pSMB)
308{
309 int rc = -EINVAL;
310 int total_size;
311 char * pBCC;
312
313 /* check for plausible wct, bcc and t2 data and parm sizes */
314 /* check for parm and data offset going beyond end of smb */
315 if(pSMB->hdr.WordCount >= 10) {
316 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
317 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
318 /* check that bcc is at least as big as parms + data */
319 /* check that bcc is less than negotiated smb buffer */
320 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
321 if(total_size < 512) {
322 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
323 /* BCC le converted in SendReceive */
Steve French09d1db52005-04-28 22:41:08 -0700324 pBCC = (pSMB->hdr.WordCount * 2) +
325 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 (char *)pSMB;
327 if((total_size <= (*(u16 *)pBCC)) &&
328 (total_size <
329 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
330 return 0;
331 }
332
333 }
334 }
335 }
336 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
337 sizeof(struct smb_t2_rsp) + 16);
338 return rc;
339}
340int
341CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
342{
343 NEGOTIATE_REQ *pSMB;
344 NEGOTIATE_RSP *pSMBr;
345 int rc = 0;
346 int bytes_returned;
347 struct TCP_Server_Info * server;
348 u16 count;
349
350 if(ses->server)
351 server = ses->server;
352 else {
353 rc = -EIO;
354 return rc;
355 }
356 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
357 (void **) &pSMB, (void **) &pSMBr);
358 if (rc)
359 return rc;
Steve French1982c342005-08-17 12:38:22 -0700360 pSMB->hdr.Mid = GetNextMid(server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
362 if (extended_security)
363 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
364
365 count = strlen(protocols[0].name) + 1;
366 strncpy(pSMB->DialectsArray, protocols[0].name, 30);
367 /* null guaranteed to be at end of source and target buffers anyway */
368
369 pSMB->hdr.smb_buf_length += count;
370 pSMB->ByteCount = cpu_to_le16(count);
371
372 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
373 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
374 if (rc == 0) {
375 server->secMode = pSMBr->SecurityMode;
Steve French09d1db52005-04-28 22:41:08 -0700376 server->secType = NTLM; /* BB override default for
377 NTLMv2 or kerberos v5 */
378 /* one byte - no need to convert this or EncryptionKeyLen
379 from little endian */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
381 /* probably no need to store and check maxvcs */
382 server->maxBuf =
383 min(le32_to_cpu(pSMBr->MaxBufferSize),
384 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
385 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
386 cFYI(0, ("Max buf = %d ", ses->server->maxBuf));
387 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
388 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
389 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
390 /* BB with UTC do we ever need to be using srvr timezone? */
391 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
392 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
393 CIFS_CRYPTO_KEY_SIZE);
394 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
395 && (pSMBr->EncryptionKeyLength == 0)) {
396 /* decode security blob */
397 } else
398 rc = -EIO;
399
400 /* BB might be helpful to save off the domain of server here */
401
402 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
403 (server->capabilities & CAP_EXTENDED_SECURITY)) {
404 count = pSMBr->ByteCount;
405 if (count < 16)
406 rc = -EIO;
407 else if (count == 16) {
408 server->secType = RawNTLMSSP;
409 if (server->socketUseCount.counter > 1) {
410 if (memcmp
411 (server->server_GUID,
412 pSMBr->u.extended_response.
413 GUID, 16) != 0) {
414 cFYI(1,
Steve French09d1db52005-04-28 22:41:08 -0700415 ("UID of server does not match previous connection to same ip address"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 memcpy(server->
417 server_GUID,
418 pSMBr->u.
419 extended_response.
420 GUID, 16);
421 }
422 } else
423 memcpy(server->server_GUID,
424 pSMBr->u.extended_response.
425 GUID, 16);
426 } else {
427 rc = decode_negTokenInit(pSMBr->u.
428 extended_response.
429 SecurityBlob,
430 count - 16,
431 &server->secType);
432 if(rc == 1) {
433 /* BB Need to fill struct for sessetup here */
434 rc = -EOPNOTSUPP;
435 } else {
436 rc = -EINVAL;
437 }
438 }
439 } else
440 server->capabilities &= ~CAP_EXTENDED_SECURITY;
441 if(sign_CIFS_PDUs == FALSE) {
442 if(server->secMode & SECMODE_SIGN_REQUIRED)
443 cERROR(1,
444 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
Steve French1982c342005-08-17 12:38:22 -0700445 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 } else if(sign_CIFS_PDUs == 1) {
447 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French1982c342005-08-17 12:38:22 -0700448 server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 }
450
451 }
Steve French1982c342005-08-17 12:38:22 -0700452
Steve French4a6d87f2005-08-13 08:15:54 -0700453 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454 return rc;
455}
456
457int
458CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
459{
460 struct smb_hdr *smb_buffer;
461 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
462 int rc = 0;
463 int length;
464
465 cFYI(1, ("In tree disconnect"));
466 /*
467 * If last user of the connection and
468 * connection alive - disconnect it
469 * If this is the last connection on the server session disconnect it
470 * (and inside session disconnect we should check if tcp socket needs
471 * to be freed and kernel thread woken up).
472 */
473 if (tcon)
474 down(&tcon->tconSem);
475 else
476 return -EIO;
477
478 atomic_dec(&tcon->useCount);
479 if (atomic_read(&tcon->useCount) > 0) {
480 up(&tcon->tconSem);
481 return -EBUSY;
482 }
483
484 /* No need to return error on this operation if tid invalidated and
485 closed on server already e.g. due to tcp session crashing */
486 if(tcon->tidStatus == CifsNeedReconnect) {
487 up(&tcon->tconSem);
488 return 0;
489 }
490
491 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
492 up(&tcon->tconSem);
493 return -EIO;
494 }
Steve French09d1db52005-04-28 22:41:08 -0700495 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
496 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 if (rc) {
498 up(&tcon->tconSem);
499 return rc;
500 } else {
501 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700502 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
504 &length, 0);
505 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700506 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508 if (smb_buffer)
509 cifs_small_buf_release(smb_buffer);
510 up(&tcon->tconSem);
511
512 /* No need to return error on this operation if tid invalidated and
513 closed on server already e.g. due to tcp session crashing */
514 if (rc == -EAGAIN)
515 rc = 0;
516
517 return rc;
518}
519
520int
521CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
522{
523 struct smb_hdr *smb_buffer_response;
524 LOGOFF_ANDX_REQ *pSMB;
525 int rc = 0;
526 int length;
527
528 cFYI(1, ("In SMBLogoff for session disconnect"));
529 if (ses)
530 down(&ses->sesSem);
531 else
532 return -EIO;
533
534 atomic_dec(&ses->inUse);
535 if (atomic_read(&ses->inUse) > 0) {
536 up(&ses->sesSem);
537 return -EBUSY;
538 }
539 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
540 if (rc) {
541 up(&ses->sesSem);
542 return rc;
543 }
544
545 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
546
547 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700548 pSMB->hdr.Mid = GetNextMid(ses->server);
549
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 if(ses->server->secMode &
551 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
552 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
553 }
554
555 pSMB->hdr.Uid = ses->Suid;
556
557 pSMB->AndXCommand = 0xFF;
558 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
559 smb_buffer_response, &length, 0);
560 if (ses->server) {
561 atomic_dec(&ses->server->socketUseCount);
562 if (atomic_read(&ses->server->socketUseCount) == 0) {
563 spin_lock(&GlobalMid_Lock);
564 ses->server->tcpStatus = CifsExiting;
565 spin_unlock(&GlobalMid_Lock);
566 rc = -ESHUTDOWN;
567 }
568 }
Steve Frencha59c6582005-08-17 12:12:19 -0700569 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700570 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571
572 /* if session dead then we do not need to do ulogoff,
573 since server closed smb session, no sense reporting
574 error */
575 if (rc == -EAGAIN)
576 rc = 0;
577 return rc;
578}
579
580int
Steve French737b7582005-04-28 22:41:06 -0700581CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
582 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583{
584 DELETE_FILE_REQ *pSMB = NULL;
585 DELETE_FILE_RSP *pSMBr = NULL;
586 int rc = 0;
587 int bytes_returned;
588 int name_len;
589
590DelFileRetry:
591 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
592 (void **) &pSMBr);
593 if (rc)
594 return rc;
595
596 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
597 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500598 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700599 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 name_len++; /* trailing null */
601 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700602 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 name_len = strnlen(fileName, PATH_MAX);
604 name_len++; /* trailing null */
605 strncpy(pSMB->fileName, fileName, name_len);
606 }
607 pSMB->SearchAttributes =
608 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
609 pSMB->BufferFormat = 0x04;
610 pSMB->hdr.smb_buf_length += name_len + 1;
611 pSMB->ByteCount = cpu_to_le16(name_len + 1);
612 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
613 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700614 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 if (rc) {
616 cFYI(1, ("Error in RMFile = %d", rc));
617 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618
619 cifs_buf_release(pSMB);
620 if (rc == -EAGAIN)
621 goto DelFileRetry;
622
623 return rc;
624}
625
626int
Steve French737b7582005-04-28 22:41:06 -0700627CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
628 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629{
630 DELETE_DIRECTORY_REQ *pSMB = NULL;
631 DELETE_DIRECTORY_RSP *pSMBr = NULL;
632 int rc = 0;
633 int bytes_returned;
634 int name_len;
635
636 cFYI(1, ("In CIFSSMBRmDir"));
637RmDirRetry:
638 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
639 (void **) &pSMBr);
640 if (rc)
641 return rc;
642
643 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700644 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
645 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 name_len++; /* trailing null */
647 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700648 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 name_len = strnlen(dirName, PATH_MAX);
650 name_len++; /* trailing null */
651 strncpy(pSMB->DirName, dirName, name_len);
652 }
653
654 pSMB->BufferFormat = 0x04;
655 pSMB->hdr.smb_buf_length += name_len + 1;
656 pSMB->ByteCount = cpu_to_le16(name_len + 1);
657 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
658 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700659 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 if (rc) {
661 cFYI(1, ("Error in RMDir = %d", rc));
662 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
664 cifs_buf_release(pSMB);
665 if (rc == -EAGAIN)
666 goto RmDirRetry;
667 return rc;
668}
669
670int
671CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700672 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673{
674 int rc = 0;
675 CREATE_DIRECTORY_REQ *pSMB = NULL;
676 CREATE_DIRECTORY_RSP *pSMBr = NULL;
677 int bytes_returned;
678 int name_len;
679
680 cFYI(1, ("In CIFSSMBMkDir"));
681MkDirRetry:
682 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
683 (void **) &pSMBr);
684 if (rc)
685 return rc;
686
687 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500688 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700689 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 name_len++; /* trailing null */
691 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700692 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 name_len = strnlen(name, PATH_MAX);
694 name_len++; /* trailing null */
695 strncpy(pSMB->DirName, name, name_len);
696 }
697
698 pSMB->BufferFormat = 0x04;
699 pSMB->hdr.smb_buf_length += name_len + 1;
700 pSMB->ByteCount = cpu_to_le16(name_len + 1);
701 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
702 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700703 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 if (rc) {
705 cFYI(1, ("Error in Mkdir = %d", rc));
706 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700707
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 cifs_buf_release(pSMB);
709 if (rc == -EAGAIN)
710 goto MkDirRetry;
711 return rc;
712}
713
Steve Frencha9d02ad2005-08-24 23:06:05 -0700714static __u16 convert_disposition(int disposition)
715{
716 __u16 ofun = 0;
717
718 switch (disposition) {
719 case FILE_SUPERSEDE:
720 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
721 break;
722 case FILE_OPEN:
723 ofun = SMBOPEN_OAPPEND;
724 break;
725 case FILE_CREATE:
726 ofun = SMBOPEN_OCREATE;
727 break;
728 case FILE_OPEN_IF:
729 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
730 break;
731 case FILE_OVERWRITE:
732 ofun = SMBOPEN_OTRUNC;
733 break;
734 case FILE_OVERWRITE_IF:
735 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
736 break;
737 default:
738 cFYI(1,("unknown disposition %d",disposition));
739 ofun = SMBOPEN_OAPPEND; /* regular open */
740 }
741 return ofun;
742}
743
744int
745SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
746 const char *fileName, const int openDisposition,
747 const int access_flags, const int create_options, __u16 * netfid,
748 int *pOplock, FILE_ALL_INFO * pfile_info,
749 const struct nls_table *nls_codepage, int remap)
750{
751 int rc = -EACCES;
752 OPENX_REQ *pSMB = NULL;
753 OPENX_RSP *pSMBr = NULL;
754 int bytes_returned;
755 int name_len;
756 __u16 count;
757
758OldOpenRetry:
759 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
760 (void **) &pSMBr);
761 if (rc)
762 return rc;
763
764 pSMB->AndXCommand = 0xFF; /* none */
765
766 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
767 count = 1; /* account for one byte pad to word boundary */
768 name_len =
769 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
770 fileName, PATH_MAX, nls_codepage, remap);
771 name_len++; /* trailing null */
772 name_len *= 2;
773 } else { /* BB improve check for buffer overruns BB */
774 count = 0; /* no pad */
775 name_len = strnlen(fileName, PATH_MAX);
776 name_len++; /* trailing null */
777 strncpy(pSMB->fileName, fileName, name_len);
778 }
779 if (*pOplock & REQ_OPLOCK)
780 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
781 else if (*pOplock & REQ_BATCHOPLOCK) {
782 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
783 }
784 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
785 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
786 /* 0 = read
787 1 = write
788 2 = rw
789 3 = execute
790 */
791 pSMB->Mode = cpu_to_le16(2);
792 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
793 /* set file as system file if special file such
794 as fifo and server expecting SFU style and
795 no Unix extensions */
796
797 if(create_options & CREATE_OPTION_SPECIAL)
798 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
799 else
Steve French3e87d802005-09-18 20:49:21 -0700800 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -0700801
802 /* if ((omode & S_IWUGO) == 0)
803 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
804 /* Above line causes problems due to vfs splitting create into two
805 pieces - need to set mode after file created not while it is
806 being created */
807
808 /* BB FIXME BB */
809/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
810 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -0700811
812 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -0700813 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700814 count += name_len;
815 pSMB->hdr.smb_buf_length += count;
816
817 pSMB->ByteCount = cpu_to_le16(count);
818 /* long_op set to 1 to allow for oplock break timeouts */
819 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
820 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
821 cifs_stats_inc(&tcon->num_opens);
822 if (rc) {
823 cFYI(1, ("Error in Open = %d", rc));
824 } else {
825 /* BB verify if wct == 15 */
826
827/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
828
829 *netfid = pSMBr->Fid; /* cifs fid stays in le */
830 /* Let caller know file was created so we can set the mode. */
831 /* Do we care about the CreateAction in any other cases? */
832 /* BB FIXME BB */
833/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
834 *pOplock |= CIFS_CREATE_ACTION; */
835 /* BB FIXME END */
836
837 if(pfile_info) {
838 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
839 pfile_info->LastAccessTime = 0; /* BB fixme */
840 pfile_info->LastWriteTime = 0; /* BB fixme */
841 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -0700842 pfile_info->Attributes =
843 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -0700844 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -0700845 pfile_info->AllocationSize =
846 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
847 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -0700848 pfile_info->NumberOfLinks = cpu_to_le32(1);
849 }
850 }
851
852 cifs_buf_release(pSMB);
853 if (rc == -EAGAIN)
854 goto OldOpenRetry;
855 return rc;
856}
857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858int
859CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
860 const char *fileName, const int openDisposition,
861 const int access_flags, const int create_options, __u16 * netfid,
862 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -0700863 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864{
865 int rc = -EACCES;
866 OPEN_REQ *pSMB = NULL;
867 OPEN_RSP *pSMBr = NULL;
868 int bytes_returned;
869 int name_len;
870 __u16 count;
871
872openRetry:
873 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
874 (void **) &pSMBr);
875 if (rc)
876 return rc;
877
878 pSMB->AndXCommand = 0xFF; /* none */
879
880 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
881 count = 1; /* account for one byte pad to word boundary */
882 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500883 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -0700884 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 name_len++; /* trailing null */
886 name_len *= 2;
887 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -0700888 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 count = 0; /* no pad */
890 name_len = strnlen(fileName, PATH_MAX);
891 name_len++; /* trailing null */
892 pSMB->NameLength = cpu_to_le16(name_len);
893 strncpy(pSMB->fileName, fileName, name_len);
894 }
895 if (*pOplock & REQ_OPLOCK)
896 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
897 else if (*pOplock & REQ_BATCHOPLOCK) {
898 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
899 }
900 pSMB->DesiredAccess = cpu_to_le32(access_flags);
901 pSMB->AllocationSize = 0;
Steve Frencheda3c022005-07-21 15:20:28 -0700902 /* set file as system file if special file such
903 as fifo and server expecting SFU style and
904 no Unix extensions */
905 if(create_options & CREATE_OPTION_SPECIAL)
906 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
907 else
908 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 /* XP does not handle ATTR_POSIX_SEMANTICS */
910 /* but it helps speed up case sensitive checks for other
911 servers such as Samba */
912 if (tcon->ses->capabilities & CAP_UNIX)
913 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
914
915 /* if ((omode & S_IWUGO) == 0)
916 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
917 /* Above line causes problems due to vfs splitting create into two
918 pieces - need to set mode after file created not while it is
919 being created */
920 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
921 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -0700922 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -0700923 /* BB Expirement with various impersonation levels and verify */
924 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 pSMB->SecurityFlags =
926 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
927
928 count += name_len;
929 pSMB->hdr.smb_buf_length += count;
930
931 pSMB->ByteCount = cpu_to_le16(count);
932 /* long_op set to 1 to allow for oplock break timeouts */
933 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
934 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -0700935 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 if (rc) {
937 cFYI(1, ("Error in Open = %d", rc));
938 } else {
Steve French09d1db52005-04-28 22:41:08 -0700939 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 *netfid = pSMBr->Fid; /* cifs fid stays in le */
941 /* Let caller know file was created so we can set the mode. */
942 /* Do we care about the CreateAction in any other cases? */
943 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
944 *pOplock |= CIFS_CREATE_ACTION;
945 if(pfile_info) {
946 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
947 36 /* CreationTime to Attributes */);
948 /* the file_info buf is endian converted by caller */
949 pfile_info->AllocationSize = pSMBr->AllocationSize;
950 pfile_info->EndOfFile = pSMBr->EndOfFile;
951 pfile_info->NumberOfLinks = cpu_to_le32(1);
952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700954
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 cifs_buf_release(pSMB);
956 if (rc == -EAGAIN)
957 goto openRetry;
958 return rc;
959}
960
961/* If no buffer passed in, then caller wants to do the copy
962 as in the case of readpages so the SMB buffer must be
963 freed by the caller */
964
965int
966CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
967 const int netfid, const unsigned int count,
968 const __u64 lseek, unsigned int *nbytes, char **buf)
969{
970 int rc = -EACCES;
971 READ_REQ *pSMB = NULL;
972 READ_RSP *pSMBr = NULL;
973 char *pReadData = NULL;
974 int bytes_returned;
Steve Frenchbfa0d752005-08-31 21:50:37 -0700975 int wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
977 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -0700978 if(tcon->ses->capabilities & CAP_LARGE_FILES)
979 wct = 12;
980 else
981 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
983 *nbytes = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -0700984 rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985 (void **) &pSMBr);
986 if (rc)
987 return rc;
988
989 /* tcon and ses pointer are checked in smb_init */
990 if (tcon->ses->server == NULL)
991 return -ECONNABORTED;
992
993 pSMB->AndXCommand = 0xFF; /* none */
994 pSMB->Fid = netfid;
995 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -0700996 if(wct == 12)
997 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
998 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
999 return -EIO;
1000
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 pSMB->Remaining = 0;
1002 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1003 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001004 if(wct == 12)
1005 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1006 else {
1007 /* old style read */
1008 struct smb_com_readx_req * pSMBW =
1009 (struct smb_com_readx_req *)pSMB;
1010 pSMBW->ByteCount = 0;
1011 }
1012
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1014 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001015 cifs_stats_inc(&tcon->num_reads);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 if (rc) {
1017 cERROR(1, ("Send error in read = %d", rc));
1018 } else {
1019 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1020 data_length = data_length << 16;
1021 data_length += le16_to_cpu(pSMBr->DataLength);
1022 *nbytes = data_length;
1023
1024 /*check that DataLength would not go beyond end of SMB */
1025 if ((data_length > CIFSMaxBufSize)
1026 || (data_length > count)) {
1027 cFYI(1,("bad length %d for count %d",data_length,count));
1028 rc = -EIO;
1029 *nbytes = 0;
1030 } else {
1031 pReadData =
1032 (char *) (&pSMBr->hdr.Protocol) +
1033 le16_to_cpu(pSMBr->DataOffset);
1034/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1035 cERROR(1,("Faulting on read rc = %d",rc));
1036 rc = -EFAULT;
1037 }*/ /* can not use copy_to_user when using page cache*/
1038 if(*buf)
1039 memcpy(*buf,pReadData,data_length);
1040 }
1041 }
1042 if(*buf)
1043 cifs_buf_release(pSMB);
1044 else
1045 *buf = (char *)pSMB;
1046
1047 /* Note: On -EAGAIN error only caller can retry on handle based calls
1048 since file handle passed in no longer valid */
1049 return rc;
1050}
1051
1052int
1053CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1054 const int netfid, const unsigned int count,
1055 const __u64 offset, unsigned int *nbytes, const char *buf,
1056 const char __user * ubuf, const int long_op)
1057{
1058 int rc = -EACCES;
1059 WRITE_REQ *pSMB = NULL;
1060 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001061 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 __u32 bytes_sent;
1063 __u16 byte_count;
1064
1065 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001066 if(tcon->ses == NULL)
1067 return -ECONNABORTED;
1068
1069 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1070 wct = 14;
1071 else
1072 wct = 12;
1073
1074 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 (void **) &pSMBr);
1076 if (rc)
1077 return rc;
1078 /* tcon and ses pointer are checked in smb_init */
1079 if (tcon->ses->server == NULL)
1080 return -ECONNABORTED;
1081
1082 pSMB->AndXCommand = 0xFF; /* none */
1083 pSMB->Fid = netfid;
1084 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001085 if(wct == 14)
1086 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1087 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1088 return -EIO;
1089
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 pSMB->Reserved = 0xFFFFFFFF;
1091 pSMB->WriteMode = 0;
1092 pSMB->Remaining = 0;
1093
1094 /* Can increase buffer size if buffer is big enough in some cases - ie we
1095 can send more if LARGE_WRITE_X capability returned by the server and if
1096 our buffer is big enough or if we convert to iovecs on socket writes
1097 and eliminate the copy to the CIFS buffer */
1098 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1099 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1100 } else {
1101 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1102 & ~0xFF;
1103 }
1104
1105 if (bytes_sent > count)
1106 bytes_sent = count;
1107 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001108 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 if(buf)
1110 memcpy(pSMB->Data,buf,bytes_sent);
1111 else if(ubuf) {
1112 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1113 cifs_buf_release(pSMB);
1114 return -EFAULT;
1115 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001116 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 /* No buffer */
1118 cifs_buf_release(pSMB);
1119 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001120 } /* else setting file size with write of zero bytes */
1121 if(wct == 14)
1122 byte_count = bytes_sent + 1; /* pad */
1123 else /* wct == 12 */ {
1124 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1127 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001128 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001129
1130 if(wct == 14)
1131 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001132 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001133 struct smb_com_writex_req * pSMBW =
1134 (struct smb_com_writex_req *)pSMB;
1135 pSMBW->ByteCount = cpu_to_le16(byte_count);
1136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137
1138 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1139 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001140 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141 if (rc) {
1142 cFYI(1, ("Send error in write = %d", rc));
1143 *nbytes = 0;
1144 } else {
1145 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1146 *nbytes = (*nbytes) << 16;
1147 *nbytes += le16_to_cpu(pSMBr->Count);
1148 }
1149
1150 cifs_buf_release(pSMB);
1151
1152 /* Note: On -EAGAIN error only caller can retry on handle based calls
1153 since file handle passed in no longer valid */
1154
1155 return rc;
1156}
1157
1158#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001159int
1160CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001162 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1163 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164{
1165 int rc = -EACCES;
1166 WRITE_REQ *pSMB = NULL;
Steve French8cc64c62005-10-03 13:49:43 -07001167 int bytes_returned, wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001168 int smb_hdr_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
Steve Frenchff7feac2005-11-15 16:45:16 -08001170 /* BB removeme BB */
1171 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1172
Steve French8cc64c62005-10-03 13:49:43 -07001173 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1174 wct = 14;
1175 else
1176 wct = 12;
1177 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 if (rc)
1179 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 /* tcon and ses pointer are checked in smb_init */
1181 if (tcon->ses->server == NULL)
1182 return -ECONNABORTED;
1183
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001184 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 pSMB->Fid = netfid;
1186 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001187 if(wct == 14)
1188 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1189 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1190 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 pSMB->Reserved = 0xFFFFFFFF;
1192 pSMB->WriteMode = 0;
1193 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001194
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 pSMB->DataOffset =
1196 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1197
Steve French3e844692005-10-03 13:37:24 -07001198 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1199 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001200 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001201 if(wct == 14)
1202 pSMB->hdr.smb_buf_length += count+1;
1203 else /* wct == 12 */
1204 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1205 if(wct == 14)
1206 pSMB->ByteCount = cpu_to_le16(count + 1);
1207 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1208 struct smb_com_writex_req * pSMBW =
1209 (struct smb_com_writex_req *)pSMB;
1210 pSMBW->ByteCount = cpu_to_le16(count + 5);
1211 }
Steve French3e844692005-10-03 13:37:24 -07001212 iov[0].iov_base = pSMB;
1213 iov[0].iov_len = smb_hdr_len + 4;
1214
1215 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned,
1216 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001217 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001219 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001221 } else {
1222 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
1223 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1224 *nbytes = (*nbytes) << 16;
1225 *nbytes += le16_to_cpu(pSMBr->Count);
1226 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
1228 cifs_small_buf_release(pSMB);
1229
1230 /* Note: On -EAGAIN error only caller can retry on handle based calls
1231 since file handle passed in no longer valid */
1232
1233 return rc;
1234}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001235
1236
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237#endif /* CIFS_EXPERIMENTAL */
1238
1239int
1240CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1241 const __u16 smb_file_id, const __u64 len,
1242 const __u64 offset, const __u32 numUnlock,
1243 const __u32 numLock, const __u8 lockType, const int waitFlag)
1244{
1245 int rc = 0;
1246 LOCK_REQ *pSMB = NULL;
1247 LOCK_RSP *pSMBr = NULL;
1248 int bytes_returned;
1249 int timeout = 0;
1250 __u16 count;
1251
1252 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001253 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1254
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 if (rc)
1256 return rc;
1257
Steve French46810cb2005-04-28 22:41:09 -07001258 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1259
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1261 timeout = -1; /* no response expected */
1262 pSMB->Timeout = 0;
1263 } else if (waitFlag == TRUE) {
1264 timeout = 3; /* blocking operation, no timeout */
1265 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1266 } else {
1267 pSMB->Timeout = 0;
1268 }
1269
1270 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1271 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1272 pSMB->LockType = lockType;
1273 pSMB->AndXCommand = 0xFF; /* none */
1274 pSMB->Fid = smb_file_id; /* netfid stays le */
1275
1276 if((numLock != 0) || (numUnlock != 0)) {
1277 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1278 /* BB where to store pid high? */
1279 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1280 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1281 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1282 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1283 count = sizeof(LOCKING_ANDX_RANGE);
1284 } else {
1285 /* oplock break */
1286 count = 0;
1287 }
1288 pSMB->hdr.smb_buf_length += count;
1289 pSMB->ByteCount = cpu_to_le16(count);
1290
1291 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1292 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Steve Frencha4544342005-08-24 13:59:35 -07001293 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 if (rc) {
1295 cFYI(1, ("Send error in Lock = %d", rc));
1296 }
Steve French46810cb2005-04-28 22:41:09 -07001297 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
1299 /* Note: On -EAGAIN error only caller can retry on handle based calls
1300 since file handle passed in no longer valid */
1301 return rc;
1302}
1303
1304int
1305CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1306{
1307 int rc = 0;
1308 CLOSE_REQ *pSMB = NULL;
1309 CLOSE_RSP *pSMBr = NULL;
1310 int bytes_returned;
1311 cFYI(1, ("In CIFSSMBClose"));
1312
1313/* do not retry on dead session on close */
1314 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1315 if(rc == -EAGAIN)
1316 return 0;
1317 if (rc)
1318 return rc;
1319
1320 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1321
1322 pSMB->FileID = (__u16) smb_file_id;
1323 pSMB->LastWriteTime = 0;
1324 pSMB->ByteCount = 0;
1325 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1326 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001327 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 if (rc) {
1329 if(rc!=-EINTR) {
1330 /* EINTR is expected when user ctl-c to kill app */
1331 cERROR(1, ("Send error in Close = %d", rc));
1332 }
1333 }
1334
1335 cifs_small_buf_release(pSMB);
1336
1337 /* Since session is dead, file will be closed on server already */
1338 if(rc == -EAGAIN)
1339 rc = 0;
1340
1341 return rc;
1342}
1343
1344int
1345CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1346 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001347 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348{
1349 int rc = 0;
1350 RENAME_REQ *pSMB = NULL;
1351 RENAME_RSP *pSMBr = NULL;
1352 int bytes_returned;
1353 int name_len, name_len2;
1354 __u16 count;
1355
1356 cFYI(1, ("In CIFSSMBRename"));
1357renameRetry:
1358 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1359 (void **) &pSMBr);
1360 if (rc)
1361 return rc;
1362
1363 pSMB->BufferFormat = 0x04;
1364 pSMB->SearchAttributes =
1365 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1366 ATTR_DIRECTORY);
1367
1368 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1369 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001370 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001371 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 name_len++; /* trailing null */
1373 name_len *= 2;
1374 pSMB->OldFileName[name_len] = 0x04; /* pad */
1375 /* protocol requires ASCII signature byte on Unicode string */
1376 pSMB->OldFileName[name_len + 1] = 0x00;
1377 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001378 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001379 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1381 name_len2 *= 2; /* convert to bytes */
1382 } else { /* BB improve the check for buffer overruns BB */
1383 name_len = strnlen(fromName, PATH_MAX);
1384 name_len++; /* trailing null */
1385 strncpy(pSMB->OldFileName, fromName, name_len);
1386 name_len2 = strnlen(toName, PATH_MAX);
1387 name_len2++; /* trailing null */
1388 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1389 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1390 name_len2++; /* trailing null */
1391 name_len2++; /* signature byte */
1392 }
1393
1394 count = 1 /* 1st signature byte */ + name_len + name_len2;
1395 pSMB->hdr.smb_buf_length += count;
1396 pSMB->ByteCount = cpu_to_le16(count);
1397
1398 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1399 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001400 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 if (rc) {
1402 cFYI(1, ("Send error in rename = %d", rc));
1403 }
1404
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 cifs_buf_release(pSMB);
1406
1407 if (rc == -EAGAIN)
1408 goto renameRetry;
1409
1410 return rc;
1411}
1412
1413int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001414 int netfid, char * target_name,
1415 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416{
1417 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1418 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1419 struct set_file_rename * rename_info;
1420 char *data_offset;
1421 char dummy_string[30];
1422 int rc = 0;
1423 int bytes_returned = 0;
1424 int len_of_str;
1425 __u16 params, param_offset, offset, count, byte_count;
1426
1427 cFYI(1, ("Rename to File by handle"));
1428 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1429 (void **) &pSMBr);
1430 if (rc)
1431 return rc;
1432
1433 params = 6;
1434 pSMB->MaxSetupCount = 0;
1435 pSMB->Reserved = 0;
1436 pSMB->Flags = 0;
1437 pSMB->Timeout = 0;
1438 pSMB->Reserved2 = 0;
1439 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1440 offset = param_offset + params;
1441
1442 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1443 rename_info = (struct set_file_rename *) data_offset;
1444 pSMB->MaxParameterCount = cpu_to_le16(2);
1445 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1446 pSMB->SetupCount = 1;
1447 pSMB->Reserved3 = 0;
1448 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1449 byte_count = 3 /* pad */ + params;
1450 pSMB->ParameterCount = cpu_to_le16(params);
1451 pSMB->TotalParameterCount = pSMB->ParameterCount;
1452 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1453 pSMB->DataOffset = cpu_to_le16(offset);
1454 /* construct random name ".cifs_tmp<inodenum><mid>" */
1455 rename_info->overwrite = cpu_to_le32(1);
1456 rename_info->root_fid = 0;
1457 /* unicode only call */
1458 if(target_name == NULL) {
1459 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001460 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001461 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001463 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001464 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 }
1466 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1467 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1468 byte_count += count;
1469 pSMB->DataCount = cpu_to_le16(count);
1470 pSMB->TotalDataCount = pSMB->DataCount;
1471 pSMB->Fid = netfid;
1472 pSMB->InformationLevel =
1473 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1474 pSMB->Reserved4 = 0;
1475 pSMB->hdr.smb_buf_length += byte_count;
1476 pSMB->ByteCount = cpu_to_le16(byte_count);
1477 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1478 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001479 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 if (rc) {
1481 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1482 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001483
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 cifs_buf_release(pSMB);
1485
1486 /* Note: On -EAGAIN error only caller can retry on handle based calls
1487 since file handle passed in no longer valid */
1488
1489 return rc;
1490}
1491
1492int
1493CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1494 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001495 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496{
1497 int rc = 0;
1498 COPY_REQ *pSMB = NULL;
1499 COPY_RSP *pSMBr = NULL;
1500 int bytes_returned;
1501 int name_len, name_len2;
1502 __u16 count;
1503
1504 cFYI(1, ("In CIFSSMBCopy"));
1505copyRetry:
1506 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1507 (void **) &pSMBr);
1508 if (rc)
1509 return rc;
1510
1511 pSMB->BufferFormat = 0x04;
1512 pSMB->Tid2 = target_tid;
1513
1514 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1515
1516 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001517 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07001518 fromName, PATH_MAX, nls_codepage,
1519 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 name_len++; /* trailing null */
1521 name_len *= 2;
1522 pSMB->OldFileName[name_len] = 0x04; /* pad */
1523 /* protocol requires ASCII signature byte on Unicode string */
1524 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05001525 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001526 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1528 name_len2 *= 2; /* convert to bytes */
1529 } else { /* BB improve the check for buffer overruns BB */
1530 name_len = strnlen(fromName, PATH_MAX);
1531 name_len++; /* trailing null */
1532 strncpy(pSMB->OldFileName, fromName, name_len);
1533 name_len2 = strnlen(toName, PATH_MAX);
1534 name_len2++; /* trailing null */
1535 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1536 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1537 name_len2++; /* trailing null */
1538 name_len2++; /* signature byte */
1539 }
1540
1541 count = 1 /* 1st signature byte */ + name_len + name_len2;
1542 pSMB->hdr.smb_buf_length += count;
1543 pSMB->ByteCount = cpu_to_le16(count);
1544
1545 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1546 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1547 if (rc) {
1548 cFYI(1, ("Send error in copy = %d with %d files copied",
1549 rc, le16_to_cpu(pSMBr->CopyCount)));
1550 }
1551 if (pSMB)
1552 cifs_buf_release(pSMB);
1553
1554 if (rc == -EAGAIN)
1555 goto copyRetry;
1556
1557 return rc;
1558}
1559
1560int
1561CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1562 const char *fromName, const char *toName,
1563 const struct nls_table *nls_codepage)
1564{
1565 TRANSACTION2_SPI_REQ *pSMB = NULL;
1566 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1567 char *data_offset;
1568 int name_len;
1569 int name_len_target;
1570 int rc = 0;
1571 int bytes_returned = 0;
1572 __u16 params, param_offset, offset, byte_count;
1573
1574 cFYI(1, ("In Symlink Unix style"));
1575createSymLinkRetry:
1576 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1577 (void **) &pSMBr);
1578 if (rc)
1579 return rc;
1580
1581 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1582 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001583 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 /* find define for this maxpathcomponent */
1585 , nls_codepage);
1586 name_len++; /* trailing null */
1587 name_len *= 2;
1588
1589 } else { /* BB improve the check for buffer overruns BB */
1590 name_len = strnlen(fromName, PATH_MAX);
1591 name_len++; /* trailing null */
1592 strncpy(pSMB->FileName, fromName, name_len);
1593 }
1594 params = 6 + name_len;
1595 pSMB->MaxSetupCount = 0;
1596 pSMB->Reserved = 0;
1597 pSMB->Flags = 0;
1598 pSMB->Timeout = 0;
1599 pSMB->Reserved2 = 0;
1600 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1601 InformationLevel) - 4;
1602 offset = param_offset + params;
1603
1604 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1605 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1606 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08001607 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608 /* find define for this maxpathcomponent */
1609 , nls_codepage);
1610 name_len_target++; /* trailing null */
1611 name_len_target *= 2;
1612 } else { /* BB improve the check for buffer overruns BB */
1613 name_len_target = strnlen(toName, PATH_MAX);
1614 name_len_target++; /* trailing null */
1615 strncpy(data_offset, toName, name_len_target);
1616 }
1617
1618 pSMB->MaxParameterCount = cpu_to_le16(2);
1619 /* BB find exact max on data count below from sess */
1620 pSMB->MaxDataCount = cpu_to_le16(1000);
1621 pSMB->SetupCount = 1;
1622 pSMB->Reserved3 = 0;
1623 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1624 byte_count = 3 /* pad */ + params + name_len_target;
1625 pSMB->DataCount = cpu_to_le16(name_len_target);
1626 pSMB->ParameterCount = cpu_to_le16(params);
1627 pSMB->TotalDataCount = pSMB->DataCount;
1628 pSMB->TotalParameterCount = pSMB->ParameterCount;
1629 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1630 pSMB->DataOffset = cpu_to_le16(offset);
1631 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1632 pSMB->Reserved4 = 0;
1633 pSMB->hdr.smb_buf_length += byte_count;
1634 pSMB->ByteCount = cpu_to_le16(byte_count);
1635 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1636 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001637 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 if (rc) {
1639 cFYI(1,
1640 ("Send error in SetPathInfo (create symlink) = %d",
1641 rc));
1642 }
1643
1644 if (pSMB)
1645 cifs_buf_release(pSMB);
1646
1647 if (rc == -EAGAIN)
1648 goto createSymLinkRetry;
1649
1650 return rc;
1651}
1652
1653int
1654CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1655 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001656 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657{
1658 TRANSACTION2_SPI_REQ *pSMB = NULL;
1659 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1660 char *data_offset;
1661 int name_len;
1662 int name_len_target;
1663 int rc = 0;
1664 int bytes_returned = 0;
1665 __u16 params, param_offset, offset, byte_count;
1666
1667 cFYI(1, ("In Create Hard link Unix style"));
1668createHardLinkRetry:
1669 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1670 (void **) &pSMBr);
1671 if (rc)
1672 return rc;
1673
1674 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05001675 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07001676 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 name_len++; /* trailing null */
1678 name_len *= 2;
1679
1680 } else { /* BB improve the check for buffer overruns BB */
1681 name_len = strnlen(toName, PATH_MAX);
1682 name_len++; /* trailing null */
1683 strncpy(pSMB->FileName, toName, name_len);
1684 }
1685 params = 6 + name_len;
1686 pSMB->MaxSetupCount = 0;
1687 pSMB->Reserved = 0;
1688 pSMB->Flags = 0;
1689 pSMB->Timeout = 0;
1690 pSMB->Reserved2 = 0;
1691 param_offset = offsetof(struct smb_com_transaction2_spi_req,
1692 InformationLevel) - 4;
1693 offset = param_offset + params;
1694
1695 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1696 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1697 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05001698 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07001699 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 name_len_target++; /* trailing null */
1701 name_len_target *= 2;
1702 } else { /* BB improve the check for buffer overruns BB */
1703 name_len_target = strnlen(fromName, PATH_MAX);
1704 name_len_target++; /* trailing null */
1705 strncpy(data_offset, fromName, name_len_target);
1706 }
1707
1708 pSMB->MaxParameterCount = cpu_to_le16(2);
1709 /* BB find exact max on data count below from sess*/
1710 pSMB->MaxDataCount = cpu_to_le16(1000);
1711 pSMB->SetupCount = 1;
1712 pSMB->Reserved3 = 0;
1713 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1714 byte_count = 3 /* pad */ + params + name_len_target;
1715 pSMB->ParameterCount = cpu_to_le16(params);
1716 pSMB->TotalParameterCount = pSMB->ParameterCount;
1717 pSMB->DataCount = cpu_to_le16(name_len_target);
1718 pSMB->TotalDataCount = pSMB->DataCount;
1719 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1720 pSMB->DataOffset = cpu_to_le16(offset);
1721 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1722 pSMB->Reserved4 = 0;
1723 pSMB->hdr.smb_buf_length += byte_count;
1724 pSMB->ByteCount = cpu_to_le16(byte_count);
1725 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1726 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001727 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 if (rc) {
1729 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1730 }
1731
1732 cifs_buf_release(pSMB);
1733 if (rc == -EAGAIN)
1734 goto createHardLinkRetry;
1735
1736 return rc;
1737}
1738
1739int
1740CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1741 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001742 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743{
1744 int rc = 0;
1745 NT_RENAME_REQ *pSMB = NULL;
1746 RENAME_RSP *pSMBr = NULL;
1747 int bytes_returned;
1748 int name_len, name_len2;
1749 __u16 count;
1750
1751 cFYI(1, ("In CIFSCreateHardLink"));
1752winCreateHardLinkRetry:
1753
1754 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1755 (void **) &pSMBr);
1756 if (rc)
1757 return rc;
1758
1759 pSMB->SearchAttributes =
1760 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1761 ATTR_DIRECTORY);
1762 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1763 pSMB->ClusterCount = 0;
1764
1765 pSMB->BufferFormat = 0x04;
1766
1767 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1768 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001769 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001770 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 name_len++; /* trailing null */
1772 name_len *= 2;
1773 pSMB->OldFileName[name_len] = 0; /* pad */
1774 pSMB->OldFileName[name_len + 1] = 0x04;
1775 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001776 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001777 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1779 name_len2 *= 2; /* convert to bytes */
1780 } else { /* BB improve the check for buffer overruns BB */
1781 name_len = strnlen(fromName, PATH_MAX);
1782 name_len++; /* trailing null */
1783 strncpy(pSMB->OldFileName, fromName, name_len);
1784 name_len2 = strnlen(toName, PATH_MAX);
1785 name_len2++; /* trailing null */
1786 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1787 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1788 name_len2++; /* trailing null */
1789 name_len2++; /* signature byte */
1790 }
1791
1792 count = 1 /* string type byte */ + name_len + name_len2;
1793 pSMB->hdr.smb_buf_length += count;
1794 pSMB->ByteCount = cpu_to_le16(count);
1795
1796 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1797 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001798 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 if (rc) {
1800 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1801 }
1802 cifs_buf_release(pSMB);
1803 if (rc == -EAGAIN)
1804 goto winCreateHardLinkRetry;
1805
1806 return rc;
1807}
1808
1809int
1810CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1811 const unsigned char *searchName,
1812 char *symlinkinfo, const int buflen,
1813 const struct nls_table *nls_codepage)
1814{
1815/* SMB_QUERY_FILE_UNIX_LINK */
1816 TRANSACTION2_QPI_REQ *pSMB = NULL;
1817 TRANSACTION2_QPI_RSP *pSMBr = NULL;
1818 int rc = 0;
1819 int bytes_returned;
1820 int name_len;
1821 __u16 params, byte_count;
1822
1823 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1824
1825querySymLinkRetry:
1826 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1827 (void **) &pSMBr);
1828 if (rc)
1829 return rc;
1830
1831 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1832 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08001833 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 /* find define for this maxpathcomponent */
1835 , nls_codepage);
1836 name_len++; /* trailing null */
1837 name_len *= 2;
1838 } else { /* BB improve the check for buffer overruns BB */
1839 name_len = strnlen(searchName, PATH_MAX);
1840 name_len++; /* trailing null */
1841 strncpy(pSMB->FileName, searchName, name_len);
1842 }
1843
1844 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
1845 pSMB->TotalDataCount = 0;
1846 pSMB->MaxParameterCount = cpu_to_le16(2);
1847 /* BB find exact max data count below from sess structure BB */
1848 pSMB->MaxDataCount = cpu_to_le16(4000);
1849 pSMB->MaxSetupCount = 0;
1850 pSMB->Reserved = 0;
1851 pSMB->Flags = 0;
1852 pSMB->Timeout = 0;
1853 pSMB->Reserved2 = 0;
1854 pSMB->ParameterOffset = cpu_to_le16(offsetof(
1855 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1856 pSMB->DataCount = 0;
1857 pSMB->DataOffset = 0;
1858 pSMB->SetupCount = 1;
1859 pSMB->Reserved3 = 0;
1860 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1861 byte_count = params + 1 /* pad */ ;
1862 pSMB->TotalParameterCount = cpu_to_le16(params);
1863 pSMB->ParameterCount = pSMB->TotalParameterCount;
1864 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1865 pSMB->Reserved4 = 0;
1866 pSMB->hdr.smb_buf_length += byte_count;
1867 pSMB->ByteCount = cpu_to_le16(byte_count);
1868
1869 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1870 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1871 if (rc) {
1872 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1873 } else {
1874 /* decode response */
1875
1876 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1877 if (rc || (pSMBr->ByteCount < 2))
1878 /* BB also check enough total bytes returned */
1879 rc = -EIO; /* bad smb */
1880 else {
1881 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1882 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1883
1884 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1885 name_len = UniStrnlen((wchar_t *) ((char *)
1886 &pSMBr->hdr.Protocol +data_offset),
1887 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07001888 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08001890 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 data_offset),
1892 name_len, nls_codepage);
1893 } else {
1894 strncpy(symlinkinfo,
1895 (char *) &pSMBr->hdr.Protocol +
1896 data_offset,
1897 min_t(const int, buflen, count));
1898 }
1899 symlinkinfo[buflen] = 0;
1900 /* just in case so calling code does not go off the end of buffer */
1901 }
1902 }
1903 cifs_buf_release(pSMB);
1904 if (rc == -EAGAIN)
1905 goto querySymLinkRetry;
1906 return rc;
1907}
1908
1909int
1910CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1911 const unsigned char *searchName,
1912 char *symlinkinfo, const int buflen,__u16 fid,
1913 const struct nls_table *nls_codepage)
1914{
1915 int rc = 0;
1916 int bytes_returned;
1917 int name_len;
1918 struct smb_com_transaction_ioctl_req * pSMB;
1919 struct smb_com_transaction_ioctl_rsp * pSMBr;
1920
1921 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1922 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1923 (void **) &pSMBr);
1924 if (rc)
1925 return rc;
1926
1927 pSMB->TotalParameterCount = 0 ;
1928 pSMB->TotalDataCount = 0;
1929 pSMB->MaxParameterCount = cpu_to_le32(2);
1930 /* BB find exact data count max from sess structure BB */
1931 pSMB->MaxDataCount = cpu_to_le32(4000);
1932 pSMB->MaxSetupCount = 4;
1933 pSMB->Reserved = 0;
1934 pSMB->ParameterOffset = 0;
1935 pSMB->DataCount = 0;
1936 pSMB->DataOffset = 0;
1937 pSMB->SetupCount = 4;
1938 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1939 pSMB->ParameterCount = pSMB->TotalParameterCount;
1940 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1941 pSMB->IsFsctl = 1; /* FSCTL */
1942 pSMB->IsRootFlag = 0;
1943 pSMB->Fid = fid; /* file handle always le */
1944 pSMB->ByteCount = 0;
1945
1946 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1947 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1948 if (rc) {
1949 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1950 } else { /* decode response */
1951 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1952 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1953 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1954 /* BB also check enough total bytes returned */
1955 rc = -EIO; /* bad smb */
1956 else {
1957 if(data_count && (data_count < 2048)) {
1958 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1959
1960 struct reparse_data * reparse_buf = (struct reparse_data *)
1961 ((char *)&pSMBr->hdr.Protocol + data_offset);
1962 if((char*)reparse_buf >= end_of_smb) {
1963 rc = -EIO;
1964 goto qreparse_out;
1965 }
1966 if((reparse_buf->LinkNamesBuf +
1967 reparse_buf->TargetNameOffset +
1968 reparse_buf->TargetNameLen) >
1969 end_of_smb) {
1970 cFYI(1,("reparse buf extended beyond SMB"));
1971 rc = -EIO;
1972 goto qreparse_out;
1973 }
1974
1975 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1976 name_len = UniStrnlen((wchar_t *)
1977 (reparse_buf->LinkNamesBuf +
1978 reparse_buf->TargetNameOffset),
1979 min(buflen/2, reparse_buf->TargetNameLen / 2));
1980 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08001981 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 reparse_buf->TargetNameOffset),
1983 name_len, nls_codepage);
1984 } else { /* ASCII names */
1985 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
1986 reparse_buf->TargetNameOffset,
1987 min_t(const int, buflen, reparse_buf->TargetNameLen));
1988 }
1989 } else {
1990 rc = -EIO;
1991 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1992 }
1993 symlinkinfo[buflen] = 0; /* just in case so the caller
1994 does not go off the end of the buffer */
1995 cFYI(1,("readlink result - %s ",symlinkinfo));
1996 }
1997 }
1998qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07001999 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000
2001 /* Note: On -EAGAIN error only caller can retry on handle based calls
2002 since file handle passed in no longer valid */
2003
2004 return rc;
2005}
2006
2007#ifdef CONFIG_CIFS_POSIX
2008
2009/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2010static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2011{
2012 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002013 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2014 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2015 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2017
2018 return;
2019}
2020
2021/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002022static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2023 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024{
2025 int size = 0;
2026 int i;
2027 __u16 count;
2028 struct cifs_posix_ace * pACE;
2029 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2030 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2031
2032 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2033 return -EOPNOTSUPP;
2034
2035 if(acl_type & ACL_TYPE_ACCESS) {
2036 count = le16_to_cpu(cifs_acl->access_entry_count);
2037 pACE = &cifs_acl->ace_array[0];
2038 size = sizeof(struct cifs_posix_acl);
2039 size += sizeof(struct cifs_posix_ace) * count;
2040 /* check if we would go beyond end of SMB */
2041 if(size_of_data_area < size) {
2042 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2043 return -EINVAL;
2044 }
2045 } else if(acl_type & ACL_TYPE_DEFAULT) {
2046 count = le16_to_cpu(cifs_acl->access_entry_count);
2047 size = sizeof(struct cifs_posix_acl);
2048 size += sizeof(struct cifs_posix_ace) * count;
2049/* skip past access ACEs to get to default ACEs */
2050 pACE = &cifs_acl->ace_array[count];
2051 count = le16_to_cpu(cifs_acl->default_entry_count);
2052 size += sizeof(struct cifs_posix_ace) * count;
2053 /* check if we would go beyond end of SMB */
2054 if(size_of_data_area < size)
2055 return -EINVAL;
2056 } else {
2057 /* illegal type */
2058 return -EINVAL;
2059 }
2060
2061 size = posix_acl_xattr_size(count);
2062 if((buflen == 0) || (local_acl == NULL)) {
2063 /* used to query ACL EA size */
2064 } else if(size > buflen) {
2065 return -ERANGE;
2066 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002067 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 for(i = 0;i < count ;i++) {
2069 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2070 pACE ++;
2071 }
2072 }
2073 return size;
2074}
2075
2076static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2077 const posix_acl_xattr_entry * local_ace)
2078{
2079 __u16 rc = 0; /* 0 = ACL converted ok */
2080
Steve Frenchff7feac2005-11-15 16:45:16 -08002081 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2082 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002084 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 /* Probably no need to le convert -1 on any arch but can not hurt */
2086 cifs_ace->cifs_uid = cpu_to_le64(-1);
2087 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002088 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2090 return rc;
2091}
2092
2093/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2094static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2095 const int acl_type)
2096{
2097 __u16 rc = 0;
2098 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2099 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2100 int count;
2101 int i;
2102
2103 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2104 return 0;
2105
2106 count = posix_acl_xattr_count((size_t)buflen);
2107 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002108 count, buflen, le32_to_cpu(local_acl->a_version)));
2109 if(le32_to_cpu(local_acl->a_version) != 2) {
2110 cFYI(1,("unknown POSIX ACL version %d",
2111 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 return 0;
2113 }
2114 cifs_acl->version = cpu_to_le16(1);
2115 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002116 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002118 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 else {
2120 cFYI(1,("unknown ACL type %d",acl_type));
2121 return 0;
2122 }
2123 for(i=0;i<count;i++) {
2124 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2125 &local_acl->a_entries[i]);
2126 if(rc != 0) {
2127 /* ACE not converted */
2128 break;
2129 }
2130 }
2131 if(rc == 0) {
2132 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2133 rc += sizeof(struct cifs_posix_acl);
2134 /* BB add check to make sure ACL does not overflow SMB */
2135 }
2136 return rc;
2137}
2138
2139int
2140CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2141 const unsigned char *searchName,
2142 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002143 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144{
2145/* SMB_QUERY_POSIX_ACL */
2146 TRANSACTION2_QPI_REQ *pSMB = NULL;
2147 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2148 int rc = 0;
2149 int bytes_returned;
2150 int name_len;
2151 __u16 params, byte_count;
2152
2153 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2154
2155queryAclRetry:
2156 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2157 (void **) &pSMBr);
2158 if (rc)
2159 return rc;
2160
2161 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2162 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002163 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002164 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 name_len++; /* trailing null */
2166 name_len *= 2;
2167 pSMB->FileName[name_len] = 0;
2168 pSMB->FileName[name_len+1] = 0;
2169 } else { /* BB improve the check for buffer overruns BB */
2170 name_len = strnlen(searchName, PATH_MAX);
2171 name_len++; /* trailing null */
2172 strncpy(pSMB->FileName, searchName, name_len);
2173 }
2174
2175 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2176 pSMB->TotalDataCount = 0;
2177 pSMB->MaxParameterCount = cpu_to_le16(2);
2178 /* BB find exact max data count below from sess structure BB */
2179 pSMB->MaxDataCount = cpu_to_le16(4000);
2180 pSMB->MaxSetupCount = 0;
2181 pSMB->Reserved = 0;
2182 pSMB->Flags = 0;
2183 pSMB->Timeout = 0;
2184 pSMB->Reserved2 = 0;
2185 pSMB->ParameterOffset = cpu_to_le16(
2186 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2187 pSMB->DataCount = 0;
2188 pSMB->DataOffset = 0;
2189 pSMB->SetupCount = 1;
2190 pSMB->Reserved3 = 0;
2191 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2192 byte_count = params + 1 /* pad */ ;
2193 pSMB->TotalParameterCount = cpu_to_le16(params);
2194 pSMB->ParameterCount = pSMB->TotalParameterCount;
2195 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2196 pSMB->Reserved4 = 0;
2197 pSMB->hdr.smb_buf_length += byte_count;
2198 pSMB->ByteCount = cpu_to_le16(byte_count);
2199
2200 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2201 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2202 if (rc) {
2203 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2204 } else {
2205 /* decode response */
2206
2207 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2208 if (rc || (pSMBr->ByteCount < 2))
2209 /* BB also check enough total bytes returned */
2210 rc = -EIO; /* bad smb */
2211 else {
2212 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2213 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2214 rc = cifs_copy_posix_acl(acl_inf,
2215 (char *)&pSMBr->hdr.Protocol+data_offset,
2216 buflen,acl_type,count);
2217 }
2218 }
2219 cifs_buf_release(pSMB);
2220 if (rc == -EAGAIN)
2221 goto queryAclRetry;
2222 return rc;
2223}
2224
2225int
2226CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2227 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002228 const char *local_acl, const int buflen,
2229 const int acl_type,
2230 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231{
2232 struct smb_com_transaction2_spi_req *pSMB = NULL;
2233 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2234 char *parm_data;
2235 int name_len;
2236 int rc = 0;
2237 int bytes_returned = 0;
2238 __u16 params, byte_count, data_count, param_offset, offset;
2239
2240 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2241setAclRetry:
2242 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2243 (void **) &pSMBr);
2244 if (rc)
2245 return rc;
2246 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2247 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002248 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002249 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 name_len++; /* trailing null */
2251 name_len *= 2;
2252 } else { /* BB improve the check for buffer overruns BB */
2253 name_len = strnlen(fileName, PATH_MAX);
2254 name_len++; /* trailing null */
2255 strncpy(pSMB->FileName, fileName, name_len);
2256 }
2257 params = 6 + name_len;
2258 pSMB->MaxParameterCount = cpu_to_le16(2);
2259 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2260 pSMB->MaxSetupCount = 0;
2261 pSMB->Reserved = 0;
2262 pSMB->Flags = 0;
2263 pSMB->Timeout = 0;
2264 pSMB->Reserved2 = 0;
2265 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2266 InformationLevel) - 4;
2267 offset = param_offset + params;
2268 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2269 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2270
2271 /* convert to on the wire format for POSIX ACL */
2272 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2273
2274 if(data_count == 0) {
2275 rc = -EOPNOTSUPP;
2276 goto setACLerrorExit;
2277 }
2278 pSMB->DataOffset = cpu_to_le16(offset);
2279 pSMB->SetupCount = 1;
2280 pSMB->Reserved3 = 0;
2281 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2282 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2283 byte_count = 3 /* pad */ + params + data_count;
2284 pSMB->DataCount = cpu_to_le16(data_count);
2285 pSMB->TotalDataCount = pSMB->DataCount;
2286 pSMB->ParameterCount = cpu_to_le16(params);
2287 pSMB->TotalParameterCount = pSMB->ParameterCount;
2288 pSMB->Reserved4 = 0;
2289 pSMB->hdr.smb_buf_length += byte_count;
2290 pSMB->ByteCount = cpu_to_le16(byte_count);
2291 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2292 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2293 if (rc) {
2294 cFYI(1, ("Set POSIX ACL returned %d", rc));
2295 }
2296
2297setACLerrorExit:
2298 cifs_buf_release(pSMB);
2299 if (rc == -EAGAIN)
2300 goto setAclRetry;
2301 return rc;
2302}
2303
Steve Frenchf654bac2005-04-28 22:41:04 -07002304/* BB fix tabs in this function FIXME BB */
2305int
2306CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2307 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2308{
2309 int rc = 0;
2310 struct smb_t2_qfi_req *pSMB = NULL;
2311 struct smb_t2_qfi_rsp *pSMBr = NULL;
2312 int bytes_returned;
2313 __u16 params, byte_count;
2314
2315 cFYI(1,("In GetExtAttr"));
2316 if(tcon == NULL)
2317 return -ENODEV;
2318
2319GetExtAttrRetry:
2320 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2321 (void **) &pSMBr);
2322 if (rc)
2323 return rc;
2324
Steve Frenchc67593a2005-04-28 22:41:04 -07002325 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002326 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002327 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002328 /* BB find exact max data count below from sess structure BB */
2329 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2330 pSMB->t2.MaxSetupCount = 0;
2331 pSMB->t2.Reserved = 0;
2332 pSMB->t2.Flags = 0;
2333 pSMB->t2.Timeout = 0;
2334 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002335 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2336 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002337 pSMB->t2.DataCount = 0;
2338 pSMB->t2.DataOffset = 0;
2339 pSMB->t2.SetupCount = 1;
2340 pSMB->t2.Reserved3 = 0;
2341 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002342 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002343 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2344 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2345 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002346 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002347 pSMB->Fid = netfid;
2348 pSMB->hdr.smb_buf_length += byte_count;
2349 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2350
2351 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2352 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2353 if (rc) {
2354 cFYI(1, ("error %d in GetExtAttr", rc));
2355 } else {
2356 /* decode response */
2357 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2358 if (rc || (pSMBr->ByteCount < 2))
2359 /* BB also check enough total bytes returned */
2360 /* If rc should we check for EOPNOSUPP and
2361 disable the srvino flag? or in caller? */
2362 rc = -EIO; /* bad smb */
2363 else {
2364 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2365 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2366 struct file_chattr_info * pfinfo;
2367 /* BB Do we need a cast or hash here ? */
2368 if(count != 16) {
2369 cFYI(1, ("Illegal size ret in GetExtAttr"));
2370 rc = -EIO;
2371 goto GetExtAttrOut;
2372 }
2373 pfinfo = (struct file_chattr_info *)
2374 (data_offset + (char *) &pSMBr->hdr.Protocol);
2375 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2376 *pMask = le64_to_cpu(pfinfo->mask);
2377 }
2378 }
2379GetExtAttrOut:
2380 cifs_buf_release(pSMB);
2381 if (rc == -EAGAIN)
2382 goto GetExtAttrRetry;
2383 return rc;
2384}
2385
2386
2387#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388
Steve French6b8edfe2005-08-23 20:26:03 -07002389/* Legacy Query Path Information call for lookup to old servers such
2390 as Win9x/WinME */
2391int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2392 const unsigned char *searchName,
2393 FILE_ALL_INFO * pFinfo,
2394 const struct nls_table *nls_codepage, int remap)
2395{
2396 QUERY_INFORMATION_REQ * pSMB;
2397 QUERY_INFORMATION_RSP * pSMBr;
2398 int rc = 0;
2399 int bytes_returned;
2400 int name_len;
2401
2402 cFYI(1, ("In SMBQPath path %s", searchName));
2403QInfRetry:
2404 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2405 (void **) &pSMBr);
2406 if (rc)
2407 return rc;
2408
2409 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2410 name_len =
2411 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2412 PATH_MAX, nls_codepage, remap);
2413 name_len++; /* trailing null */
2414 name_len *= 2;
2415 } else {
2416 name_len = strnlen(searchName, PATH_MAX);
2417 name_len++; /* trailing null */
2418 strncpy(pSMB->FileName, searchName, name_len);
2419 }
2420 pSMB->BufferFormat = 0x04;
2421 name_len++; /* account for buffer type byte */
2422 pSMB->hdr.smb_buf_length += (__u16) name_len;
2423 pSMB->ByteCount = cpu_to_le16(name_len);
2424
2425 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2426 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2427 if (rc) {
2428 cFYI(1, ("Send error in QueryInfo = %d", rc));
2429 } else if (pFinfo) { /* decode response */
2430 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French70ca7342005-09-22 16:32:06 -07002431 pFinfo->AllocationSize =
2432 cpu_to_le64(le32_to_cpu(pSMBr->size));
2433 pFinfo->EndOfFile = pFinfo->AllocationSize;
2434 pFinfo->Attributes =
2435 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07002436 } else
2437 rc = -EIO; /* bad buffer passed in */
2438
2439 cifs_buf_release(pSMB);
2440
2441 if (rc == -EAGAIN)
2442 goto QInfRetry;
2443
2444 return rc;
2445}
2446
2447
2448
2449
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450int
2451CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2452 const unsigned char *searchName,
2453 FILE_ALL_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002454 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455{
2456/* level 263 SMB_QUERY_FILE_ALL_INFO */
2457 TRANSACTION2_QPI_REQ *pSMB = NULL;
2458 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2459 int rc = 0;
2460 int bytes_returned;
2461 int name_len;
2462 __u16 params, byte_count;
2463
2464/* cFYI(1, ("In QPathInfo path %s", searchName)); */
2465QPathInfoRetry:
2466 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2467 (void **) &pSMBr);
2468 if (rc)
2469 return rc;
2470
2471 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2472 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002473 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002474 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 name_len++; /* trailing null */
2476 name_len *= 2;
2477 } else { /* BB improve the check for buffer overruns BB */
2478 name_len = strnlen(searchName, PATH_MAX);
2479 name_len++; /* trailing null */
2480 strncpy(pSMB->FileName, searchName, name_len);
2481 }
2482
2483 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2484 pSMB->TotalDataCount = 0;
2485 pSMB->MaxParameterCount = cpu_to_le16(2);
2486 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2487 pSMB->MaxSetupCount = 0;
2488 pSMB->Reserved = 0;
2489 pSMB->Flags = 0;
2490 pSMB->Timeout = 0;
2491 pSMB->Reserved2 = 0;
2492 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2493 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2494 pSMB->DataCount = 0;
2495 pSMB->DataOffset = 0;
2496 pSMB->SetupCount = 1;
2497 pSMB->Reserved3 = 0;
2498 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2499 byte_count = params + 1 /* pad */ ;
2500 pSMB->TotalParameterCount = cpu_to_le16(params);
2501 pSMB->ParameterCount = pSMB->TotalParameterCount;
2502 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2503 pSMB->Reserved4 = 0;
2504 pSMB->hdr.smb_buf_length += byte_count;
2505 pSMB->ByteCount = cpu_to_le16(byte_count);
2506
2507 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2508 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2509 if (rc) {
2510 cFYI(1, ("Send error in QPathInfo = %d", rc));
2511 } else { /* decode response */
2512 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2513
2514 if (rc || (pSMBr->ByteCount < 40))
2515 rc = -EIO; /* bad smb */
2516 else if (pFindData){
2517 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2518 memcpy((char *) pFindData,
2519 (char *) &pSMBr->hdr.Protocol +
2520 data_offset, sizeof (FILE_ALL_INFO));
2521 } else
2522 rc = -ENOMEM;
2523 }
2524 cifs_buf_release(pSMB);
2525 if (rc == -EAGAIN)
2526 goto QPathInfoRetry;
2527
2528 return rc;
2529}
2530
2531int
2532CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2533 const unsigned char *searchName,
2534 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07002535 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536{
2537/* SMB_QUERY_FILE_UNIX_BASIC */
2538 TRANSACTION2_QPI_REQ *pSMB = NULL;
2539 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2540 int rc = 0;
2541 int bytes_returned = 0;
2542 int name_len;
2543 __u16 params, byte_count;
2544
2545 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2546UnixQPathInfoRetry:
2547 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2548 (void **) &pSMBr);
2549 if (rc)
2550 return rc;
2551
2552 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2553 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002554 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002555 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 name_len++; /* trailing null */
2557 name_len *= 2;
2558 } else { /* BB improve the check for buffer overruns BB */
2559 name_len = strnlen(searchName, PATH_MAX);
2560 name_len++; /* trailing null */
2561 strncpy(pSMB->FileName, searchName, name_len);
2562 }
2563
2564 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2565 pSMB->TotalDataCount = 0;
2566 pSMB->MaxParameterCount = cpu_to_le16(2);
2567 /* BB find exact max SMB PDU from sess structure BB */
2568 pSMB->MaxDataCount = cpu_to_le16(4000);
2569 pSMB->MaxSetupCount = 0;
2570 pSMB->Reserved = 0;
2571 pSMB->Flags = 0;
2572 pSMB->Timeout = 0;
2573 pSMB->Reserved2 = 0;
2574 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2575 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2576 pSMB->DataCount = 0;
2577 pSMB->DataOffset = 0;
2578 pSMB->SetupCount = 1;
2579 pSMB->Reserved3 = 0;
2580 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2581 byte_count = params + 1 /* pad */ ;
2582 pSMB->TotalParameterCount = cpu_to_le16(params);
2583 pSMB->ParameterCount = pSMB->TotalParameterCount;
2584 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2585 pSMB->Reserved4 = 0;
2586 pSMB->hdr.smb_buf_length += byte_count;
2587 pSMB->ByteCount = cpu_to_le16(byte_count);
2588
2589 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2590 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2591 if (rc) {
2592 cFYI(1, ("Send error in QPathInfo = %d", rc));
2593 } else { /* decode response */
2594 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2595
2596 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2597 rc = -EIO; /* bad smb */
2598 } else {
2599 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2600 memcpy((char *) pFindData,
2601 (char *) &pSMBr->hdr.Protocol +
2602 data_offset,
2603 sizeof (FILE_UNIX_BASIC_INFO));
2604 }
2605 }
2606 cifs_buf_release(pSMB);
2607 if (rc == -EAGAIN)
2608 goto UnixQPathInfoRetry;
2609
2610 return rc;
2611}
2612
2613#if 0 /* function unused at present */
2614int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2615 const char *searchName, FILE_ALL_INFO * findData,
2616 const struct nls_table *nls_codepage)
2617{
2618/* level 257 SMB_ */
2619 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2620 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2621 int rc = 0;
2622 int bytes_returned;
2623 int name_len;
2624 __u16 params, byte_count;
2625
2626 cFYI(1, ("In FindUnique"));
2627findUniqueRetry:
2628 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2629 (void **) &pSMBr);
2630 if (rc)
2631 return rc;
2632
2633 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2634 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002635 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 /* find define for this maxpathcomponent */
2637 , nls_codepage);
2638 name_len++; /* trailing null */
2639 name_len *= 2;
2640 } else { /* BB improve the check for buffer overruns BB */
2641 name_len = strnlen(searchName, PATH_MAX);
2642 name_len++; /* trailing null */
2643 strncpy(pSMB->FileName, searchName, name_len);
2644 }
2645
2646 params = 12 + name_len /* includes null */ ;
2647 pSMB->TotalDataCount = 0; /* no EAs */
2648 pSMB->MaxParameterCount = cpu_to_le16(2);
2649 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2650 pSMB->MaxSetupCount = 0;
2651 pSMB->Reserved = 0;
2652 pSMB->Flags = 0;
2653 pSMB->Timeout = 0;
2654 pSMB->Reserved2 = 0;
2655 pSMB->ParameterOffset = cpu_to_le16(
2656 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2657 pSMB->DataCount = 0;
2658 pSMB->DataOffset = 0;
2659 pSMB->SetupCount = 1; /* one byte, no need to le convert */
2660 pSMB->Reserved3 = 0;
2661 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2662 byte_count = params + 1 /* pad */ ;
2663 pSMB->TotalParameterCount = cpu_to_le16(params);
2664 pSMB->ParameterCount = pSMB->TotalParameterCount;
2665 pSMB->SearchAttributes =
2666 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2667 ATTR_DIRECTORY);
2668 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
2669 pSMB->SearchFlags = cpu_to_le16(1);
2670 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2671 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
2672 pSMB->hdr.smb_buf_length += byte_count;
2673 pSMB->ByteCount = cpu_to_le16(byte_count);
2674
2675 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2676 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2677
2678 if (rc) {
2679 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2680 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07002681 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 /* BB fill in */
2683 }
2684
2685 cifs_buf_release(pSMB);
2686 if (rc == -EAGAIN)
2687 goto findUniqueRetry;
2688
2689 return rc;
2690}
2691#endif /* end unused (temporarily) function */
2692
2693/* xid, tcon, searchName and codepage are input parms, rest are returned */
2694int
2695CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2696 const char *searchName,
2697 const struct nls_table *nls_codepage,
2698 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07002699 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700{
2701/* level 257 SMB_ */
2702 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2703 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2704 T2_FFIRST_RSP_PARMS * parms;
2705 int rc = 0;
2706 int bytes_returned = 0;
2707 int name_len;
2708 __u16 params, byte_count;
2709
Steve French737b7582005-04-28 22:41:06 -07002710 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711
2712findFirstRetry:
2713 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2714 (void **) &pSMBr);
2715 if (rc)
2716 return rc;
2717
2718 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2719 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002720 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07002721 PATH_MAX, nls_codepage, remap);
2722 /* We can not add the asterik earlier in case
2723 it got remapped to 0xF03A as if it were part of the
2724 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07002726 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07002727 pSMB->FileName[name_len+1] = 0;
2728 pSMB->FileName[name_len+2] = '*';
2729 pSMB->FileName[name_len+3] = 0;
2730 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2732 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07002733 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 } else { /* BB add check for overrun of SMB buf BB */
2735 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002736/* BB fix here and in unicode clause above ie
2737 if(name_len > buffersize-header)
2738 free buffer exit; BB */
2739 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07002740 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07002741 pSMB->FileName[name_len+1] = '*';
2742 pSMB->FileName[name_len+2] = 0;
2743 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 }
2745
2746 params = 12 + name_len /* includes null */ ;
2747 pSMB->TotalDataCount = 0; /* no EAs */
2748 pSMB->MaxParameterCount = cpu_to_le16(10);
2749 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2750 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2751 pSMB->MaxSetupCount = 0;
2752 pSMB->Reserved = 0;
2753 pSMB->Flags = 0;
2754 pSMB->Timeout = 0;
2755 pSMB->Reserved2 = 0;
2756 byte_count = params + 1 /* pad */ ;
2757 pSMB->TotalParameterCount = cpu_to_le16(params);
2758 pSMB->ParameterCount = pSMB->TotalParameterCount;
2759 pSMB->ParameterOffset = cpu_to_le16(
2760 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2761 pSMB->DataCount = 0;
2762 pSMB->DataOffset = 0;
2763 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
2764 pSMB->Reserved3 = 0;
2765 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2766 pSMB->SearchAttributes =
2767 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2768 ATTR_DIRECTORY);
2769 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2770 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
2771 CIFS_SEARCH_RETURN_RESUME);
2772 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2773
2774 /* BB what should we set StorageType to? Does it matter? BB */
2775 pSMB->SearchStorageType = 0;
2776 pSMB->hdr.smb_buf_length += byte_count;
2777 pSMB->ByteCount = cpu_to_le16(byte_count);
2778
2779 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2780 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002781 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782
Steve French1982c342005-08-17 12:38:22 -07002783 if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 /* BB Add code to handle unsupported level rc */
2785 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07002786
2787 if (pSMB)
2788 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789
2790 /* BB eventually could optimize out free and realloc of buf */
2791 /* for this case */
2792 if (rc == -EAGAIN)
2793 goto findFirstRetry;
2794 } else { /* decode response */
2795 /* BB remember to free buffer if error BB */
2796 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2797 if(rc == 0) {
2798 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2799 psrch_inf->unicode = TRUE;
2800 else
2801 psrch_inf->unicode = FALSE;
2802
2803 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2804 psrch_inf->srch_entries_start =
2805 (char *) &pSMBr->hdr.Protocol +
2806 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2808 le16_to_cpu(pSMBr->t2.ParameterOffset));
2809
2810 if(parms->EndofSearch)
2811 psrch_inf->endOfSearch = TRUE;
2812 else
2813 psrch_inf->endOfSearch = FALSE;
2814
2815 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2816 psrch_inf->index_of_last_entry =
2817 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 *pnetfid = parms->SearchHandle;
2819 } else {
2820 cifs_buf_release(pSMB);
2821 }
2822 }
2823
2824 return rc;
2825}
2826
2827int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2828 __u16 searchHandle, struct cifs_search_info * psrch_inf)
2829{
2830 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2831 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2832 T2_FNEXT_RSP_PARMS * parms;
2833 char *response_data;
2834 int rc = 0;
2835 int bytes_returned, name_len;
2836 __u16 params, byte_count;
2837
2838 cFYI(1, ("In FindNext"));
2839
2840 if(psrch_inf->endOfSearch == TRUE)
2841 return -ENOENT;
2842
2843 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2844 (void **) &pSMBr);
2845 if (rc)
2846 return rc;
2847
2848 params = 14; /* includes 2 bytes of null string, converted to LE below */
2849 byte_count = 0;
2850 pSMB->TotalDataCount = 0; /* no EAs */
2851 pSMB->MaxParameterCount = cpu_to_le16(8);
2852 pSMB->MaxDataCount =
2853 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2854 pSMB->MaxSetupCount = 0;
2855 pSMB->Reserved = 0;
2856 pSMB->Flags = 0;
2857 pSMB->Timeout = 0;
2858 pSMB->Reserved2 = 0;
2859 pSMB->ParameterOffset = cpu_to_le16(
2860 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2861 pSMB->DataCount = 0;
2862 pSMB->DataOffset = 0;
2863 pSMB->SetupCount = 1;
2864 pSMB->Reserved3 = 0;
2865 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2866 pSMB->SearchHandle = searchHandle; /* always kept as le */
2867 pSMB->SearchCount =
2868 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2869 /* test for Unix extensions */
2870/* if (tcon->ses->capabilities & CAP_UNIX) {
2871 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2872 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2873 } else {
2874 pSMB->InformationLevel =
2875 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2876 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2877 } */
2878 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2879 pSMB->ResumeKey = psrch_inf->resume_key;
2880 pSMB->SearchFlags =
2881 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2882
2883 name_len = psrch_inf->resume_name_len;
2884 params += name_len;
2885 if(name_len < PATH_MAX) {
2886 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2887 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07002888 /* 14 byte parm len above enough for 2 byte null terminator */
2889 pSMB->ResumeFileName[name_len] = 0;
2890 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 } else {
2892 rc = -EINVAL;
2893 goto FNext2_err_exit;
2894 }
2895 byte_count = params + 1 /* pad */ ;
2896 pSMB->TotalParameterCount = cpu_to_le16(params);
2897 pSMB->ParameterCount = pSMB->TotalParameterCount;
2898 pSMB->hdr.smb_buf_length += byte_count;
2899 pSMB->ByteCount = cpu_to_le16(byte_count);
2900
2901 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2902 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002903 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904 if (rc) {
2905 if (rc == -EBADF) {
2906 psrch_inf->endOfSearch = TRUE;
2907 rc = 0; /* search probably was closed at end of search above */
2908 } else
2909 cFYI(1, ("FindNext returned = %d", rc));
2910 } else { /* decode response */
2911 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2912
2913 if(rc == 0) {
2914 /* BB fixme add lock for file (srch_info) struct here */
2915 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2916 psrch_inf->unicode = TRUE;
2917 else
2918 psrch_inf->unicode = FALSE;
2919 response_data = (char *) &pSMBr->hdr.Protocol +
2920 le16_to_cpu(pSMBr->t2.ParameterOffset);
2921 parms = (T2_FNEXT_RSP_PARMS *)response_data;
2922 response_data = (char *)&pSMBr->hdr.Protocol +
2923 le16_to_cpu(pSMBr->t2.DataOffset);
2924 cifs_buf_release(psrch_inf->ntwrk_buf_start);
2925 psrch_inf->srch_entries_start = response_data;
2926 psrch_inf->ntwrk_buf_start = (char *)pSMB;
2927 if(parms->EndofSearch)
2928 psrch_inf->endOfSearch = TRUE;
2929 else
2930 psrch_inf->endOfSearch = FALSE;
2931
2932 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
2933 psrch_inf->index_of_last_entry +=
2934 psrch_inf->entries_in_buffer;
2935/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2936
2937 /* BB fixme add unlock here */
2938 }
2939
2940 }
2941
2942 /* BB On error, should we leave previous search buf (and count and
2943 last entry fields) intact or free the previous one? */
2944
2945 /* Note: On -EAGAIN error only caller can retry on handle based calls
2946 since file handle passed in no longer valid */
2947FNext2_err_exit:
2948 if (rc != 0)
2949 cifs_buf_release(pSMB);
2950
2951 return rc;
2952}
2953
2954int
2955CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2956{
2957 int rc = 0;
2958 FINDCLOSE_REQ *pSMB = NULL;
2959 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2960 int bytes_returned;
2961
2962 cFYI(1, ("In CIFSSMBFindClose"));
2963 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2964
2965 /* no sense returning error if session restarted
2966 as file handle has been closed */
2967 if(rc == -EAGAIN)
2968 return 0;
2969 if (rc)
2970 return rc;
2971
2972 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
2973 pSMB->FileID = searchHandle;
2974 pSMB->ByteCount = 0;
2975 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2976 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2977 if (rc) {
2978 cERROR(1, ("Send error in FindClose = %d", rc));
2979 }
Steve Frencha4544342005-08-24 13:59:35 -07002980 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981 cifs_small_buf_release(pSMB);
2982
2983 /* Since session is dead, search handle closed on server already */
2984 if (rc == -EAGAIN)
2985 rc = 0;
2986
2987 return rc;
2988}
2989
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990int
2991CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2992 const unsigned char *searchName,
2993 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07002994 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995{
2996 int rc = 0;
2997 TRANSACTION2_QPI_REQ *pSMB = NULL;
2998 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2999 int name_len, bytes_returned;
3000 __u16 params, byte_count;
3001
3002 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3003 if(tcon == NULL)
3004 return -ENODEV;
3005
3006GetInodeNumberRetry:
3007 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3008 (void **) &pSMBr);
3009 if (rc)
3010 return rc;
3011
3012
3013 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3014 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003015 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003016 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 name_len++; /* trailing null */
3018 name_len *= 2;
3019 } else { /* BB improve the check for buffer overruns BB */
3020 name_len = strnlen(searchName, PATH_MAX);
3021 name_len++; /* trailing null */
3022 strncpy(pSMB->FileName, searchName, name_len);
3023 }
3024
3025 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3026 pSMB->TotalDataCount = 0;
3027 pSMB->MaxParameterCount = cpu_to_le16(2);
3028 /* BB find exact max data count below from sess structure BB */
3029 pSMB->MaxDataCount = cpu_to_le16(4000);
3030 pSMB->MaxSetupCount = 0;
3031 pSMB->Reserved = 0;
3032 pSMB->Flags = 0;
3033 pSMB->Timeout = 0;
3034 pSMB->Reserved2 = 0;
3035 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3036 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3037 pSMB->DataCount = 0;
3038 pSMB->DataOffset = 0;
3039 pSMB->SetupCount = 1;
3040 pSMB->Reserved3 = 0;
3041 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3042 byte_count = params + 1 /* pad */ ;
3043 pSMB->TotalParameterCount = cpu_to_le16(params);
3044 pSMB->ParameterCount = pSMB->TotalParameterCount;
3045 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3046 pSMB->Reserved4 = 0;
3047 pSMB->hdr.smb_buf_length += byte_count;
3048 pSMB->ByteCount = cpu_to_le16(byte_count);
3049
3050 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3051 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3052 if (rc) {
3053 cFYI(1, ("error %d in QueryInternalInfo", rc));
3054 } else {
3055 /* decode response */
3056 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3057 if (rc || (pSMBr->ByteCount < 2))
3058 /* BB also check enough total bytes returned */
3059 /* If rc should we check for EOPNOSUPP and
3060 disable the srvino flag? or in caller? */
3061 rc = -EIO; /* bad smb */
3062 else {
3063 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3064 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3065 struct file_internal_info * pfinfo;
3066 /* BB Do we need a cast or hash here ? */
3067 if(count < 8) {
3068 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3069 rc = -EIO;
3070 goto GetInodeNumOut;
3071 }
3072 pfinfo = (struct file_internal_info *)
3073 (data_offset + (char *) &pSMBr->hdr.Protocol);
3074 *inode_number = pfinfo->UniqueId;
3075 }
3076 }
3077GetInodeNumOut:
3078 cifs_buf_release(pSMB);
3079 if (rc == -EAGAIN)
3080 goto GetInodeNumberRetry;
3081 return rc;
3082}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003083
3084int
3085CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3086 const unsigned char *searchName,
3087 unsigned char **targetUNCs,
3088 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003089 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003090{
3091/* TRANS2_GET_DFS_REFERRAL */
3092 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3093 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3094 struct dfs_referral_level_3 * referrals = NULL;
3095 int rc = 0;
3096 int bytes_returned;
3097 int name_len;
3098 unsigned int i;
3099 char * temp;
3100 __u16 params, byte_count;
3101 *number_of_UNC_in_array = 0;
3102 *targetUNCs = NULL;
3103
3104 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3105 if (ses == NULL)
3106 return -ENODEV;
3107getDFSRetry:
3108 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3109 (void **) &pSMBr);
3110 if (rc)
3111 return rc;
Steve French1982c342005-08-17 12:38:22 -07003112
3113 /* server pointer checked in called function,
3114 but should never be null here anyway */
3115 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 pSMB->hdr.Tid = ses->ipc_tid;
3117 pSMB->hdr.Uid = ses->Suid;
3118 if (ses->capabilities & CAP_STATUS32) {
3119 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3120 }
3121 if (ses->capabilities & CAP_DFS) {
3122 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3123 }
3124
3125 if (ses->capabilities & CAP_UNICODE) {
3126 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3127 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003128 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003129 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 name_len++; /* trailing null */
3131 name_len *= 2;
3132 } else { /* BB improve the check for buffer overruns BB */
3133 name_len = strnlen(searchName, PATH_MAX);
3134 name_len++; /* trailing null */
3135 strncpy(pSMB->RequestFileName, searchName, name_len);
3136 }
3137
3138 params = 2 /* level */ + name_len /*includes null */ ;
3139 pSMB->TotalDataCount = 0;
3140 pSMB->DataCount = 0;
3141 pSMB->DataOffset = 0;
3142 pSMB->MaxParameterCount = 0;
3143 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3144 pSMB->MaxSetupCount = 0;
3145 pSMB->Reserved = 0;
3146 pSMB->Flags = 0;
3147 pSMB->Timeout = 0;
3148 pSMB->Reserved2 = 0;
3149 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3150 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3151 pSMB->SetupCount = 1;
3152 pSMB->Reserved3 = 0;
3153 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3154 byte_count = params + 3 /* pad */ ;
3155 pSMB->ParameterCount = cpu_to_le16(params);
3156 pSMB->TotalParameterCount = pSMB->ParameterCount;
3157 pSMB->MaxReferralLevel = cpu_to_le16(3);
3158 pSMB->hdr.smb_buf_length += byte_count;
3159 pSMB->ByteCount = cpu_to_le16(byte_count);
3160
3161 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3162 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3163 if (rc) {
3164 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3165 } else { /* decode response */
3166/* BB Add logic to parse referrals here */
3167 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3168
3169 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3170 rc = -EIO; /* bad smb */
3171 else {
3172 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3173 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3174
3175 cFYI(1,
3176 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3177 pSMBr->ByteCount, data_offset));
3178 referrals =
3179 (struct dfs_referral_level_3 *)
3180 (8 /* sizeof start of data block */ +
3181 data_offset +
3182 (char *) &pSMBr->hdr.Protocol);
3183 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",
3184 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)));
3185 /* BB This field is actually two bytes in from start of
3186 data block so we could do safety check that DataBlock
3187 begins at address of pSMBr->NumberOfReferrals */
3188 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3189
3190 /* BB Fix below so can return more than one referral */
3191 if(*number_of_UNC_in_array > 1)
3192 *number_of_UNC_in_array = 1;
3193
3194 /* get the length of the strings describing refs */
3195 name_len = 0;
3196 for(i=0;i<*number_of_UNC_in_array;i++) {
3197 /* make sure that DfsPathOffset not past end */
3198 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3199 if (offset > data_count) {
3200 /* if invalid referral, stop here and do
3201 not try to copy any more */
3202 *number_of_UNC_in_array = i;
3203 break;
3204 }
3205 temp = ((char *)referrals) + offset;
3206
3207 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3208 name_len += UniStrnlen((wchar_t *)temp,data_count);
3209 } else {
3210 name_len += strnlen(temp,data_count);
3211 }
3212 referrals++;
3213 /* BB add check that referral pointer does not fall off end PDU */
3214
3215 }
3216 /* BB add check for name_len bigger than bcc */
3217 *targetUNCs =
3218 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3219 if(*targetUNCs == NULL) {
3220 rc = -ENOMEM;
3221 goto GetDFSRefExit;
3222 }
3223 /* copy the ref strings */
3224 referrals =
3225 (struct dfs_referral_level_3 *)
3226 (8 /* sizeof data hdr */ +
3227 data_offset +
3228 (char *) &pSMBr->hdr.Protocol);
3229
3230 for(i=0;i<*number_of_UNC_in_array;i++) {
3231 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3232 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3233 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003234 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 } else {
3236 strncpy(*targetUNCs,temp,name_len);
3237 }
3238 /* BB update target_uncs pointers */
3239 referrals++;
3240 }
3241 temp = *targetUNCs;
3242 temp[name_len] = 0;
3243 }
3244
3245 }
3246GetDFSRefExit:
3247 if (pSMB)
3248 cifs_buf_release(pSMB);
3249
3250 if (rc == -EAGAIN)
3251 goto getDFSRetry;
3252
3253 return rc;
3254}
3255
Steve French20962432005-09-21 22:05:57 -07003256/* Query File System Info such as free space to old servers such as Win 9x */
3257int
3258SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3259{
3260/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3261 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3262 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3263 FILE_SYSTEM_ALLOC_INFO *response_data;
3264 int rc = 0;
3265 int bytes_returned = 0;
3266 __u16 params, byte_count;
3267
3268 cFYI(1, ("OldQFSInfo"));
3269oldQFSInfoRetry:
3270 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3271 (void **) &pSMBr);
3272 if (rc)
3273 return rc;
3274 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3275 (void **) &pSMBr);
3276 if (rc)
3277 return rc;
3278
3279 params = 2; /* level */
3280 pSMB->TotalDataCount = 0;
3281 pSMB->MaxParameterCount = cpu_to_le16(2);
3282 pSMB->MaxDataCount = cpu_to_le16(1000);
3283 pSMB->MaxSetupCount = 0;
3284 pSMB->Reserved = 0;
3285 pSMB->Flags = 0;
3286 pSMB->Timeout = 0;
3287 pSMB->Reserved2 = 0;
3288 byte_count = params + 1 /* pad */ ;
3289 pSMB->TotalParameterCount = cpu_to_le16(params);
3290 pSMB->ParameterCount = pSMB->TotalParameterCount;
3291 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3292 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3293 pSMB->DataCount = 0;
3294 pSMB->DataOffset = 0;
3295 pSMB->SetupCount = 1;
3296 pSMB->Reserved3 = 0;
3297 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3298 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3299 pSMB->hdr.smb_buf_length += byte_count;
3300 pSMB->ByteCount = cpu_to_le16(byte_count);
3301
3302 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3303 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3304 if (rc) {
3305 cFYI(1, ("Send error in QFSInfo = %d", rc));
3306 } else { /* decode response */
3307 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3308
3309 if (rc || (pSMBr->ByteCount < 18))
3310 rc = -EIO; /* bad smb */
3311 else {
3312 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3313 cFYI(1,("qfsinf resp BCC: %d Offset %d",
3314 pSMBr->ByteCount, data_offset));
3315
3316 response_data =
3317 (FILE_SYSTEM_ALLOC_INFO *)
3318 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3319 FSData->f_bsize =
3320 le16_to_cpu(response_data->BytesPerSector) *
3321 le32_to_cpu(response_data->
3322 SectorsPerAllocationUnit);
3323 FSData->f_blocks =
3324 le32_to_cpu(response_data->TotalAllocationUnits);
3325 FSData->f_bfree = FSData->f_bavail =
3326 le32_to_cpu(response_data->FreeAllocationUnits);
3327 cFYI(1,
3328 ("Blocks: %lld Free: %lld Block size %ld",
3329 (unsigned long long)FSData->f_blocks,
3330 (unsigned long long)FSData->f_bfree,
3331 FSData->f_bsize));
3332 }
3333 }
3334 cifs_buf_release(pSMB);
3335
3336 if (rc == -EAGAIN)
3337 goto oldQFSInfoRetry;
3338
3339 return rc;
3340}
3341
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342int
Steve French737b7582005-04-28 22:41:06 -07003343CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344{
3345/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3346 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3347 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3348 FILE_SYSTEM_INFO *response_data;
3349 int rc = 0;
3350 int bytes_returned = 0;
3351 __u16 params, byte_count;
3352
3353 cFYI(1, ("In QFSInfo"));
3354QFSInfoRetry:
3355 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3356 (void **) &pSMBr);
3357 if (rc)
3358 return rc;
3359
3360 params = 2; /* level */
3361 pSMB->TotalDataCount = 0;
3362 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07003363 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 pSMB->MaxSetupCount = 0;
3365 pSMB->Reserved = 0;
3366 pSMB->Flags = 0;
3367 pSMB->Timeout = 0;
3368 pSMB->Reserved2 = 0;
3369 byte_count = params + 1 /* pad */ ;
3370 pSMB->TotalParameterCount = cpu_to_le16(params);
3371 pSMB->ParameterCount = pSMB->TotalParameterCount;
3372 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3373 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3374 pSMB->DataCount = 0;
3375 pSMB->DataOffset = 0;
3376 pSMB->SetupCount = 1;
3377 pSMB->Reserved3 = 0;
3378 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3379 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3380 pSMB->hdr.smb_buf_length += byte_count;
3381 pSMB->ByteCount = cpu_to_le16(byte_count);
3382
3383 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3384 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3385 if (rc) {
Steve French20962432005-09-21 22:05:57 -07003386 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 } else { /* decode response */
3388 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3389
Steve French20962432005-09-21 22:05:57 -07003390 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003391 rc = -EIO; /* bad smb */
3392 else {
3393 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394
3395 response_data =
3396 (FILE_SYSTEM_INFO
3397 *) (((char *) &pSMBr->hdr.Protocol) +
3398 data_offset);
3399 FSData->f_bsize =
3400 le32_to_cpu(response_data->BytesPerSector) *
3401 le32_to_cpu(response_data->
3402 SectorsPerAllocationUnit);
3403 FSData->f_blocks =
3404 le64_to_cpu(response_data->TotalAllocationUnits);
3405 FSData->f_bfree = FSData->f_bavail =
3406 le64_to_cpu(response_data->FreeAllocationUnits);
3407 cFYI(1,
3408 ("Blocks: %lld Free: %lld Block size %ld",
3409 (unsigned long long)FSData->f_blocks,
3410 (unsigned long long)FSData->f_bfree,
3411 FSData->f_bsize));
3412 }
3413 }
3414 cifs_buf_release(pSMB);
3415
3416 if (rc == -EAGAIN)
3417 goto QFSInfoRetry;
3418
3419 return rc;
3420}
3421
3422int
Steve French737b7582005-04-28 22:41:06 -07003423CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003424{
3425/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
3426 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3427 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3428 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3429 int rc = 0;
3430 int bytes_returned = 0;
3431 __u16 params, byte_count;
3432
3433 cFYI(1, ("In QFSAttributeInfo"));
3434QFSAttributeRetry:
3435 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3436 (void **) &pSMBr);
3437 if (rc)
3438 return rc;
3439
3440 params = 2; /* level */
3441 pSMB->TotalDataCount = 0;
3442 pSMB->MaxParameterCount = cpu_to_le16(2);
3443 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3444 pSMB->MaxSetupCount = 0;
3445 pSMB->Reserved = 0;
3446 pSMB->Flags = 0;
3447 pSMB->Timeout = 0;
3448 pSMB->Reserved2 = 0;
3449 byte_count = params + 1 /* pad */ ;
3450 pSMB->TotalParameterCount = cpu_to_le16(params);
3451 pSMB->ParameterCount = pSMB->TotalParameterCount;
3452 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3453 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3454 pSMB->DataCount = 0;
3455 pSMB->DataOffset = 0;
3456 pSMB->SetupCount = 1;
3457 pSMB->Reserved3 = 0;
3458 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3459 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3460 pSMB->hdr.smb_buf_length += byte_count;
3461 pSMB->ByteCount = cpu_to_le16(byte_count);
3462
3463 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3464 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3465 if (rc) {
3466 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3467 } else { /* decode response */
3468 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3469
3470 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
3471 rc = -EIO; /* bad smb */
3472 } else {
3473 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3474 response_data =
3475 (FILE_SYSTEM_ATTRIBUTE_INFO
3476 *) (((char *) &pSMBr->hdr.Protocol) +
3477 data_offset);
3478 memcpy(&tcon->fsAttrInfo, response_data,
3479 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3480 }
3481 }
3482 cifs_buf_release(pSMB);
3483
3484 if (rc == -EAGAIN)
3485 goto QFSAttributeRetry;
3486
3487 return rc;
3488}
3489
3490int
Steve French737b7582005-04-28 22:41:06 -07003491CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003492{
3493/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3494 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3495 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3496 FILE_SYSTEM_DEVICE_INFO *response_data;
3497 int rc = 0;
3498 int bytes_returned = 0;
3499 __u16 params, byte_count;
3500
3501 cFYI(1, ("In QFSDeviceInfo"));
3502QFSDeviceRetry:
3503 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3504 (void **) &pSMBr);
3505 if (rc)
3506 return rc;
3507
3508 params = 2; /* level */
3509 pSMB->TotalDataCount = 0;
3510 pSMB->MaxParameterCount = cpu_to_le16(2);
3511 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3512 pSMB->MaxSetupCount = 0;
3513 pSMB->Reserved = 0;
3514 pSMB->Flags = 0;
3515 pSMB->Timeout = 0;
3516 pSMB->Reserved2 = 0;
3517 byte_count = params + 1 /* pad */ ;
3518 pSMB->TotalParameterCount = cpu_to_le16(params);
3519 pSMB->ParameterCount = pSMB->TotalParameterCount;
3520 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3521 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3522
3523 pSMB->DataCount = 0;
3524 pSMB->DataOffset = 0;
3525 pSMB->SetupCount = 1;
3526 pSMB->Reserved3 = 0;
3527 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3528 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3529 pSMB->hdr.smb_buf_length += byte_count;
3530 pSMB->ByteCount = cpu_to_le16(byte_count);
3531
3532 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3533 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3534 if (rc) {
3535 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3536 } else { /* decode response */
3537 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3538
3539 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3540 rc = -EIO; /* bad smb */
3541 else {
3542 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3543 response_data =
Steve French737b7582005-04-28 22:41:06 -07003544 (FILE_SYSTEM_DEVICE_INFO *)
3545 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546 data_offset);
3547 memcpy(&tcon->fsDevInfo, response_data,
3548 sizeof (FILE_SYSTEM_DEVICE_INFO));
3549 }
3550 }
3551 cifs_buf_release(pSMB);
3552
3553 if (rc == -EAGAIN)
3554 goto QFSDeviceRetry;
3555
3556 return rc;
3557}
3558
3559int
Steve French737b7582005-04-28 22:41:06 -07003560CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561{
3562/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
3563 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3564 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3565 FILE_SYSTEM_UNIX_INFO *response_data;
3566 int rc = 0;
3567 int bytes_returned = 0;
3568 __u16 params, byte_count;
3569
3570 cFYI(1, ("In QFSUnixInfo"));
3571QFSUnixRetry:
3572 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3573 (void **) &pSMBr);
3574 if (rc)
3575 return rc;
3576
3577 params = 2; /* level */
3578 pSMB->TotalDataCount = 0;
3579 pSMB->DataCount = 0;
3580 pSMB->DataOffset = 0;
3581 pSMB->MaxParameterCount = cpu_to_le16(2);
3582 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3583 pSMB->MaxSetupCount = 0;
3584 pSMB->Reserved = 0;
3585 pSMB->Flags = 0;
3586 pSMB->Timeout = 0;
3587 pSMB->Reserved2 = 0;
3588 byte_count = params + 1 /* pad */ ;
3589 pSMB->ParameterCount = cpu_to_le16(params);
3590 pSMB->TotalParameterCount = pSMB->ParameterCount;
3591 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3592 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3593 pSMB->SetupCount = 1;
3594 pSMB->Reserved3 = 0;
3595 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3596 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3597 pSMB->hdr.smb_buf_length += byte_count;
3598 pSMB->ByteCount = cpu_to_le16(byte_count);
3599
3600 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3601 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3602 if (rc) {
3603 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3604 } else { /* decode response */
3605 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3606
3607 if (rc || (pSMBr->ByteCount < 13)) {
3608 rc = -EIO; /* bad smb */
3609 } else {
3610 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3611 response_data =
3612 (FILE_SYSTEM_UNIX_INFO
3613 *) (((char *) &pSMBr->hdr.Protocol) +
3614 data_offset);
3615 memcpy(&tcon->fsUnixInfo, response_data,
3616 sizeof (FILE_SYSTEM_UNIX_INFO));
3617 }
3618 }
3619 cifs_buf_release(pSMB);
3620
3621 if (rc == -EAGAIN)
3622 goto QFSUnixRetry;
3623
3624
3625 return rc;
3626}
3627
Jeremy Allisonac670552005-06-22 17:26:35 -07003628int
Steve French45abc6e2005-06-23 13:42:03 -05003629CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07003630{
3631/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
3632 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3633 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3634 int rc = 0;
3635 int bytes_returned = 0;
3636 __u16 params, param_offset, offset, byte_count;
3637
3638 cFYI(1, ("In SETFSUnixInfo"));
3639SETFSUnixRetry:
3640 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3641 (void **) &pSMBr);
3642 if (rc)
3643 return rc;
3644
3645 params = 4; /* 2 bytes zero followed by info level. */
3646 pSMB->MaxSetupCount = 0;
3647 pSMB->Reserved = 0;
3648 pSMB->Flags = 0;
3649 pSMB->Timeout = 0;
3650 pSMB->Reserved2 = 0;
3651 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3652 offset = param_offset + params;
3653
3654 pSMB->MaxParameterCount = cpu_to_le16(4);
3655 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3656 pSMB->SetupCount = 1;
3657 pSMB->Reserved3 = 0;
3658 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3659 byte_count = 1 /* pad */ + params + 12;
3660
3661 pSMB->DataCount = cpu_to_le16(12);
3662 pSMB->ParameterCount = cpu_to_le16(params);
3663 pSMB->TotalDataCount = pSMB->DataCount;
3664 pSMB->TotalParameterCount = pSMB->ParameterCount;
3665 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3666 pSMB->DataOffset = cpu_to_le16(offset);
3667
3668 /* Params. */
3669 pSMB->FileNum = 0;
3670 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3671
3672 /* Data. */
3673 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3674 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3675 pSMB->ClientUnixCap = cpu_to_le64(cap);
3676
3677 pSMB->hdr.smb_buf_length += byte_count;
3678 pSMB->ByteCount = cpu_to_le16(byte_count);
3679
3680 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3681 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3682 if (rc) {
3683 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3684 } else { /* decode response */
3685 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3686 if (rc) {
3687 rc = -EIO; /* bad smb */
3688 }
3689 }
3690 cifs_buf_release(pSMB);
3691
3692 if (rc == -EAGAIN)
3693 goto SETFSUnixRetry;
3694
3695 return rc;
3696}
3697
3698
Linus Torvalds1da177e2005-04-16 15:20:36 -07003699
3700int
3701CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07003702 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003703{
3704/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
3705 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3706 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3707 FILE_SYSTEM_POSIX_INFO *response_data;
3708 int rc = 0;
3709 int bytes_returned = 0;
3710 __u16 params, byte_count;
3711
3712 cFYI(1, ("In QFSPosixInfo"));
3713QFSPosixRetry:
3714 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3715 (void **) &pSMBr);
3716 if (rc)
3717 return rc;
3718
3719 params = 2; /* level */
3720 pSMB->TotalDataCount = 0;
3721 pSMB->DataCount = 0;
3722 pSMB->DataOffset = 0;
3723 pSMB->MaxParameterCount = cpu_to_le16(2);
3724 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
3725 pSMB->MaxSetupCount = 0;
3726 pSMB->Reserved = 0;
3727 pSMB->Flags = 0;
3728 pSMB->Timeout = 0;
3729 pSMB->Reserved2 = 0;
3730 byte_count = params + 1 /* pad */ ;
3731 pSMB->ParameterCount = cpu_to_le16(params);
3732 pSMB->TotalParameterCount = pSMB->ParameterCount;
3733 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
3734 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3735 pSMB->SetupCount = 1;
3736 pSMB->Reserved3 = 0;
3737 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3738 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3739 pSMB->hdr.smb_buf_length += byte_count;
3740 pSMB->ByteCount = cpu_to_le16(byte_count);
3741
3742 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3743 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3744 if (rc) {
3745 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3746 } else { /* decode response */
3747 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3748
3749 if (rc || (pSMBr->ByteCount < 13)) {
3750 rc = -EIO; /* bad smb */
3751 } else {
3752 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3753 response_data =
3754 (FILE_SYSTEM_POSIX_INFO
3755 *) (((char *) &pSMBr->hdr.Protocol) +
3756 data_offset);
3757 FSData->f_bsize =
3758 le32_to_cpu(response_data->BlockSize);
3759 FSData->f_blocks =
3760 le64_to_cpu(response_data->TotalBlocks);
3761 FSData->f_bfree =
3762 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07003763 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764 FSData->f_bavail = FSData->f_bfree;
3765 } else {
3766 FSData->f_bavail =
3767 le64_to_cpu(response_data->UserBlocksAvail);
3768 }
Steve French70ca7342005-09-22 16:32:06 -07003769 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003770 FSData->f_files =
3771 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07003772 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773 FSData->f_ffree =
3774 le64_to_cpu(response_data->FreeFileNodes);
3775 }
3776 }
3777 cifs_buf_release(pSMB);
3778
3779 if (rc == -EAGAIN)
3780 goto QFSPosixRetry;
3781
3782 return rc;
3783}
3784
3785
3786/* We can not use write of zero bytes trick to
3787 set file size due to need for large file support. Also note that
3788 this SetPathInfo is preferred to SetFileInfo based method in next
3789 routine which is only needed to work around a sharing violation bug
3790 in Samba which this routine can run into */
3791
3792int
3793CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07003794 __u64 size, int SetAllocation,
3795 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003796{
3797 struct smb_com_transaction2_spi_req *pSMB = NULL;
3798 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3799 struct file_end_of_file_info *parm_data;
3800 int name_len;
3801 int rc = 0;
3802 int bytes_returned = 0;
3803 __u16 params, byte_count, data_count, param_offset, offset;
3804
3805 cFYI(1, ("In SetEOF"));
3806SetEOFRetry:
3807 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3808 (void **) &pSMBr);
3809 if (rc)
3810 return rc;
3811
3812 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3813 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003814 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07003815 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816 name_len++; /* trailing null */
3817 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07003818 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 name_len = strnlen(fileName, PATH_MAX);
3820 name_len++; /* trailing null */
3821 strncpy(pSMB->FileName, fileName, name_len);
3822 }
3823 params = 6 + name_len;
3824 data_count = sizeof (struct file_end_of_file_info);
3825 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07003826 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003827 pSMB->MaxSetupCount = 0;
3828 pSMB->Reserved = 0;
3829 pSMB->Flags = 0;
3830 pSMB->Timeout = 0;
3831 pSMB->Reserved2 = 0;
3832 param_offset = offsetof(struct smb_com_transaction2_spi_req,
3833 InformationLevel) - 4;
3834 offset = param_offset + params;
3835 if(SetAllocation) {
3836 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3837 pSMB->InformationLevel =
3838 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3839 else
3840 pSMB->InformationLevel =
3841 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3842 } else /* Set File Size */ {
3843 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3844 pSMB->InformationLevel =
3845 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3846 else
3847 pSMB->InformationLevel =
3848 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3849 }
3850
3851 parm_data =
3852 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3853 offset);
3854 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3855 pSMB->DataOffset = cpu_to_le16(offset);
3856 pSMB->SetupCount = 1;
3857 pSMB->Reserved3 = 0;
3858 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3859 byte_count = 3 /* pad */ + params + data_count;
3860 pSMB->DataCount = cpu_to_le16(data_count);
3861 pSMB->TotalDataCount = pSMB->DataCount;
3862 pSMB->ParameterCount = cpu_to_le16(params);
3863 pSMB->TotalParameterCount = pSMB->ParameterCount;
3864 pSMB->Reserved4 = 0;
3865 pSMB->hdr.smb_buf_length += byte_count;
3866 parm_data->FileSize = cpu_to_le64(size);
3867 pSMB->ByteCount = cpu_to_le16(byte_count);
3868 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3869 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3870 if (rc) {
3871 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3872 }
3873
3874 cifs_buf_release(pSMB);
3875
3876 if (rc == -EAGAIN)
3877 goto SetEOFRetry;
3878
3879 return rc;
3880}
3881
3882int
3883CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
3884 __u16 fid, __u32 pid_of_opener, int SetAllocation)
3885{
3886 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3887 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3888 char *data_offset;
3889 struct file_end_of_file_info *parm_data;
3890 int rc = 0;
3891 int bytes_returned = 0;
3892 __u16 params, param_offset, offset, byte_count, count;
3893
3894 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3895 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07003896 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3897
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 if (rc)
3899 return rc;
3900
Steve Frenchcd634992005-04-28 22:41:10 -07003901 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3902
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3904 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3905
3906 params = 6;
3907 pSMB->MaxSetupCount = 0;
3908 pSMB->Reserved = 0;
3909 pSMB->Flags = 0;
3910 pSMB->Timeout = 0;
3911 pSMB->Reserved2 = 0;
3912 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3913 offset = param_offset + params;
3914
3915 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3916
3917 count = sizeof(struct file_end_of_file_info);
3918 pSMB->MaxParameterCount = cpu_to_le16(2);
3919 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3920 pSMB->SetupCount = 1;
3921 pSMB->Reserved3 = 0;
3922 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3923 byte_count = 3 /* pad */ + params + count;
3924 pSMB->DataCount = cpu_to_le16(count);
3925 pSMB->ParameterCount = cpu_to_le16(params);
3926 pSMB->TotalDataCount = pSMB->DataCount;
3927 pSMB->TotalParameterCount = pSMB->ParameterCount;
3928 pSMB->ParameterOffset = cpu_to_le16(param_offset);
3929 parm_data =
3930 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3931 offset);
3932 pSMB->DataOffset = cpu_to_le16(offset);
3933 parm_data->FileSize = cpu_to_le64(size);
3934 pSMB->Fid = fid;
3935 if(SetAllocation) {
3936 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3937 pSMB->InformationLevel =
3938 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3939 else
3940 pSMB->InformationLevel =
3941 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3942 } else /* Set File Size */ {
3943 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3944 pSMB->InformationLevel =
3945 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3946 else
3947 pSMB->InformationLevel =
3948 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3949 }
3950 pSMB->Reserved4 = 0;
3951 pSMB->hdr.smb_buf_length += byte_count;
3952 pSMB->ByteCount = cpu_to_le16(byte_count);
3953 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3954 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3955 if (rc) {
3956 cFYI(1,
3957 ("Send error in SetFileInfo (SetFileSize) = %d",
3958 rc));
3959 }
3960
3961 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07003962 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963
3964 /* Note: On -EAGAIN error only caller can retry on handle based calls
3965 since file handle passed in no longer valid */
3966
3967 return rc;
3968}
3969
3970/* Some legacy servers such as NT4 require that the file times be set on
3971 an open handle, rather than by pathname - this is awkward due to
3972 potential access conflicts on the open, but it is unavoidable for these
3973 old servers since the only other choice is to go from 100 nanosecond DCE
3974 time and resort to the original setpathinfo level which takes the ancient
3975 DOS time format with 2 second granularity */
3976int
3977CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
3978 __u16 fid)
3979{
3980 struct smb_com_transaction2_sfi_req *pSMB = NULL;
3981 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3982 char *data_offset;
3983 int rc = 0;
3984 int bytes_returned = 0;
3985 __u16 params, param_offset, offset, byte_count, count;
3986
3987 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07003988 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3989
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 if (rc)
3991 return rc;
3992
Steve Frenchcd634992005-04-28 22:41:10 -07003993 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3994
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 /* At this point there is no need to override the current pid
3996 with the pid of the opener, but that could change if we someday
3997 use an existing handle (rather than opening one on the fly) */
3998 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3999 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4000
4001 params = 6;
4002 pSMB->MaxSetupCount = 0;
4003 pSMB->Reserved = 0;
4004 pSMB->Flags = 0;
4005 pSMB->Timeout = 0;
4006 pSMB->Reserved2 = 0;
4007 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4008 offset = param_offset + params;
4009
4010 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4011
4012 count = sizeof (FILE_BASIC_INFO);
4013 pSMB->MaxParameterCount = cpu_to_le16(2);
4014 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4015 pSMB->SetupCount = 1;
4016 pSMB->Reserved3 = 0;
4017 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4018 byte_count = 3 /* pad */ + params + count;
4019 pSMB->DataCount = cpu_to_le16(count);
4020 pSMB->ParameterCount = cpu_to_le16(params);
4021 pSMB->TotalDataCount = pSMB->DataCount;
4022 pSMB->TotalParameterCount = pSMB->ParameterCount;
4023 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4024 pSMB->DataOffset = cpu_to_le16(offset);
4025 pSMB->Fid = fid;
4026 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4027 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4028 else
4029 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4030 pSMB->Reserved4 = 0;
4031 pSMB->hdr.smb_buf_length += byte_count;
4032 pSMB->ByteCount = cpu_to_le16(byte_count);
4033 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4034 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4035 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4036 if (rc) {
4037 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4038 }
4039
Steve Frenchcd634992005-04-28 22:41:10 -07004040 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041
4042 /* Note: On -EAGAIN error only caller can retry on handle based calls
4043 since file handle passed in no longer valid */
4044
4045 return rc;
4046}
4047
4048
4049int
4050CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4051 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004052 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004053{
4054 TRANSACTION2_SPI_REQ *pSMB = NULL;
4055 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4056 int name_len;
4057 int rc = 0;
4058 int bytes_returned = 0;
4059 char *data_offset;
4060 __u16 params, param_offset, offset, byte_count, count;
4061
4062 cFYI(1, ("In SetTimes"));
4063
4064SetTimesRetry:
4065 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4066 (void **) &pSMBr);
4067 if (rc)
4068 return rc;
4069
4070 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4071 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004072 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004073 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004074 name_len++; /* trailing null */
4075 name_len *= 2;
4076 } else { /* BB improve the check for buffer overruns BB */
4077 name_len = strnlen(fileName, PATH_MAX);
4078 name_len++; /* trailing null */
4079 strncpy(pSMB->FileName, fileName, name_len);
4080 }
4081
4082 params = 6 + name_len;
4083 count = sizeof (FILE_BASIC_INFO);
4084 pSMB->MaxParameterCount = cpu_to_le16(2);
4085 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4086 pSMB->MaxSetupCount = 0;
4087 pSMB->Reserved = 0;
4088 pSMB->Flags = 0;
4089 pSMB->Timeout = 0;
4090 pSMB->Reserved2 = 0;
4091 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4092 InformationLevel) - 4;
4093 offset = param_offset + params;
4094 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4095 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4096 pSMB->DataOffset = cpu_to_le16(offset);
4097 pSMB->SetupCount = 1;
4098 pSMB->Reserved3 = 0;
4099 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4100 byte_count = 3 /* pad */ + params + count;
4101
4102 pSMB->DataCount = cpu_to_le16(count);
4103 pSMB->ParameterCount = cpu_to_le16(params);
4104 pSMB->TotalDataCount = pSMB->DataCount;
4105 pSMB->TotalParameterCount = pSMB->ParameterCount;
4106 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4107 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4108 else
4109 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4110 pSMB->Reserved4 = 0;
4111 pSMB->hdr.smb_buf_length += byte_count;
4112 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4113 pSMB->ByteCount = cpu_to_le16(byte_count);
4114 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4115 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4116 if (rc) {
4117 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4118 }
4119
4120 cifs_buf_release(pSMB);
4121
4122 if (rc == -EAGAIN)
4123 goto SetTimesRetry;
4124
4125 return rc;
4126}
4127
4128/* Can not be used to set time stamps yet (due to old DOS time format) */
4129/* Can be used to set attributes */
4130#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4131 handling it anyway and NT4 was what we thought it would be needed for
4132 Do not delete it until we prove whether needed for Win9x though */
4133int
4134CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4135 __u16 dos_attrs, const struct nls_table *nls_codepage)
4136{
4137 SETATTR_REQ *pSMB = NULL;
4138 SETATTR_RSP *pSMBr = NULL;
4139 int rc = 0;
4140 int bytes_returned;
4141 int name_len;
4142
4143 cFYI(1, ("In SetAttrLegacy"));
4144
4145SetAttrLgcyRetry:
4146 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4147 (void **) &pSMBr);
4148 if (rc)
4149 return rc;
4150
4151 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4152 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004153 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154 PATH_MAX, nls_codepage);
4155 name_len++; /* trailing null */
4156 name_len *= 2;
4157 } else { /* BB improve the check for buffer overruns BB */
4158 name_len = strnlen(fileName, PATH_MAX);
4159 name_len++; /* trailing null */
4160 strncpy(pSMB->fileName, fileName, name_len);
4161 }
4162 pSMB->attr = cpu_to_le16(dos_attrs);
4163 pSMB->BufferFormat = 0x04;
4164 pSMB->hdr.smb_buf_length += name_len + 1;
4165 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4166 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4167 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4168 if (rc) {
4169 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4170 }
4171
4172 cifs_buf_release(pSMB);
4173
4174 if (rc == -EAGAIN)
4175 goto SetAttrLgcyRetry;
4176
4177 return rc;
4178}
4179#endif /* temporarily unneeded SetAttr legacy function */
4180
4181int
4182CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004183 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4184 dev_t device, const struct nls_table *nls_codepage,
4185 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186{
4187 TRANSACTION2_SPI_REQ *pSMB = NULL;
4188 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4189 int name_len;
4190 int rc = 0;
4191 int bytes_returned = 0;
4192 FILE_UNIX_BASIC_INFO *data_offset;
4193 __u16 params, param_offset, offset, count, byte_count;
4194
4195 cFYI(1, ("In SetUID/GID/Mode"));
4196setPermsRetry:
4197 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4198 (void **) &pSMBr);
4199 if (rc)
4200 return rc;
4201
4202 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4203 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004204 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004205 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206 name_len++; /* trailing null */
4207 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004208 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004209 name_len = strnlen(fileName, PATH_MAX);
4210 name_len++; /* trailing null */
4211 strncpy(pSMB->FileName, fileName, name_len);
4212 }
4213
4214 params = 6 + name_len;
4215 count = sizeof (FILE_UNIX_BASIC_INFO);
4216 pSMB->MaxParameterCount = cpu_to_le16(2);
4217 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4218 pSMB->MaxSetupCount = 0;
4219 pSMB->Reserved = 0;
4220 pSMB->Flags = 0;
4221 pSMB->Timeout = 0;
4222 pSMB->Reserved2 = 0;
4223 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4224 InformationLevel) - 4;
4225 offset = param_offset + params;
4226 data_offset =
4227 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4228 offset);
4229 memset(data_offset, 0, count);
4230 pSMB->DataOffset = cpu_to_le16(offset);
4231 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4232 pSMB->SetupCount = 1;
4233 pSMB->Reserved3 = 0;
4234 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4235 byte_count = 3 /* pad */ + params + count;
4236 pSMB->ParameterCount = cpu_to_le16(params);
4237 pSMB->DataCount = cpu_to_le16(count);
4238 pSMB->TotalParameterCount = pSMB->ParameterCount;
4239 pSMB->TotalDataCount = pSMB->DataCount;
4240 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4241 pSMB->Reserved4 = 0;
4242 pSMB->hdr.smb_buf_length += byte_count;
4243 data_offset->Uid = cpu_to_le64(uid);
4244 data_offset->Gid = cpu_to_le64(gid);
4245 /* better to leave device as zero when it is */
4246 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4247 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4248 data_offset->Permissions = cpu_to_le64(mode);
4249
4250 if(S_ISREG(mode))
4251 data_offset->Type = cpu_to_le32(UNIX_FILE);
4252 else if(S_ISDIR(mode))
4253 data_offset->Type = cpu_to_le32(UNIX_DIR);
4254 else if(S_ISLNK(mode))
4255 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4256 else if(S_ISCHR(mode))
4257 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4258 else if(S_ISBLK(mode))
4259 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4260 else if(S_ISFIFO(mode))
4261 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4262 else if(S_ISSOCK(mode))
4263 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4264
4265
4266 pSMB->ByteCount = cpu_to_le16(byte_count);
4267 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4268 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4269 if (rc) {
4270 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4271 }
4272
4273 if (pSMB)
4274 cifs_buf_release(pSMB);
4275 if (rc == -EAGAIN)
4276 goto setPermsRetry;
4277 return rc;
4278}
4279
4280int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004281 const int notify_subdirs, const __u16 netfid,
4282 __u32 filter, struct file * pfile, int multishot,
4283 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004284{
4285 int rc = 0;
4286 struct smb_com_transaction_change_notify_req * pSMB = NULL;
4287 struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004288 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 int bytes_returned;
4290
4291 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4292 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4293 (void **) &pSMBr);
4294 if (rc)
4295 return rc;
4296
4297 pSMB->TotalParameterCount = 0 ;
4298 pSMB->TotalDataCount = 0;
4299 pSMB->MaxParameterCount = cpu_to_le32(2);
4300 /* BB find exact data count max from sess structure BB */
4301 pSMB->MaxDataCount = 0; /* same in little endian or be */
4302 pSMB->MaxSetupCount = 4;
4303 pSMB->Reserved = 0;
4304 pSMB->ParameterOffset = 0;
4305 pSMB->DataCount = 0;
4306 pSMB->DataOffset = 0;
4307 pSMB->SetupCount = 4; /* single byte does not need le conversion */
4308 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4309 pSMB->ParameterCount = pSMB->TotalParameterCount;
4310 if(notify_subdirs)
4311 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4312 pSMB->Reserved2 = 0;
4313 pSMB->CompletionFilter = cpu_to_le32(filter);
4314 pSMB->Fid = netfid; /* file handle always le */
4315 pSMB->ByteCount = 0;
4316
4317 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4318 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4319 if (rc) {
4320 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07004321 } else {
4322 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07004323 /* BB change to kmem cache alloc */
Steve Frenchff5dbd92005-08-24 17:10:36 -07004324 dnotify_req = (struct dir_notify_req *) kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07004325 sizeof(struct dir_notify_req),
4326 GFP_KERNEL);
4327 if(dnotify_req) {
4328 dnotify_req->Pid = pSMB->hdr.Pid;
4329 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4330 dnotify_req->Mid = pSMB->hdr.Mid;
4331 dnotify_req->Tid = pSMB->hdr.Tid;
4332 dnotify_req->Uid = pSMB->hdr.Uid;
4333 dnotify_req->netfid = netfid;
4334 dnotify_req->pfile = pfile;
4335 dnotify_req->filter = filter;
4336 dnotify_req->multishot = multishot;
4337 spin_lock(&GlobalMid_Lock);
4338 list_add_tail(&dnotify_req->lhead,
4339 &GlobalDnotifyReqList);
4340 spin_unlock(&GlobalMid_Lock);
4341 } else
4342 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 }
4344 cifs_buf_release(pSMB);
4345 return rc;
4346}
4347#ifdef CONFIG_CIFS_XATTR
4348ssize_t
4349CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4350 const unsigned char *searchName,
4351 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004352 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353{
4354 /* BB assumes one setup word */
4355 TRANSACTION2_QPI_REQ *pSMB = NULL;
4356 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4357 int rc = 0;
4358 int bytes_returned;
4359 int name_len;
4360 struct fea * temp_fea;
4361 char * temp_ptr;
4362 __u16 params, byte_count;
4363
4364 cFYI(1, ("In Query All EAs path %s", searchName));
4365QAllEAsRetry:
4366 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4367 (void **) &pSMBr);
4368 if (rc)
4369 return rc;
4370
4371 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4372 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004373 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004374 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375 name_len++; /* trailing null */
4376 name_len *= 2;
4377 } else { /* BB improve the check for buffer overruns BB */
4378 name_len = strnlen(searchName, PATH_MAX);
4379 name_len++; /* trailing null */
4380 strncpy(pSMB->FileName, searchName, name_len);
4381 }
4382
4383 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4384 pSMB->TotalDataCount = 0;
4385 pSMB->MaxParameterCount = cpu_to_le16(2);
4386 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4387 pSMB->MaxSetupCount = 0;
4388 pSMB->Reserved = 0;
4389 pSMB->Flags = 0;
4390 pSMB->Timeout = 0;
4391 pSMB->Reserved2 = 0;
4392 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4393 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4394 pSMB->DataCount = 0;
4395 pSMB->DataOffset = 0;
4396 pSMB->SetupCount = 1;
4397 pSMB->Reserved3 = 0;
4398 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4399 byte_count = params + 1 /* pad */ ;
4400 pSMB->TotalParameterCount = cpu_to_le16(params);
4401 pSMB->ParameterCount = pSMB->TotalParameterCount;
4402 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4403 pSMB->Reserved4 = 0;
4404 pSMB->hdr.smb_buf_length += byte_count;
4405 pSMB->ByteCount = cpu_to_le16(byte_count);
4406
4407 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4408 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4409 if (rc) {
4410 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4411 } else { /* decode response */
4412 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4413
4414 /* BB also check enough total bytes returned */
4415 /* BB we need to improve the validity checking
4416 of these trans2 responses */
4417 if (rc || (pSMBr->ByteCount < 4))
4418 rc = -EIO; /* bad smb */
4419 /* else if (pFindData){
4420 memcpy((char *) pFindData,
4421 (char *) &pSMBr->hdr.Protocol +
4422 data_offset, kl);
4423 }*/ else {
4424 /* check that length of list is not more than bcc */
4425 /* check that each entry does not go beyond length
4426 of list */
4427 /* check that each element of each entry does not
4428 go beyond end of list */
4429 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4430 struct fealist * ea_response_data;
4431 rc = 0;
4432 /* validate_trans2_offsets() */
4433 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4434 ea_response_data = (struct fealist *)
4435 (((char *) &pSMBr->hdr.Protocol) +
4436 data_offset);
4437 name_len = le32_to_cpu(ea_response_data->list_len);
4438 cFYI(1,("ea length %d", name_len));
4439 if(name_len <= 8) {
4440 /* returned EA size zeroed at top of function */
4441 cFYI(1,("empty EA list returned from server"));
4442 } else {
4443 /* account for ea list len */
4444 name_len -= 4;
4445 temp_fea = ea_response_data->list;
4446 temp_ptr = (char *)temp_fea;
4447 while(name_len > 0) {
4448 __u16 value_len;
4449 name_len -= 4;
4450 temp_ptr += 4;
4451 rc += temp_fea->name_len;
4452 /* account for prefix user. and trailing null */
4453 rc = rc + 5 + 1;
4454 if(rc<(int)buf_size) {
4455 memcpy(EAData,"user.",5);
4456 EAData+=5;
4457 memcpy(EAData,temp_ptr,temp_fea->name_len);
4458 EAData+=temp_fea->name_len;
4459 /* null terminate name */
4460 *EAData = 0;
4461 EAData = EAData + 1;
4462 } else if(buf_size == 0) {
4463 /* skip copy - calc size only */
4464 } else {
4465 /* stop before overrun buffer */
4466 rc = -ERANGE;
4467 break;
4468 }
4469 name_len -= temp_fea->name_len;
4470 temp_ptr += temp_fea->name_len;
4471 /* account for trailing null */
4472 name_len--;
4473 temp_ptr++;
4474 value_len = le16_to_cpu(temp_fea->value_len);
4475 name_len -= value_len;
4476 temp_ptr += value_len;
4477 /* BB check that temp_ptr is still within smb BB*/
4478 /* no trailing null to account for in value len */
4479 /* go on to next EA */
4480 temp_fea = (struct fea *)temp_ptr;
4481 }
4482 }
4483 }
4484 }
4485 if (pSMB)
4486 cifs_buf_release(pSMB);
4487 if (rc == -EAGAIN)
4488 goto QAllEAsRetry;
4489
4490 return (ssize_t)rc;
4491}
4492
4493ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4494 const unsigned char * searchName,const unsigned char * ea_name,
4495 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07004496 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497{
4498 TRANSACTION2_QPI_REQ *pSMB = NULL;
4499 TRANSACTION2_QPI_RSP *pSMBr = NULL;
4500 int rc = 0;
4501 int bytes_returned;
4502 int name_len;
4503 struct fea * temp_fea;
4504 char * temp_ptr;
4505 __u16 params, byte_count;
4506
4507 cFYI(1, ("In Query EA path %s", searchName));
4508QEARetry:
4509 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4510 (void **) &pSMBr);
4511 if (rc)
4512 return rc;
4513
4514 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4515 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004516 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07004517 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004518 name_len++; /* trailing null */
4519 name_len *= 2;
4520 } else { /* BB improve the check for buffer overruns BB */
4521 name_len = strnlen(searchName, PATH_MAX);
4522 name_len++; /* trailing null */
4523 strncpy(pSMB->FileName, searchName, name_len);
4524 }
4525
4526 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4527 pSMB->TotalDataCount = 0;
4528 pSMB->MaxParameterCount = cpu_to_le16(2);
4529 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4530 pSMB->MaxSetupCount = 0;
4531 pSMB->Reserved = 0;
4532 pSMB->Flags = 0;
4533 pSMB->Timeout = 0;
4534 pSMB->Reserved2 = 0;
4535 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4536 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4537 pSMB->DataCount = 0;
4538 pSMB->DataOffset = 0;
4539 pSMB->SetupCount = 1;
4540 pSMB->Reserved3 = 0;
4541 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4542 byte_count = params + 1 /* pad */ ;
4543 pSMB->TotalParameterCount = cpu_to_le16(params);
4544 pSMB->ParameterCount = pSMB->TotalParameterCount;
4545 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4546 pSMB->Reserved4 = 0;
4547 pSMB->hdr.smb_buf_length += byte_count;
4548 pSMB->ByteCount = cpu_to_le16(byte_count);
4549
4550 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4551 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4552 if (rc) {
4553 cFYI(1, ("Send error in Query EA = %d", rc));
4554 } else { /* decode response */
4555 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4556
4557 /* BB also check enough total bytes returned */
4558 /* BB we need to improve the validity checking
4559 of these trans2 responses */
4560 if (rc || (pSMBr->ByteCount < 4))
4561 rc = -EIO; /* bad smb */
4562 /* else if (pFindData){
4563 memcpy((char *) pFindData,
4564 (char *) &pSMBr->hdr.Protocol +
4565 data_offset, kl);
4566 }*/ else {
4567 /* check that length of list is not more than bcc */
4568 /* check that each entry does not go beyond length
4569 of list */
4570 /* check that each element of each entry does not
4571 go beyond end of list */
4572 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4573 struct fealist * ea_response_data;
4574 rc = -ENODATA;
4575 /* validate_trans2_offsets() */
4576 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4577 ea_response_data = (struct fealist *)
4578 (((char *) &pSMBr->hdr.Protocol) +
4579 data_offset);
4580 name_len = le32_to_cpu(ea_response_data->list_len);
4581 cFYI(1,("ea length %d", name_len));
4582 if(name_len <= 8) {
4583 /* returned EA size zeroed at top of function */
4584 cFYI(1,("empty EA list returned from server"));
4585 } else {
4586 /* account for ea list len */
4587 name_len -= 4;
4588 temp_fea = ea_response_data->list;
4589 temp_ptr = (char *)temp_fea;
4590 /* loop through checking if we have a matching
4591 name and then return the associated value */
4592 while(name_len > 0) {
4593 __u16 value_len;
4594 name_len -= 4;
4595 temp_ptr += 4;
4596 value_len = le16_to_cpu(temp_fea->value_len);
4597 /* BB validate that value_len falls within SMB,
4598 even though maximum for name_len is 255 */
4599 if(memcmp(temp_fea->name,ea_name,
4600 temp_fea->name_len) == 0) {
4601 /* found a match */
4602 rc = value_len;
4603 /* account for prefix user. and trailing null */
4604 if(rc<=(int)buf_size) {
4605 memcpy(ea_value,
4606 temp_fea->name+temp_fea->name_len+1,
4607 rc);
4608 /* ea values, unlike ea names,
4609 are not null terminated */
4610 } else if(buf_size == 0) {
4611 /* skip copy - calc size only */
4612 } else {
4613 /* stop before overrun buffer */
4614 rc = -ERANGE;
4615 }
4616 break;
4617 }
4618 name_len -= temp_fea->name_len;
4619 temp_ptr += temp_fea->name_len;
4620 /* account for trailing null */
4621 name_len--;
4622 temp_ptr++;
4623 name_len -= value_len;
4624 temp_ptr += value_len;
4625 /* no trailing null to account for in value len */
4626 /* go on to next EA */
4627 temp_fea = (struct fea *)temp_ptr;
4628 }
4629 }
4630 }
4631 }
4632 if (pSMB)
4633 cifs_buf_release(pSMB);
4634 if (rc == -EAGAIN)
4635 goto QEARetry;
4636
4637 return (ssize_t)rc;
4638}
4639
4640int
4641CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4642 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07004643 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4644 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645{
4646 struct smb_com_transaction2_spi_req *pSMB = NULL;
4647 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4648 struct fealist *parm_data;
4649 int name_len;
4650 int rc = 0;
4651 int bytes_returned = 0;
4652 __u16 params, param_offset, byte_count, offset, count;
4653
4654 cFYI(1, ("In SetEA"));
4655SetEARetry:
4656 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4657 (void **) &pSMBr);
4658 if (rc)
4659 return rc;
4660
4661 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4662 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004663 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004664 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 name_len++; /* trailing null */
4666 name_len *= 2;
4667 } else { /* BB improve the check for buffer overruns BB */
4668 name_len = strnlen(fileName, PATH_MAX);
4669 name_len++; /* trailing null */
4670 strncpy(pSMB->FileName, fileName, name_len);
4671 }
4672
4673 params = 6 + name_len;
4674
4675 /* done calculating parms using name_len of file name,
4676 now use name_len to calculate length of ea name
4677 we are going to create in the inode xattrs */
4678 if(ea_name == NULL)
4679 name_len = 0;
4680 else
4681 name_len = strnlen(ea_name,255);
4682
4683 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4684 pSMB->MaxParameterCount = cpu_to_le16(2);
4685 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4686 pSMB->MaxSetupCount = 0;
4687 pSMB->Reserved = 0;
4688 pSMB->Flags = 0;
4689 pSMB->Timeout = 0;
4690 pSMB->Reserved2 = 0;
4691 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4692 InformationLevel) - 4;
4693 offset = param_offset + params;
4694 pSMB->InformationLevel =
4695 cpu_to_le16(SMB_SET_FILE_EA);
4696
4697 parm_data =
4698 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4699 offset);
4700 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4701 pSMB->DataOffset = cpu_to_le16(offset);
4702 pSMB->SetupCount = 1;
4703 pSMB->Reserved3 = 0;
4704 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4705 byte_count = 3 /* pad */ + params + count;
4706 pSMB->DataCount = cpu_to_le16(count);
4707 parm_data->list_len = cpu_to_le32(count);
4708 parm_data->list[0].EA_flags = 0;
4709 /* we checked above that name len is less than 255 */
4710 parm_data->list[0].name_len = (__u8)name_len;;
4711 /* EA names are always ASCII */
4712 if(ea_name)
4713 strncpy(parm_data->list[0].name,ea_name,name_len);
4714 parm_data->list[0].name[name_len] = 0;
4715 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4716 /* caller ensures that ea_value_len is less than 64K but
4717 we need to ensure that it fits within the smb */
4718
4719 /*BB add length check that it would fit in negotiated SMB buffer size BB */
4720 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4721 if(ea_value_len)
4722 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4723
4724 pSMB->TotalDataCount = pSMB->DataCount;
4725 pSMB->ParameterCount = cpu_to_le16(params);
4726 pSMB->TotalParameterCount = pSMB->ParameterCount;
4727 pSMB->Reserved4 = 0;
4728 pSMB->hdr.smb_buf_length += byte_count;
4729 pSMB->ByteCount = cpu_to_le16(byte_count);
4730 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4731 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4732 if (rc) {
4733 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4734 }
4735
4736 cifs_buf_release(pSMB);
4737
4738 if (rc == -EAGAIN)
4739 goto SetEARetry;
4740
4741 return rc;
4742}
4743
4744#endif