blob: b4916eb6fd43adb76304db586e5502fee7e68810 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve French2dd29d32007-04-23 22:07:35 +00004 * Copyright (C) International Business Machines Corp., 2002,2007
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * 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 */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
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"
Steve Frencheeac8042006-01-13 21:34:58 -080040#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#ifdef CONFIG_CIFS_POSIX
43static struct {
44 int index;
45 char *name;
46} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000047#ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000049 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000050#endif /* weak password hashing for legacy clients */
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000052 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 {BAD_PROT, "\2"}
54};
55#else
56static struct {
57 int index;
58 char *name;
59} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000060#ifdef CONFIG_CIFS_WEAK_PW_HASH
61 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000062 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000063#endif /* weak password hashing for legacy clients */
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 {CIFS_PROT, "\2NT LM 0.12"},
65 {BAD_PROT, "\2"}
66};
67#endif
68
Steve French39798772006-05-31 22:40:51 +000069/* define the number of elements in the cifs dialect array */
70#ifdef CONFIG_CIFS_POSIX
71#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000072#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000073#else
74#define CIFS_NUM_PROT 2
75#endif /* CIFS_WEAK_PW_HASH */
76#else /* not posix */
77#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000078#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000079#else
80#define CIFS_NUM_PROT 1
81#endif /* CONFIG_CIFS_WEAK_PW_HASH */
82#endif /* CIFS_POSIX */
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85/* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
87static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
88{
89 struct cifsFileInfo *open_file = NULL;
90 struct list_head * tmp;
91 struct list_head * tmp1;
92
93/* list all files open on tree connection and mark them invalid */
94 write_lock(&GlobalSMBSeslock);
95 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
96 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
97 if(open_file) {
98 open_file->invalidHandle = TRUE;
99 }
100 }
101 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700102 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
103 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104}
105
106/* If the return code is zero, this function must fill in request_buf pointer */
107static int
108small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
109 void **request_buf /* returned */)
110{
111 int rc = 0;
112
113 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
114 check for tcp and smb session status done differently
115 for those three - in the calling routine */
116 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800117 if(tcon->tidStatus == CifsExiting) {
118 /* only tree disconnect, open, and write,
119 (and ulogoff which does not have tcon)
120 are allowed as we start force umount */
121 if((smb_command != SMB_COM_WRITE_ANDX) &&
122 (smb_command != SMB_COM_OPEN_ANDX) &&
123 (smb_command != SMB_COM_TREE_DISCONNECT)) {
124 cFYI(1,("can not send cmd %d while umounting",
125 smb_command));
126 return -ENODEV;
127 }
128 }
Steve French31ca3bc2005-04-28 22:41:11 -0700129 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
130 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 struct nls_table *nls_codepage;
132 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700133 reconnect, should be greater than cifs socket
134 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
136 wait_event_interruptible_timeout(tcon->ses->server->response_q,
137 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
138 if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
139 /* on "soft" mounts we wait once */
140 if((tcon->retry == FALSE) ||
141 (tcon->ses->status == CifsExiting)) {
142 cFYI(1,("gave up waiting on reconnect in smb_init"));
143 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700144 } /* else "hard" mount - keep retrying
145 until process is killed or server
146 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 } else /* TCP session is reestablished now */
148 break;
149
150 }
151
152 nls_codepage = load_nls_default();
153 /* need to prevent multiple threads trying to
154 simultaneously reconnect the same SMB session */
155 down(&tcon->ses->sesSem);
156 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700157 rc = cifs_setup_session(0, tcon->ses,
158 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
160 mark_open_files_invalid(tcon);
Steve French8af18972007-02-14 04:42:51 +0000161 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
162 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 up(&tcon->ses->sesSem);
Steve French8af18972007-02-14 04:42:51 +0000164 /* tell server which Unix caps we support */
165 if (tcon->ses->capabilities & CAP_UNIX)
166 reset_cifs_unix_caps(0 /* no xid */,
167 tcon,
168 NULL /* we do not know sb */,
169 NULL /* no vol info */);
Steve French3e844692005-10-03 13:37:24 -0700170 /* BB FIXME add code to check if wsize needs
171 update due to negotiated smb buffer size
172 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 if(rc == 0)
174 atomic_inc(&tconInfoReconnectCount);
175
176 cFYI(1, ("reconnect tcon rc = %d", rc));
177 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700178 it is safer (and faster) to reopen files
179 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
181 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700182 know whether we can continue or not without
183 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 switch(smb_command) {
185 case SMB_COM_READ_ANDX:
186 case SMB_COM_WRITE_ANDX:
187 case SMB_COM_CLOSE:
188 case SMB_COM_FIND_CLOSE2:
189 case SMB_COM_LOCKING_ANDX: {
190 unload_nls(nls_codepage);
191 return -EAGAIN;
192 }
193 }
194 } else {
195 up(&tcon->ses->sesSem);
196 }
197 unload_nls(nls_codepage);
198
199 } else {
200 return -EIO;
201 }
202 }
203 if(rc)
204 return rc;
205
206 *request_buf = cifs_small_buf_get();
207 if (*request_buf == NULL) {
208 /* BB should we add a retry in here if not a writepage? */
209 return -ENOMEM;
210 }
211
212 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
213
Steve Frencha4544342005-08-24 13:59:35 -0700214 if(tcon != NULL)
215 cifs_stats_inc(&tcon->num_smbs_sent);
216
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000218}
219
Steve French12b3b8f2006-02-09 21:12:47 +0000220int
Steve French5815449d2006-02-14 01:36:20 +0000221small_smb_init_no_tc(const int smb_command, const int wct,
222 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000223{
224 int rc;
225 struct smb_hdr * buffer;
226
Steve French5815449d2006-02-14 01:36:20 +0000227 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French12b3b8f2006-02-09 21:12:47 +0000228 if(rc)
229 return rc;
230
Steve French04fdabe2006-02-10 05:52:50 +0000231 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000232 buffer->Mid = GetNextMid(ses->server);
233 if (ses->capabilities & CAP_UNICODE)
234 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000235 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000236 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
237
238 /* uid, tid can stay at zero as set in header assemble */
239
240 /* BB add support for turning on the signing when
241 this function is used after 1st of session setup requests */
242
243 return rc;
244}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
246/* If the return code is zero, this function must fill in request_buf pointer */
247static int
248smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
249 void **request_buf /* returned */ ,
250 void **response_buf /* returned */ )
251{
252 int rc = 0;
253
254 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
255 check for tcp and smb session status done differently
256 for those three - in the calling routine */
257 if(tcon) {
Steve French6ab16d22005-11-29 20:55:11 -0800258 if(tcon->tidStatus == CifsExiting) {
259 /* only tree disconnect, open, and write,
260 (and ulogoff which does not have tcon)
261 are allowed as we start force umount */
262 if((smb_command != SMB_COM_WRITE_ANDX) &&
263 (smb_command != SMB_COM_OPEN_ANDX) &&
264 (smb_command != SMB_COM_TREE_DISCONNECT)) {
265 cFYI(1,("can not send cmd %d while umounting",
266 smb_command));
267 return -ENODEV;
268 }
269 }
270
Steve French31ca3bc2005-04-28 22:41:11 -0700271 if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
272 (tcon->ses->server)){
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700274 /* Give Demultiplex thread up to 10 seconds to
275 reconnect, should be greater than cifs socket
276 timeout which is 7 seconds */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
278 wait_event_interruptible_timeout(tcon->ses->server->response_q,
279 (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
Steve French09d1db52005-04-28 22:41:08 -0700280 if(tcon->ses->server->tcpStatus ==
281 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 /* on "soft" mounts we wait once */
283 if((tcon->retry == FALSE) ||
284 (tcon->ses->status == CifsExiting)) {
285 cFYI(1,("gave up waiting on reconnect in smb_init"));
286 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700287 } /* else "hard" mount - keep retrying
288 until process is killed or server
289 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 } else /* TCP session is reestablished now */
291 break;
292
293 }
294
295 nls_codepage = load_nls_default();
296 /* need to prevent multiple threads trying to
297 simultaneously reconnect the same SMB session */
298 down(&tcon->ses->sesSem);
299 if(tcon->ses->status == CifsNeedReconnect)
Steve French09d1db52005-04-28 22:41:08 -0700300 rc = cifs_setup_session(0, tcon->ses,
301 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
303 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700304 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
305 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 up(&tcon->ses->sesSem);
Steve French8af18972007-02-14 04:42:51 +0000307 /* tell server which Unix caps we support */
308 if (tcon->ses->capabilities & CAP_UNIX)
309 reset_cifs_unix_caps(0 /* no xid */,
310 tcon,
311 NULL /* do not know sb */,
312 NULL /* no vol info */);
Steve French3e844692005-10-03 13:37:24 -0700313 /* BB FIXME add code to check if wsize needs
314 update due to negotiated smb buffer size
315 shrinking */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 if(rc == 0)
317 atomic_inc(&tconInfoReconnectCount);
318
319 cFYI(1, ("reconnect tcon rc = %d", rc));
320 /* Removed call to reopen open files here -
Steve French09d1db52005-04-28 22:41:08 -0700321 it is safer (and faster) to reopen files
322 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700325 know whether we can continue or not without
326 returning to caller to reset file handle */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327 switch(smb_command) {
328 case SMB_COM_READ_ANDX:
329 case SMB_COM_WRITE_ANDX:
330 case SMB_COM_CLOSE:
331 case SMB_COM_FIND_CLOSE2:
332 case SMB_COM_LOCKING_ANDX: {
333 unload_nls(nls_codepage);
334 return -EAGAIN;
335 }
336 }
337 } else {
338 up(&tcon->ses->sesSem);
339 }
340 unload_nls(nls_codepage);
341
342 } else {
343 return -EIO;
344 }
345 }
346 if(rc)
347 return rc;
348
349 *request_buf = cifs_buf_get();
350 if (*request_buf == NULL) {
351 /* BB should we add a retry in here if not a writepage? */
352 return -ENOMEM;
353 }
354 /* Although the original thought was we needed the response buf for */
355 /* potential retries of smb operations it turns out we can determine */
356 /* from the mid flags when the request buffer can be resent without */
357 /* having to use a second distinct buffer for the response */
Steve French39798772006-05-31 22:40:51 +0000358 if(response_buf)
359 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
361 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
362 wct /*wct */ );
363
Steve Frencha4544342005-08-24 13:59:35 -0700364 if(tcon != NULL)
365 cifs_stats_inc(&tcon->num_smbs_sent);
366
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 return rc;
368}
369
370static int validate_t2(struct smb_t2_rsp * pSMB)
371{
372 int rc = -EINVAL;
373 int total_size;
374 char * pBCC;
375
376 /* check for plausible wct, bcc and t2 data and parm sizes */
377 /* check for parm and data offset going beyond end of smb */
378 if(pSMB->hdr.WordCount >= 10) {
379 if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
380 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
381 /* check that bcc is at least as big as parms + data */
382 /* check that bcc is less than negotiated smb buffer */
383 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
384 if(total_size < 512) {
385 total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
386 /* BCC le converted in SendReceive */
Steve French09d1db52005-04-28 22:41:08 -0700387 pBCC = (pSMB->hdr.WordCount * 2) +
388 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 (char *)pSMB;
390 if((total_size <= (*(u16 *)pBCC)) &&
391 (total_size <
392 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
393 return 0;
394 }
395
396 }
397 }
398 }
399 cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
400 sizeof(struct smb_t2_rsp) + 16);
401 return rc;
402}
403int
404CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
405{
406 NEGOTIATE_REQ *pSMB;
407 NEGOTIATE_RSP *pSMBr;
408 int rc = 0;
409 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000410 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 struct TCP_Server_Info * server;
412 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000413 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100414 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
416 if(ses->server)
417 server = ses->server;
418 else {
419 rc = -EIO;
420 return rc;
421 }
422 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
423 (void **) &pSMB, (void **) &pSMBr);
424 if (rc)
425 return rc;
Steve French750d1152006-06-27 06:28:30 +0000426
427 /* if any of auth flags (ie not sign or seal) are overriden use them */
428 if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000429 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000430 else /* if override flags set only sign/seal OR them with global auth */
431 secFlags = extended_security | ses->overrideSecFlg;
432
Steve French762e5ab2007-06-28 18:41:42 +0000433 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000434
Steve French1982c342005-08-17 12:38:22 -0700435 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000436 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
437 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000438 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve French39798772006-05-31 22:40:51 +0000439
440 count = 0;
441 for(i=0;i<CIFS_NUM_PROT;i++) {
442 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
443 count += strlen(protocols[i].name) + 1;
444 /* null at end of source and target buffers anyway */
445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 pSMB->hdr.smb_buf_length += count;
447 pSMB->ByteCount = cpu_to_le16(count);
448
449 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
450 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French254e55e2006-06-04 05:53:15 +0000451 if (rc != 0)
452 goto neg_err_exit;
453
Al Viro733f99a2006-10-14 16:48:26 +0100454 dialect = le16_to_cpu(pSMBr->DialectIndex);
455 cFYI(1,("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000456 /* Check wct = 1 error case */
Al Viro733f99a2006-10-14 16:48:26 +0100457 if((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000458 /* core returns wct = 1, but we do not ask for core - otherwise
459 small wct just comes when dialect index is -1 indicating we
460 could not negotiate a common dialect */
461 rc = -EOPNOTSUPP;
462 goto neg_err_exit;
463#ifdef CONFIG_CIFS_WEAK_PW_HASH
464 } else if((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100465 && ((dialect == LANMAN_PROT)
466 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000467 __s16 tmp;
Steve French254e55e2006-06-04 05:53:15 +0000468 struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
469
Steve French750d1152006-06-27 06:28:30 +0000470 if((secFlags & CIFSSEC_MAY_LANMAN) ||
471 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000472 server->secType = LANMAN;
473 else {
474 cERROR(1, ("mount failed weak security disabled"
475 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000476 rc = -EOPNOTSUPP;
477 goto neg_err_exit;
Steve French254e55e2006-06-04 05:53:15 +0000478 }
479 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
480 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
481 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000482 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000483 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
484 /* even though we do not use raw we might as well set this
485 accurately, in case we ever find a need for it */
486 if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
487 server->maxRw = 0xFF00;
488 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
489 } else {
490 server->maxRw = 0;/* we do not need to use raw anyway */
491 server->capabilities = CAP_MPX_MODE;
492 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000493 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000494 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000495 /* OS/2 often does not set timezone therefore
496 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000497 * Could deviate slightly from the right zone.
498 * Smallest defined timezone difference is 15 minutes
499 * (i.e. Nepal). Rounding up/down is done to match
500 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000501 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000502 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000503 struct timespec ts, utc;
504 utc = CURRENT_TIME;
505 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
506 le16_to_cpu(rsp->SrvTime.Time));
507 cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
508 (int)ts.tv_sec, (int)utc.tv_sec,
509 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000510 val = (int)(utc.tv_sec - ts.tv_sec);
511 seconds = val < 0 ? -val : val;
Steve French947a5062006-10-02 05:55:25 +0000512 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000513 remain = seconds % MIN_TZ_ADJ;
514 if(remain >= (MIN_TZ_ADJ / 2))
515 result += MIN_TZ_ADJ;
516 if(val < 0)
517 result = - result;
518 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000519 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000520 server->timeAdj = (int)tmp;
521 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000522 }
Steve French175ec9e2006-09-30 01:07:38 +0000523 cFYI(1,("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000524
Steve French39798772006-05-31 22:40:51 +0000525
Steve French254e55e2006-06-04 05:53:15 +0000526 /* BB get server time for time conversions and add
527 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000528
Steve French25ee4a92006-09-30 00:54:23 +0000529 if (rsp->EncryptionKeyLength ==
530 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000531 memcpy(server->cryptKey, rsp->EncryptionKey,
532 CIFS_CRYPTO_KEY_SIZE);
533 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
534 rc = -EIO; /* need cryptkey unless plain text */
535 goto neg_err_exit;
536 }
Steve French39798772006-05-31 22:40:51 +0000537
Steve French254e55e2006-06-04 05:53:15 +0000538 cFYI(1,("LANMAN negotiated"));
539 /* we will not end up setting signing flags - as no signing
540 was in LANMAN and server did not return the flags on */
541 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000542#else /* weak security disabled */
Steve French254e55e2006-06-04 05:53:15 +0000543 } else if(pSMBr->hdr.WordCount == 13) {
544 cERROR(1,("mount failed, cifs module not built "
545 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000546 rc = -EOPNOTSUPP;
547#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000548 goto neg_err_exit;
549 } else if(pSMBr->hdr.WordCount != 17) {
550 /* unknown wct */
551 rc = -EOPNOTSUPP;
552 goto neg_err_exit;
553 }
554 /* else wct == 17 NTLM */
555 server->secMode = pSMBr->SecurityMode;
556 if((server->secMode & SECMODE_USER) == 0)
557 cFYI(1,("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000558
Steve French254e55e2006-06-04 05:53:15 +0000559 if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000560#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000561 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000562#endif /* CIFS_WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000563 cERROR(1,("Server requests plain text password"
564 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000565
Steve Frenchf40c5622006-06-28 00:13:38 +0000566 if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000567 server->secType = NTLMv2;
Steve Frenchf40c5622006-06-28 00:13:38 +0000568 else if(secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000569 server->secType = NTLM;
Steve Frenchf40c5622006-06-28 00:13:38 +0000570 else if(secFlags & CIFSSEC_MAY_NTLMV2)
571 server->secType = NTLMv2;
572 /* else krb5 ... any others ... */
Steve French7c7b25b2006-06-01 19:20:10 +0000573
Steve French254e55e2006-06-04 05:53:15 +0000574 /* one byte, so no need to convert this or EncryptionKeyLen from
575 little endian */
576 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
577 /* probably no need to store and check maxvcs */
578 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000580 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
581 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
582 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
583 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000584 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
585 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000586 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
587 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
588 CIFS_CRYPTO_KEY_SIZE);
589 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
590 && (pSMBr->EncryptionKeyLength == 0)) {
591 /* decode security blob */
592 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
593 rc = -EIO; /* no crypt key only if plain text pwd */
594 goto neg_err_exit;
595 }
596
597 /* BB might be helpful to save off the domain of server here */
598
599 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
600 (server->capabilities & CAP_EXTENDED_SECURITY)) {
601 count = pSMBr->ByteCount;
602 if (count < 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 rc = -EIO;
Steve French254e55e2006-06-04 05:53:15 +0000604 else if (count == 16) {
605 server->secType = RawNTLMSSP;
606 if (server->socketUseCount.counter > 1) {
607 if (memcmp(server->server_GUID,
608 pSMBr->u.extended_response.
609 GUID, 16) != 0) {
610 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 memcpy(server->server_GUID,
Steve French254e55e2006-06-04 05:53:15 +0000612 pSMBr->u.extended_response.GUID,
613 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 }
Steve French254e55e2006-06-04 05:53:15 +0000615 } else
616 memcpy(server->server_GUID,
617 pSMBr->u.extended_response.GUID, 16);
618 } else {
619 rc = decode_negTokenInit(pSMBr->u.extended_response.
620 SecurityBlob,
621 count - 16,
622 &server->secType);
623 if(rc == 1) {
624 /* BB Need to fill struct for sessetup here */
625 rc = -EOPNOTSUPP;
626 } else {
627 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 }
Steve French254e55e2006-06-04 05:53:15 +0000630 } else
631 server->capabilities &= ~CAP_EXTENDED_SECURITY;
632
Steve French6344a422006-06-12 04:18:35 +0000633#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000634signing_check:
Steve French6344a422006-06-12 04:18:35 +0000635#endif
Steve French762e5ab2007-06-28 18:41:42 +0000636 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
637 /* MUST_SIGN already includes the MAY_SIGN FLAG
638 so if this is zero it means that signing is disabled */
639 cFYI(1, ("Signing disabled"));
Steve French254e55e2006-06-04 05:53:15 +0000640 if(server->secMode & SECMODE_SIGN_REQUIRED)
Steve French762e5ab2007-06-28 18:41:42 +0000641 cERROR(1, ("Server requires "
642 "/proc/fs/cifs/PacketSigningEnabled "
643 "to be on"));
Steve French254e55e2006-06-04 05:53:15 +0000644 server->secMode &=
645 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000646 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
647 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000648 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000649 if ((server->secMode &
650 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
651 cERROR(1,
652 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000653 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000654 } else
655 server->secMode |= SECMODE_SIGN_REQUIRED;
656 } else {
657 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French254e55e2006-06-04 05:53:15 +0000658 if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
659 server->secMode &=
660 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 }
Steve French762e5ab2007-06-28 18:41:42 +0000662
Steve French39798772006-05-31 22:40:51 +0000663neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700664 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000665
666 cFYI(1,("negprot rc %d",rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 return rc;
668}
669
670int
671CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
672{
673 struct smb_hdr *smb_buffer;
674 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
675 int rc = 0;
676 int length;
677
678 cFYI(1, ("In tree disconnect"));
679 /*
680 * If last user of the connection and
681 * connection alive - disconnect it
682 * If this is the last connection on the server session disconnect it
683 * (and inside session disconnect we should check if tcp socket needs
684 * to be freed and kernel thread woken up).
685 */
686 if (tcon)
687 down(&tcon->tconSem);
688 else
689 return -EIO;
690
691 atomic_dec(&tcon->useCount);
692 if (atomic_read(&tcon->useCount) > 0) {
693 up(&tcon->tconSem);
694 return -EBUSY;
695 }
696
697 /* No need to return error on this operation if tid invalidated and
698 closed on server already e.g. due to tcp session crashing */
699 if(tcon->tidStatus == CifsNeedReconnect) {
700 up(&tcon->tconSem);
701 return 0;
702 }
703
704 if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
705 up(&tcon->tconSem);
706 return -EIO;
707 }
Steve French09d1db52005-04-28 22:41:08 -0700708 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
709 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 if (rc) {
711 up(&tcon->tconSem);
712 return rc;
713 } else {
714 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700715 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
717 &length, 0);
718 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700719 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
721 if (smb_buffer)
722 cifs_small_buf_release(smb_buffer);
723 up(&tcon->tconSem);
724
725 /* No need to return error on this operation if tid invalidated and
726 closed on server already e.g. due to tcp session crashing */
727 if (rc == -EAGAIN)
728 rc = 0;
729
730 return rc;
731}
732
733int
734CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
735{
736 struct smb_hdr *smb_buffer_response;
737 LOGOFF_ANDX_REQ *pSMB;
738 int rc = 0;
739 int length;
740
741 cFYI(1, ("In SMBLogoff for session disconnect"));
742 if (ses)
743 down(&ses->sesSem);
744 else
745 return -EIO;
746
747 atomic_dec(&ses->inUse);
748 if (atomic_read(&ses->inUse) > 0) {
749 up(&ses->sesSem);
750 return -EBUSY;
751 }
752 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
753 if (rc) {
754 up(&ses->sesSem);
755 return rc;
756 }
757
758 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
759
760 if(ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700761 pSMB->hdr.Mid = GetNextMid(ses->server);
762
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 if(ses->server->secMode &
764 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
765 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
766 }
767
768 pSMB->hdr.Uid = ses->Suid;
769
770 pSMB->AndXCommand = 0xFF;
771 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
772 smb_buffer_response, &length, 0);
773 if (ses->server) {
774 atomic_dec(&ses->server->socketUseCount);
775 if (atomic_read(&ses->server->socketUseCount) == 0) {
776 spin_lock(&GlobalMid_Lock);
777 ses->server->tcpStatus = CifsExiting;
778 spin_unlock(&GlobalMid_Lock);
779 rc = -ESHUTDOWN;
780 }
781 }
Steve Frencha59c6582005-08-17 12:12:19 -0700782 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700783 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784
785 /* if session dead then we do not need to do ulogoff,
786 since server closed smb session, no sense reporting
787 error */
788 if (rc == -EAGAIN)
789 rc = 0;
790 return rc;
791}
792
793int
Steve French737b7582005-04-28 22:41:06 -0700794CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
795 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796{
797 DELETE_FILE_REQ *pSMB = NULL;
798 DELETE_FILE_RSP *pSMBr = NULL;
799 int rc = 0;
800 int bytes_returned;
801 int name_len;
802
803DelFileRetry:
804 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
805 (void **) &pSMBr);
806 if (rc)
807 return rc;
808
809 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
810 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -0500811 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700812 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 name_len++; /* trailing null */
814 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700815 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 name_len = strnlen(fileName, PATH_MAX);
817 name_len++; /* trailing null */
818 strncpy(pSMB->fileName, fileName, name_len);
819 }
820 pSMB->SearchAttributes =
821 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
822 pSMB->BufferFormat = 0x04;
823 pSMB->hdr.smb_buf_length += name_len + 1;
824 pSMB->ByteCount = cpu_to_le16(name_len + 1);
825 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
826 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700827 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 if (rc) {
829 cFYI(1, ("Error in RMFile = %d", rc));
830 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831
832 cifs_buf_release(pSMB);
833 if (rc == -EAGAIN)
834 goto DelFileRetry;
835
836 return rc;
837}
838
839int
Steve French737b7582005-04-28 22:41:06 -0700840CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
841 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842{
843 DELETE_DIRECTORY_REQ *pSMB = NULL;
844 DELETE_DIRECTORY_RSP *pSMBr = NULL;
845 int rc = 0;
846 int bytes_returned;
847 int name_len;
848
849 cFYI(1, ("In CIFSSMBRmDir"));
850RmDirRetry:
851 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
852 (void **) &pSMBr);
853 if (rc)
854 return rc;
855
856 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700857 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
858 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 name_len++; /* trailing null */
860 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700861 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 name_len = strnlen(dirName, PATH_MAX);
863 name_len++; /* trailing null */
864 strncpy(pSMB->DirName, dirName, name_len);
865 }
866
867 pSMB->BufferFormat = 0x04;
868 pSMB->hdr.smb_buf_length += name_len + 1;
869 pSMB->ByteCount = cpu_to_le16(name_len + 1);
870 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
871 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700872 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 if (rc) {
874 cFYI(1, ("Error in RMDir = %d", rc));
875 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876
877 cifs_buf_release(pSMB);
878 if (rc == -EAGAIN)
879 goto RmDirRetry;
880 return rc;
881}
882
883int
884CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700885 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886{
887 int rc = 0;
888 CREATE_DIRECTORY_REQ *pSMB = NULL;
889 CREATE_DIRECTORY_RSP *pSMBr = NULL;
890 int bytes_returned;
891 int name_len;
892
893 cFYI(1, ("In CIFSSMBMkDir"));
894MkDirRetry:
895 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
896 (void **) &pSMBr);
897 if (rc)
898 return rc;
899
900 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -0500901 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700902 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903 name_len++; /* trailing null */
904 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700905 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 name_len = strnlen(name, PATH_MAX);
907 name_len++; /* trailing null */
908 strncpy(pSMB->DirName, name, name_len);
909 }
910
911 pSMB->BufferFormat = 0x04;
912 pSMB->hdr.smb_buf_length += name_len + 1;
913 pSMB->ByteCount = cpu_to_le16(name_len + 1);
914 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
915 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700916 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 if (rc) {
918 cFYI(1, ("Error in Mkdir = %d", rc));
919 }
Steve Frencha5a2b482005-08-20 21:42:53 -0700920
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 cifs_buf_release(pSMB);
922 if (rc == -EAGAIN)
923 goto MkDirRetry;
924 return rc;
925}
926
Steve French2dd29d32007-04-23 22:07:35 +0000927int
928CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
929 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
930 __u32 *pOplock, const char *name,
931 const struct nls_table *nls_codepage, int remap)
932{
933 TRANSACTION2_SPI_REQ *pSMB = NULL;
934 TRANSACTION2_SPI_RSP *pSMBr = NULL;
935 int name_len;
936 int rc = 0;
937 int bytes_returned = 0;
938 char *data_offset;
939 __u16 params, param_offset, offset, byte_count, count;
940 OPEN_PSX_REQ * pdata;
941 OPEN_PSX_RSP * psx_rsp;
942
943 cFYI(1, ("In POSIX Create"));
944PsxCreat:
945 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
946 (void **) &pSMBr);
947 if (rc)
948 return rc;
949
950 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
951 name_len =
952 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
953 PATH_MAX, nls_codepage, remap);
954 name_len++; /* trailing null */
955 name_len *= 2;
956 } else { /* BB improve the check for buffer overruns BB */
957 name_len = strnlen(name, PATH_MAX);
958 name_len++; /* trailing null */
959 strncpy(pSMB->FileName, name, name_len);
960 }
961
962 params = 6 + name_len;
963 count = sizeof(OPEN_PSX_REQ);
964 pSMB->MaxParameterCount = cpu_to_le16(2);
965 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
966 pSMB->MaxSetupCount = 0;
967 pSMB->Reserved = 0;
968 pSMB->Flags = 0;
969 pSMB->Timeout = 0;
970 pSMB->Reserved2 = 0;
971 param_offset = offsetof(struct smb_com_transaction2_spi_req,
972 InformationLevel) - 4;
973 offset = param_offset + params;
974 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
975 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
976 pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
977 pdata->Permissions = cpu_to_le64(mode);
978 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
979 pdata->OpenFlags = cpu_to_le32(*pOplock);
980 pSMB->ParameterOffset = cpu_to_le16(param_offset);
981 pSMB->DataOffset = cpu_to_le16(offset);
982 pSMB->SetupCount = 1;
983 pSMB->Reserved3 = 0;
984 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
985 byte_count = 3 /* pad */ + params + count;
986
987 pSMB->DataCount = cpu_to_le16(count);
988 pSMB->ParameterCount = cpu_to_le16(params);
989 pSMB->TotalDataCount = pSMB->DataCount;
990 pSMB->TotalParameterCount = pSMB->ParameterCount;
991 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
992 pSMB->Reserved4 = 0;
993 pSMB->hdr.smb_buf_length += byte_count;
994 pSMB->ByteCount = cpu_to_le16(byte_count);
995 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
996 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
997 if (rc) {
998 cFYI(1, ("Posix create returned %d", rc));
999 goto psx_create_err;
1000 }
1001
1002 cFYI(1,("copying inode info"));
1003 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1004
1005 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1006 rc = -EIO; /* bad smb */
1007 goto psx_create_err;
1008 }
1009
1010 /* copy return information to pRetData */
1011 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
1012 + le16_to_cpu(pSMBr->t2.DataOffset));
1013
1014 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
1015 if(netfid)
1016 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1017 /* Let caller know file was created so we can set the mode. */
1018 /* Do we care about the CreateAction in any other cases? */
1019 if(cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
1020 *pOplock |= CIFS_CREATE_ACTION;
1021 /* check to make sure response data is there */
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001022 if(psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) {
1023 pRetData->Type = -1; /* unknown */
1024#ifdef CONFIG_CIFS_DEBUG2
1025 cFYI(1,("unknown type"));
1026#endif
1027 } else {
Steve French2dd29d32007-04-23 22:07:35 +00001028 if(pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
1029 + sizeof(FILE_UNIX_BASIC_INFO)) {
1030 cERROR(1,("Open response data too small"));
1031 pRetData->Type = -1;
1032 goto psx_create_err;
1033 }
1034 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001035 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French2dd29d32007-04-23 22:07:35 +00001036 sizeof (FILE_UNIX_BASIC_INFO));
1037 }
1038
1039
1040psx_create_err:
1041 cifs_buf_release(pSMB);
1042
1043 cifs_stats_inc(&tcon->num_mkdirs);
1044
1045 if (rc == -EAGAIN)
1046 goto PsxCreat;
1047
1048 return rc;
1049}
1050
Steve Frencha9d02ad2005-08-24 23:06:05 -07001051static __u16 convert_disposition(int disposition)
1052{
1053 __u16 ofun = 0;
1054
1055 switch (disposition) {
1056 case FILE_SUPERSEDE:
1057 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1058 break;
1059 case FILE_OPEN:
1060 ofun = SMBOPEN_OAPPEND;
1061 break;
1062 case FILE_CREATE:
1063 ofun = SMBOPEN_OCREATE;
1064 break;
1065 case FILE_OPEN_IF:
1066 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1067 break;
1068 case FILE_OVERWRITE:
1069 ofun = SMBOPEN_OTRUNC;
1070 break;
1071 case FILE_OVERWRITE_IF:
1072 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1073 break;
1074 default:
1075 cFYI(1,("unknown disposition %d",disposition));
1076 ofun = SMBOPEN_OAPPEND; /* regular open */
1077 }
1078 return ofun;
1079}
1080
1081int
1082SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1083 const char *fileName, const int openDisposition,
1084 const int access_flags, const int create_options, __u16 * netfid,
1085 int *pOplock, FILE_ALL_INFO * pfile_info,
1086 const struct nls_table *nls_codepage, int remap)
1087{
1088 int rc = -EACCES;
1089 OPENX_REQ *pSMB = NULL;
1090 OPENX_RSP *pSMBr = NULL;
1091 int bytes_returned;
1092 int name_len;
1093 __u16 count;
1094
1095OldOpenRetry:
1096 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1097 (void **) &pSMBr);
1098 if (rc)
1099 return rc;
1100
1101 pSMB->AndXCommand = 0xFF; /* none */
1102
1103 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1104 count = 1; /* account for one byte pad to word boundary */
1105 name_len =
1106 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1107 fileName, PATH_MAX, nls_codepage, remap);
1108 name_len++; /* trailing null */
1109 name_len *= 2;
1110 } else { /* BB improve check for buffer overruns BB */
1111 count = 0; /* no pad */
1112 name_len = strnlen(fileName, PATH_MAX);
1113 name_len++; /* trailing null */
1114 strncpy(pSMB->fileName, fileName, name_len);
1115 }
1116 if (*pOplock & REQ_OPLOCK)
1117 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
1118 else if (*pOplock & REQ_BATCHOPLOCK) {
1119 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
1120 }
1121 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1122 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1123 /* 0 = read
1124 1 = write
1125 2 = rw
1126 3 = execute
1127 */
1128 pSMB->Mode = cpu_to_le16(2);
1129 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1130 /* set file as system file if special file such
1131 as fifo and server expecting SFU style and
1132 no Unix extensions */
1133
1134 if(create_options & CREATE_OPTION_SPECIAL)
1135 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1136 else
Steve French3e87d802005-09-18 20:49:21 -07001137 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001138
1139 /* if ((omode & S_IWUGO) == 0)
1140 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1141 /* Above line causes problems due to vfs splitting create into two
1142 pieces - need to set mode after file created not while it is
1143 being created */
1144
1145 /* BB FIXME BB */
1146/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
1147 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001148
1149 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001150 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001151 count += name_len;
1152 pSMB->hdr.smb_buf_length += count;
1153
1154 pSMB->ByteCount = cpu_to_le16(count);
1155 /* long_op set to 1 to allow for oplock break timeouts */
1156 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1157 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
1158 cifs_stats_inc(&tcon->num_opens);
1159 if (rc) {
1160 cFYI(1, ("Error in Open = %d", rc));
1161 } else {
1162 /* BB verify if wct == 15 */
1163
1164/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1165
1166 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1167 /* Let caller know file was created so we can set the mode. */
1168 /* Do we care about the CreateAction in any other cases? */
1169 /* BB FIXME BB */
1170/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1171 *pOplock |= CIFS_CREATE_ACTION; */
1172 /* BB FIXME END */
1173
1174 if(pfile_info) {
1175 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1176 pfile_info->LastAccessTime = 0; /* BB fixme */
1177 pfile_info->LastWriteTime = 0; /* BB fixme */
1178 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001179 pfile_info->Attributes =
1180 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001181 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001182 pfile_info->AllocationSize =
1183 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1184 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001185 pfile_info->NumberOfLinks = cpu_to_le32(1);
1186 }
1187 }
1188
1189 cifs_buf_release(pSMB);
1190 if (rc == -EAGAIN)
1191 goto OldOpenRetry;
1192 return rc;
1193}
1194
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195int
1196CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1197 const char *fileName, const int openDisposition,
1198 const int access_flags, const int create_options, __u16 * netfid,
1199 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001200 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201{
1202 int rc = -EACCES;
1203 OPEN_REQ *pSMB = NULL;
1204 OPEN_RSP *pSMBr = NULL;
1205 int bytes_returned;
1206 int name_len;
1207 __u16 count;
1208
1209openRetry:
1210 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1211 (void **) &pSMBr);
1212 if (rc)
1213 return rc;
1214
1215 pSMB->AndXCommand = 0xFF; /* none */
1216
1217 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1218 count = 1; /* account for one byte pad to word boundary */
1219 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001220 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001221 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 name_len++; /* trailing null */
1223 name_len *= 2;
1224 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001225 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 count = 0; /* no pad */
1227 name_len = strnlen(fileName, PATH_MAX);
1228 name_len++; /* trailing null */
1229 pSMB->NameLength = cpu_to_le16(name_len);
1230 strncpy(pSMB->fileName, fileName, name_len);
1231 }
1232 if (*pOplock & REQ_OPLOCK)
1233 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
1234 else if (*pOplock & REQ_BATCHOPLOCK) {
1235 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
1236 }
1237 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1238 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001239 /* set file as system file if special file such
1240 as fifo and server expecting SFU style and
1241 no Unix extensions */
1242 if(create_options & CREATE_OPTION_SPECIAL)
1243 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1244 else
1245 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 /* XP does not handle ATTR_POSIX_SEMANTICS */
1247 /* but it helps speed up case sensitive checks for other
1248 servers such as Samba */
1249 if (tcon->ses->capabilities & CAP_UNIX)
1250 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1251
1252 /* if ((omode & S_IWUGO) == 0)
1253 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1254 /* Above line causes problems due to vfs splitting create into two
1255 pieces - need to set mode after file created not while it is
1256 being created */
1257 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1258 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001259 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001260 /* BB Expirement with various impersonation levels and verify */
1261 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 pSMB->SecurityFlags =
1263 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1264
1265 count += name_len;
1266 pSMB->hdr.smb_buf_length += count;
1267
1268 pSMB->ByteCount = cpu_to_le16(count);
1269 /* long_op set to 1 to allow for oplock break timeouts */
1270 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1271 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001272 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 if (rc) {
1274 cFYI(1, ("Error in Open = %d", rc));
1275 } else {
Steve French09d1db52005-04-28 22:41:08 -07001276 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1278 /* Let caller know file was created so we can set the mode. */
1279 /* Do we care about the CreateAction in any other cases? */
1280 if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
1281 *pOplock |= CIFS_CREATE_ACTION;
1282 if(pfile_info) {
1283 memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
1284 36 /* CreationTime to Attributes */);
1285 /* the file_info buf is endian converted by caller */
1286 pfile_info->AllocationSize = pSMBr->AllocationSize;
1287 pfile_info->EndOfFile = pSMBr->EndOfFile;
1288 pfile_info->NumberOfLinks = cpu_to_le32(1);
1289 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001291
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 cifs_buf_release(pSMB);
1293 if (rc == -EAGAIN)
1294 goto openRetry;
1295 return rc;
1296}
1297
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298int
1299CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
Steve Frenchec637e32005-12-12 20:53:18 -08001300 const int netfid, const unsigned int count,
1301 const __u64 lseek, unsigned int *nbytes, char **buf,
1302 int * pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303{
1304 int rc = -EACCES;
1305 READ_REQ *pSMB = NULL;
1306 READ_RSP *pSMBr = NULL;
1307 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001308 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001309 int resp_buf_type = 0;
1310 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311
1312 cFYI(1,("Reading %d bytes on fid %d",count,netfid));
Steve Frenchbfa0d752005-08-31 21:50:37 -07001313 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1314 wct = 12;
1315 else
1316 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
1318 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001319 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 if (rc)
1321 return rc;
1322
1323 /* tcon and ses pointer are checked in smb_init */
1324 if (tcon->ses->server == NULL)
1325 return -ECONNABORTED;
1326
Steve Frenchec637e32005-12-12 20:53:18 -08001327 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 pSMB->Fid = netfid;
1329 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001330 if(wct == 12)
1331 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchec637e32005-12-12 20:53:18 -08001332 else if((lseek >> 32) > 0) /* can not handle this big offset for old */
1333 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001334
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 pSMB->Remaining = 0;
1336 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1337 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001338 if(wct == 12)
1339 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1340 else {
1341 /* old style read */
Steve Frenchec637e32005-12-12 20:53:18 -08001342 struct smb_com_readx_req * pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001343 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001344 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001345 }
Steve Frenchec637e32005-12-12 20:53:18 -08001346
1347 iov[0].iov_base = (char *)pSMB;
1348 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1349 rc = SendReceive2(xid, tcon->ses, iov,
1350 1 /* num iovecs */,
1351 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001352 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001353 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 if (rc) {
1355 cERROR(1, ("Send error in read = %d", rc));
1356 } else {
1357 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1358 data_length = data_length << 16;
1359 data_length += le16_to_cpu(pSMBr->DataLength);
1360 *nbytes = data_length;
1361
1362 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001363 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 || (data_length > count)) {
1365 cFYI(1,("bad length %d for count %d",data_length,count));
1366 rc = -EIO;
1367 *nbytes = 0;
1368 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001369 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 le16_to_cpu(pSMBr->DataOffset);
Steve Frenchec637e32005-12-12 20:53:18 -08001371/* if(rc = copy_to_user(buf, pReadData, data_length)) {
1372 cERROR(1,("Faulting on read rc = %d",rc));
1373 rc = -EFAULT;
1374 }*/ /* can not use copy_to_user when using page cache*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375 if(*buf)
Steve Frenchec637e32005-12-12 20:53:18 -08001376 memcpy(*buf,pReadData,data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377 }
1378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379
Steve French4b8f9302006-02-26 16:41:18 +00001380/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001381 if(*buf) {
1382 if(resp_buf_type == CIFS_SMALL_BUFFER)
1383 cifs_small_buf_release(iov[0].iov_base);
1384 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1385 cifs_buf_release(iov[0].iov_base);
Steve French6cec2ae2006-02-22 17:31:52 -06001386 } else if(resp_buf_type != CIFS_NO_BUFFER) {
1387 /* return buffer to caller to free */
1388 *buf = iov[0].iov_base;
Steve Frenchec637e32005-12-12 20:53:18 -08001389 if(resp_buf_type == CIFS_SMALL_BUFFER)
1390 *pbuf_type = CIFS_SMALL_BUFFER;
1391 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1392 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001393 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001394
1395 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 since file handle passed in no longer valid */
1397 return rc;
1398}
1399
Steve Frenchec637e32005-12-12 20:53:18 -08001400
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401int
1402CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1403 const int netfid, const unsigned int count,
1404 const __u64 offset, unsigned int *nbytes, const char *buf,
1405 const char __user * ubuf, const int long_op)
1406{
1407 int rc = -EACCES;
1408 WRITE_REQ *pSMB = NULL;
1409 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001410 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 __u32 bytes_sent;
1412 __u16 byte_count;
1413
1414 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French1c955182005-08-30 20:58:07 -07001415 if(tcon->ses == NULL)
1416 return -ECONNABORTED;
1417
1418 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1419 wct = 14;
1420 else
1421 wct = 12;
1422
1423 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 (void **) &pSMBr);
1425 if (rc)
1426 return rc;
1427 /* tcon and ses pointer are checked in smb_init */
1428 if (tcon->ses->server == NULL)
1429 return -ECONNABORTED;
1430
1431 pSMB->AndXCommand = 0xFF; /* none */
1432 pSMB->Fid = netfid;
1433 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French1c955182005-08-30 20:58:07 -07001434 if(wct == 14)
1435 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1436 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1437 return -EIO;
1438
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 pSMB->Reserved = 0xFFFFFFFF;
1440 pSMB->WriteMode = 0;
1441 pSMB->Remaining = 0;
1442
1443 /* Can increase buffer size if buffer is big enough in some cases - ie we
1444 can send more if LARGE_WRITE_X capability returned by the server and if
1445 our buffer is big enough or if we convert to iovecs on socket writes
1446 and eliminate the copy to the CIFS buffer */
1447 if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1448 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1449 } else {
1450 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1451 & ~0xFF;
1452 }
1453
1454 if (bytes_sent > count)
1455 bytes_sent = count;
1456 pSMB->DataOffset =
Steve Frenche30dcf32005-09-20 20:49:16 -07001457 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 if(buf)
1459 memcpy(pSMB->Data,buf,bytes_sent);
1460 else if(ubuf) {
1461 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1462 cifs_buf_release(pSMB);
1463 return -EFAULT;
1464 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001465 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 /* No buffer */
1467 cifs_buf_release(pSMB);
1468 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001469 } /* else setting file size with write of zero bytes */
1470 if(wct == 14)
1471 byte_count = bytes_sent + 1; /* pad */
1472 else /* wct == 12 */ {
1473 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1476 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001477 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001478
1479 if(wct == 14)
1480 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve Frenche30dcf32005-09-20 20:49:16 -07001481 else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
Steve French1c955182005-08-30 20:58:07 -07001482 struct smb_com_writex_req * pSMBW =
1483 (struct smb_com_writex_req *)pSMB;
1484 pSMBW->ByteCount = cpu_to_le16(byte_count);
1485 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486
1487 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1488 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001489 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 if (rc) {
1491 cFYI(1, ("Send error in write = %d", rc));
1492 *nbytes = 0;
1493 } else {
1494 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1495 *nbytes = (*nbytes) << 16;
1496 *nbytes += le16_to_cpu(pSMBr->Count);
1497 }
1498
1499 cifs_buf_release(pSMB);
1500
1501 /* Note: On -EAGAIN error only caller can retry on handle based calls
1502 since file handle passed in no longer valid */
1503
1504 return rc;
1505}
1506
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001507int
1508CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001510 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1511 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512{
1513 int rc = -EACCES;
1514 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001515 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001516 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001517 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518
Steve Frenchff7feac2005-11-15 16:45:16 -08001519 cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
1520
Steve French8cc64c62005-10-03 13:49:43 -07001521 if(tcon->ses->capabilities & CAP_LARGE_FILES)
1522 wct = 14;
1523 else
1524 wct = 12;
1525 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 if (rc)
1527 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528 /* tcon and ses pointer are checked in smb_init */
1529 if (tcon->ses->server == NULL)
1530 return -ECONNABORTED;
1531
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001532 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 pSMB->Fid = netfid;
1534 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French8cc64c62005-10-03 13:49:43 -07001535 if(wct == 14)
1536 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1537 else if((offset >> 32) > 0) /* can not handle this big offset for old */
1538 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 pSMB->Reserved = 0xFFFFFFFF;
1540 pSMB->WriteMode = 0;
1541 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001542
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 pSMB->DataOffset =
1544 cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1545
Steve French3e844692005-10-03 13:37:24 -07001546 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1547 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001548 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French8cc64c62005-10-03 13:49:43 -07001549 if(wct == 14)
1550 pSMB->hdr.smb_buf_length += count+1;
1551 else /* wct == 12 */
1552 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1553 if(wct == 14)
1554 pSMB->ByteCount = cpu_to_le16(count + 1);
1555 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
1556 struct smb_com_writex_req * pSMBW =
1557 (struct smb_com_writex_req *)pSMB;
1558 pSMBW->ByteCount = cpu_to_le16(count + 5);
1559 }
Steve French3e844692005-10-03 13:37:24 -07001560 iov[0].iov_base = pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001561 if(wct == 14)
1562 iov[0].iov_len = smb_hdr_len + 4;
1563 else /* wct == 12 pad bigger by four bytes */
1564 iov[0].iov_len = smb_hdr_len + 8;
1565
Steve French3e844692005-10-03 13:37:24 -07001566
Steve Frenchec637e32005-12-12 20:53:18 -08001567 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001568 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001569 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001571 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001573 } else if(resp_buf_type == 0) {
1574 /* presumably this can not happen, but best to be safe */
1575 rc = -EIO;
1576 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001577 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001578 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001579 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1580 *nbytes = (*nbytes) << 16;
1581 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French84afc292005-12-02 13:32:45 -08001582 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583
Steve French4b8f9302006-02-26 16:41:18 +00001584/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve Frenchec637e32005-12-12 20:53:18 -08001585 if(resp_buf_type == CIFS_SMALL_BUFFER)
1586 cifs_small_buf_release(iov[0].iov_base);
1587 else if(resp_buf_type == CIFS_LARGE_BUFFER)
1588 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589
1590 /* Note: On -EAGAIN error only caller can retry on handle based calls
1591 since file handle passed in no longer valid */
1592
1593 return rc;
1594}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001595
1596
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597int
1598CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1599 const __u16 smb_file_id, const __u64 len,
1600 const __u64 offset, const __u32 numUnlock,
1601 const __u32 numLock, const __u8 lockType, const int waitFlag)
1602{
1603 int rc = 0;
1604 LOCK_REQ *pSMB = NULL;
1605 LOCK_RSP *pSMBr = NULL;
1606 int bytes_returned;
1607 int timeout = 0;
1608 __u16 count;
1609
1610 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
Steve French46810cb2005-04-28 22:41:09 -07001611 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1612
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 if (rc)
1614 return rc;
1615
Steve French46810cb2005-04-28 22:41:09 -07001616 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1617
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1619 timeout = -1; /* no response expected */
1620 pSMB->Timeout = 0;
1621 } else if (waitFlag == TRUE) {
1622 timeout = 3; /* blocking operation, no timeout */
1623 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1624 } else {
1625 pSMB->Timeout = 0;
1626 }
1627
1628 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1629 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1630 pSMB->LockType = lockType;
1631 pSMB->AndXCommand = 0xFF; /* none */
1632 pSMB->Fid = smb_file_id; /* netfid stays le */
1633
1634 if((numLock != 0) || (numUnlock != 0)) {
1635 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1636 /* BB where to store pid high? */
1637 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1638 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1639 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1640 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1641 count = sizeof(LOCKING_ANDX_RANGE);
1642 } else {
1643 /* oplock break */
1644 count = 0;
1645 }
1646 pSMB->hdr.smb_buf_length += count;
1647 pSMB->ByteCount = cpu_to_le16(count);
1648
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001649 if (waitFlag) {
1650 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1651 (struct smb_hdr *) pSMBr, &bytes_returned);
1652 } else {
1653 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001655 }
Steve Frencha4544342005-08-24 13:59:35 -07001656 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 if (rc) {
1658 cFYI(1, ("Send error in Lock = %d", rc));
1659 }
Steve French46810cb2005-04-28 22:41:09 -07001660 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
1662 /* Note: On -EAGAIN error only caller can retry on handle based calls
1663 since file handle passed in no longer valid */
1664 return rc;
1665}
1666
1667int
Steve French08547b02006-02-28 22:39:25 +00001668CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1669 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001670 struct file_lock *pLockData, const __u16 lock_type,
1671 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001672{
1673 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1674 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1675 char *data_offset;
1676 struct cifs_posix_lock *parm_data;
1677 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001678 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001679 int bytes_returned = 0;
1680 __u16 params, param_offset, offset, byte_count, count;
1681
1682 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001683
1684 if(pLockData == NULL)
1685 return EINVAL;
1686
Steve French08547b02006-02-28 22:39:25 +00001687 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1688
1689 if (rc)
1690 return rc;
1691
1692 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1693
1694 params = 6;
1695 pSMB->MaxSetupCount = 0;
1696 pSMB->Reserved = 0;
1697 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001698 pSMB->Reserved2 = 0;
1699 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1700 offset = param_offset + params;
1701
1702 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1703
1704 count = sizeof(struct cifs_posix_lock);
1705 pSMB->MaxParameterCount = cpu_to_le16(2);
1706 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1707 pSMB->SetupCount = 1;
1708 pSMB->Reserved3 = 0;
1709 if(get_flag)
1710 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1711 else
1712 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1713 byte_count = 3 /* pad */ + params + count;
1714 pSMB->DataCount = cpu_to_le16(count);
1715 pSMB->ParameterCount = cpu_to_le16(params);
1716 pSMB->TotalDataCount = pSMB->DataCount;
1717 pSMB->TotalParameterCount = pSMB->ParameterCount;
1718 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1719 parm_data = (struct cifs_posix_lock *)
1720 (((char *) &pSMB->hdr.Protocol) + offset);
1721
1722 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French3a5ff612006-07-14 22:37:11 +00001723 if(waitFlag) {
1724 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001725 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001726 pSMB->Timeout = cpu_to_le32(-1);
1727 } else
1728 pSMB->Timeout = 0;
1729
Steve French08547b02006-02-28 22:39:25 +00001730 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001731 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001732 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001733
1734 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001735 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001736 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1737 pSMB->Reserved4 = 0;
1738 pSMB->hdr.smb_buf_length += byte_count;
1739 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001740 if (waitFlag) {
1741 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1742 (struct smb_hdr *) pSMBr, &bytes_returned);
1743 } else {
1744 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001745 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001746 }
1747
Steve French08547b02006-02-28 22:39:25 +00001748 if (rc) {
1749 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001750 } else if (get_flag) {
1751 /* lock structure can be returned on get */
1752 __u16 data_offset;
1753 __u16 data_count;
1754 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001755
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001756 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1757 rc = -EIO; /* bad smb */
1758 goto plk_err_exit;
1759 }
1760 if(pLockData == NULL) {
1761 rc = -EINVAL;
1762 goto plk_err_exit;
1763 }
1764 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1765 data_count = le16_to_cpu(pSMBr->t2.DataCount);
1766 if(data_count < sizeof(struct cifs_posix_lock)) {
1767 rc = -EIO;
1768 goto plk_err_exit;
1769 }
1770 parm_data = (struct cifs_posix_lock *)
1771 ((char *)&pSMBr->hdr.Protocol + data_offset);
1772 if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
1773 pLockData->fl_type = F_UNLCK;
1774 }
1775
1776plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001777 if (pSMB)
1778 cifs_small_buf_release(pSMB);
1779
1780 /* Note: On -EAGAIN error only caller can retry on handle based calls
1781 since file handle passed in no longer valid */
1782
1783 return rc;
1784}
1785
1786
1787int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001788CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1789{
1790 int rc = 0;
1791 CLOSE_REQ *pSMB = NULL;
1792 CLOSE_RSP *pSMBr = NULL;
1793 int bytes_returned;
1794 cFYI(1, ("In CIFSSMBClose"));
1795
1796/* do not retry on dead session on close */
1797 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1798 if(rc == -EAGAIN)
1799 return 0;
1800 if (rc)
1801 return rc;
1802
1803 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1804
1805 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001806 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 pSMB->ByteCount = 0;
1808 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1809 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001810 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 if (rc) {
1812 if(rc!=-EINTR) {
1813 /* EINTR is expected when user ctl-c to kill app */
1814 cERROR(1, ("Send error in Close = %d", rc));
1815 }
1816 }
1817
1818 cifs_small_buf_release(pSMB);
1819
1820 /* Since session is dead, file will be closed on server already */
1821 if(rc == -EAGAIN)
1822 rc = 0;
1823
1824 return rc;
1825}
1826
1827int
1828CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1829 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001830 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831{
1832 int rc = 0;
1833 RENAME_REQ *pSMB = NULL;
1834 RENAME_RSP *pSMBr = NULL;
1835 int bytes_returned;
1836 int name_len, name_len2;
1837 __u16 count;
1838
1839 cFYI(1, ("In CIFSSMBRename"));
1840renameRetry:
1841 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1842 (void **) &pSMBr);
1843 if (rc)
1844 return rc;
1845
1846 pSMB->BufferFormat = 0x04;
1847 pSMB->SearchAttributes =
1848 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1849 ATTR_DIRECTORY);
1850
1851 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1852 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001853 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001854 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 name_len++; /* trailing null */
1856 name_len *= 2;
1857 pSMB->OldFileName[name_len] = 0x04; /* pad */
1858 /* protocol requires ASCII signature byte on Unicode string */
1859 pSMB->OldFileName[name_len + 1] = 0x00;
1860 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001861 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001862 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1864 name_len2 *= 2; /* convert to bytes */
1865 } else { /* BB improve the check for buffer overruns BB */
1866 name_len = strnlen(fromName, PATH_MAX);
1867 name_len++; /* trailing null */
1868 strncpy(pSMB->OldFileName, fromName, name_len);
1869 name_len2 = strnlen(toName, PATH_MAX);
1870 name_len2++; /* trailing null */
1871 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1872 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1873 name_len2++; /* trailing null */
1874 name_len2++; /* signature byte */
1875 }
1876
1877 count = 1 /* 1st signature byte */ + name_len + name_len2;
1878 pSMB->hdr.smb_buf_length += count;
1879 pSMB->ByteCount = cpu_to_le16(count);
1880
1881 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1882 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001883 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 if (rc) {
1885 cFYI(1, ("Send error in rename = %d", rc));
1886 }
1887
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 cifs_buf_release(pSMB);
1889
1890 if (rc == -EAGAIN)
1891 goto renameRetry;
1892
1893 return rc;
1894}
1895
1896int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
Steve French737b7582005-04-28 22:41:06 -07001897 int netfid, char * target_name,
1898 const struct nls_table * nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899{
1900 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1901 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1902 struct set_file_rename * rename_info;
1903 char *data_offset;
1904 char dummy_string[30];
1905 int rc = 0;
1906 int bytes_returned = 0;
1907 int len_of_str;
1908 __u16 params, param_offset, offset, count, byte_count;
1909
1910 cFYI(1, ("Rename to File by handle"));
1911 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1912 (void **) &pSMBr);
1913 if (rc)
1914 return rc;
1915
1916 params = 6;
1917 pSMB->MaxSetupCount = 0;
1918 pSMB->Reserved = 0;
1919 pSMB->Flags = 0;
1920 pSMB->Timeout = 0;
1921 pSMB->Reserved2 = 0;
1922 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1923 offset = param_offset + params;
1924
1925 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1926 rename_info = (struct set_file_rename *) data_offset;
1927 pSMB->MaxParameterCount = cpu_to_le16(2);
1928 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1929 pSMB->SetupCount = 1;
1930 pSMB->Reserved3 = 0;
1931 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1932 byte_count = 3 /* pad */ + params;
1933 pSMB->ParameterCount = cpu_to_le16(params);
1934 pSMB->TotalParameterCount = pSMB->ParameterCount;
1935 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1936 pSMB->DataOffset = cpu_to_le16(offset);
1937 /* construct random name ".cifs_tmp<inodenum><mid>" */
1938 rename_info->overwrite = cpu_to_le32(1);
1939 rename_info->root_fid = 0;
1940 /* unicode only call */
1941 if(target_name == NULL) {
1942 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
Steve Frenchb1a45692005-05-17 16:07:23 -05001943 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001944 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001946 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001947 target_name, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 }
1949 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1950 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1951 byte_count += count;
1952 pSMB->DataCount = cpu_to_le16(count);
1953 pSMB->TotalDataCount = pSMB->DataCount;
1954 pSMB->Fid = netfid;
1955 pSMB->InformationLevel =
1956 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1957 pSMB->Reserved4 = 0;
1958 pSMB->hdr.smb_buf_length += byte_count;
1959 pSMB->ByteCount = cpu_to_le16(byte_count);
1960 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1961 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001962 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 if (rc) {
1964 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1965 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001966
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 cifs_buf_release(pSMB);
1968
1969 /* Note: On -EAGAIN error only caller can retry on handle based calls
1970 since file handle passed in no longer valid */
1971
1972 return rc;
1973}
1974
1975int
1976CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
1977 const __u16 target_tid, const char *toName, const int flags,
Steve French737b7582005-04-28 22:41:06 -07001978 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979{
1980 int rc = 0;
1981 COPY_REQ *pSMB = NULL;
1982 COPY_RSP *pSMBr = NULL;
1983 int bytes_returned;
1984 int name_len, name_len2;
1985 __u16 count;
1986
1987 cFYI(1, ("In CIFSSMBCopy"));
1988copyRetry:
1989 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1990 (void **) &pSMBr);
1991 if (rc)
1992 return rc;
1993
1994 pSMB->BufferFormat = 0x04;
1995 pSMB->Tid2 = target_tid;
1996
1997 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1998
1999 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002000 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002001 fromName, PATH_MAX, nls_codepage,
2002 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 name_len++; /* trailing null */
2004 name_len *= 2;
2005 pSMB->OldFileName[name_len] = 0x04; /* pad */
2006 /* protocol requires ASCII signature byte on Unicode string */
2007 pSMB->OldFileName[name_len + 1] = 0x00;
Steve Frenchb1a45692005-05-17 16:07:23 -05002008 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002009 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2011 name_len2 *= 2; /* convert to bytes */
2012 } else { /* BB improve the check for buffer overruns BB */
2013 name_len = strnlen(fromName, PATH_MAX);
2014 name_len++; /* trailing null */
2015 strncpy(pSMB->OldFileName, fromName, name_len);
2016 name_len2 = strnlen(toName, PATH_MAX);
2017 name_len2++; /* trailing null */
2018 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2019 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2020 name_len2++; /* trailing null */
2021 name_len2++; /* signature byte */
2022 }
2023
2024 count = 1 /* 1st signature byte */ + name_len + name_len2;
2025 pSMB->hdr.smb_buf_length += count;
2026 pSMB->ByteCount = cpu_to_le16(count);
2027
2028 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2029 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2030 if (rc) {
2031 cFYI(1, ("Send error in copy = %d with %d files copied",
2032 rc, le16_to_cpu(pSMBr->CopyCount)));
2033 }
2034 if (pSMB)
2035 cifs_buf_release(pSMB);
2036
2037 if (rc == -EAGAIN)
2038 goto copyRetry;
2039
2040 return rc;
2041}
2042
2043int
2044CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2045 const char *fromName, const char *toName,
2046 const struct nls_table *nls_codepage)
2047{
2048 TRANSACTION2_SPI_REQ *pSMB = NULL;
2049 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2050 char *data_offset;
2051 int name_len;
2052 int name_len_target;
2053 int rc = 0;
2054 int bytes_returned = 0;
2055 __u16 params, param_offset, offset, byte_count;
2056
2057 cFYI(1, ("In Symlink Unix style"));
2058createSymLinkRetry:
2059 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2060 (void **) &pSMBr);
2061 if (rc)
2062 return rc;
2063
2064 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2065 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002066 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 /* find define for this maxpathcomponent */
2068 , nls_codepage);
2069 name_len++; /* trailing null */
2070 name_len *= 2;
2071
2072 } else { /* BB improve the check for buffer overruns BB */
2073 name_len = strnlen(fromName, PATH_MAX);
2074 name_len++; /* trailing null */
2075 strncpy(pSMB->FileName, fromName, name_len);
2076 }
2077 params = 6 + name_len;
2078 pSMB->MaxSetupCount = 0;
2079 pSMB->Reserved = 0;
2080 pSMB->Flags = 0;
2081 pSMB->Timeout = 0;
2082 pSMB->Reserved2 = 0;
2083 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2084 InformationLevel) - 4;
2085 offset = param_offset + params;
2086
2087 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2088 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2089 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002090 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 /* find define for this maxpathcomponent */
2092 , nls_codepage);
2093 name_len_target++; /* trailing null */
2094 name_len_target *= 2;
2095 } else { /* BB improve the check for buffer overruns BB */
2096 name_len_target = strnlen(toName, PATH_MAX);
2097 name_len_target++; /* trailing null */
2098 strncpy(data_offset, toName, name_len_target);
2099 }
2100
2101 pSMB->MaxParameterCount = cpu_to_le16(2);
2102 /* BB find exact max on data count below from sess */
2103 pSMB->MaxDataCount = cpu_to_le16(1000);
2104 pSMB->SetupCount = 1;
2105 pSMB->Reserved3 = 0;
2106 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2107 byte_count = 3 /* pad */ + params + name_len_target;
2108 pSMB->DataCount = cpu_to_le16(name_len_target);
2109 pSMB->ParameterCount = cpu_to_le16(params);
2110 pSMB->TotalDataCount = pSMB->DataCount;
2111 pSMB->TotalParameterCount = pSMB->ParameterCount;
2112 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2113 pSMB->DataOffset = cpu_to_le16(offset);
2114 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2115 pSMB->Reserved4 = 0;
2116 pSMB->hdr.smb_buf_length += byte_count;
2117 pSMB->ByteCount = cpu_to_le16(byte_count);
2118 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2119 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002120 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121 if (rc) {
2122 cFYI(1,
2123 ("Send error in SetPathInfo (create symlink) = %d",
2124 rc));
2125 }
2126
2127 if (pSMB)
2128 cifs_buf_release(pSMB);
2129
2130 if (rc == -EAGAIN)
2131 goto createSymLinkRetry;
2132
2133 return rc;
2134}
2135
2136int
2137CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2138 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002139 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140{
2141 TRANSACTION2_SPI_REQ *pSMB = NULL;
2142 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2143 char *data_offset;
2144 int name_len;
2145 int name_len_target;
2146 int rc = 0;
2147 int bytes_returned = 0;
2148 __u16 params, param_offset, offset, byte_count;
2149
2150 cFYI(1, ("In Create Hard link Unix style"));
2151createHardLinkRetry:
2152 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2153 (void **) &pSMBr);
2154 if (rc)
2155 return rc;
2156
2157 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002158 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002159 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 name_len++; /* trailing null */
2161 name_len *= 2;
2162
2163 } else { /* BB improve the check for buffer overruns BB */
2164 name_len = strnlen(toName, PATH_MAX);
2165 name_len++; /* trailing null */
2166 strncpy(pSMB->FileName, toName, name_len);
2167 }
2168 params = 6 + name_len;
2169 pSMB->MaxSetupCount = 0;
2170 pSMB->Reserved = 0;
2171 pSMB->Flags = 0;
2172 pSMB->Timeout = 0;
2173 pSMB->Reserved2 = 0;
2174 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2175 InformationLevel) - 4;
2176 offset = param_offset + params;
2177
2178 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2179 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2180 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002181 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002182 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 name_len_target++; /* trailing null */
2184 name_len_target *= 2;
2185 } else { /* BB improve the check for buffer overruns BB */
2186 name_len_target = strnlen(fromName, PATH_MAX);
2187 name_len_target++; /* trailing null */
2188 strncpy(data_offset, fromName, name_len_target);
2189 }
2190
2191 pSMB->MaxParameterCount = cpu_to_le16(2);
2192 /* BB find exact max on data count below from sess*/
2193 pSMB->MaxDataCount = cpu_to_le16(1000);
2194 pSMB->SetupCount = 1;
2195 pSMB->Reserved3 = 0;
2196 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2197 byte_count = 3 /* pad */ + params + name_len_target;
2198 pSMB->ParameterCount = cpu_to_le16(params);
2199 pSMB->TotalParameterCount = pSMB->ParameterCount;
2200 pSMB->DataCount = cpu_to_le16(name_len_target);
2201 pSMB->TotalDataCount = pSMB->DataCount;
2202 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2203 pSMB->DataOffset = cpu_to_le16(offset);
2204 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2205 pSMB->Reserved4 = 0;
2206 pSMB->hdr.smb_buf_length += byte_count;
2207 pSMB->ByteCount = cpu_to_le16(byte_count);
2208 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2209 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002210 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211 if (rc) {
2212 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2213 }
2214
2215 cifs_buf_release(pSMB);
2216 if (rc == -EAGAIN)
2217 goto createHardLinkRetry;
2218
2219 return rc;
2220}
2221
2222int
2223CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2224 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002225 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226{
2227 int rc = 0;
2228 NT_RENAME_REQ *pSMB = NULL;
2229 RENAME_RSP *pSMBr = NULL;
2230 int bytes_returned;
2231 int name_len, name_len2;
2232 __u16 count;
2233
2234 cFYI(1, ("In CIFSCreateHardLink"));
2235winCreateHardLinkRetry:
2236
2237 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2238 (void **) &pSMBr);
2239 if (rc)
2240 return rc;
2241
2242 pSMB->SearchAttributes =
2243 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2244 ATTR_DIRECTORY);
2245 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2246 pSMB->ClusterCount = 0;
2247
2248 pSMB->BufferFormat = 0x04;
2249
2250 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2251 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002252 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002253 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 name_len++; /* trailing null */
2255 name_len *= 2;
2256 pSMB->OldFileName[name_len] = 0; /* pad */
2257 pSMB->OldFileName[name_len + 1] = 0x04;
2258 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05002259 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002260 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2262 name_len2 *= 2; /* convert to bytes */
2263 } else { /* BB improve the check for buffer overruns BB */
2264 name_len = strnlen(fromName, PATH_MAX);
2265 name_len++; /* trailing null */
2266 strncpy(pSMB->OldFileName, fromName, name_len);
2267 name_len2 = strnlen(toName, PATH_MAX);
2268 name_len2++; /* trailing null */
2269 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2270 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2271 name_len2++; /* trailing null */
2272 name_len2++; /* signature byte */
2273 }
2274
2275 count = 1 /* string type byte */ + name_len + name_len2;
2276 pSMB->hdr.smb_buf_length += count;
2277 pSMB->ByteCount = cpu_to_le16(count);
2278
2279 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2280 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002281 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 if (rc) {
2283 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2284 }
2285 cifs_buf_release(pSMB);
2286 if (rc == -EAGAIN)
2287 goto winCreateHardLinkRetry;
2288
2289 return rc;
2290}
2291
2292int
2293CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2294 const unsigned char *searchName,
2295 char *symlinkinfo, const int buflen,
2296 const struct nls_table *nls_codepage)
2297{
2298/* SMB_QUERY_FILE_UNIX_LINK */
2299 TRANSACTION2_QPI_REQ *pSMB = NULL;
2300 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2301 int rc = 0;
2302 int bytes_returned;
2303 int name_len;
2304 __u16 params, byte_count;
2305
2306 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2307
2308querySymLinkRetry:
2309 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2310 (void **) &pSMBr);
2311 if (rc)
2312 return rc;
2313
2314 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2315 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002316 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 /* find define for this maxpathcomponent */
2318 , nls_codepage);
2319 name_len++; /* trailing null */
2320 name_len *= 2;
2321 } else { /* BB improve the check for buffer overruns BB */
2322 name_len = strnlen(searchName, PATH_MAX);
2323 name_len++; /* trailing null */
2324 strncpy(pSMB->FileName, searchName, name_len);
2325 }
2326
2327 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2328 pSMB->TotalDataCount = 0;
2329 pSMB->MaxParameterCount = cpu_to_le16(2);
2330 /* BB find exact max data count below from sess structure BB */
2331 pSMB->MaxDataCount = cpu_to_le16(4000);
2332 pSMB->MaxSetupCount = 0;
2333 pSMB->Reserved = 0;
2334 pSMB->Flags = 0;
2335 pSMB->Timeout = 0;
2336 pSMB->Reserved2 = 0;
2337 pSMB->ParameterOffset = cpu_to_le16(offsetof(
2338 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2339 pSMB->DataCount = 0;
2340 pSMB->DataOffset = 0;
2341 pSMB->SetupCount = 1;
2342 pSMB->Reserved3 = 0;
2343 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2344 byte_count = params + 1 /* pad */ ;
2345 pSMB->TotalParameterCount = cpu_to_le16(params);
2346 pSMB->ParameterCount = pSMB->TotalParameterCount;
2347 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2348 pSMB->Reserved4 = 0;
2349 pSMB->hdr.smb_buf_length += byte_count;
2350 pSMB->ByteCount = cpu_to_le16(byte_count);
2351
2352 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2353 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2354 if (rc) {
2355 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2356 } else {
2357 /* decode response */
2358
2359 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2360 if (rc || (pSMBr->ByteCount < 2))
2361 /* BB also check enough total bytes returned */
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
2367 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2368 name_len = UniStrnlen((wchar_t *) ((char *)
2369 &pSMBr->hdr.Protocol +data_offset),
2370 min_t(const int, buflen,count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002371 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002372 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002373 (__le16 *) ((char *)&pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 data_offset),
2375 name_len, nls_codepage);
2376 } else {
2377 strncpy(symlinkinfo,
2378 (char *) &pSMBr->hdr.Protocol +
2379 data_offset,
2380 min_t(const int, buflen, count));
2381 }
2382 symlinkinfo[buflen] = 0;
2383 /* just in case so calling code does not go off the end of buffer */
2384 }
2385 }
2386 cifs_buf_release(pSMB);
2387 if (rc == -EAGAIN)
2388 goto querySymLinkRetry;
2389 return rc;
2390}
2391
Steve French0a4b92c2006-01-12 15:44:21 -08002392/* Initialize NT TRANSACT SMB into small smb request buffer.
2393 This assumes that all NT TRANSACTS that we init here have
2394 total parm and data under about 400 bytes (to fit in small cifs
2395 buffer size), which is the case so far, it easily fits. NB:
2396 Setup words themselves and ByteCount
2397 MaxSetupCount (size of returned setup area) and
2398 MaxParameterCount (returned parms size) must be set by caller */
2399static int
2400smb_init_ntransact(const __u16 sub_command, const int setup_count,
2401 const int parm_len, struct cifsTconInfo *tcon,
2402 void ** ret_buf)
2403{
2404 int rc;
2405 __u32 temp_offset;
2406 struct smb_com_ntransact_req * pSMB;
2407
2408 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2409 (void **)&pSMB);
2410 if (rc)
2411 return rc;
2412 *ret_buf = (void *)pSMB;
2413 pSMB->Reserved = 0;
2414 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2415 pSMB->TotalDataCount = 0;
2416 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2417 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2418 pSMB->ParameterCount = pSMB->TotalParameterCount;
2419 pSMB->DataCount = pSMB->TotalDataCount;
2420 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2421 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2422 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2423 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2424 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2425 pSMB->SubCommand = cpu_to_le16(sub_command);
2426 return 0;
2427}
2428
2429static int
2430validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
2431 int * pdatalen, int * pparmlen)
2432{
2433 char * end_of_smb;
2434 __u32 data_count, data_offset, parm_count, parm_offset;
2435 struct smb_com_ntransact_rsp * pSMBr;
2436
2437 if(buf == NULL)
2438 return -EINVAL;
2439
2440 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2441
2442 /* ByteCount was converted from little endian in SendReceive */
2443 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
2444 (char *)&pSMBr->ByteCount;
2445
2446
2447 data_offset = le32_to_cpu(pSMBr->DataOffset);
2448 data_count = le32_to_cpu(pSMBr->DataCount);
2449 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
2450 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2451
2452 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2453 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2454
2455 /* should we also check that parm and data areas do not overlap? */
2456 if(*ppparm > end_of_smb) {
2457 cFYI(1,("parms start after end of smb"));
2458 return -EINVAL;
2459 } else if(parm_count + *ppparm > end_of_smb) {
2460 cFYI(1,("parm end after end of smb"));
2461 return -EINVAL;
2462 } else if(*ppdata > end_of_smb) {
2463 cFYI(1,("data starts after end of smb"));
2464 return -EINVAL;
2465 } else if(data_count + *ppdata > end_of_smb) {
2466 cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
2467 *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
2468 return -EINVAL;
2469 } else if(parm_count + data_count > pSMBr->ByteCount) {
2470 cFYI(1,("parm count and data count larger than SMB"));
2471 return -EINVAL;
2472 }
2473 return 0;
2474}
2475
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476int
2477CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2478 const unsigned char *searchName,
2479 char *symlinkinfo, const int buflen,__u16 fid,
2480 const struct nls_table *nls_codepage)
2481{
2482 int rc = 0;
2483 int bytes_returned;
2484 int name_len;
2485 struct smb_com_transaction_ioctl_req * pSMB;
2486 struct smb_com_transaction_ioctl_rsp * pSMBr;
2487
2488 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2489 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2490 (void **) &pSMBr);
2491 if (rc)
2492 return rc;
2493
2494 pSMB->TotalParameterCount = 0 ;
2495 pSMB->TotalDataCount = 0;
2496 pSMB->MaxParameterCount = cpu_to_le32(2);
2497 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002498 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2499 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 pSMB->MaxSetupCount = 4;
2501 pSMB->Reserved = 0;
2502 pSMB->ParameterOffset = 0;
2503 pSMB->DataCount = 0;
2504 pSMB->DataOffset = 0;
2505 pSMB->SetupCount = 4;
2506 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2507 pSMB->ParameterCount = pSMB->TotalParameterCount;
2508 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2509 pSMB->IsFsctl = 1; /* FSCTL */
2510 pSMB->IsRootFlag = 0;
2511 pSMB->Fid = fid; /* file handle always le */
2512 pSMB->ByteCount = 0;
2513
2514 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2515 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2516 if (rc) {
2517 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2518 } else { /* decode response */
2519 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2520 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2521 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2522 /* BB also check enough total bytes returned */
2523 rc = -EIO; /* bad smb */
2524 else {
2525 if(data_count && (data_count < 2048)) {
Steve French0a4b92c2006-01-12 15:44:21 -08002526 char * end_of_smb = 2 /* sizeof byte count */ +
2527 pSMBr->ByteCount +
2528 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529
2530 struct reparse_data * reparse_buf = (struct reparse_data *)
2531 ((char *)&pSMBr->hdr.Protocol + data_offset);
2532 if((char*)reparse_buf >= end_of_smb) {
2533 rc = -EIO;
2534 goto qreparse_out;
2535 }
2536 if((reparse_buf->LinkNamesBuf +
2537 reparse_buf->TargetNameOffset +
2538 reparse_buf->TargetNameLen) >
2539 end_of_smb) {
2540 cFYI(1,("reparse buf extended beyond SMB"));
2541 rc = -EIO;
2542 goto qreparse_out;
2543 }
2544
2545 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2546 name_len = UniStrnlen((wchar_t *)
2547 (reparse_buf->LinkNamesBuf +
2548 reparse_buf->TargetNameOffset),
2549 min(buflen/2, reparse_buf->TargetNameLen / 2));
2550 cifs_strfromUCS_le(symlinkinfo,
Steve Frenche89dc922005-11-11 15:18:19 -08002551 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 reparse_buf->TargetNameOffset),
2553 name_len, nls_codepage);
2554 } else { /* ASCII names */
2555 strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
2556 reparse_buf->TargetNameOffset,
2557 min_t(const int, buflen, reparse_buf->TargetNameLen));
2558 }
2559 } else {
2560 rc = -EIO;
2561 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2562 }
2563 symlinkinfo[buflen] = 0; /* just in case so the caller
2564 does not go off the end of the buffer */
Steve French26a21b92006-05-31 18:05:34 +00002565 cFYI(1,("readlink result - %s",symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 }
2567 }
2568qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002569 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570
2571 /* Note: On -EAGAIN error only caller can retry on handle based calls
2572 since file handle passed in no longer valid */
2573
2574 return rc;
2575}
2576
2577#ifdef CONFIG_CIFS_POSIX
2578
2579/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2580static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2581{
2582 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002583 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2584 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2585 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2587
2588 return;
2589}
2590
2591/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French737b7582005-04-28 22:41:06 -07002592static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2593 const int acl_type,const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002594{
2595 int size = 0;
2596 int i;
2597 __u16 count;
2598 struct cifs_posix_ace * pACE;
2599 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2600 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2601
2602 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2603 return -EOPNOTSUPP;
2604
2605 if(acl_type & ACL_TYPE_ACCESS) {
2606 count = le16_to_cpu(cifs_acl->access_entry_count);
2607 pACE = &cifs_acl->ace_array[0];
2608 size = sizeof(struct cifs_posix_acl);
2609 size += sizeof(struct cifs_posix_ace) * count;
2610 /* check if we would go beyond end of SMB */
2611 if(size_of_data_area < size) {
2612 cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2613 return -EINVAL;
2614 }
2615 } else if(acl_type & ACL_TYPE_DEFAULT) {
2616 count = le16_to_cpu(cifs_acl->access_entry_count);
2617 size = sizeof(struct cifs_posix_acl);
2618 size += sizeof(struct cifs_posix_ace) * count;
2619/* skip past access ACEs to get to default ACEs */
2620 pACE = &cifs_acl->ace_array[count];
2621 count = le16_to_cpu(cifs_acl->default_entry_count);
2622 size += sizeof(struct cifs_posix_ace) * count;
2623 /* check if we would go beyond end of SMB */
2624 if(size_of_data_area < size)
2625 return -EINVAL;
2626 } else {
2627 /* illegal type */
2628 return -EINVAL;
2629 }
2630
2631 size = posix_acl_xattr_size(count);
2632 if((buflen == 0) || (local_acl == NULL)) {
2633 /* used to query ACL EA size */
2634 } else if(size > buflen) {
2635 return -ERANGE;
2636 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002637 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 for(i = 0;i < count ;i++) {
2639 cifs_convert_ace(&local_acl->a_entries[i],pACE);
2640 pACE ++;
2641 }
2642 }
2643 return size;
2644}
2645
2646static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2647 const posix_acl_xattr_entry * local_ace)
2648{
2649 __u16 rc = 0; /* 0 = ACL converted ok */
2650
Steve Frenchff7feac2005-11-15 16:45:16 -08002651 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2652 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 /* BB is there a better way to handle the large uid? */
Steve Frenchff7feac2005-11-15 16:45:16 -08002654 if(local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 /* Probably no need to le convert -1 on any arch but can not hurt */
2656 cifs_ace->cifs_uid = cpu_to_le64(-1);
2657 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002658 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2660 return rc;
2661}
2662
2663/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2664static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2665 const int acl_type)
2666{
2667 __u16 rc = 0;
2668 struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2669 posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2670 int count;
2671 int i;
2672
2673 if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2674 return 0;
2675
2676 count = posix_acl_xattr_count((size_t)buflen);
2677 cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002678 count, buflen, le32_to_cpu(local_acl->a_version)));
2679 if(le32_to_cpu(local_acl->a_version) != 2) {
2680 cFYI(1,("unknown POSIX ACL version %d",
2681 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 return 0;
2683 }
2684 cifs_acl->version = cpu_to_le16(1);
2685 if(acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002686 cifs_acl->access_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 else if(acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002688 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 else {
2690 cFYI(1,("unknown ACL type %d",acl_type));
2691 return 0;
2692 }
2693 for(i=0;i<count;i++) {
2694 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2695 &local_acl->a_entries[i]);
2696 if(rc != 0) {
2697 /* ACE not converted */
2698 break;
2699 }
2700 }
2701 if(rc == 0) {
2702 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2703 rc += sizeof(struct cifs_posix_acl);
2704 /* BB add check to make sure ACL does not overflow SMB */
2705 }
2706 return rc;
2707}
2708
2709int
2710CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2711 const unsigned char *searchName,
2712 char *acl_inf, const int buflen, const int acl_type,
Steve French737b7582005-04-28 22:41:06 -07002713 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714{
2715/* SMB_QUERY_POSIX_ACL */
2716 TRANSACTION2_QPI_REQ *pSMB = NULL;
2717 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2718 int rc = 0;
2719 int bytes_returned;
2720 int name_len;
2721 __u16 params, byte_count;
2722
2723 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2724
2725queryAclRetry:
2726 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2727 (void **) &pSMBr);
2728 if (rc)
2729 return rc;
2730
2731 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2732 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002733 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002734 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 name_len++; /* trailing null */
2736 name_len *= 2;
2737 pSMB->FileName[name_len] = 0;
2738 pSMB->FileName[name_len+1] = 0;
2739 } else { /* BB improve the check for buffer overruns BB */
2740 name_len = strnlen(searchName, PATH_MAX);
2741 name_len++; /* trailing null */
2742 strncpy(pSMB->FileName, searchName, name_len);
2743 }
2744
2745 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2746 pSMB->TotalDataCount = 0;
2747 pSMB->MaxParameterCount = cpu_to_le16(2);
2748 /* BB find exact max data count below from sess structure BB */
2749 pSMB->MaxDataCount = cpu_to_le16(4000);
2750 pSMB->MaxSetupCount = 0;
2751 pSMB->Reserved = 0;
2752 pSMB->Flags = 0;
2753 pSMB->Timeout = 0;
2754 pSMB->Reserved2 = 0;
2755 pSMB->ParameterOffset = cpu_to_le16(
2756 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2757 pSMB->DataCount = 0;
2758 pSMB->DataOffset = 0;
2759 pSMB->SetupCount = 1;
2760 pSMB->Reserved3 = 0;
2761 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2762 byte_count = params + 1 /* pad */ ;
2763 pSMB->TotalParameterCount = cpu_to_le16(params);
2764 pSMB->ParameterCount = pSMB->TotalParameterCount;
2765 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2766 pSMB->Reserved4 = 0;
2767 pSMB->hdr.smb_buf_length += byte_count;
2768 pSMB->ByteCount = cpu_to_le16(byte_count);
2769
2770 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2771 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002772 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 if (rc) {
2774 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2775 } else {
2776 /* decode response */
2777
2778 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2779 if (rc || (pSMBr->ByteCount < 2))
2780 /* BB also check enough total bytes returned */
2781 rc = -EIO; /* bad smb */
2782 else {
2783 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2784 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2785 rc = cifs_copy_posix_acl(acl_inf,
2786 (char *)&pSMBr->hdr.Protocol+data_offset,
2787 buflen,acl_type,count);
2788 }
2789 }
2790 cifs_buf_release(pSMB);
2791 if (rc == -EAGAIN)
2792 goto queryAclRetry;
2793 return rc;
2794}
2795
2796int
2797CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2798 const unsigned char *fileName,
Steve French737b7582005-04-28 22:41:06 -07002799 const char *local_acl, const int buflen,
2800 const int acl_type,
2801 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802{
2803 struct smb_com_transaction2_spi_req *pSMB = NULL;
2804 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2805 char *parm_data;
2806 int name_len;
2807 int rc = 0;
2808 int bytes_returned = 0;
2809 __u16 params, byte_count, data_count, param_offset, offset;
2810
2811 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2812setAclRetry:
2813 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2814 (void **) &pSMBr);
2815 if (rc)
2816 return rc;
2817 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2818 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002819 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002820 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 name_len++; /* trailing null */
2822 name_len *= 2;
2823 } else { /* BB improve the check for buffer overruns BB */
2824 name_len = strnlen(fileName, PATH_MAX);
2825 name_len++; /* trailing null */
2826 strncpy(pSMB->FileName, fileName, name_len);
2827 }
2828 params = 6 + name_len;
2829 pSMB->MaxParameterCount = cpu_to_le16(2);
2830 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2831 pSMB->MaxSetupCount = 0;
2832 pSMB->Reserved = 0;
2833 pSMB->Flags = 0;
2834 pSMB->Timeout = 0;
2835 pSMB->Reserved2 = 0;
2836 param_offset = offsetof(struct smb_com_transaction2_spi_req,
2837 InformationLevel) - 4;
2838 offset = param_offset + params;
2839 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2840 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2841
2842 /* convert to on the wire format for POSIX ACL */
2843 data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2844
2845 if(data_count == 0) {
2846 rc = -EOPNOTSUPP;
2847 goto setACLerrorExit;
2848 }
2849 pSMB->DataOffset = cpu_to_le16(offset);
2850 pSMB->SetupCount = 1;
2851 pSMB->Reserved3 = 0;
2852 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2853 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2854 byte_count = 3 /* pad */ + params + data_count;
2855 pSMB->DataCount = cpu_to_le16(data_count);
2856 pSMB->TotalDataCount = pSMB->DataCount;
2857 pSMB->ParameterCount = cpu_to_le16(params);
2858 pSMB->TotalParameterCount = pSMB->ParameterCount;
2859 pSMB->Reserved4 = 0;
2860 pSMB->hdr.smb_buf_length += byte_count;
2861 pSMB->ByteCount = cpu_to_le16(byte_count);
2862 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2863 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2864 if (rc) {
2865 cFYI(1, ("Set POSIX ACL returned %d", rc));
2866 }
2867
2868setACLerrorExit:
2869 cifs_buf_release(pSMB);
2870 if (rc == -EAGAIN)
2871 goto setAclRetry;
2872 return rc;
2873}
2874
Steve Frenchf654bac2005-04-28 22:41:04 -07002875/* BB fix tabs in this function FIXME BB */
2876int
2877CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2878 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2879{
2880 int rc = 0;
2881 struct smb_t2_qfi_req *pSMB = NULL;
2882 struct smb_t2_qfi_rsp *pSMBr = NULL;
2883 int bytes_returned;
2884 __u16 params, byte_count;
2885
2886 cFYI(1,("In GetExtAttr"));
2887 if(tcon == NULL)
2888 return -ENODEV;
2889
2890GetExtAttrRetry:
2891 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2892 (void **) &pSMBr);
2893 if (rc)
2894 return rc;
2895
Steve Frenchc67593a2005-04-28 22:41:04 -07002896 params = 2 /* level */ +2 /* fid */;
Steve Frenchf654bac2005-04-28 22:41:04 -07002897 pSMB->t2.TotalDataCount = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002898 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002899 /* BB find exact max data count below from sess structure BB */
2900 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2901 pSMB->t2.MaxSetupCount = 0;
2902 pSMB->t2.Reserved = 0;
2903 pSMB->t2.Flags = 0;
2904 pSMB->t2.Timeout = 0;
2905 pSMB->t2.Reserved2 = 0;
Steve Frenchc67593a2005-04-28 22:41:04 -07002906 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2907 Fid) - 4);
Steve Frenchf654bac2005-04-28 22:41:04 -07002908 pSMB->t2.DataCount = 0;
2909 pSMB->t2.DataOffset = 0;
2910 pSMB->t2.SetupCount = 1;
2911 pSMB->t2.Reserved3 = 0;
2912 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
Steve Frenchc67593a2005-04-28 22:41:04 -07002913 byte_count = params + 1 /* pad */ ;
Steve Frenchf654bac2005-04-28 22:41:04 -07002914 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2915 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2916 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
Steve Frenchc67593a2005-04-28 22:41:04 -07002917 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002918 pSMB->Fid = netfid;
2919 pSMB->hdr.smb_buf_length += byte_count;
2920 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2921
2922 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2923 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2924 if (rc) {
2925 cFYI(1, ("error %d in GetExtAttr", rc));
2926 } else {
2927 /* decode response */
2928 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2929 if (rc || (pSMBr->ByteCount < 2))
2930 /* BB also check enough total bytes returned */
2931 /* If rc should we check for EOPNOSUPP and
2932 disable the srvino flag? or in caller? */
2933 rc = -EIO; /* bad smb */
2934 else {
2935 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2936 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2937 struct file_chattr_info * pfinfo;
2938 /* BB Do we need a cast or hash here ? */
2939 if(count != 16) {
2940 cFYI(1, ("Illegal size ret in GetExtAttr"));
2941 rc = -EIO;
2942 goto GetExtAttrOut;
2943 }
2944 pfinfo = (struct file_chattr_info *)
2945 (data_offset + (char *) &pSMBr->hdr.Protocol);
2946 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2947 *pMask = le64_to_cpu(pfinfo->mask);
2948 }
2949 }
2950GetExtAttrOut:
2951 cifs_buf_release(pSMB);
2952 if (rc == -EAGAIN)
2953 goto GetExtAttrRetry;
2954 return rc;
2955}
2956
2957
2958#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959
Steve Frencheeac8042006-01-13 21:34:58 -08002960
2961/* security id for everyone */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01002962static const struct cifs_sid sid_everyone =
Steve French2cd646a2006-09-28 19:43:08 +00002963 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002964/* group users */
Tobias Klauserc5a69d52007-02-17 20:11:19 +01002965static const struct cifs_sid sid_user =
Steve French2cd646a2006-09-28 19:43:08 +00002966 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
Steve Frencheeac8042006-01-13 21:34:58 -08002967
Steve French0a4b92c2006-01-12 15:44:21 -08002968/* Convert CIFS ACL to POSIX form */
Steve Frencheeac8042006-01-13 21:34:58 -08002969static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
Steve French0a4b92c2006-01-12 15:44:21 -08002970{
Steve French0a4b92c2006-01-12 15:44:21 -08002971 return 0;
2972}
2973
2974/* Get Security Descriptor (by handle) from remote server for a file or dir */
2975int
2976CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2977 /* BB fix up return info */ char *acl_inf, const int buflen,
2978 const int acl_type /* ACCESS/DEFAULT not sure implication */)
2979{
2980 int rc = 0;
2981 int buf_type = 0;
2982 QUERY_SEC_DESC_REQ * pSMB;
2983 struct kvec iov[1];
2984
2985 cFYI(1, ("GetCifsACL"));
2986
2987 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
2988 8 /* parm len */, tcon, (void **) &pSMB);
2989 if (rc)
2990 return rc;
2991
2992 pSMB->MaxParameterCount = cpu_to_le32(4);
2993 /* BB TEST with big acls that might need to be e.g. larger than 16K */
2994 pSMB->MaxSetupCount = 0;
2995 pSMB->Fid = fid; /* file handle always le */
2996 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2997 CIFS_ACL_DACL);
2998 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2999 pSMB->hdr.smb_buf_length += 11;
3000 iov[0].iov_base = (char *)pSMB;
3001 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3002
3003 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
3004 cifs_stats_inc(&tcon->num_acl_get);
3005 if (rc) {
3006 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3007 } else { /* decode response */
Steve Frenchd41f0842006-01-17 19:16:53 -08003008 struct cifs_sid * psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08003009 __le32 * parm;
3010 int parm_len;
3011 int data_len;
3012 int acl_len;
3013 struct smb_com_ntransact_rsp * pSMBr;
3014
3015/* validate_nttransact */
3016 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
3017 (char **)&psec_desc,
3018 &parm_len, &data_len);
3019
3020 if(rc)
3021 goto qsec_out;
3022 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3023
3024 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
3025
3026 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3027 rc = -EIO; /* bad smb */
3028 goto qsec_out;
3029 }
3030
3031/* BB check that data area is minimum length and as big as acl_len */
3032
3033 acl_len = le32_to_cpu(*(__le32 *)parm);
3034 /* BB check if(acl_len > bufsize) */
3035
3036 parse_sec_desc(psec_desc, acl_len);
3037 }
3038qsec_out:
3039 if(buf_type == CIFS_SMALL_BUFFER)
3040 cifs_small_buf_release(iov[0].iov_base);
3041 else if(buf_type == CIFS_LARGE_BUFFER)
3042 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003043/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003044 return rc;
3045}
3046
Steve French6b8edfe2005-08-23 20:26:03 -07003047/* Legacy Query Path Information call for lookup to old servers such
3048 as Win9x/WinME */
3049int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
3050 const unsigned char *searchName,
3051 FILE_ALL_INFO * pFinfo,
3052 const struct nls_table *nls_codepage, int remap)
3053{
3054 QUERY_INFORMATION_REQ * pSMB;
3055 QUERY_INFORMATION_RSP * pSMBr;
3056 int rc = 0;
3057 int bytes_returned;
3058 int name_len;
3059
3060 cFYI(1, ("In SMBQPath path %s", searchName));
3061QInfRetry:
3062 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
3063 (void **) &pSMBr);
3064 if (rc)
3065 return rc;
3066
3067 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3068 name_len =
3069 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3070 PATH_MAX, nls_codepage, remap);
3071 name_len++; /* trailing null */
3072 name_len *= 2;
3073 } else {
3074 name_len = strnlen(searchName, PATH_MAX);
3075 name_len++; /* trailing null */
3076 strncpy(pSMB->FileName, searchName, name_len);
3077 }
3078 pSMB->BufferFormat = 0x04;
3079 name_len++; /* account for buffer type byte */
3080 pSMB->hdr.smb_buf_length += (__u16) name_len;
3081 pSMB->ByteCount = cpu_to_le16(name_len);
3082
3083 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3084 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3085 if (rc) {
3086 cFYI(1, ("Send error in QueryInfo = %d", rc));
3087 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003088 struct timespec ts;
3089 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3090 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003091 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003092 ts.tv_nsec = 0;
3093 ts.tv_sec = time;
3094 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003095 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003096 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3097 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003098 pFinfo->AllocationSize =
3099 cpu_to_le64(le32_to_cpu(pSMBr->size));
3100 pFinfo->EndOfFile = pFinfo->AllocationSize;
3101 pFinfo->Attributes =
3102 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003103 } else
3104 rc = -EIO; /* bad buffer passed in */
3105
3106 cifs_buf_release(pSMB);
3107
3108 if (rc == -EAGAIN)
3109 goto QInfRetry;
3110
3111 return rc;
3112}
3113
3114
3115
3116
Linus Torvalds1da177e2005-04-16 15:20:36 -07003117int
3118CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3119 const unsigned char *searchName,
3120 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003121 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003122 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123{
3124/* level 263 SMB_QUERY_FILE_ALL_INFO */
3125 TRANSACTION2_QPI_REQ *pSMB = NULL;
3126 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3127 int rc = 0;
3128 int bytes_returned;
3129 int name_len;
3130 __u16 params, byte_count;
3131
3132/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3133QPathInfoRetry:
3134 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3135 (void **) &pSMBr);
3136 if (rc)
3137 return rc;
3138
3139 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3140 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003141 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003142 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003143 name_len++; /* trailing null */
3144 name_len *= 2;
3145 } else { /* BB improve the check for buffer overruns BB */
3146 name_len = strnlen(searchName, PATH_MAX);
3147 name_len++; /* trailing null */
3148 strncpy(pSMB->FileName, searchName, name_len);
3149 }
3150
3151 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3152 pSMB->TotalDataCount = 0;
3153 pSMB->MaxParameterCount = cpu_to_le16(2);
3154 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3155 pSMB->MaxSetupCount = 0;
3156 pSMB->Reserved = 0;
3157 pSMB->Flags = 0;
3158 pSMB->Timeout = 0;
3159 pSMB->Reserved2 = 0;
3160 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3161 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3162 pSMB->DataCount = 0;
3163 pSMB->DataOffset = 0;
3164 pSMB->SetupCount = 1;
3165 pSMB->Reserved3 = 0;
3166 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3167 byte_count = params + 1 /* pad */ ;
3168 pSMB->TotalParameterCount = cpu_to_le16(params);
3169 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003170 if(legacy)
3171 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3172 else
3173 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174 pSMB->Reserved4 = 0;
3175 pSMB->hdr.smb_buf_length += byte_count;
3176 pSMB->ByteCount = cpu_to_le16(byte_count);
3177
3178 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3179 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3180 if (rc) {
3181 cFYI(1, ("Send error in QPathInfo = %d", rc));
3182 } else { /* decode response */
3183 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3184
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003185 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3186 rc = -EIO;
3187 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 rc = -EIO; /* bad smb */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003189 else if(legacy && (pSMBr->ByteCount < 24))
3190 rc = -EIO; /* 24 or 26 expected but we do not read last field */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 else if (pFindData){
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003192 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003193 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003194 if(legacy) /* we do not read the last field, EAsize, fortunately
3195 since it varies by subdialect and on Set vs. Get, is
3196 two bytes or 4 bytes depending but we don't care here */
3197 size = sizeof(FILE_INFO_STANDARD);
3198 else
3199 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 memcpy((char *) pFindData,
3201 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003202 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203 } else
3204 rc = -ENOMEM;
3205 }
3206 cifs_buf_release(pSMB);
3207 if (rc == -EAGAIN)
3208 goto QPathInfoRetry;
3209
3210 return rc;
3211}
3212
3213int
3214CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3215 const unsigned char *searchName,
3216 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003217 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003218{
3219/* SMB_QUERY_FILE_UNIX_BASIC */
3220 TRANSACTION2_QPI_REQ *pSMB = NULL;
3221 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3222 int rc = 0;
3223 int bytes_returned = 0;
3224 int name_len;
3225 __u16 params, byte_count;
3226
3227 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3228UnixQPathInfoRetry:
3229 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3230 (void **) &pSMBr);
3231 if (rc)
3232 return rc;
3233
3234 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3235 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003236 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003237 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 name_len++; /* trailing null */
3239 name_len *= 2;
3240 } else { /* BB improve the check for buffer overruns BB */
3241 name_len = strnlen(searchName, PATH_MAX);
3242 name_len++; /* trailing null */
3243 strncpy(pSMB->FileName, searchName, name_len);
3244 }
3245
3246 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3247 pSMB->TotalDataCount = 0;
3248 pSMB->MaxParameterCount = cpu_to_le16(2);
3249 /* BB find exact max SMB PDU from sess structure BB */
3250 pSMB->MaxDataCount = cpu_to_le16(4000);
3251 pSMB->MaxSetupCount = 0;
3252 pSMB->Reserved = 0;
3253 pSMB->Flags = 0;
3254 pSMB->Timeout = 0;
3255 pSMB->Reserved2 = 0;
3256 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3257 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3258 pSMB->DataCount = 0;
3259 pSMB->DataOffset = 0;
3260 pSMB->SetupCount = 1;
3261 pSMB->Reserved3 = 0;
3262 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3263 byte_count = params + 1 /* pad */ ;
3264 pSMB->TotalParameterCount = cpu_to_le16(params);
3265 pSMB->ParameterCount = pSMB->TotalParameterCount;
3266 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3267 pSMB->Reserved4 = 0;
3268 pSMB->hdr.smb_buf_length += byte_count;
3269 pSMB->ByteCount = cpu_to_le16(byte_count);
3270
3271 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3272 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3273 if (rc) {
3274 cFYI(1, ("Send error in QPathInfo = %d", rc));
3275 } else { /* decode response */
3276 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3277
3278 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
3279 rc = -EIO; /* bad smb */
3280 } else {
3281 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3282 memcpy((char *) pFindData,
3283 (char *) &pSMBr->hdr.Protocol +
3284 data_offset,
3285 sizeof (FILE_UNIX_BASIC_INFO));
3286 }
3287 }
3288 cifs_buf_release(pSMB);
3289 if (rc == -EAGAIN)
3290 goto UnixQPathInfoRetry;
3291
3292 return rc;
3293}
3294
3295#if 0 /* function unused at present */
3296int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3297 const char *searchName, FILE_ALL_INFO * findData,
3298 const struct nls_table *nls_codepage)
3299{
3300/* level 257 SMB_ */
3301 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3302 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3303 int rc = 0;
3304 int bytes_returned;
3305 int name_len;
3306 __u16 params, byte_count;
3307
3308 cFYI(1, ("In FindUnique"));
3309findUniqueRetry:
3310 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3311 (void **) &pSMBr);
3312 if (rc)
3313 return rc;
3314
3315 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3316 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003317 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318 /* find define for this maxpathcomponent */
3319 , nls_codepage);
3320 name_len++; /* trailing null */
3321 name_len *= 2;
3322 } else { /* BB improve the check for buffer overruns BB */
3323 name_len = strnlen(searchName, PATH_MAX);
3324 name_len++; /* trailing null */
3325 strncpy(pSMB->FileName, searchName, name_len);
3326 }
3327
3328 params = 12 + name_len /* includes null */ ;
3329 pSMB->TotalDataCount = 0; /* no EAs */
3330 pSMB->MaxParameterCount = cpu_to_le16(2);
3331 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3332 pSMB->MaxSetupCount = 0;
3333 pSMB->Reserved = 0;
3334 pSMB->Flags = 0;
3335 pSMB->Timeout = 0;
3336 pSMB->Reserved2 = 0;
3337 pSMB->ParameterOffset = cpu_to_le16(
3338 offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
3339 pSMB->DataCount = 0;
3340 pSMB->DataOffset = 0;
3341 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3342 pSMB->Reserved3 = 0;
3343 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3344 byte_count = params + 1 /* pad */ ;
3345 pSMB->TotalParameterCount = cpu_to_le16(params);
3346 pSMB->ParameterCount = pSMB->TotalParameterCount;
3347 pSMB->SearchAttributes =
3348 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3349 ATTR_DIRECTORY);
3350 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3351 pSMB->SearchFlags = cpu_to_le16(1);
3352 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3353 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3354 pSMB->hdr.smb_buf_length += byte_count;
3355 pSMB->ByteCount = cpu_to_le16(byte_count);
3356
3357 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3358 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3359
3360 if (rc) {
3361 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3362 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003363 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 /* BB fill in */
3365 }
3366
3367 cifs_buf_release(pSMB);
3368 if (rc == -EAGAIN)
3369 goto findUniqueRetry;
3370
3371 return rc;
3372}
3373#endif /* end unused (temporarily) function */
3374
3375/* xid, tcon, searchName and codepage are input parms, rest are returned */
3376int
3377CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
3378 const char *searchName,
3379 const struct nls_table *nls_codepage,
3380 __u16 * pnetfid,
Jeremy Allisonac670552005-06-22 17:26:35 -07003381 struct cifs_search_info * psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382{
3383/* level 257 SMB_ */
3384 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3385 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3386 T2_FFIRST_RSP_PARMS * parms;
3387 int rc = 0;
3388 int bytes_returned = 0;
3389 int name_len;
3390 __u16 params, byte_count;
3391
Steve French737b7582005-04-28 22:41:06 -07003392 cFYI(1, ("In FindFirst for %s",searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003393
3394findFirstRetry:
3395 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3396 (void **) &pSMBr);
3397 if (rc)
3398 return rc;
3399
3400 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3401 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003402 cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
Steve French737b7582005-04-28 22:41:06 -07003403 PATH_MAX, nls_codepage, remap);
3404 /* We can not add the asterik earlier in case
3405 it got remapped to 0xF03A as if it were part of the
3406 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003407 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003408 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003409 pSMB->FileName[name_len+1] = 0;
3410 pSMB->FileName[name_len+2] = '*';
3411 pSMB->FileName[name_len+3] = 0;
3412 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3414 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003415 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 } else { /* BB add check for overrun of SMB buf BB */
3417 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418/* BB fix here and in unicode clause above ie
3419 if(name_len > buffersize-header)
3420 free buffer exit; BB */
3421 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003422 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003423 pSMB->FileName[name_len+1] = '*';
3424 pSMB->FileName[name_len+2] = 0;
3425 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 }
3427
3428 params = 12 + name_len /* includes null */ ;
3429 pSMB->TotalDataCount = 0; /* no EAs */
3430 pSMB->MaxParameterCount = cpu_to_le16(10);
3431 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3432 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3433 pSMB->MaxSetupCount = 0;
3434 pSMB->Reserved = 0;
3435 pSMB->Flags = 0;
3436 pSMB->Timeout = 0;
3437 pSMB->Reserved2 = 0;
3438 byte_count = params + 1 /* pad */ ;
3439 pSMB->TotalParameterCount = cpu_to_le16(params);
3440 pSMB->ParameterCount = pSMB->TotalParameterCount;
3441 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003442 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3443 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 pSMB->DataCount = 0;
3445 pSMB->DataOffset = 0;
3446 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3447 pSMB->Reserved3 = 0;
3448 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3449 pSMB->SearchAttributes =
3450 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3451 ATTR_DIRECTORY);
3452 pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3453 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
3454 CIFS_SEARCH_RETURN_RESUME);
3455 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3456
3457 /* BB what should we set StorageType to? Does it matter? BB */
3458 pSMB->SearchStorageType = 0;
3459 pSMB->hdr.smb_buf_length += byte_count;
3460 pSMB->ByteCount = cpu_to_le16(byte_count);
3461
3462 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3463 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003464 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465
Steve French88274812006-03-09 22:21:45 +00003466 if (rc) {/* BB add logic to retry regular search if Unix search
3467 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 /* BB Add code to handle unsupported level rc */
3469 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003470
Steve French88274812006-03-09 22:21:45 +00003471 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472
3473 /* BB eventually could optimize out free and realloc of buf */
3474 /* for this case */
3475 if (rc == -EAGAIN)
3476 goto findFirstRetry;
3477 } else { /* decode response */
3478 /* BB remember to free buffer if error BB */
3479 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3480 if(rc == 0) {
3481 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3482 psrch_inf->unicode = TRUE;
3483 else
3484 psrch_inf->unicode = FALSE;
3485
3486 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003487 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003488 psrch_inf->srch_entries_start =
3489 (char *) &pSMBr->hdr.Protocol +
3490 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3492 le16_to_cpu(pSMBr->t2.ParameterOffset));
3493
3494 if(parms->EndofSearch)
3495 psrch_inf->endOfSearch = TRUE;
3496 else
3497 psrch_inf->endOfSearch = FALSE;
3498
3499 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003500 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 *pnetfid = parms->SearchHandle;
3503 } else {
3504 cifs_buf_release(pSMB);
3505 }
3506 }
3507
3508 return rc;
3509}
3510
3511int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3512 __u16 searchHandle, struct cifs_search_info * psrch_inf)
3513{
3514 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3515 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3516 T2_FNEXT_RSP_PARMS * parms;
3517 char *response_data;
3518 int rc = 0;
3519 int bytes_returned, name_len;
3520 __u16 params, byte_count;
3521
3522 cFYI(1, ("In FindNext"));
3523
3524 if(psrch_inf->endOfSearch == TRUE)
3525 return -ENOENT;
3526
3527 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3528 (void **) &pSMBr);
3529 if (rc)
3530 return rc;
3531
3532 params = 14; /* includes 2 bytes of null string, converted to LE below */
3533 byte_count = 0;
3534 pSMB->TotalDataCount = 0; /* no EAs */
3535 pSMB->MaxParameterCount = cpu_to_le16(8);
3536 pSMB->MaxDataCount =
3537 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3538 pSMB->MaxSetupCount = 0;
3539 pSMB->Reserved = 0;
3540 pSMB->Flags = 0;
3541 pSMB->Timeout = 0;
3542 pSMB->Reserved2 = 0;
3543 pSMB->ParameterOffset = cpu_to_le16(
3544 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3545 pSMB->DataCount = 0;
3546 pSMB->DataOffset = 0;
3547 pSMB->SetupCount = 1;
3548 pSMB->Reserved3 = 0;
3549 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3550 pSMB->SearchHandle = searchHandle; /* always kept as le */
3551 pSMB->SearchCount =
3552 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3553 /* test for Unix extensions */
3554/* if (tcon->ses->capabilities & CAP_UNIX) {
3555 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3556 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3557 } else {
3558 pSMB->InformationLevel =
3559 cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3560 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3561 } */
3562 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3563 pSMB->ResumeKey = psrch_inf->resume_key;
3564 pSMB->SearchFlags =
3565 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3566
3567 name_len = psrch_inf->resume_name_len;
3568 params += name_len;
3569 if(name_len < PATH_MAX) {
3570 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3571 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003572 /* 14 byte parm len above enough for 2 byte null terminator */
3573 pSMB->ResumeFileName[name_len] = 0;
3574 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003575 } else {
3576 rc = -EINVAL;
3577 goto FNext2_err_exit;
3578 }
3579 byte_count = params + 1 /* pad */ ;
3580 pSMB->TotalParameterCount = cpu_to_le16(params);
3581 pSMB->ParameterCount = pSMB->TotalParameterCount;
3582 pSMB->hdr.smb_buf_length += byte_count;
3583 pSMB->ByteCount = cpu_to_le16(byte_count);
3584
3585 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3586 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003587 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 if (rc) {
3589 if (rc == -EBADF) {
3590 psrch_inf->endOfSearch = TRUE;
3591 rc = 0; /* search probably was closed at end of search above */
3592 } else
3593 cFYI(1, ("FindNext returned = %d", rc));
3594 } else { /* decode response */
3595 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3596
3597 if(rc == 0) {
3598 /* BB fixme add lock for file (srch_info) struct here */
3599 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3600 psrch_inf->unicode = TRUE;
3601 else
3602 psrch_inf->unicode = FALSE;
3603 response_data = (char *) &pSMBr->hdr.Protocol +
3604 le16_to_cpu(pSMBr->t2.ParameterOffset);
3605 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3606 response_data = (char *)&pSMBr->hdr.Protocol +
3607 le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchd47d7c12006-02-28 03:45:48 +00003608 if(psrch_inf->smallBuf)
3609 cifs_small_buf_release(
3610 psrch_inf->ntwrk_buf_start);
3611 else
3612 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 psrch_inf->srch_entries_start = response_data;
3614 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003615 psrch_inf->smallBuf = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 if(parms->EndofSearch)
3617 psrch_inf->endOfSearch = TRUE;
3618 else
3619 psrch_inf->endOfSearch = FALSE;
3620
3621 psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
3622 psrch_inf->index_of_last_entry +=
3623 psrch_inf->entries_in_buffer;
3624/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3625
3626 /* BB fixme add unlock here */
3627 }
3628
3629 }
3630
3631 /* BB On error, should we leave previous search buf (and count and
3632 last entry fields) intact or free the previous one? */
3633
3634 /* Note: On -EAGAIN error only caller can retry on handle based calls
3635 since file handle passed in no longer valid */
3636FNext2_err_exit:
3637 if (rc != 0)
3638 cifs_buf_release(pSMB);
3639
3640 return rc;
3641}
3642
3643int
3644CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3645{
3646 int rc = 0;
3647 FINDCLOSE_REQ *pSMB = NULL;
3648 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3649 int bytes_returned;
3650
3651 cFYI(1, ("In CIFSSMBFindClose"));
3652 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3653
3654 /* no sense returning error if session restarted
3655 as file handle has been closed */
3656 if(rc == -EAGAIN)
3657 return 0;
3658 if (rc)
3659 return rc;
3660
3661 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3662 pSMB->FileID = searchHandle;
3663 pSMB->ByteCount = 0;
3664 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3665 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3666 if (rc) {
3667 cERROR(1, ("Send error in FindClose = %d", rc));
3668 }
Steve Frencha4544342005-08-24 13:59:35 -07003669 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003670 cifs_small_buf_release(pSMB);
3671
3672 /* Since session is dead, search handle closed on server already */
3673 if (rc == -EAGAIN)
3674 rc = 0;
3675
3676 return rc;
3677}
3678
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679int
3680CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3681 const unsigned char *searchName,
3682 __u64 * inode_number,
Steve French737b7582005-04-28 22:41:06 -07003683 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003684{
3685 int rc = 0;
3686 TRANSACTION2_QPI_REQ *pSMB = NULL;
3687 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3688 int name_len, bytes_returned;
3689 __u16 params, byte_count;
3690
3691 cFYI(1,("In GetSrvInodeNum for %s",searchName));
3692 if(tcon == NULL)
3693 return -ENODEV;
3694
3695GetInodeNumberRetry:
3696 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3697 (void **) &pSMBr);
3698 if (rc)
3699 return rc;
3700
3701
3702 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3703 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003704 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003705 PATH_MAX,nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 name_len++; /* trailing null */
3707 name_len *= 2;
3708 } else { /* BB improve the check for buffer overruns BB */
3709 name_len = strnlen(searchName, PATH_MAX);
3710 name_len++; /* trailing null */
3711 strncpy(pSMB->FileName, searchName, name_len);
3712 }
3713
3714 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3715 pSMB->TotalDataCount = 0;
3716 pSMB->MaxParameterCount = cpu_to_le16(2);
3717 /* BB find exact max data count below from sess structure BB */
3718 pSMB->MaxDataCount = cpu_to_le16(4000);
3719 pSMB->MaxSetupCount = 0;
3720 pSMB->Reserved = 0;
3721 pSMB->Flags = 0;
3722 pSMB->Timeout = 0;
3723 pSMB->Reserved2 = 0;
3724 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3725 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3726 pSMB->DataCount = 0;
3727 pSMB->DataOffset = 0;
3728 pSMB->SetupCount = 1;
3729 pSMB->Reserved3 = 0;
3730 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3731 byte_count = params + 1 /* pad */ ;
3732 pSMB->TotalParameterCount = cpu_to_le16(params);
3733 pSMB->ParameterCount = pSMB->TotalParameterCount;
3734 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3735 pSMB->Reserved4 = 0;
3736 pSMB->hdr.smb_buf_length += byte_count;
3737 pSMB->ByteCount = cpu_to_le16(byte_count);
3738
3739 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3740 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3741 if (rc) {
3742 cFYI(1, ("error %d in QueryInternalInfo", rc));
3743 } else {
3744 /* decode response */
3745 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3746 if (rc || (pSMBr->ByteCount < 2))
3747 /* BB also check enough total bytes returned */
3748 /* If rc should we check for EOPNOSUPP and
3749 disable the srvino flag? or in caller? */
3750 rc = -EIO; /* bad smb */
3751 else {
3752 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3753 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3754 struct file_internal_info * pfinfo;
3755 /* BB Do we need a cast or hash here ? */
3756 if(count < 8) {
3757 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3758 rc = -EIO;
3759 goto GetInodeNumOut;
3760 }
3761 pfinfo = (struct file_internal_info *)
3762 (data_offset + (char *) &pSMBr->hdr.Protocol);
3763 *inode_number = pfinfo->UniqueId;
3764 }
3765 }
3766GetInodeNumOut:
3767 cifs_buf_release(pSMB);
3768 if (rc == -EAGAIN)
3769 goto GetInodeNumberRetry;
3770 return rc;
3771}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003772
3773int
3774CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3775 const unsigned char *searchName,
3776 unsigned char **targetUNCs,
3777 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003778 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779{
3780/* TRANS2_GET_DFS_REFERRAL */
3781 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3782 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3783 struct dfs_referral_level_3 * referrals = NULL;
3784 int rc = 0;
3785 int bytes_returned;
3786 int name_len;
3787 unsigned int i;
3788 char * temp;
3789 __u16 params, byte_count;
3790 *number_of_UNC_in_array = 0;
3791 *targetUNCs = NULL;
3792
3793 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3794 if (ses == NULL)
3795 return -ENODEV;
3796getDFSRetry:
3797 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3798 (void **) &pSMBr);
3799 if (rc)
3800 return rc;
Steve French1982c342005-08-17 12:38:22 -07003801
3802 /* server pointer checked in called function,
3803 but should never be null here anyway */
3804 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003805 pSMB->hdr.Tid = ses->ipc_tid;
3806 pSMB->hdr.Uid = ses->Suid;
3807 if (ses->capabilities & CAP_STATUS32) {
3808 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3809 }
3810 if (ses->capabilities & CAP_DFS) {
3811 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3812 }
3813
3814 if (ses->capabilities & CAP_UNICODE) {
3815 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3816 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003817 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003818 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 name_len++; /* trailing null */
3820 name_len *= 2;
3821 } else { /* BB improve the check for buffer overruns BB */
3822 name_len = strnlen(searchName, PATH_MAX);
3823 name_len++; /* trailing null */
3824 strncpy(pSMB->RequestFileName, searchName, name_len);
3825 }
3826
Steve French1a4e15a2006-10-12 21:33:51 +00003827 if(ses->server) {
3828 if(ses->server->secMode &
3829 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3830 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3831 }
3832
3833 pSMB->hdr.Uid = ses->Suid;
3834
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 params = 2 /* level */ + name_len /*includes null */ ;
3836 pSMB->TotalDataCount = 0;
3837 pSMB->DataCount = 0;
3838 pSMB->DataOffset = 0;
3839 pSMB->MaxParameterCount = 0;
3840 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3841 pSMB->MaxSetupCount = 0;
3842 pSMB->Reserved = 0;
3843 pSMB->Flags = 0;
3844 pSMB->Timeout = 0;
3845 pSMB->Reserved2 = 0;
3846 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3847 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3848 pSMB->SetupCount = 1;
3849 pSMB->Reserved3 = 0;
3850 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3851 byte_count = params + 3 /* pad */ ;
3852 pSMB->ParameterCount = cpu_to_le16(params);
3853 pSMB->TotalParameterCount = pSMB->ParameterCount;
3854 pSMB->MaxReferralLevel = cpu_to_le16(3);
3855 pSMB->hdr.smb_buf_length += byte_count;
3856 pSMB->ByteCount = cpu_to_le16(byte_count);
3857
3858 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3859 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3860 if (rc) {
3861 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3862 } else { /* decode response */
3863/* BB Add logic to parse referrals here */
3864 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3865
3866 if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
3867 rc = -EIO; /* bad smb */
3868 else {
3869 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3870 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3871
3872 cFYI(1,
3873 ("Decoding GetDFSRefer response. BCC: %d Offset %d",
3874 pSMBr->ByteCount, data_offset));
3875 referrals =
3876 (struct dfs_referral_level_3 *)
3877 (8 /* sizeof start of data block */ +
3878 data_offset +
3879 (char *) &pSMBr->hdr.Protocol);
3880 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",
3881 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)));
3882 /* BB This field is actually two bytes in from start of
3883 data block so we could do safety check that DataBlock
3884 begins at address of pSMBr->NumberOfReferrals */
3885 *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3886
3887 /* BB Fix below so can return more than one referral */
3888 if(*number_of_UNC_in_array > 1)
3889 *number_of_UNC_in_array = 1;
3890
3891 /* get the length of the strings describing refs */
3892 name_len = 0;
3893 for(i=0;i<*number_of_UNC_in_array;i++) {
3894 /* make sure that DfsPathOffset not past end */
3895 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3896 if (offset > data_count) {
3897 /* if invalid referral, stop here and do
3898 not try to copy any more */
3899 *number_of_UNC_in_array = i;
3900 break;
3901 }
3902 temp = ((char *)referrals) + offset;
3903
3904 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3905 name_len += UniStrnlen((wchar_t *)temp,data_count);
3906 } else {
3907 name_len += strnlen(temp,data_count);
3908 }
3909 referrals++;
3910 /* BB add check that referral pointer does not fall off end PDU */
3911
3912 }
3913 /* BB add check for name_len bigger than bcc */
3914 *targetUNCs =
3915 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3916 if(*targetUNCs == NULL) {
3917 rc = -ENOMEM;
3918 goto GetDFSRefExit;
3919 }
3920 /* copy the ref strings */
3921 referrals =
3922 (struct dfs_referral_level_3 *)
3923 (8 /* sizeof data hdr */ +
3924 data_offset +
3925 (char *) &pSMBr->hdr.Protocol);
3926
3927 for(i=0;i<*number_of_UNC_in_array;i++) {
3928 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3929 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3930 cifs_strfromUCS_le(*targetUNCs,
Steve Frenche89dc922005-11-11 15:18:19 -08003931 (__le16 *) temp, name_len, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003932 } else {
3933 strncpy(*targetUNCs,temp,name_len);
3934 }
3935 /* BB update target_uncs pointers */
3936 referrals++;
3937 }
3938 temp = *targetUNCs;
3939 temp[name_len] = 0;
3940 }
3941
3942 }
3943GetDFSRefExit:
3944 if (pSMB)
3945 cifs_buf_release(pSMB);
3946
3947 if (rc == -EAGAIN)
3948 goto getDFSRetry;
3949
3950 return rc;
3951}
3952
Steve French20962432005-09-21 22:05:57 -07003953/* Query File System Info such as free space to old servers such as Win 9x */
3954int
3955SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3956{
3957/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3958 TRANSACTION2_QFSI_REQ *pSMB = NULL;
3959 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3960 FILE_SYSTEM_ALLOC_INFO *response_data;
3961 int rc = 0;
3962 int bytes_returned = 0;
3963 __u16 params, byte_count;
3964
3965 cFYI(1, ("OldQFSInfo"));
3966oldQFSInfoRetry:
3967 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3968 (void **) &pSMBr);
3969 if (rc)
3970 return rc;
3971 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3972 (void **) &pSMBr);
3973 if (rc)
3974 return rc;
3975
3976 params = 2; /* level */
3977 pSMB->TotalDataCount = 0;
3978 pSMB->MaxParameterCount = cpu_to_le16(2);
3979 pSMB->MaxDataCount = cpu_to_le16(1000);
3980 pSMB->MaxSetupCount = 0;
3981 pSMB->Reserved = 0;
3982 pSMB->Flags = 0;
3983 pSMB->Timeout = 0;
3984 pSMB->Reserved2 = 0;
3985 byte_count = params + 1 /* pad */ ;
3986 pSMB->TotalParameterCount = cpu_to_le16(params);
3987 pSMB->ParameterCount = pSMB->TotalParameterCount;
3988 pSMB->ParameterOffset = cpu_to_le16(offsetof(
3989 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3990 pSMB->DataCount = 0;
3991 pSMB->DataOffset = 0;
3992 pSMB->SetupCount = 1;
3993 pSMB->Reserved3 = 0;
3994 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3995 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3996 pSMB->hdr.smb_buf_length += byte_count;
3997 pSMB->ByteCount = cpu_to_le16(byte_count);
3998
3999 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4000 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4001 if (rc) {
4002 cFYI(1, ("Send error in QFSInfo = %d", rc));
4003 } else { /* decode response */
4004 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4005
4006 if (rc || (pSMBr->ByteCount < 18))
4007 rc = -EIO; /* bad smb */
4008 else {
4009 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4010 cFYI(1,("qfsinf resp BCC: %d Offset %d",
4011 pSMBr->ByteCount, data_offset));
4012
4013 response_data =
4014 (FILE_SYSTEM_ALLOC_INFO *)
4015 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4016 FSData->f_bsize =
4017 le16_to_cpu(response_data->BytesPerSector) *
4018 le32_to_cpu(response_data->
4019 SectorsPerAllocationUnit);
4020 FSData->f_blocks =
4021 le32_to_cpu(response_data->TotalAllocationUnits);
4022 FSData->f_bfree = FSData->f_bavail =
4023 le32_to_cpu(response_data->FreeAllocationUnits);
4024 cFYI(1,
4025 ("Blocks: %lld Free: %lld Block size %ld",
4026 (unsigned long long)FSData->f_blocks,
4027 (unsigned long long)FSData->f_bfree,
4028 FSData->f_bsize));
4029 }
4030 }
4031 cifs_buf_release(pSMB);
4032
4033 if (rc == -EAGAIN)
4034 goto oldQFSInfoRetry;
4035
4036 return rc;
4037}
4038
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039int
Steve French737b7582005-04-28 22:41:06 -07004040CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041{
4042/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4043 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4044 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4045 FILE_SYSTEM_INFO *response_data;
4046 int rc = 0;
4047 int bytes_returned = 0;
4048 __u16 params, byte_count;
4049
4050 cFYI(1, ("In QFSInfo"));
4051QFSInfoRetry:
4052 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4053 (void **) &pSMBr);
4054 if (rc)
4055 return rc;
4056
4057 params = 2; /* level */
4058 pSMB->TotalDataCount = 0;
4059 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004060 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061 pSMB->MaxSetupCount = 0;
4062 pSMB->Reserved = 0;
4063 pSMB->Flags = 0;
4064 pSMB->Timeout = 0;
4065 pSMB->Reserved2 = 0;
4066 byte_count = params + 1 /* pad */ ;
4067 pSMB->TotalParameterCount = cpu_to_le16(params);
4068 pSMB->ParameterCount = pSMB->TotalParameterCount;
4069 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4070 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4071 pSMB->DataCount = 0;
4072 pSMB->DataOffset = 0;
4073 pSMB->SetupCount = 1;
4074 pSMB->Reserved3 = 0;
4075 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4076 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4077 pSMB->hdr.smb_buf_length += byte_count;
4078 pSMB->ByteCount = cpu_to_le16(byte_count);
4079
4080 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4081 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4082 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004083 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084 } else { /* decode response */
4085 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4086
Steve French20962432005-09-21 22:05:57 -07004087 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088 rc = -EIO; /* bad smb */
4089 else {
4090 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004091
4092 response_data =
4093 (FILE_SYSTEM_INFO
4094 *) (((char *) &pSMBr->hdr.Protocol) +
4095 data_offset);
4096 FSData->f_bsize =
4097 le32_to_cpu(response_data->BytesPerSector) *
4098 le32_to_cpu(response_data->
4099 SectorsPerAllocationUnit);
4100 FSData->f_blocks =
4101 le64_to_cpu(response_data->TotalAllocationUnits);
4102 FSData->f_bfree = FSData->f_bavail =
4103 le64_to_cpu(response_data->FreeAllocationUnits);
4104 cFYI(1,
4105 ("Blocks: %lld Free: %lld Block size %ld",
4106 (unsigned long long)FSData->f_blocks,
4107 (unsigned long long)FSData->f_bfree,
4108 FSData->f_bsize));
4109 }
4110 }
4111 cifs_buf_release(pSMB);
4112
4113 if (rc == -EAGAIN)
4114 goto QFSInfoRetry;
4115
4116 return rc;
4117}
4118
4119int
Steve French737b7582005-04-28 22:41:06 -07004120CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121{
4122/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4123 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4124 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4125 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4126 int rc = 0;
4127 int bytes_returned = 0;
4128 __u16 params, byte_count;
4129
4130 cFYI(1, ("In QFSAttributeInfo"));
4131QFSAttributeRetry:
4132 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4133 (void **) &pSMBr);
4134 if (rc)
4135 return rc;
4136
4137 params = 2; /* level */
4138 pSMB->TotalDataCount = 0;
4139 pSMB->MaxParameterCount = cpu_to_le16(2);
4140 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4141 pSMB->MaxSetupCount = 0;
4142 pSMB->Reserved = 0;
4143 pSMB->Flags = 0;
4144 pSMB->Timeout = 0;
4145 pSMB->Reserved2 = 0;
4146 byte_count = params + 1 /* pad */ ;
4147 pSMB->TotalParameterCount = cpu_to_le16(params);
4148 pSMB->ParameterCount = pSMB->TotalParameterCount;
4149 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4150 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4151 pSMB->DataCount = 0;
4152 pSMB->DataOffset = 0;
4153 pSMB->SetupCount = 1;
4154 pSMB->Reserved3 = 0;
4155 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4156 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4157 pSMB->hdr.smb_buf_length += byte_count;
4158 pSMB->ByteCount = cpu_to_le16(byte_count);
4159
4160 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4161 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4162 if (rc) {
4163 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4164 } else { /* decode response */
4165 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4166
4167 if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
4168 rc = -EIO; /* bad smb */
4169 } else {
4170 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4171 response_data =
4172 (FILE_SYSTEM_ATTRIBUTE_INFO
4173 *) (((char *) &pSMBr->hdr.Protocol) +
4174 data_offset);
4175 memcpy(&tcon->fsAttrInfo, response_data,
4176 sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
4177 }
4178 }
4179 cifs_buf_release(pSMB);
4180
4181 if (rc == -EAGAIN)
4182 goto QFSAttributeRetry;
4183
4184 return rc;
4185}
4186
4187int
Steve French737b7582005-04-28 22:41:06 -07004188CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004189{
4190/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4191 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4192 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4193 FILE_SYSTEM_DEVICE_INFO *response_data;
4194 int rc = 0;
4195 int bytes_returned = 0;
4196 __u16 params, byte_count;
4197
4198 cFYI(1, ("In QFSDeviceInfo"));
4199QFSDeviceRetry:
4200 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4201 (void **) &pSMBr);
4202 if (rc)
4203 return rc;
4204
4205 params = 2; /* level */
4206 pSMB->TotalDataCount = 0;
4207 pSMB->MaxParameterCount = cpu_to_le16(2);
4208 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4209 pSMB->MaxSetupCount = 0;
4210 pSMB->Reserved = 0;
4211 pSMB->Flags = 0;
4212 pSMB->Timeout = 0;
4213 pSMB->Reserved2 = 0;
4214 byte_count = params + 1 /* pad */ ;
4215 pSMB->TotalParameterCount = cpu_to_le16(params);
4216 pSMB->ParameterCount = pSMB->TotalParameterCount;
4217 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4218 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4219
4220 pSMB->DataCount = 0;
4221 pSMB->DataOffset = 0;
4222 pSMB->SetupCount = 1;
4223 pSMB->Reserved3 = 0;
4224 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4225 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4226 pSMB->hdr.smb_buf_length += byte_count;
4227 pSMB->ByteCount = cpu_to_le16(byte_count);
4228
4229 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4230 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4231 if (rc) {
4232 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4233 } else { /* decode response */
4234 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4235
4236 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4237 rc = -EIO; /* bad smb */
4238 else {
4239 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4240 response_data =
Steve French737b7582005-04-28 22:41:06 -07004241 (FILE_SYSTEM_DEVICE_INFO *)
4242 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004243 data_offset);
4244 memcpy(&tcon->fsDevInfo, response_data,
4245 sizeof (FILE_SYSTEM_DEVICE_INFO));
4246 }
4247 }
4248 cifs_buf_release(pSMB);
4249
4250 if (rc == -EAGAIN)
4251 goto QFSDeviceRetry;
4252
4253 return rc;
4254}
4255
4256int
Steve French737b7582005-04-28 22:41:06 -07004257CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258{
4259/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4260 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4261 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4262 FILE_SYSTEM_UNIX_INFO *response_data;
4263 int rc = 0;
4264 int bytes_returned = 0;
4265 __u16 params, byte_count;
4266
4267 cFYI(1, ("In QFSUnixInfo"));
4268QFSUnixRetry:
4269 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4270 (void **) &pSMBr);
4271 if (rc)
4272 return rc;
4273
4274 params = 2; /* level */
4275 pSMB->TotalDataCount = 0;
4276 pSMB->DataCount = 0;
4277 pSMB->DataOffset = 0;
4278 pSMB->MaxParameterCount = cpu_to_le16(2);
4279 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4280 pSMB->MaxSetupCount = 0;
4281 pSMB->Reserved = 0;
4282 pSMB->Flags = 0;
4283 pSMB->Timeout = 0;
4284 pSMB->Reserved2 = 0;
4285 byte_count = params + 1 /* pad */ ;
4286 pSMB->ParameterCount = cpu_to_le16(params);
4287 pSMB->TotalParameterCount = pSMB->ParameterCount;
4288 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4289 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4290 pSMB->SetupCount = 1;
4291 pSMB->Reserved3 = 0;
4292 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4293 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4294 pSMB->hdr.smb_buf_length += byte_count;
4295 pSMB->ByteCount = cpu_to_le16(byte_count);
4296
4297 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4298 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4299 if (rc) {
4300 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4301 } else { /* decode response */
4302 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4303
4304 if (rc || (pSMBr->ByteCount < 13)) {
4305 rc = -EIO; /* bad smb */
4306 } else {
4307 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4308 response_data =
4309 (FILE_SYSTEM_UNIX_INFO
4310 *) (((char *) &pSMBr->hdr.Protocol) +
4311 data_offset);
4312 memcpy(&tcon->fsUnixInfo, response_data,
4313 sizeof (FILE_SYSTEM_UNIX_INFO));
4314 }
4315 }
4316 cifs_buf_release(pSMB);
4317
4318 if (rc == -EAGAIN)
4319 goto QFSUnixRetry;
4320
4321
4322 return rc;
4323}
4324
Jeremy Allisonac670552005-06-22 17:26:35 -07004325int
Steve French45abc6e2005-06-23 13:42:03 -05004326CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004327{
4328/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4329 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4330 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4331 int rc = 0;
4332 int bytes_returned = 0;
4333 __u16 params, param_offset, offset, byte_count;
4334
4335 cFYI(1, ("In SETFSUnixInfo"));
4336SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004337 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004338 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4339 (void **) &pSMBr);
4340 if (rc)
4341 return rc;
4342
4343 params = 4; /* 2 bytes zero followed by info level. */
4344 pSMB->MaxSetupCount = 0;
4345 pSMB->Reserved = 0;
4346 pSMB->Flags = 0;
4347 pSMB->Timeout = 0;
4348 pSMB->Reserved2 = 0;
4349 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
4350 offset = param_offset + params;
4351
4352 pSMB->MaxParameterCount = cpu_to_le16(4);
4353 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4354 pSMB->SetupCount = 1;
4355 pSMB->Reserved3 = 0;
4356 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4357 byte_count = 1 /* pad */ + params + 12;
4358
4359 pSMB->DataCount = cpu_to_le16(12);
4360 pSMB->ParameterCount = cpu_to_le16(params);
4361 pSMB->TotalDataCount = pSMB->DataCount;
4362 pSMB->TotalParameterCount = pSMB->ParameterCount;
4363 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4364 pSMB->DataOffset = cpu_to_le16(offset);
4365
4366 /* Params. */
4367 pSMB->FileNum = 0;
4368 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4369
4370 /* Data. */
4371 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4372 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4373 pSMB->ClientUnixCap = cpu_to_le64(cap);
4374
4375 pSMB->hdr.smb_buf_length += byte_count;
4376 pSMB->ByteCount = cpu_to_le16(byte_count);
4377
4378 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4379 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4380 if (rc) {
4381 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4382 } else { /* decode response */
4383 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4384 if (rc) {
4385 rc = -EIO; /* bad smb */
4386 }
4387 }
4388 cifs_buf_release(pSMB);
4389
4390 if (rc == -EAGAIN)
4391 goto SETFSUnixRetry;
4392
4393 return rc;
4394}
4395
4396
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397
4398int
4399CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004400 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401{
4402/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4403 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4404 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4405 FILE_SYSTEM_POSIX_INFO *response_data;
4406 int rc = 0;
4407 int bytes_returned = 0;
4408 __u16 params, byte_count;
4409
4410 cFYI(1, ("In QFSPosixInfo"));
4411QFSPosixRetry:
4412 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4413 (void **) &pSMBr);
4414 if (rc)
4415 return rc;
4416
4417 params = 2; /* level */
4418 pSMB->TotalDataCount = 0;
4419 pSMB->DataCount = 0;
4420 pSMB->DataOffset = 0;
4421 pSMB->MaxParameterCount = cpu_to_le16(2);
4422 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4423 pSMB->MaxSetupCount = 0;
4424 pSMB->Reserved = 0;
4425 pSMB->Flags = 0;
4426 pSMB->Timeout = 0;
4427 pSMB->Reserved2 = 0;
4428 byte_count = params + 1 /* pad */ ;
4429 pSMB->ParameterCount = cpu_to_le16(params);
4430 pSMB->TotalParameterCount = pSMB->ParameterCount;
4431 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4432 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4433 pSMB->SetupCount = 1;
4434 pSMB->Reserved3 = 0;
4435 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4436 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4437 pSMB->hdr.smb_buf_length += byte_count;
4438 pSMB->ByteCount = cpu_to_le16(byte_count);
4439
4440 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4441 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4442 if (rc) {
4443 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4444 } else { /* decode response */
4445 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4446
4447 if (rc || (pSMBr->ByteCount < 13)) {
4448 rc = -EIO; /* bad smb */
4449 } else {
4450 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4451 response_data =
4452 (FILE_SYSTEM_POSIX_INFO
4453 *) (((char *) &pSMBr->hdr.Protocol) +
4454 data_offset);
4455 FSData->f_bsize =
4456 le32_to_cpu(response_data->BlockSize);
4457 FSData->f_blocks =
4458 le64_to_cpu(response_data->TotalBlocks);
4459 FSData->f_bfree =
4460 le64_to_cpu(response_data->BlocksAvail);
Steve French70ca7342005-09-22 16:32:06 -07004461 if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 FSData->f_bavail = FSData->f_bfree;
4463 } else {
4464 FSData->f_bavail =
4465 le64_to_cpu(response_data->UserBlocksAvail);
4466 }
Steve French70ca7342005-09-22 16:32:06 -07004467 if(response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 FSData->f_files =
4469 le64_to_cpu(response_data->TotalFileNodes);
Steve French70ca7342005-09-22 16:32:06 -07004470 if(response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471 FSData->f_ffree =
4472 le64_to_cpu(response_data->FreeFileNodes);
4473 }
4474 }
4475 cifs_buf_release(pSMB);
4476
4477 if (rc == -EAGAIN)
4478 goto QFSPosixRetry;
4479
4480 return rc;
4481}
4482
4483
4484/* We can not use write of zero bytes trick to
4485 set file size due to need for large file support. Also note that
4486 this SetPathInfo is preferred to SetFileInfo based method in next
4487 routine which is only needed to work around a sharing violation bug
4488 in Samba which this routine can run into */
4489
4490int
4491CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French737b7582005-04-28 22:41:06 -07004492 __u64 size, int SetAllocation,
4493 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494{
4495 struct smb_com_transaction2_spi_req *pSMB = NULL;
4496 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4497 struct file_end_of_file_info *parm_data;
4498 int name_len;
4499 int rc = 0;
4500 int bytes_returned = 0;
4501 __u16 params, byte_count, data_count, param_offset, offset;
4502
4503 cFYI(1, ("In SetEOF"));
4504SetEOFRetry:
4505 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4506 (void **) &pSMBr);
4507 if (rc)
4508 return rc;
4509
4510 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4511 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004512 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004513 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 name_len++; /* trailing null */
4515 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004516 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517 name_len = strnlen(fileName, PATH_MAX);
4518 name_len++; /* trailing null */
4519 strncpy(pSMB->FileName, fileName, name_len);
4520 }
4521 params = 6 + name_len;
4522 data_count = sizeof (struct file_end_of_file_info);
4523 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004524 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004525 pSMB->MaxSetupCount = 0;
4526 pSMB->Reserved = 0;
4527 pSMB->Flags = 0;
4528 pSMB->Timeout = 0;
4529 pSMB->Reserved2 = 0;
4530 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4531 InformationLevel) - 4;
4532 offset = param_offset + params;
4533 if(SetAllocation) {
4534 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4535 pSMB->InformationLevel =
4536 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4537 else
4538 pSMB->InformationLevel =
4539 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4540 } else /* Set File Size */ {
4541 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4542 pSMB->InformationLevel =
4543 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4544 else
4545 pSMB->InformationLevel =
4546 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4547 }
4548
4549 parm_data =
4550 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4551 offset);
4552 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4553 pSMB->DataOffset = cpu_to_le16(offset);
4554 pSMB->SetupCount = 1;
4555 pSMB->Reserved3 = 0;
4556 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4557 byte_count = 3 /* pad */ + params + data_count;
4558 pSMB->DataCount = cpu_to_le16(data_count);
4559 pSMB->TotalDataCount = pSMB->DataCount;
4560 pSMB->ParameterCount = cpu_to_le16(params);
4561 pSMB->TotalParameterCount = pSMB->ParameterCount;
4562 pSMB->Reserved4 = 0;
4563 pSMB->hdr.smb_buf_length += byte_count;
4564 parm_data->FileSize = cpu_to_le64(size);
4565 pSMB->ByteCount = cpu_to_le16(byte_count);
4566 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4567 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4568 if (rc) {
4569 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4570 }
4571
4572 cifs_buf_release(pSMB);
4573
4574 if (rc == -EAGAIN)
4575 goto SetEOFRetry;
4576
4577 return rc;
4578}
4579
4580int
4581CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4582 __u16 fid, __u32 pid_of_opener, int SetAllocation)
4583{
4584 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4585 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4586 char *data_offset;
4587 struct file_end_of_file_info *parm_data;
4588 int rc = 0;
4589 int bytes_returned = 0;
4590 __u16 params, param_offset, offset, byte_count, count;
4591
4592 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4593 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004594 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4595
Linus Torvalds1da177e2005-04-16 15:20:36 -07004596 if (rc)
4597 return rc;
4598
Steve Frenchcd634992005-04-28 22:41:10 -07004599 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4600
Linus Torvalds1da177e2005-04-16 15:20:36 -07004601 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4602 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4603
4604 params = 6;
4605 pSMB->MaxSetupCount = 0;
4606 pSMB->Reserved = 0;
4607 pSMB->Flags = 0;
4608 pSMB->Timeout = 0;
4609 pSMB->Reserved2 = 0;
4610 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4611 offset = param_offset + params;
4612
4613 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4614
4615 count = sizeof(struct file_end_of_file_info);
4616 pSMB->MaxParameterCount = cpu_to_le16(2);
4617 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4618 pSMB->SetupCount = 1;
4619 pSMB->Reserved3 = 0;
4620 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4621 byte_count = 3 /* pad */ + params + count;
4622 pSMB->DataCount = cpu_to_le16(count);
4623 pSMB->ParameterCount = cpu_to_le16(params);
4624 pSMB->TotalDataCount = pSMB->DataCount;
4625 pSMB->TotalParameterCount = pSMB->ParameterCount;
4626 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4627 parm_data =
4628 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4629 offset);
4630 pSMB->DataOffset = cpu_to_le16(offset);
4631 parm_data->FileSize = cpu_to_le64(size);
4632 pSMB->Fid = fid;
4633 if(SetAllocation) {
4634 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4635 pSMB->InformationLevel =
4636 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4637 else
4638 pSMB->InformationLevel =
4639 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4640 } else /* Set File Size */ {
4641 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4642 pSMB->InformationLevel =
4643 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4644 else
4645 pSMB->InformationLevel =
4646 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4647 }
4648 pSMB->Reserved4 = 0;
4649 pSMB->hdr.smb_buf_length += byte_count;
4650 pSMB->ByteCount = cpu_to_le16(byte_count);
4651 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4652 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4653 if (rc) {
4654 cFYI(1,
4655 ("Send error in SetFileInfo (SetFileSize) = %d",
4656 rc));
4657 }
4658
4659 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004660 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004661
4662 /* Note: On -EAGAIN error only caller can retry on handle based calls
4663 since file handle passed in no longer valid */
4664
4665 return rc;
4666}
4667
4668/* Some legacy servers such as NT4 require that the file times be set on
4669 an open handle, rather than by pathname - this is awkward due to
4670 potential access conflicts on the open, but it is unavoidable for these
4671 old servers since the only other choice is to go from 100 nanosecond DCE
4672 time and resort to the original setpathinfo level which takes the ancient
4673 DOS time format with 2 second granularity */
4674int
4675CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
4676 __u16 fid)
4677{
4678 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4679 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4680 char *data_offset;
4681 int rc = 0;
4682 int bytes_returned = 0;
4683 __u16 params, param_offset, offset, byte_count, count;
4684
4685 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004686 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4687
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688 if (rc)
4689 return rc;
4690
Steve Frenchcd634992005-04-28 22:41:10 -07004691 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4692
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693 /* At this point there is no need to override the current pid
4694 with the pid of the opener, but that could change if we someday
4695 use an existing handle (rather than opening one on the fly) */
4696 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4697 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4698
4699 params = 6;
4700 pSMB->MaxSetupCount = 0;
4701 pSMB->Reserved = 0;
4702 pSMB->Flags = 0;
4703 pSMB->Timeout = 0;
4704 pSMB->Reserved2 = 0;
4705 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4706 offset = param_offset + params;
4707
4708 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4709
4710 count = sizeof (FILE_BASIC_INFO);
4711 pSMB->MaxParameterCount = cpu_to_le16(2);
4712 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4713 pSMB->SetupCount = 1;
4714 pSMB->Reserved3 = 0;
4715 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4716 byte_count = 3 /* pad */ + params + count;
4717 pSMB->DataCount = cpu_to_le16(count);
4718 pSMB->ParameterCount = cpu_to_le16(params);
4719 pSMB->TotalDataCount = pSMB->DataCount;
4720 pSMB->TotalParameterCount = pSMB->ParameterCount;
4721 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4722 pSMB->DataOffset = cpu_to_le16(offset);
4723 pSMB->Fid = fid;
4724 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4725 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4726 else
4727 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4728 pSMB->Reserved4 = 0;
4729 pSMB->hdr.smb_buf_length += byte_count;
4730 pSMB->ByteCount = cpu_to_le16(byte_count);
4731 memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4732 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4733 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4734 if (rc) {
4735 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4736 }
4737
Steve Frenchcd634992005-04-28 22:41:10 -07004738 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739
4740 /* Note: On -EAGAIN error only caller can retry on handle based calls
4741 since file handle passed in no longer valid */
4742
4743 return rc;
4744}
4745
4746
4747int
4748CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4749 const FILE_BASIC_INFO * data,
Steve French737b7582005-04-28 22:41:06 -07004750 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751{
4752 TRANSACTION2_SPI_REQ *pSMB = NULL;
4753 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4754 int name_len;
4755 int rc = 0;
4756 int bytes_returned = 0;
4757 char *data_offset;
4758 __u16 params, param_offset, offset, byte_count, count;
4759
4760 cFYI(1, ("In SetTimes"));
4761
4762SetTimesRetry:
4763 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4764 (void **) &pSMBr);
4765 if (rc)
4766 return rc;
4767
4768 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4769 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004770 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004771 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772 name_len++; /* trailing null */
4773 name_len *= 2;
4774 } else { /* BB improve the check for buffer overruns BB */
4775 name_len = strnlen(fileName, PATH_MAX);
4776 name_len++; /* trailing null */
4777 strncpy(pSMB->FileName, fileName, name_len);
4778 }
4779
4780 params = 6 + name_len;
4781 count = sizeof (FILE_BASIC_INFO);
4782 pSMB->MaxParameterCount = cpu_to_le16(2);
4783 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4784 pSMB->MaxSetupCount = 0;
4785 pSMB->Reserved = 0;
4786 pSMB->Flags = 0;
4787 pSMB->Timeout = 0;
4788 pSMB->Reserved2 = 0;
4789 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4790 InformationLevel) - 4;
4791 offset = param_offset + params;
4792 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4793 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4794 pSMB->DataOffset = cpu_to_le16(offset);
4795 pSMB->SetupCount = 1;
4796 pSMB->Reserved3 = 0;
4797 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4798 byte_count = 3 /* pad */ + params + count;
4799
4800 pSMB->DataCount = cpu_to_le16(count);
4801 pSMB->ParameterCount = cpu_to_le16(params);
4802 pSMB->TotalDataCount = pSMB->DataCount;
4803 pSMB->TotalParameterCount = pSMB->ParameterCount;
4804 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4805 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4806 else
4807 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4808 pSMB->Reserved4 = 0;
4809 pSMB->hdr.smb_buf_length += byte_count;
4810 memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4811 pSMB->ByteCount = cpu_to_le16(byte_count);
4812 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4813 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4814 if (rc) {
4815 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4816 }
4817
4818 cifs_buf_release(pSMB);
4819
4820 if (rc == -EAGAIN)
4821 goto SetTimesRetry;
4822
4823 return rc;
4824}
4825
4826/* Can not be used to set time stamps yet (due to old DOS time format) */
4827/* Can be used to set attributes */
4828#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4829 handling it anyway and NT4 was what we thought it would be needed for
4830 Do not delete it until we prove whether needed for Win9x though */
4831int
4832CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4833 __u16 dos_attrs, const struct nls_table *nls_codepage)
4834{
4835 SETATTR_REQ *pSMB = NULL;
4836 SETATTR_RSP *pSMBr = NULL;
4837 int rc = 0;
4838 int bytes_returned;
4839 int name_len;
4840
4841 cFYI(1, ("In SetAttrLegacy"));
4842
4843SetAttrLgcyRetry:
4844 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4845 (void **) &pSMBr);
4846 if (rc)
4847 return rc;
4848
4849 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4850 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004851 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 PATH_MAX, nls_codepage);
4853 name_len++; /* trailing null */
4854 name_len *= 2;
4855 } else { /* BB improve the check for buffer overruns BB */
4856 name_len = strnlen(fileName, PATH_MAX);
4857 name_len++; /* trailing null */
4858 strncpy(pSMB->fileName, fileName, name_len);
4859 }
4860 pSMB->attr = cpu_to_le16(dos_attrs);
4861 pSMB->BufferFormat = 0x04;
4862 pSMB->hdr.smb_buf_length += name_len + 1;
4863 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4864 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4865 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4866 if (rc) {
4867 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4868 }
4869
4870 cifs_buf_release(pSMB);
4871
4872 if (rc == -EAGAIN)
4873 goto SetAttrLgcyRetry;
4874
4875 return rc;
4876}
4877#endif /* temporarily unneeded SetAttr legacy function */
4878
4879int
4880CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004881 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4882 dev_t device, const struct nls_table *nls_codepage,
4883 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884{
4885 TRANSACTION2_SPI_REQ *pSMB = NULL;
4886 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4887 int name_len;
4888 int rc = 0;
4889 int bytes_returned = 0;
4890 FILE_UNIX_BASIC_INFO *data_offset;
4891 __u16 params, param_offset, offset, count, byte_count;
4892
4893 cFYI(1, ("In SetUID/GID/Mode"));
4894setPermsRetry:
4895 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4896 (void **) &pSMBr);
4897 if (rc)
4898 return rc;
4899
4900 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4901 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004902 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004903 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004904 name_len++; /* trailing null */
4905 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004906 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004907 name_len = strnlen(fileName, PATH_MAX);
4908 name_len++; /* trailing null */
4909 strncpy(pSMB->FileName, fileName, name_len);
4910 }
4911
4912 params = 6 + name_len;
4913 count = sizeof (FILE_UNIX_BASIC_INFO);
4914 pSMB->MaxParameterCount = cpu_to_le16(2);
4915 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4916 pSMB->MaxSetupCount = 0;
4917 pSMB->Reserved = 0;
4918 pSMB->Flags = 0;
4919 pSMB->Timeout = 0;
4920 pSMB->Reserved2 = 0;
4921 param_offset = offsetof(struct smb_com_transaction2_spi_req,
4922 InformationLevel) - 4;
4923 offset = param_offset + params;
4924 data_offset =
4925 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4926 offset);
4927 memset(data_offset, 0, count);
4928 pSMB->DataOffset = cpu_to_le16(offset);
4929 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4930 pSMB->SetupCount = 1;
4931 pSMB->Reserved3 = 0;
4932 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4933 byte_count = 3 /* pad */ + params + count;
4934 pSMB->ParameterCount = cpu_to_le16(params);
4935 pSMB->DataCount = cpu_to_le16(count);
4936 pSMB->TotalParameterCount = pSMB->ParameterCount;
4937 pSMB->TotalDataCount = pSMB->DataCount;
4938 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4939 pSMB->Reserved4 = 0;
4940 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00004941 /* Samba server ignores set of file size to zero due to bugs in some
4942 older clients, but we should be precise - we use SetFileSize to
4943 set file size and do not want to truncate file size to zero
4944 accidently as happened on one Samba server beta by putting
4945 zero instead of -1 here */
4946 data_offset->EndOfFile = NO_CHANGE_64;
4947 data_offset->NumOfBytes = NO_CHANGE_64;
4948 data_offset->LastStatusChange = NO_CHANGE_64;
4949 data_offset->LastAccessTime = NO_CHANGE_64;
4950 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951 data_offset->Uid = cpu_to_le64(uid);
4952 data_offset->Gid = cpu_to_le64(gid);
4953 /* better to leave device as zero when it is */
4954 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4955 data_offset->DevMinor = cpu_to_le64(MINOR(device));
4956 data_offset->Permissions = cpu_to_le64(mode);
4957
4958 if(S_ISREG(mode))
4959 data_offset->Type = cpu_to_le32(UNIX_FILE);
4960 else if(S_ISDIR(mode))
4961 data_offset->Type = cpu_to_le32(UNIX_DIR);
4962 else if(S_ISLNK(mode))
4963 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4964 else if(S_ISCHR(mode))
4965 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4966 else if(S_ISBLK(mode))
4967 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4968 else if(S_ISFIFO(mode))
4969 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4970 else if(S_ISSOCK(mode))
4971 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4972
4973
4974 pSMB->ByteCount = cpu_to_le16(byte_count);
4975 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4976 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4977 if (rc) {
4978 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4979 }
4980
4981 if (pSMB)
4982 cifs_buf_release(pSMB);
4983 if (rc == -EAGAIN)
4984 goto setPermsRetry;
4985 return rc;
4986}
4987
4988int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07004989 const int notify_subdirs, const __u16 netfid,
4990 __u32 filter, struct file * pfile, int multishot,
4991 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992{
4993 int rc = 0;
4994 struct smb_com_transaction_change_notify_req * pSMB = NULL;
Steve French0a4b92c2006-01-12 15:44:21 -08004995 struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07004996 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004997 int bytes_returned;
4998
4999 cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
5000 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
5001 (void **) &pSMBr);
5002 if (rc)
5003 return rc;
5004
5005 pSMB->TotalParameterCount = 0 ;
5006 pSMB->TotalDataCount = 0;
5007 pSMB->MaxParameterCount = cpu_to_le32(2);
5008 /* BB find exact data count max from sess structure BB */
5009 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005010/* BB VERIFY verify which is correct for above BB */
5011 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5012 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5013
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 pSMB->MaxSetupCount = 4;
5015 pSMB->Reserved = 0;
5016 pSMB->ParameterOffset = 0;
5017 pSMB->DataCount = 0;
5018 pSMB->DataOffset = 0;
5019 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5020 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5021 pSMB->ParameterCount = pSMB->TotalParameterCount;
5022 if(notify_subdirs)
5023 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5024 pSMB->Reserved2 = 0;
5025 pSMB->CompletionFilter = cpu_to_le32(filter);
5026 pSMB->Fid = netfid; /* file handle always le */
5027 pSMB->ByteCount = 0;
5028
5029 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5030 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
5031 if (rc) {
5032 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005033 } else {
5034 /* Add file to outstanding requests */
Steve French47c786e2005-10-11 20:03:18 -07005035 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005036 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005037 sizeof(struct dir_notify_req),
5038 GFP_KERNEL);
5039 if(dnotify_req) {
5040 dnotify_req->Pid = pSMB->hdr.Pid;
5041 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5042 dnotify_req->Mid = pSMB->hdr.Mid;
5043 dnotify_req->Tid = pSMB->hdr.Tid;
5044 dnotify_req->Uid = pSMB->hdr.Uid;
5045 dnotify_req->netfid = netfid;
5046 dnotify_req->pfile = pfile;
5047 dnotify_req->filter = filter;
5048 dnotify_req->multishot = multishot;
5049 spin_lock(&GlobalMid_Lock);
5050 list_add_tail(&dnotify_req->lhead,
5051 &GlobalDnotifyReqList);
5052 spin_unlock(&GlobalMid_Lock);
5053 } else
5054 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005055 }
5056 cifs_buf_release(pSMB);
5057 return rc;
5058}
5059#ifdef CONFIG_CIFS_XATTR
5060ssize_t
5061CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5062 const unsigned char *searchName,
5063 char * EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005064 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005065{
5066 /* BB assumes one setup word */
5067 TRANSACTION2_QPI_REQ *pSMB = NULL;
5068 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5069 int rc = 0;
5070 int bytes_returned;
5071 int name_len;
5072 struct fea * temp_fea;
5073 char * temp_ptr;
5074 __u16 params, byte_count;
5075
5076 cFYI(1, ("In Query All EAs path %s", searchName));
5077QAllEAsRetry:
5078 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5079 (void **) &pSMBr);
5080 if (rc)
5081 return rc;
5082
5083 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5084 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005085 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005086 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087 name_len++; /* trailing null */
5088 name_len *= 2;
5089 } else { /* BB improve the check for buffer overruns BB */
5090 name_len = strnlen(searchName, PATH_MAX);
5091 name_len++; /* trailing null */
5092 strncpy(pSMB->FileName, searchName, name_len);
5093 }
5094
5095 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5096 pSMB->TotalDataCount = 0;
5097 pSMB->MaxParameterCount = cpu_to_le16(2);
5098 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5099 pSMB->MaxSetupCount = 0;
5100 pSMB->Reserved = 0;
5101 pSMB->Flags = 0;
5102 pSMB->Timeout = 0;
5103 pSMB->Reserved2 = 0;
5104 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5105 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5106 pSMB->DataCount = 0;
5107 pSMB->DataOffset = 0;
5108 pSMB->SetupCount = 1;
5109 pSMB->Reserved3 = 0;
5110 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5111 byte_count = params + 1 /* pad */ ;
5112 pSMB->TotalParameterCount = cpu_to_le16(params);
5113 pSMB->ParameterCount = pSMB->TotalParameterCount;
5114 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5115 pSMB->Reserved4 = 0;
5116 pSMB->hdr.smb_buf_length += byte_count;
5117 pSMB->ByteCount = cpu_to_le16(byte_count);
5118
5119 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5120 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5121 if (rc) {
5122 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5123 } else { /* decode response */
5124 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5125
5126 /* BB also check enough total bytes returned */
5127 /* BB we need to improve the validity checking
5128 of these trans2 responses */
5129 if (rc || (pSMBr->ByteCount < 4))
5130 rc = -EIO; /* bad smb */
5131 /* else if (pFindData){
5132 memcpy((char *) pFindData,
5133 (char *) &pSMBr->hdr.Protocol +
5134 data_offset, kl);
5135 }*/ else {
5136 /* check that length of list is not more than bcc */
5137 /* check that each entry does not go beyond length
5138 of list */
5139 /* check that each element of each entry does not
5140 go beyond end of list */
5141 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5142 struct fealist * ea_response_data;
5143 rc = 0;
5144 /* validate_trans2_offsets() */
5145 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5146 ea_response_data = (struct fealist *)
5147 (((char *) &pSMBr->hdr.Protocol) +
5148 data_offset);
5149 name_len = le32_to_cpu(ea_response_data->list_len);
5150 cFYI(1,("ea length %d", name_len));
5151 if(name_len <= 8) {
5152 /* returned EA size zeroed at top of function */
5153 cFYI(1,("empty EA list returned from server"));
5154 } else {
5155 /* account for ea list len */
5156 name_len -= 4;
5157 temp_fea = ea_response_data->list;
5158 temp_ptr = (char *)temp_fea;
5159 while(name_len > 0) {
5160 __u16 value_len;
5161 name_len -= 4;
5162 temp_ptr += 4;
5163 rc += temp_fea->name_len;
5164 /* account for prefix user. and trailing null */
5165 rc = rc + 5 + 1;
5166 if(rc<(int)buf_size) {
5167 memcpy(EAData,"user.",5);
5168 EAData+=5;
5169 memcpy(EAData,temp_ptr,temp_fea->name_len);
5170 EAData+=temp_fea->name_len;
5171 /* null terminate name */
5172 *EAData = 0;
5173 EAData = EAData + 1;
5174 } else if(buf_size == 0) {
5175 /* skip copy - calc size only */
5176 } else {
5177 /* stop before overrun buffer */
5178 rc = -ERANGE;
5179 break;
5180 }
5181 name_len -= temp_fea->name_len;
5182 temp_ptr += temp_fea->name_len;
5183 /* account for trailing null */
5184 name_len--;
5185 temp_ptr++;
5186 value_len = le16_to_cpu(temp_fea->value_len);
5187 name_len -= value_len;
5188 temp_ptr += value_len;
5189 /* BB check that temp_ptr is still within smb BB*/
5190 /* no trailing null to account for in value len */
5191 /* go on to next EA */
5192 temp_fea = (struct fea *)temp_ptr;
5193 }
5194 }
5195 }
5196 }
5197 if (pSMB)
5198 cifs_buf_release(pSMB);
5199 if (rc == -EAGAIN)
5200 goto QAllEAsRetry;
5201
5202 return (ssize_t)rc;
5203}
5204
5205ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
5206 const unsigned char * searchName,const unsigned char * ea_name,
5207 unsigned char * ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005208 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005209{
5210 TRANSACTION2_QPI_REQ *pSMB = NULL;
5211 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5212 int rc = 0;
5213 int bytes_returned;
5214 int name_len;
5215 struct fea * temp_fea;
5216 char * temp_ptr;
5217 __u16 params, byte_count;
5218
5219 cFYI(1, ("In Query EA path %s", searchName));
5220QEARetry:
5221 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5222 (void **) &pSMBr);
5223 if (rc)
5224 return rc;
5225
5226 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5227 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005228 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005229 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230 name_len++; /* trailing null */
5231 name_len *= 2;
5232 } else { /* BB improve the check for buffer overruns BB */
5233 name_len = strnlen(searchName, PATH_MAX);
5234 name_len++; /* trailing null */
5235 strncpy(pSMB->FileName, searchName, name_len);
5236 }
5237
5238 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
5239 pSMB->TotalDataCount = 0;
5240 pSMB->MaxParameterCount = cpu_to_le16(2);
5241 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5242 pSMB->MaxSetupCount = 0;
5243 pSMB->Reserved = 0;
5244 pSMB->Flags = 0;
5245 pSMB->Timeout = 0;
5246 pSMB->Reserved2 = 0;
5247 pSMB->ParameterOffset = cpu_to_le16(offsetof(
5248 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
5249 pSMB->DataCount = 0;
5250 pSMB->DataOffset = 0;
5251 pSMB->SetupCount = 1;
5252 pSMB->Reserved3 = 0;
5253 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5254 byte_count = params + 1 /* pad */ ;
5255 pSMB->TotalParameterCount = cpu_to_le16(params);
5256 pSMB->ParameterCount = pSMB->TotalParameterCount;
5257 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5258 pSMB->Reserved4 = 0;
5259 pSMB->hdr.smb_buf_length += byte_count;
5260 pSMB->ByteCount = cpu_to_le16(byte_count);
5261
5262 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5263 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5264 if (rc) {
5265 cFYI(1, ("Send error in Query EA = %d", rc));
5266 } else { /* decode response */
5267 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5268
5269 /* BB also check enough total bytes returned */
5270 /* BB we need to improve the validity checking
5271 of these trans2 responses */
5272 if (rc || (pSMBr->ByteCount < 4))
5273 rc = -EIO; /* bad smb */
5274 /* else if (pFindData){
5275 memcpy((char *) pFindData,
5276 (char *) &pSMBr->hdr.Protocol +
5277 data_offset, kl);
5278 }*/ else {
5279 /* check that length of list is not more than bcc */
5280 /* check that each entry does not go beyond length
5281 of list */
5282 /* check that each element of each entry does not
5283 go beyond end of list */
5284 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
5285 struct fealist * ea_response_data;
5286 rc = -ENODATA;
5287 /* validate_trans2_offsets() */
5288 /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
5289 ea_response_data = (struct fealist *)
5290 (((char *) &pSMBr->hdr.Protocol) +
5291 data_offset);
5292 name_len = le32_to_cpu(ea_response_data->list_len);
5293 cFYI(1,("ea length %d", name_len));
5294 if(name_len <= 8) {
5295 /* returned EA size zeroed at top of function */
5296 cFYI(1,("empty EA list returned from server"));
5297 } else {
5298 /* account for ea list len */
5299 name_len -= 4;
5300 temp_fea = ea_response_data->list;
5301 temp_ptr = (char *)temp_fea;
5302 /* loop through checking if we have a matching
5303 name and then return the associated value */
5304 while(name_len > 0) {
5305 __u16 value_len;
5306 name_len -= 4;
5307 temp_ptr += 4;
5308 value_len = le16_to_cpu(temp_fea->value_len);
5309 /* BB validate that value_len falls within SMB,
5310 even though maximum for name_len is 255 */
5311 if(memcmp(temp_fea->name,ea_name,
5312 temp_fea->name_len) == 0) {
5313 /* found a match */
5314 rc = value_len;
5315 /* account for prefix user. and trailing null */
5316 if(rc<=(int)buf_size) {
5317 memcpy(ea_value,
5318 temp_fea->name+temp_fea->name_len+1,
5319 rc);
5320 /* ea values, unlike ea names,
5321 are not null terminated */
5322 } else if(buf_size == 0) {
5323 /* skip copy - calc size only */
5324 } else {
5325 /* stop before overrun buffer */
5326 rc = -ERANGE;
5327 }
5328 break;
5329 }
5330 name_len -= temp_fea->name_len;
5331 temp_ptr += temp_fea->name_len;
5332 /* account for trailing null */
5333 name_len--;
5334 temp_ptr++;
5335 name_len -= value_len;
5336 temp_ptr += value_len;
5337 /* no trailing null to account for in value len */
5338 /* go on to next EA */
5339 temp_fea = (struct fea *)temp_ptr;
5340 }
5341 }
5342 }
5343 }
5344 if (pSMB)
5345 cifs_buf_release(pSMB);
5346 if (rc == -EAGAIN)
5347 goto QEARetry;
5348
5349 return (ssize_t)rc;
5350}
5351
5352int
5353CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
5354 const char * ea_name, const void * ea_value,
Steve French737b7582005-04-28 22:41:06 -07005355 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5356 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005357{
5358 struct smb_com_transaction2_spi_req *pSMB = NULL;
5359 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5360 struct fealist *parm_data;
5361 int name_len;
5362 int rc = 0;
5363 int bytes_returned = 0;
5364 __u16 params, param_offset, byte_count, offset, count;
5365
5366 cFYI(1, ("In SetEA"));
5367SetEARetry:
5368 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5369 (void **) &pSMBr);
5370 if (rc)
5371 return rc;
5372
5373 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5374 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05005375 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005376 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 name_len++; /* trailing null */
5378 name_len *= 2;
5379 } else { /* BB improve the check for buffer overruns BB */
5380 name_len = strnlen(fileName, PATH_MAX);
5381 name_len++; /* trailing null */
5382 strncpy(pSMB->FileName, fileName, name_len);
5383 }
5384
5385 params = 6 + name_len;
5386
5387 /* done calculating parms using name_len of file name,
5388 now use name_len to calculate length of ea name
5389 we are going to create in the inode xattrs */
5390 if(ea_name == NULL)
5391 name_len = 0;
5392 else
5393 name_len = strnlen(ea_name,255);
5394
5395 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5396 pSMB->MaxParameterCount = cpu_to_le16(2);
5397 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5398 pSMB->MaxSetupCount = 0;
5399 pSMB->Reserved = 0;
5400 pSMB->Flags = 0;
5401 pSMB->Timeout = 0;
5402 pSMB->Reserved2 = 0;
5403 param_offset = offsetof(struct smb_com_transaction2_spi_req,
5404 InformationLevel) - 4;
5405 offset = param_offset + params;
5406 pSMB->InformationLevel =
5407 cpu_to_le16(SMB_SET_FILE_EA);
5408
5409 parm_data =
5410 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5411 offset);
5412 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5413 pSMB->DataOffset = cpu_to_le16(offset);
5414 pSMB->SetupCount = 1;
5415 pSMB->Reserved3 = 0;
5416 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5417 byte_count = 3 /* pad */ + params + count;
5418 pSMB->DataCount = cpu_to_le16(count);
5419 parm_data->list_len = cpu_to_le32(count);
5420 parm_data->list[0].EA_flags = 0;
5421 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005422 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005423 /* EA names are always ASCII */
5424 if(ea_name)
5425 strncpy(parm_data->list[0].name,ea_name,name_len);
5426 parm_data->list[0].name[name_len] = 0;
5427 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5428 /* caller ensures that ea_value_len is less than 64K but
5429 we need to ensure that it fits within the smb */
5430
5431 /*BB add length check that it would fit in negotiated SMB buffer size BB */
5432 /* if(ea_value_len > buffer_size - 512 (enough for header)) */
5433 if(ea_value_len)
5434 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
5435
5436 pSMB->TotalDataCount = pSMB->DataCount;
5437 pSMB->ParameterCount = cpu_to_le16(params);
5438 pSMB->TotalParameterCount = pSMB->ParameterCount;
5439 pSMB->Reserved4 = 0;
5440 pSMB->hdr.smb_buf_length += byte_count;
5441 pSMB->ByteCount = cpu_to_le16(byte_count);
5442 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5443 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5444 if (rc) {
5445 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5446 }
5447
5448 cifs_buf_release(pSMB);
5449
5450 if (rc == -EAGAIN)
5451 goto SetEARetry;
5452
5453 return rc;
5454}
5455
5456#endif