blob: 301e307e127900e71eb1291ae80c050a03d8aa98 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve Frenchd185cda2009-04-30 17:45:10 +00004 * Copyright (C) International Business Machines Corp., 2002,2009
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"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000037#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include "cifsproto.h"
39#include "cifs_unicode.h"
40#include "cifs_debug.h"
41
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 */
Steve French50c2f752007-07-13 00:33:32 +000051 {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 */
Steve French790fe572007-07-07 19:25:05 +000064 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 {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/* Mark as invalid, all open files on tree connections since they
85 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +000086static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070087{
88 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000089 struct list_head *tmp;
90 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
92/* list all files open on tree connection and mark them invalid */
93 write_lock(&GlobalSMBSeslock);
94 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000095 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve Frenchad8b15f2008-08-08 21:10:16 +000096 open_file->invalidHandle = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 }
98 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -070099 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
100 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101}
102
Jeff Layton9162ab22009-09-03 12:07:17 -0400103/* reconnect the socket, tcon, and smb session if needed */
104static int
105cifs_reconnect_tcon(struct cifsTconInfo *tcon, int smb_command)
106{
107 int rc = 0;
108 struct cifsSesInfo *ses;
109 struct TCP_Server_Info *server;
110 struct nls_table *nls_codepage;
111
112 /*
113 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
114 * tcp and smb session status done differently for those three - in the
115 * calling routine
116 */
117 if (!tcon)
118 return 0;
119
120 ses = tcon->ses;
121 server = ses->server;
122
123 /*
124 * only tree disconnect, open, and write, (and ulogoff which does not
125 * have tcon) are allowed as we start force umount
126 */
127 if (tcon->tidStatus == CifsExiting) {
128 if (smb_command != SMB_COM_WRITE_ANDX &&
129 smb_command != SMB_COM_OPEN_ANDX &&
130 smb_command != SMB_COM_TREE_DISCONNECT) {
131 cFYI(1, ("can not send cmd %d while umounting",
132 smb_command));
133 return -ENODEV;
134 }
135 }
136
137 if (ses->status == CifsExiting)
138 return -EIO;
139
140 /*
141 * Give demultiplex thread up to 10 seconds to reconnect, should be
142 * greater than cifs socket timeout which is 7 seconds
143 */
144 while (server->tcpStatus == CifsNeedReconnect) {
145 wait_event_interruptible_timeout(server->response_q,
146 (server->tcpStatus == CifsGood), 10 * HZ);
147
148 /* is TCP session is reestablished now ?*/
149 if (server->tcpStatus != CifsNeedReconnect)
150 break;
151
152 /*
153 * on "soft" mounts we wait once. Hard mounts keep
154 * retrying until process is killed or server comes
155 * back on-line
156 */
157 if (!tcon->retry || ses->status == CifsExiting) {
158 cFYI(1, ("gave up waiting on reconnect in smb_init"));
159 return -EHOSTDOWN;
160 }
161 }
162
163 if (!ses->need_reconnect && !tcon->need_reconnect)
164 return 0;
165
166 nls_codepage = load_nls_default();
167
168 /*
169 * need to prevent multiple threads trying to simultaneously
170 * reconnect the same SMB session
171 */
172 down(&ses->sesSem);
173 if (ses->need_reconnect)
174 rc = cifs_setup_session(0, ses, nls_codepage);
175
176 /* do we need to reconnect tcon? */
177 if (rc || !tcon->need_reconnect) {
178 up(&ses->sesSem);
179 goto out;
180 }
181
182 mark_open_files_invalid(tcon);
183 rc = CIFSTCon(0, ses, tcon->treeName, tcon, nls_codepage);
184 up(&ses->sesSem);
185 cFYI(1, ("reconnect tcon rc = %d", rc));
186
187 if (rc)
188 goto out;
189
190 /*
191 * FIXME: check if wsize needs updated due to negotiated smb buffer
192 * size shrinking
193 */
194 atomic_inc(&tconInfoReconnectCount);
195
196 /* tell server Unix caps we support */
197 if (ses->capabilities & CAP_UNIX)
198 reset_cifs_unix_caps(0, tcon, NULL, NULL);
199
200 /*
201 * Removed call to reopen open files here. It is safer (and faster) to
202 * reopen files one at a time as needed in read and write.
203 *
204 * FIXME: what about file locks? don't we need to reclaim them ASAP?
205 */
206
207out:
208 /*
209 * Check if handle based operation so we know whether we can continue
210 * or not without returning to caller to reset file handle
211 */
212 switch (smb_command) {
213 case SMB_COM_READ_ANDX:
214 case SMB_COM_WRITE_ANDX:
215 case SMB_COM_CLOSE:
216 case SMB_COM_FIND_CLOSE2:
217 case SMB_COM_LOCKING_ANDX:
218 rc = -EAGAIN;
219 }
220
221 unload_nls(nls_codepage);
222 return rc;
223}
224
Steve Frenchad7a2922008-02-07 23:25:02 +0000225/* Allocate and return pointer to an SMB request buffer, and set basic
226 SMB information in the SMB header. If the return code is zero, this
227 function must have filled in request_buf pointer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228static int
229small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000230 void **request_buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
232 int rc = 0;
233
Jeff Layton9162ab22009-09-03 12:07:17 -0400234 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000235 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 return rc;
237
238 *request_buf = cifs_small_buf_get();
239 if (*request_buf == NULL) {
240 /* BB should we add a retry in here if not a writepage? */
241 return -ENOMEM;
242 }
243
Steve French63135e02007-07-17 17:34:02 +0000244 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000245 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
Steve French790fe572007-07-07 19:25:05 +0000247 if (tcon != NULL)
248 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700249
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000251}
252
Steve French12b3b8f2006-02-09 21:12:47 +0000253int
Steve French50c2f752007-07-13 00:33:32 +0000254small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000255 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000256{
257 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000258 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000259
Steve French5815449d2006-02-14 01:36:20 +0000260 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000261 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000262 return rc;
263
Steve French04fdabe2006-02-10 05:52:50 +0000264 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000265 buffer->Mid = GetNextMid(ses->server);
266 if (ses->capabilities & CAP_UNICODE)
267 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000268 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000269 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
270
271 /* uid, tid can stay at zero as set in header assemble */
272
Steve French50c2f752007-07-13 00:33:32 +0000273 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000274 this function is used after 1st of session setup requests */
275
276 return rc;
277}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
279/* If the return code is zero, this function must fill in request_buf pointer */
280static int
281smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
282 void **request_buf /* returned */ ,
283 void **response_buf /* returned */ )
284{
285 int rc = 0;
286
Jeff Layton9162ab22009-09-03 12:07:17 -0400287 rc = cifs_reconnect_tcon(tcon, smb_command);
Steve French790fe572007-07-07 19:25:05 +0000288 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 return rc;
290
291 *request_buf = cifs_buf_get();
292 if (*request_buf == NULL) {
293 /* BB should we add a retry in here if not a writepage? */
294 return -ENOMEM;
295 }
296 /* Although the original thought was we needed the response buf for */
297 /* potential retries of smb operations it turns out we can determine */
298 /* from the mid flags when the request buffer can be resent without */
299 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000300 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000301 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
303 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +0000304 wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
Steve French790fe572007-07-07 19:25:05 +0000306 if (tcon != NULL)
307 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700308
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 return rc;
310}
311
Steve French50c2f752007-07-13 00:33:32 +0000312static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
314 int rc = -EINVAL;
315 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000316 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317
318 /* check for plausible wct, bcc and t2 data and parm sizes */
319 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000320 if (pSMB->hdr.WordCount >= 10) {
321 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
323 /* check that bcc is at least as big as parms + data */
324 /* check that bcc is less than negotiated smb buffer */
325 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000326 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000327 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000328 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000330 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700331 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000333 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000334 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
336 return 0;
337 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 }
339 }
340 }
Steve French50c2f752007-07-13 00:33:32 +0000341 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 sizeof(struct smb_t2_rsp) + 16);
343 return rc;
344}
345int
346CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
347{
348 NEGOTIATE_REQ *pSMB;
349 NEGOTIATE_RSP *pSMBr;
350 int rc = 0;
351 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000352 int i;
Steve French50c2f752007-07-13 00:33:32 +0000353 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000355 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100356 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
Steve French790fe572007-07-07 19:25:05 +0000358 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 server = ses->server;
360 else {
361 rc = -EIO;
362 return rc;
363 }
364 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
365 (void **) &pSMB, (void **) &pSMBr);
366 if (rc)
367 return rc;
Steve French750d1152006-06-27 06:28:30 +0000368
369 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000370 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000371 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000372 else /* if override flags set only sign/seal OR them with global auth */
373 secFlags = extended_security | ses->overrideSecFlg;
374
Steve French762e5ab2007-06-28 18:41:42 +0000375 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000376
Steve French1982c342005-08-17 12:38:22 -0700377 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000378 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000379
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000380 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000381 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000382 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
383 cFYI(1, ("Kerberos only mechanism, enable extended security"));
384 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
385 }
Steve Frenchac683922009-05-06 04:16:04 +0000386#ifdef CONFIG_CIFS_EXPERIMENTAL
387 else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
388 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
389 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
390 cFYI(1, ("NTLMSSP only mechanism, enable extended security"));
391 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
392 }
393#endif
Steve French50c2f752007-07-13 00:33:32 +0000394
Steve French39798772006-05-31 22:40:51 +0000395 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000396 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000397 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
398 count += strlen(protocols[i].name) + 1;
399 /* null at end of source and target buffers anyway */
400 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 pSMB->hdr.smb_buf_length += count;
402 pSMB->ByteCount = cpu_to_le16(count);
403
404 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
405 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000406 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000407 goto neg_err_exit;
408
Al Viro733f99a2006-10-14 16:48:26 +0100409 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000410 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000411 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000412 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000413 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000414 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000415 could not negotiate a common dialect */
416 rc = -EOPNOTSUPP;
417 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000418#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000419 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100420 && ((dialect == LANMAN_PROT)
421 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000422 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000423 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000424
Steve French790fe572007-07-07 19:25:05 +0000425 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000426 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000427 server->secType = LANMAN;
428 else {
429 cERROR(1, ("mount failed weak security disabled"
430 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000431 rc = -EOPNOTSUPP;
432 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000433 }
Steve French254e55e2006-06-04 05:53:15 +0000434 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
435 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
436 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000437 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000438 server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
Steve French254e55e2006-06-04 05:53:15 +0000439 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
440 /* even though we do not use raw we might as well set this
441 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000442 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve Frencheca6acf2009-02-20 05:43:09 +0000443 server->max_rw = 0xFF00;
Steve French254e55e2006-06-04 05:53:15 +0000444 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
445 } else {
Steve Frencheca6acf2009-02-20 05:43:09 +0000446 server->max_rw = 0;/* do not need to use raw anyway */
Steve French254e55e2006-06-04 05:53:15 +0000447 server->capabilities = CAP_MPX_MODE;
448 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000449 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000450 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000451 /* OS/2 often does not set timezone therefore
452 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000453 * Could deviate slightly from the right zone.
454 * Smallest defined timezone difference is 15 minutes
455 * (i.e. Nepal). Rounding up/down is done to match
456 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000457 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000458 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000459 struct timespec ts, utc;
460 utc = CURRENT_TIME;
Jeff Laytonc4a2c082009-05-27 09:37:33 -0400461 ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
462 rsp->SrvTime.Time, 0);
Steve French50c2f752007-07-13 00:33:32 +0000463 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
464 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000465 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000466 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000467 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000468 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000469 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000470 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000471 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000472 if (val < 0)
Steve Frenchad7a2922008-02-07 23:25:02 +0000473 result = -result;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000474 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000475 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000476 server->timeAdj = (int)tmp;
477 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000478 }
Steve French790fe572007-07-07 19:25:05 +0000479 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000480
Steve French39798772006-05-31 22:40:51 +0000481
Steve French254e55e2006-06-04 05:53:15 +0000482 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000483 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000484
Steve French50c2f752007-07-13 00:33:32 +0000485 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000486 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000487 memcpy(server->cryptKey, rsp->EncryptionKey,
488 CIFS_CRYPTO_KEY_SIZE);
489 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
490 rc = -EIO; /* need cryptkey unless plain text */
491 goto neg_err_exit;
492 }
Steve French39798772006-05-31 22:40:51 +0000493
Steve French790fe572007-07-07 19:25:05 +0000494 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000495 /* we will not end up setting signing flags - as no signing
496 was in LANMAN and server did not return the flags on */
497 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000498#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000499 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000500 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000501 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000502 rc = -EOPNOTSUPP;
503#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000504 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000505 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000506 /* unknown wct */
507 rc = -EOPNOTSUPP;
508 goto neg_err_exit;
509 }
510 /* else wct == 17 NTLM */
511 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000512 if ((server->secMode & SECMODE_USER) == 0)
513 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000514
Steve French790fe572007-07-07 19:25:05 +0000515 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000516#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000517 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000518#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000519 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000520 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000521
Steve French790fe572007-07-07 19:25:05 +0000522 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000523 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000524 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000525 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000526 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000527 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000528 else if (secFlags & CIFSSEC_MAY_KRB5)
529 server->secType = Kerberos;
Steve Frenchac683922009-05-06 04:16:04 +0000530 else if (secFlags & CIFSSEC_MAY_NTLMSSP)
Steve Frenchf46c7232009-06-25 03:04:20 +0000531 server->secType = RawNTLMSSP;
Steve Frencha0136892007-10-04 20:05:09 +0000532 else if (secFlags & CIFSSEC_MAY_LANMAN)
533 server->secType = LANMAN;
534/* #ifdef CONFIG_CIFS_EXPERIMENTAL
535 else if (secFlags & CIFSSEC_MAY_PLNTXT)
536 server->secType = ??
537#endif */
538 else {
539 rc = -EOPNOTSUPP;
540 cERROR(1, ("Invalid security type"));
541 goto neg_err_exit;
542 }
543 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000544
Steve French254e55e2006-06-04 05:53:15 +0000545 /* one byte, so no need to convert this or EncryptionKeyLen from
546 little endian */
547 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
548 /* probably no need to store and check maxvcs */
549 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve Frencheca6acf2009-02-20 05:43:09 +0000551 server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
Steve French90c81e02008-02-12 20:32:36 +0000552 cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
Steve French254e55e2006-06-04 05:53:15 +0000553 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
554 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000555 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
556 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000557 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
558 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
559 CIFS_CRYPTO_KEY_SIZE);
560 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
561 && (pSMBr->EncryptionKeyLength == 0)) {
562 /* decode security blob */
563 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
564 rc = -EIO; /* no crypt key only if plain text pwd */
565 goto neg_err_exit;
566 }
567
568 /* BB might be helpful to save off the domain of server here */
569
Steve French50c2f752007-07-13 00:33:32 +0000570 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000571 (server->capabilities & CAP_EXTENDED_SECURITY)) {
572 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000573 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000575 goto neg_err_exit;
576 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500577 read_lock(&cifs_tcp_ses_lock);
578 if (server->srv_count > 1) {
579 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000580 if (memcmp(server->server_GUID,
581 pSMBr->u.extended_response.
582 GUID, 16) != 0) {
583 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000584 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000585 pSMBr->u.extended_response.GUID,
586 16);
587 }
Jeff Laytone7ddee92008-11-14 13:44:38 -0500588 } else {
589 read_unlock(&cifs_tcp_ses_lock);
Jeff Laytone187e442007-10-16 17:10:44 +0000590 memcpy(server->server_GUID,
591 pSMBr->u.extended_response.GUID, 16);
Jeff Laytone7ddee92008-11-14 13:44:38 -0500592 }
Jeff Laytone187e442007-10-16 17:10:44 +0000593
594 if (count == 16) {
595 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000596 } else {
597 rc = decode_negTokenInit(pSMBr->u.extended_response.
598 SecurityBlob,
599 count - 16,
600 &server->secType);
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000601 if (rc == 1)
Jeff Laytone5459372007-11-03 05:11:06 +0000602 rc = 0;
Shirish Pargaonkaref571ca2008-07-24 15:56:05 +0000603 else
Steve French254e55e2006-06-04 05:53:15 +0000604 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 }
Steve French254e55e2006-06-04 05:53:15 +0000606 } else
607 server->capabilities &= ~CAP_EXTENDED_SECURITY;
608
Steve French6344a422006-06-12 04:18:35 +0000609#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000610signing_check:
Steve French6344a422006-06-12 04:18:35 +0000611#endif
Steve French762e5ab2007-06-28 18:41:42 +0000612 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
613 /* MUST_SIGN already includes the MAY_SIGN FLAG
614 so if this is zero it means that signing is disabled */
615 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000616 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000617 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000618 "packet signing to be enabled in "
619 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000620 rc = -EOPNOTSUPP;
621 }
Steve French50c2f752007-07-13 00:33:32 +0000622 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000623 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000624 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
625 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000626 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000627 if ((server->secMode &
628 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
629 cERROR(1,
630 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000631 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000632 } else
633 server->secMode |= SECMODE_SIGN_REQUIRED;
634 } else {
635 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000636 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000637 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000638 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 }
Steve French50c2f752007-07-13 00:33:32 +0000640
641neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700642 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000643
Steve French790fe572007-07-07 19:25:05 +0000644 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 return rc;
646}
647
648int
649CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
650{
651 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
654 cFYI(1, ("In tree disconnect"));
Jeff Laytonf1987b42008-11-15 11:12:47 -0500655
656 /* BB: do we need to check this? These should never be NULL. */
657 if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
658 return -EIO;
659
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 /*
Jeff Laytonf1987b42008-11-15 11:12:47 -0500661 * No need to return error on this operation if tid invalidated and
662 * closed on server already e.g. due to tcp session crashing. Also,
663 * the tcon is no longer on the list, so no need to take lock before
664 * checking this.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 */
Steve French268875b2009-06-25 00:29:21 +0000666 if ((tcon->need_reconnect) || (tcon->ses->need_reconnect))
Steve French50c2f752007-07-13 00:33:32 +0000667 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Steve French50c2f752007-07-13 00:33:32 +0000669 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700670 (void **)&smb_buffer);
Jeff Laytonf1987b42008-11-15 11:12:47 -0500671 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 return rc;
Steve French133672e2007-11-13 22:41:37 +0000673
674 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700676 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677
Steve French50c2f752007-07-13 00:33:32 +0000678 /* No need to return error on this operation if tid invalidated and
Jeff Laytonf1987b42008-11-15 11:12:47 -0500679 closed on server already e.g. due to tcp session crashing */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 if (rc == -EAGAIN)
681 rc = 0;
682
683 return rc;
684}
685
686int
687CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
688{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 LOGOFF_ANDX_REQ *pSMB;
690 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691
692 cFYI(1, ("In SMBLogoff for session disconnect"));
Jeff Layton14fbf502008-11-14 13:53:46 -0500693
694 /*
695 * BB: do we need to check validity of ses and server? They should
696 * always be valid since we have an active reference. If not, that
697 * should probably be a BUG()
698 */
699 if (!ses || !ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 return -EIO;
701
Jeff Layton14fbf502008-11-14 13:53:46 -0500702 down(&ses->sesSem);
Steve French3b795212008-11-13 19:45:32 +0000703 if (ses->need_reconnect)
704 goto session_already_dead; /* no need to send SMBlogoff if uid
705 already closed due to reconnect */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
707 if (rc) {
708 up(&ses->sesSem);
709 return rc;
710 }
711
Steve French3b795212008-11-13 19:45:32 +0000712 pSMB->hdr.Mid = GetNextMid(ses->server);
Steve French1982c342005-08-17 12:38:22 -0700713
Steve French3b795212008-11-13 19:45:32 +0000714 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
716 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
718 pSMB->hdr.Uid = ses->Suid;
719
720 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000721 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Steve French3b795212008-11-13 19:45:32 +0000722session_already_dead:
Steve Frencha59c6582005-08-17 12:12:19 -0700723 up(&ses->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
725 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000726 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 error */
728 if (rc == -EAGAIN)
729 rc = 0;
730 return rc;
731}
732
733int
Steve French2d785a52007-07-15 01:48:57 +0000734CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
735 __u16 type, const struct nls_table *nls_codepage, int remap)
736{
737 TRANSACTION2_SPI_REQ *pSMB = NULL;
738 TRANSACTION2_SPI_RSP *pSMBr = NULL;
739 struct unlink_psx_rq *pRqD;
740 int name_len;
741 int rc = 0;
742 int bytes_returned = 0;
743 __u16 params, param_offset, offset, byte_count;
744
745 cFYI(1, ("In POSIX delete"));
746PsxDelete:
747 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
748 (void **) &pSMBr);
749 if (rc)
750 return rc;
751
752 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
753 name_len =
754 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
755 PATH_MAX, nls_codepage, remap);
756 name_len++; /* trailing null */
757 name_len *= 2;
758 } else { /* BB add path length overrun check */
759 name_len = strnlen(fileName, PATH_MAX);
760 name_len++; /* trailing null */
761 strncpy(pSMB->FileName, fileName, name_len);
762 }
763
764 params = 6 + name_len;
765 pSMB->MaxParameterCount = cpu_to_le16(2);
766 pSMB->MaxDataCount = 0; /* BB double check this with jra */
767 pSMB->MaxSetupCount = 0;
768 pSMB->Reserved = 0;
769 pSMB->Flags = 0;
770 pSMB->Timeout = 0;
771 pSMB->Reserved2 = 0;
772 param_offset = offsetof(struct smb_com_transaction2_spi_req,
773 InformationLevel) - 4;
774 offset = param_offset + params;
775
776 /* Setup pointer to Request Data (inode type) */
777 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
778 pRqD->type = cpu_to_le16(type);
779 pSMB->ParameterOffset = cpu_to_le16(param_offset);
780 pSMB->DataOffset = cpu_to_le16(offset);
781 pSMB->SetupCount = 1;
782 pSMB->Reserved3 = 0;
783 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
784 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
785
786 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
787 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
788 pSMB->ParameterCount = cpu_to_le16(params);
789 pSMB->TotalParameterCount = pSMB->ParameterCount;
790 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
791 pSMB->Reserved4 = 0;
792 pSMB->hdr.smb_buf_length += byte_count;
793 pSMB->ByteCount = cpu_to_le16(byte_count);
794 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
795 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +0000796 if (rc)
Steve French2d785a52007-07-15 01:48:57 +0000797 cFYI(1, ("Posix delete returned %d", rc));
Steve French2d785a52007-07-15 01:48:57 +0000798 cifs_buf_release(pSMB);
799
800 cifs_stats_inc(&tcon->num_deletes);
801
802 if (rc == -EAGAIN)
803 goto PsxDelete;
804
805 return rc;
806}
807
808int
Steve French737b7582005-04-28 22:41:06 -0700809CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
810 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811{
812 DELETE_FILE_REQ *pSMB = NULL;
813 DELETE_FILE_RSP *pSMBr = NULL;
814 int rc = 0;
815 int bytes_returned;
816 int name_len;
817
818DelFileRetry:
819 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
820 (void **) &pSMBr);
821 if (rc)
822 return rc;
823
824 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
825 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000826 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700827 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 name_len++; /* trailing null */
829 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700830 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 name_len = strnlen(fileName, PATH_MAX);
832 name_len++; /* trailing null */
833 strncpy(pSMB->fileName, fileName, name_len);
834 }
835 pSMB->SearchAttributes =
836 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
837 pSMB->BufferFormat = 0x04;
838 pSMB->hdr.smb_buf_length += name_len + 1;
839 pSMB->ByteCount = cpu_to_le16(name_len + 1);
840 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
841 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700842 cifs_stats_inc(&tcon->num_deletes);
Steve Frenchad7a2922008-02-07 23:25:02 +0000843 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 cFYI(1, ("Error in RMFile = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845
846 cifs_buf_release(pSMB);
847 if (rc == -EAGAIN)
848 goto DelFileRetry;
849
850 return rc;
851}
852
853int
Steve French50c2f752007-07-13 00:33:32 +0000854CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700855 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856{
857 DELETE_DIRECTORY_REQ *pSMB = NULL;
858 DELETE_DIRECTORY_RSP *pSMBr = NULL;
859 int rc = 0;
860 int bytes_returned;
861 int name_len;
862
863 cFYI(1, ("In CIFSSMBRmDir"));
864RmDirRetry:
865 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
866 (void **) &pSMBr);
867 if (rc)
868 return rc;
869
870 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700871 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
872 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 name_len++; /* trailing null */
874 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700875 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 name_len = strnlen(dirName, PATH_MAX);
877 name_len++; /* trailing null */
878 strncpy(pSMB->DirName, dirName, name_len);
879 }
880
881 pSMB->BufferFormat = 0x04;
882 pSMB->hdr.smb_buf_length += name_len + 1;
883 pSMB->ByteCount = cpu_to_le16(name_len + 1);
884 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
885 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700886 cifs_stats_inc(&tcon->num_rmdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000887 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 cFYI(1, ("Error in RMDir = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889
890 cifs_buf_release(pSMB);
891 if (rc == -EAGAIN)
892 goto RmDirRetry;
893 return rc;
894}
895
896int
897CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700898 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899{
900 int rc = 0;
901 CREATE_DIRECTORY_REQ *pSMB = NULL;
902 CREATE_DIRECTORY_RSP *pSMBr = NULL;
903 int bytes_returned;
904 int name_len;
905
906 cFYI(1, ("In CIFSSMBMkDir"));
907MkDirRetry:
908 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
909 (void **) &pSMBr);
910 if (rc)
911 return rc;
912
913 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000914 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700915 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 name_len++; /* trailing null */
917 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700918 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 name_len = strnlen(name, PATH_MAX);
920 name_len++; /* trailing null */
921 strncpy(pSMB->DirName, name, name_len);
922 }
923
924 pSMB->BufferFormat = 0x04;
925 pSMB->hdr.smb_buf_length += name_len + 1;
926 pSMB->ByteCount = cpu_to_le16(name_len + 1);
927 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
928 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700929 cifs_stats_inc(&tcon->num_mkdirs);
Steve Frenchad7a2922008-02-07 23:25:02 +0000930 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 cFYI(1, ("Error in Mkdir = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -0700932
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933 cifs_buf_release(pSMB);
934 if (rc == -EAGAIN)
935 goto MkDirRetry;
936 return rc;
937}
938
Steve French2dd29d32007-04-23 22:07:35 +0000939int
940CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
Steve Frenchad7a2922008-02-07 23:25:02 +0000941 __u64 mode, __u16 *netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +0000942 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +0000943 const struct nls_table *nls_codepage, int remap)
944{
945 TRANSACTION2_SPI_REQ *pSMB = NULL;
946 TRANSACTION2_SPI_RSP *pSMBr = NULL;
947 int name_len;
948 int rc = 0;
949 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +0000950 __u16 params, param_offset, offset, byte_count, count;
Steve Frenchad7a2922008-02-07 23:25:02 +0000951 OPEN_PSX_REQ *pdata;
952 OPEN_PSX_RSP *psx_rsp;
Steve French2dd29d32007-04-23 22:07:35 +0000953
954 cFYI(1, ("In POSIX Create"));
955PsxCreat:
956 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
957 (void **) &pSMBr);
958 if (rc)
959 return rc;
960
961 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
962 name_len =
963 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
964 PATH_MAX, nls_codepage, remap);
965 name_len++; /* trailing null */
966 name_len *= 2;
967 } else { /* BB improve the check for buffer overruns BB */
968 name_len = strnlen(name, PATH_MAX);
969 name_len++; /* trailing null */
970 strncpy(pSMB->FileName, name, name_len);
971 }
972
973 params = 6 + name_len;
974 count = sizeof(OPEN_PSX_REQ);
975 pSMB->MaxParameterCount = cpu_to_le16(2);
976 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
977 pSMB->MaxSetupCount = 0;
978 pSMB->Reserved = 0;
979 pSMB->Flags = 0;
980 pSMB->Timeout = 0;
981 pSMB->Reserved2 = 0;
982 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +0000983 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +0000984 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +0000985 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +0000986 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +0000987 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +0000988 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +0000989 pdata->OpenFlags = cpu_to_le32(*pOplock);
990 pSMB->ParameterOffset = cpu_to_le16(param_offset);
991 pSMB->DataOffset = cpu_to_le16(offset);
992 pSMB->SetupCount = 1;
993 pSMB->Reserved3 = 0;
994 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
995 byte_count = 3 /* pad */ + params + count;
996
997 pSMB->DataCount = cpu_to_le16(count);
998 pSMB->ParameterCount = cpu_to_le16(params);
999 pSMB->TotalDataCount = pSMB->DataCount;
1000 pSMB->TotalParameterCount = pSMB->ParameterCount;
1001 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1002 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001003 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001004 pSMB->ByteCount = cpu_to_le16(byte_count);
1005 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1006 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1007 if (rc) {
1008 cFYI(1, ("Posix create returned %d", rc));
1009 goto psx_create_err;
1010 }
1011
Steve French790fe572007-07-07 19:25:05 +00001012 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001013 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1014
1015 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1016 rc = -EIO; /* bad smb */
1017 goto psx_create_err;
1018 }
1019
1020 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001021 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001022 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001023
Steve French2dd29d32007-04-23 22:07:35 +00001024 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001025 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001026 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1027 /* Let caller know file was created so we can set the mode. */
1028 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001029 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001030 *pOplock |= CIFS_CREATE_ACTION;
1031 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001032 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1033 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve French90c81e02008-02-12 20:32:36 +00001034 cFYI(DBG2, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001035 } else {
Steve French790fe572007-07-07 19:25:05 +00001036 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001037 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001038 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001039 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001040 goto psx_create_err;
1041 }
Steve French50c2f752007-07-13 00:33:32 +00001042 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001043 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001044 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001045 }
Steve French2dd29d32007-04-23 22:07:35 +00001046
1047psx_create_err:
1048 cifs_buf_release(pSMB);
1049
Steve French65bc98b2009-07-10 15:27:25 +00001050 if (posix_flags & SMB_O_DIRECTORY)
1051 cifs_stats_inc(&tcon->num_posixmkdirs);
1052 else
1053 cifs_stats_inc(&tcon->num_posixopens);
Steve French2dd29d32007-04-23 22:07:35 +00001054
1055 if (rc == -EAGAIN)
1056 goto PsxCreat;
1057
Steve French50c2f752007-07-13 00:33:32 +00001058 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001059}
1060
Steve Frencha9d02ad2005-08-24 23:06:05 -07001061static __u16 convert_disposition(int disposition)
1062{
1063 __u16 ofun = 0;
1064
1065 switch (disposition) {
1066 case FILE_SUPERSEDE:
1067 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1068 break;
1069 case FILE_OPEN:
1070 ofun = SMBOPEN_OAPPEND;
1071 break;
1072 case FILE_CREATE:
1073 ofun = SMBOPEN_OCREATE;
1074 break;
1075 case FILE_OPEN_IF:
1076 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1077 break;
1078 case FILE_OVERWRITE:
1079 ofun = SMBOPEN_OTRUNC;
1080 break;
1081 case FILE_OVERWRITE_IF:
1082 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1083 break;
1084 default:
Steve French790fe572007-07-07 19:25:05 +00001085 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001086 ofun = SMBOPEN_OAPPEND; /* regular open */
1087 }
1088 return ofun;
1089}
1090
Jeff Layton35fc37d2008-05-14 10:22:03 -07001091static int
1092access_flags_to_smbopen_mode(const int access_flags)
1093{
1094 int masked_flags = access_flags & (GENERIC_READ | GENERIC_WRITE);
1095
1096 if (masked_flags == GENERIC_READ)
1097 return SMBOPEN_READ;
1098 else if (masked_flags == GENERIC_WRITE)
1099 return SMBOPEN_WRITE;
1100
1101 /* just go for read/write */
1102 return SMBOPEN_READWRITE;
1103}
1104
Steve Frencha9d02ad2005-08-24 23:06:05 -07001105int
1106SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1107 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001108 const int access_flags, const int create_options, __u16 *netfid,
1109 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001110 const struct nls_table *nls_codepage, int remap)
1111{
1112 int rc = -EACCES;
1113 OPENX_REQ *pSMB = NULL;
1114 OPENX_RSP *pSMBr = NULL;
1115 int bytes_returned;
1116 int name_len;
1117 __u16 count;
1118
1119OldOpenRetry:
1120 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1121 (void **) &pSMBr);
1122 if (rc)
1123 return rc;
1124
1125 pSMB->AndXCommand = 0xFF; /* none */
1126
1127 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1128 count = 1; /* account for one byte pad to word boundary */
1129 name_len =
1130 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1131 fileName, PATH_MAX, nls_codepage, remap);
1132 name_len++; /* trailing null */
1133 name_len *= 2;
1134 } else { /* BB improve check for buffer overruns BB */
1135 count = 0; /* no pad */
1136 name_len = strnlen(fileName, PATH_MAX);
1137 name_len++; /* trailing null */
1138 strncpy(pSMB->fileName, fileName, name_len);
1139 }
1140 if (*pOplock & REQ_OPLOCK)
1141 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001142 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001143 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001144
Steve Frencha9d02ad2005-08-24 23:06:05 -07001145 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
Jeff Layton35fc37d2008-05-14 10:22:03 -07001146 pSMB->Mode = cpu_to_le16(access_flags_to_smbopen_mode(access_flags));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001147 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1148 /* set file as system file if special file such
1149 as fifo and server expecting SFU style and
1150 no Unix extensions */
1151
Steve French790fe572007-07-07 19:25:05 +00001152 if (create_options & CREATE_OPTION_SPECIAL)
1153 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
Steve Frenchad7a2922008-02-07 23:25:02 +00001154 else /* BB FIXME BB */
1155 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001156
Jeff Layton67750fb2008-05-09 22:28:02 +00001157 if (create_options & CREATE_OPTION_READONLY)
1158 pSMB->FileAttributes |= cpu_to_le16(ATTR_READONLY);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001159
1160 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001161/* pSMB->CreateOptions = cpu_to_le32(create_options &
1162 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001163 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001164
1165 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001166 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001167 count += name_len;
1168 pSMB->hdr.smb_buf_length += count;
1169
1170 pSMB->ByteCount = cpu_to_le16(count);
1171 /* long_op set to 1 to allow for oplock break timeouts */
1172 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001173 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001174 cifs_stats_inc(&tcon->num_opens);
1175 if (rc) {
1176 cFYI(1, ("Error in Open = %d", rc));
1177 } else {
1178 /* BB verify if wct == 15 */
1179
Steve French582d21e2008-05-13 04:54:12 +00001180/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field*/
Steve Frencha9d02ad2005-08-24 23:06:05 -07001181
1182 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1183 /* Let caller know file was created so we can set the mode. */
1184 /* Do we care about the CreateAction in any other cases? */
1185 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001186/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001187 *pOplock |= CIFS_CREATE_ACTION; */
1188 /* BB FIXME END */
1189
Steve French790fe572007-07-07 19:25:05 +00001190 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001191 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1192 pfile_info->LastAccessTime = 0; /* BB fixme */
1193 pfile_info->LastWriteTime = 0; /* BB fixme */
1194 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001195 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001196 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001197 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001198 pfile_info->AllocationSize =
1199 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1200 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001201 pfile_info->NumberOfLinks = cpu_to_le32(1);
Jeff Layton9a8165f2008-10-17 21:03:20 -04001202 pfile_info->DeletePending = 0;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001203 }
1204 }
1205
1206 cifs_buf_release(pSMB);
1207 if (rc == -EAGAIN)
1208 goto OldOpenRetry;
1209 return rc;
1210}
1211
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212int
1213CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1214 const char *fileName, const int openDisposition,
Steve Frenchad7a2922008-02-07 23:25:02 +00001215 const int access_flags, const int create_options, __u16 *netfid,
1216 int *pOplock, FILE_ALL_INFO *pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001217 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218{
1219 int rc = -EACCES;
1220 OPEN_REQ *pSMB = NULL;
1221 OPEN_RSP *pSMBr = NULL;
1222 int bytes_returned;
1223 int name_len;
1224 __u16 count;
1225
1226openRetry:
1227 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1228 (void **) &pSMBr);
1229 if (rc)
1230 return rc;
1231
1232 pSMB->AndXCommand = 0xFF; /* none */
1233
1234 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1235 count = 1; /* account for one byte pad to word boundary */
1236 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001237 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001238 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 name_len++; /* trailing null */
1240 name_len *= 2;
1241 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001242 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 count = 0; /* no pad */
1244 name_len = strnlen(fileName, PATH_MAX);
1245 name_len++; /* trailing null */
1246 pSMB->NameLength = cpu_to_le16(name_len);
1247 strncpy(pSMB->fileName, fileName, name_len);
1248 }
1249 if (*pOplock & REQ_OPLOCK)
1250 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001251 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1254 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001255 /* set file as system file if special file such
1256 as fifo and server expecting SFU style and
1257 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001258 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001259 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1260 else
1261 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Jeff Layton67750fb2008-05-09 22:28:02 +00001262
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 /* XP does not handle ATTR_POSIX_SEMANTICS */
1264 /* but it helps speed up case sensitive checks for other
1265 servers such as Samba */
1266 if (tcon->ses->capabilities & CAP_UNIX)
1267 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1268
Jeff Layton67750fb2008-05-09 22:28:02 +00001269 if (create_options & CREATE_OPTION_READONLY)
1270 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);
1271
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1273 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001274 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001275 /* BB Expirement with various impersonation levels and verify */
1276 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 pSMB->SecurityFlags =
1278 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1279
1280 count += name_len;
1281 pSMB->hdr.smb_buf_length += count;
1282
1283 pSMB->ByteCount = cpu_to_le16(count);
1284 /* long_op set to 1 to allow for oplock break timeouts */
1285 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001286 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha4544342005-08-24 13:59:35 -07001287 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 if (rc) {
1289 cFYI(1, ("Error in Open = %d", rc));
1290 } else {
Steve French09d1db52005-04-28 22:41:08 -07001291 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1293 /* Let caller know file was created so we can set the mode. */
1294 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001295 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001296 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001297 if (pfile_info) {
Steve French61e74802008-12-03 00:57:54 +00001298 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
1299 36 /* CreationTime to Attributes */);
1300 /* the file_info buf is endian converted by caller */
1301 pfile_info->AllocationSize = pSMBr->AllocationSize;
1302 pfile_info->EndOfFile = pSMBr->EndOfFile;
1303 pfile_info->NumberOfLinks = cpu_to_le32(1);
1304 pfile_info->DeletePending = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001306 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001307
Linus Torvalds1da177e2005-04-16 15:20:36 -07001308 cifs_buf_release(pSMB);
1309 if (rc == -EAGAIN)
1310 goto openRetry;
1311 return rc;
1312}
1313
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314int
Steve French50c2f752007-07-13 00:33:32 +00001315CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1316 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1317 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318{
1319 int rc = -EACCES;
1320 READ_REQ *pSMB = NULL;
1321 READ_RSP *pSMBr = NULL;
1322 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001323 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001324 int resp_buf_type = 0;
1325 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
Steve French790fe572007-07-07 19:25:05 +00001327 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1328 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001329 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001330 else {
Steve Frenchbfa0d752005-08-31 21:50:37 -07001331 wct = 10; /* old style read */
Steve French4c3130e2008-12-09 00:28:16 +00001332 if ((lseek >> 32) > 0) {
1333 /* can not handle this big offset for old */
1334 return -EIO;
1335 }
1336 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337
1338 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001339 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 if (rc)
1341 return rc;
1342
1343 /* tcon and ses pointer are checked in smb_init */
1344 if (tcon->ses->server == NULL)
1345 return -ECONNABORTED;
1346
Steve Frenchec637e32005-12-12 20:53:18 -08001347 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 pSMB->Fid = netfid;
1349 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001350 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001351 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve Frenchbfa0d752005-08-31 21:50:37 -07001352
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 pSMB->Remaining = 0;
1354 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1355 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001356 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001357 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1358 else {
1359 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001360 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001361 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001362 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001363 }
Steve Frenchec637e32005-12-12 20:53:18 -08001364
1365 iov[0].iov_base = (char *)pSMB;
1366 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001367 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001368 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001369 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001370 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 if (rc) {
1372 cERROR(1, ("Send error in read = %d", rc));
1373 } else {
1374 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1375 data_length = data_length << 16;
1376 data_length += le16_to_cpu(pSMBr->DataLength);
1377 *nbytes = data_length;
1378
1379 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001380 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001382 cFYI(1, ("bad length %d for count %d",
1383 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 rc = -EIO;
1385 *nbytes = 0;
1386 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001387 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001388 le16_to_cpu(pSMBr->DataOffset);
1389/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001390 cERROR(1,("Faulting on read rc = %d",rc));
1391 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001392 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001393 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001394 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395 }
1396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397
Steve French4b8f9302006-02-26 16:41:18 +00001398/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001399 if (*buf) {
1400 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001401 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001402 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001403 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001404 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001405 /* return buffer to caller to free */
1406 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001407 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001408 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001409 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001410 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001411 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001412
1413 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 since file handle passed in no longer valid */
1415 return rc;
1416}
1417
Steve Frenchec637e32005-12-12 20:53:18 -08001418
Linus Torvalds1da177e2005-04-16 15:20:36 -07001419int
1420CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1421 const int netfid, const unsigned int count,
1422 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001423 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424{
1425 int rc = -EACCES;
1426 WRITE_REQ *pSMB = NULL;
1427 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001428 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 __u32 bytes_sent;
1430 __u16 byte_count;
1431
Steve French61de8002008-10-30 20:15:22 +00001432 /* cFYI(1, ("write at %lld %d bytes", offset, count));*/
Steve French790fe572007-07-07 19:25:05 +00001433 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001434 return -ECONNABORTED;
1435
Steve French790fe572007-07-07 19:25:05 +00001436 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001437 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001438 else {
Steve French1c955182005-08-30 20:58:07 -07001439 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001440 if ((offset >> 32) > 0) {
1441 /* can not handle big offset for old srv */
1442 return -EIO;
1443 }
1444 }
Steve French1c955182005-08-30 20:58:07 -07001445
1446 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 (void **) &pSMBr);
1448 if (rc)
1449 return rc;
1450 /* tcon and ses pointer are checked in smb_init */
1451 if (tcon->ses->server == NULL)
1452 return -ECONNABORTED;
1453
1454 pSMB->AndXCommand = 0xFF; /* none */
1455 pSMB->Fid = netfid;
1456 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001457 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001458 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French50c2f752007-07-13 00:33:32 +00001459
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 pSMB->Reserved = 0xFFFFFFFF;
1461 pSMB->WriteMode = 0;
1462 pSMB->Remaining = 0;
1463
Steve French50c2f752007-07-13 00:33:32 +00001464 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 can send more if LARGE_WRITE_X capability returned by the server and if
1466 our buffer is big enough or if we convert to iovecs on socket writes
1467 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001468 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1470 } else {
1471 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1472 & ~0xFF;
1473 }
1474
1475 if (bytes_sent > count)
1476 bytes_sent = count;
1477 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001478 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001479 if (buf)
Steve French61e74802008-12-03 00:57:54 +00001480 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001481 else if (ubuf) {
1482 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 cifs_buf_release(pSMB);
1484 return -EFAULT;
1485 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001486 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487 /* No buffer */
1488 cifs_buf_release(pSMB);
1489 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001490 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001491 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001492 byte_count = bytes_sent + 1; /* pad */
Steve Frenchad7a2922008-02-07 23:25:02 +00001493 else /* wct == 12 */
Steve Frenche30dcf32005-09-20 20:49:16 -07001494 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Steve Frenchad7a2922008-02-07 23:25:02 +00001495
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1497 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001498 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001499
Steve French790fe572007-07-07 19:25:05 +00001500 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001501 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001502 else { /* old style write has byte count 4 bytes earlier
1503 so 4 bytes pad */
1504 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001505 (struct smb_com_writex_req *)pSMB;
1506 pSMBW->ByteCount = cpu_to_le16(byte_count);
1507 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508
1509 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1510 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001511 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 if (rc) {
1513 cFYI(1, ("Send error in write = %d", rc));
1514 *nbytes = 0;
1515 } else {
1516 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1517 *nbytes = (*nbytes) << 16;
1518 *nbytes += le16_to_cpu(pSMBr->Count);
1519 }
1520
1521 cifs_buf_release(pSMB);
1522
Steve French50c2f752007-07-13 00:33:32 +00001523 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 since file handle passed in no longer valid */
1525
1526 return rc;
1527}
1528
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001529int
1530CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001532 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1533 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534{
1535 int rc = -EACCES;
1536 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001537 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001538 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001539 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540
Jeff Laytonfbec9ab2009-04-03 13:44:00 -04001541 *nbytes = 0;
1542
Steve French790fe572007-07-07 19:25:05 +00001543 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001544
Steve French4c3130e2008-12-09 00:28:16 +00001545 if (tcon->ses->capabilities & CAP_LARGE_FILES) {
Steve French8cc64c62005-10-03 13:49:43 -07001546 wct = 14;
Steve French4c3130e2008-12-09 00:28:16 +00001547 } else {
Steve French8cc64c62005-10-03 13:49:43 -07001548 wct = 12;
Steve French4c3130e2008-12-09 00:28:16 +00001549 if ((offset >> 32) > 0) {
1550 /* can not handle big offset for old srv */
1551 return -EIO;
1552 }
1553 }
Steve French8cc64c62005-10-03 13:49:43 -07001554 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 if (rc)
1556 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 /* tcon and ses pointer are checked in smb_init */
1558 if (tcon->ses->server == NULL)
1559 return -ECONNABORTED;
1560
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001561 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 pSMB->Fid = netfid;
1563 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001564 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001565 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 pSMB->Reserved = 0xFFFFFFFF;
1567 pSMB->WriteMode = 0;
1568 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001569
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001571 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
Steve French3e844692005-10-03 13:37:24 -07001573 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1574 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001575 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001576 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001577 pSMB->hdr.smb_buf_length += count+1;
1578 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001579 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1580 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001581 pSMB->ByteCount = cpu_to_le16(count + 1);
1582 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001583 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001584 (struct smb_com_writex_req *)pSMB;
1585 pSMBW->ByteCount = cpu_to_le16(count + 5);
1586 }
Steve French3e844692005-10-03 13:37:24 -07001587 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001588 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001589 iov[0].iov_len = smb_hdr_len + 4;
1590 else /* wct == 12 pad bigger by four bytes */
1591 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001592
Steve French3e844692005-10-03 13:37:24 -07001593
Steve Frenchec637e32005-12-12 20:53:18 -08001594 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001595 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001596 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001598 cFYI(1, ("Send error Write2 = %d", rc));
Steve French790fe572007-07-07 19:25:05 +00001599 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001600 /* presumably this can not happen, but best to be safe */
1601 rc = -EIO;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001602 } else {
Steve Frenchad7a2922008-02-07 23:25:02 +00001603 WRITE_RSP *pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001604 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1605 *nbytes = (*nbytes) << 16;
1606 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001607 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608
Steve French4b8f9302006-02-26 16:41:18 +00001609/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001610 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001611 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001612 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001613 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614
Steve French50c2f752007-07-13 00:33:32 +00001615 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 since file handle passed in no longer valid */
1617
1618 return rc;
1619}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001620
1621
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622int
1623CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1624 const __u16 smb_file_id, const __u64 len,
1625 const __u64 offset, const __u32 numUnlock,
Steve French4b18f2a2008-04-29 00:06:05 +00001626 const __u32 numLock, const __u8 lockType, const bool waitFlag)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627{
1628 int rc = 0;
1629 LOCK_REQ *pSMB = NULL;
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001630/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 int bytes_returned;
1632 int timeout = 0;
1633 __u16 count;
1634
Steve French4b18f2a2008-04-29 00:06:05 +00001635 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", (int)waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001636 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1637
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 if (rc)
1639 return rc;
1640
Steve French790fe572007-07-07 19:25:05 +00001641 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001642 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 pSMB->Timeout = 0;
Steve French4b18f2a2008-04-29 00:06:05 +00001644 } else if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001645 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1647 } else {
1648 pSMB->Timeout = 0;
1649 }
1650
1651 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1652 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1653 pSMB->LockType = lockType;
1654 pSMB->AndXCommand = 0xFF; /* none */
1655 pSMB->Fid = smb_file_id; /* netfid stays le */
1656
Steve French790fe572007-07-07 19:25:05 +00001657 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1659 /* BB where to store pid high? */
1660 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1661 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1662 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1663 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1664 count = sizeof(LOCKING_ANDX_RANGE);
1665 } else {
1666 /* oplock break */
1667 count = 0;
1668 }
1669 pSMB->hdr.smb_buf_length += count;
1670 pSMB->ByteCount = cpu_to_le16(count);
1671
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001672 if (waitFlag) {
1673 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
Steve Frenchaaa9bbe2008-05-23 17:38:32 +00001674 (struct smb_hdr *) pSMB, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001675 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001676 } else {
Steve French133672e2007-11-13 22:41:37 +00001677 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1678 timeout);
1679 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001680 }
Steve Frencha4544342005-08-24 13:59:35 -07001681 cifs_stats_inc(&tcon->num_locks);
Steve Frenchad7a2922008-02-07 23:25:02 +00001682 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 cFYI(1, ("Send error in Lock = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
Steve French50c2f752007-07-13 00:33:32 +00001685 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 since file handle passed in no longer valid */
1687 return rc;
1688}
1689
1690int
Steve French08547b02006-02-28 22:39:25 +00001691CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1692 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001693 struct file_lock *pLockData, const __u16 lock_type,
Steve French4b18f2a2008-04-29 00:06:05 +00001694 const bool waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001695{
1696 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1697 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001698 struct cifs_posix_lock *parm_data;
1699 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001700 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001701 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001702 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001703 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001704 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001705
1706 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001707
Steve French790fe572007-07-07 19:25:05 +00001708 if (pLockData == NULL)
Marcin Slusarzed5f0372008-05-13 04:01:01 +00001709 return -EINVAL;
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001710
Steve French08547b02006-02-28 22:39:25 +00001711 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1712
1713 if (rc)
1714 return rc;
1715
1716 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1717
Steve French50c2f752007-07-13 00:33:32 +00001718 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001719 pSMB->MaxSetupCount = 0;
1720 pSMB->Reserved = 0;
1721 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001722 pSMB->Reserved2 = 0;
1723 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1724 offset = param_offset + params;
1725
Steve French08547b02006-02-28 22:39:25 +00001726 count = sizeof(struct cifs_posix_lock);
1727 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001728 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Steve French08547b02006-02-28 22:39:25 +00001729 pSMB->SetupCount = 1;
1730 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001731 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001732 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1733 else
1734 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1735 byte_count = 3 /* pad */ + params + count;
1736 pSMB->DataCount = cpu_to_le16(count);
1737 pSMB->ParameterCount = cpu_to_le16(params);
1738 pSMB->TotalDataCount = pSMB->DataCount;
1739 pSMB->TotalParameterCount = pSMB->ParameterCount;
1740 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001741 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001742 (((char *) &pSMB->hdr.Protocol) + offset);
1743
1744 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001745 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001746 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001747 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001748 pSMB->Timeout = cpu_to_le32(-1);
1749 } else
1750 pSMB->Timeout = 0;
1751
Steve French08547b02006-02-28 22:39:25 +00001752 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001753 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001754 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001755
1756 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001757 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001758 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1759 pSMB->Reserved4 = 0;
1760 pSMB->hdr.smb_buf_length += byte_count;
1761 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001762 if (waitFlag) {
1763 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1764 (struct smb_hdr *) pSMBr, &bytes_returned);
1765 } else {
Steve French133672e2007-11-13 22:41:37 +00001766 iov[0].iov_base = (char *)pSMB;
1767 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1768 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1769 &resp_buf_type, timeout);
1770 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1771 not try to free it twice below on exit */
1772 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001773 }
1774
Steve French08547b02006-02-28 22:39:25 +00001775 if (rc) {
1776 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001777 } else if (get_flag) {
1778 /* lock structure can be returned on get */
1779 __u16 data_offset;
1780 __u16 data_count;
1781 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001782
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001783 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1784 rc = -EIO; /* bad smb */
1785 goto plk_err_exit;
1786 }
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001787 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1788 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001789 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001790 rc = -EIO;
1791 goto plk_err_exit;
1792 }
1793 parm_data = (struct cifs_posix_lock *)
1794 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001795 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001796 pLockData->fl_type = F_UNLCK;
1797 }
Steve French50c2f752007-07-13 00:33:32 +00001798
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001799plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001800 if (pSMB)
1801 cifs_small_buf_release(pSMB);
1802
Steve French133672e2007-11-13 22:41:37 +00001803 if (resp_buf_type == CIFS_SMALL_BUFFER)
1804 cifs_small_buf_release(iov[0].iov_base);
1805 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1806 cifs_buf_release(iov[0].iov_base);
1807
Steve French08547b02006-02-28 22:39:25 +00001808 /* Note: On -EAGAIN error only caller can retry on handle based calls
1809 since file handle passed in no longer valid */
1810
1811 return rc;
1812}
1813
1814
1815int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1817{
1818 int rc = 0;
1819 CLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 cFYI(1, ("In CIFSSMBClose"));
1821
1822/* do not retry on dead session on close */
1823 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001824 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 return 0;
1826 if (rc)
1827 return rc;
1828
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001830 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001832 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001833 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001835 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001836 /* EINTR is expected when user ctl-c to kill app */
1837 cERROR(1, ("Send error in Close = %d", rc));
1838 }
1839 }
1840
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001842 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843 rc = 0;
1844
1845 return rc;
1846}
1847
1848int
Steve Frenchb298f222009-02-21 21:17:43 +00001849CIFSSMBFlush(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1850{
1851 int rc = 0;
1852 FLUSH_REQ *pSMB = NULL;
1853 cFYI(1, ("In CIFSSMBFlush"));
1854
1855 rc = small_smb_init(SMB_COM_FLUSH, 1, tcon, (void **) &pSMB);
1856 if (rc)
1857 return rc;
1858
1859 pSMB->FileID = (__u16) smb_file_id;
1860 pSMB->ByteCount = 0;
1861 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
1862 cifs_stats_inc(&tcon->num_flushes);
1863 if (rc)
1864 cERROR(1, ("Send error in Flush = %d", rc));
1865
1866 return rc;
1867}
1868
1869int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1871 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001872 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873{
1874 int rc = 0;
1875 RENAME_REQ *pSMB = NULL;
1876 RENAME_RSP *pSMBr = NULL;
1877 int bytes_returned;
1878 int name_len, name_len2;
1879 __u16 count;
1880
1881 cFYI(1, ("In CIFSSMBRename"));
1882renameRetry:
1883 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1884 (void **) &pSMBr);
1885 if (rc)
1886 return rc;
1887
1888 pSMB->BufferFormat = 0x04;
1889 pSMB->SearchAttributes =
1890 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1891 ATTR_DIRECTORY);
1892
1893 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1894 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001895 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001896 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 name_len++; /* trailing null */
1898 name_len *= 2;
1899 pSMB->OldFileName[name_len] = 0x04; /* pad */
1900 /* protocol requires ASCII signature byte on Unicode string */
1901 pSMB->OldFileName[name_len + 1] = 0x00;
1902 name_len2 =
Steve French582d21e2008-05-13 04:54:12 +00001903 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001904 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1906 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001907 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 name_len = strnlen(fromName, PATH_MAX);
1909 name_len++; /* trailing null */
1910 strncpy(pSMB->OldFileName, fromName, name_len);
1911 name_len2 = strnlen(toName, PATH_MAX);
1912 name_len2++; /* trailing null */
1913 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1914 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1915 name_len2++; /* trailing null */
1916 name_len2++; /* signature byte */
1917 }
1918
1919 count = 1 /* 1st signature byte */ + name_len + name_len2;
1920 pSMB->hdr.smb_buf_length += count;
1921 pSMB->ByteCount = cpu_to_le16(count);
1922
1923 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1924 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001925 cifs_stats_inc(&tcon->num_renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00001926 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001927 cFYI(1, ("Send error in rename = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 cifs_buf_release(pSMB);
1930
1931 if (rc == -EAGAIN)
1932 goto renameRetry;
1933
1934 return rc;
1935}
1936
Steve French50c2f752007-07-13 00:33:32 +00001937int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
Jeff Layton391e5752008-09-24 11:32:59 -04001938 int netfid, const char *target_name,
Steve French50c2f752007-07-13 00:33:32 +00001939 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940{
1941 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1942 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001943 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 char *data_offset;
1945 char dummy_string[30];
1946 int rc = 0;
1947 int bytes_returned = 0;
1948 int len_of_str;
1949 __u16 params, param_offset, offset, count, byte_count;
1950
1951 cFYI(1, ("Rename to File by handle"));
1952 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1953 (void **) &pSMBr);
1954 if (rc)
1955 return rc;
1956
1957 params = 6;
1958 pSMB->MaxSetupCount = 0;
1959 pSMB->Reserved = 0;
1960 pSMB->Flags = 0;
1961 pSMB->Timeout = 0;
1962 pSMB->Reserved2 = 0;
1963 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1964 offset = param_offset + params;
1965
1966 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1967 rename_info = (struct set_file_rename *) data_offset;
1968 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve Frenchad7a2922008-02-07 23:25:02 +00001969 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB from sess */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 pSMB->SetupCount = 1;
1971 pSMB->Reserved3 = 0;
1972 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1973 byte_count = 3 /* pad */ + params;
1974 pSMB->ParameterCount = cpu_to_le16(params);
1975 pSMB->TotalParameterCount = pSMB->ParameterCount;
1976 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1977 pSMB->DataOffset = cpu_to_le16(offset);
1978 /* construct random name ".cifs_tmp<inodenum><mid>" */
1979 rename_info->overwrite = cpu_to_le32(1);
1980 rename_info->root_fid = 0;
1981 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00001982 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00001983 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
1984 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07001985 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05001987 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00001988 target_name, PATH_MAX, nls_codepage,
1989 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990 }
1991 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
Jeff Layton391e5752008-09-24 11:32:59 -04001992 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 byte_count += count;
1994 pSMB->DataCount = cpu_to_le16(count);
1995 pSMB->TotalDataCount = pSMB->DataCount;
1996 pSMB->Fid = netfid;
1997 pSMB->InformationLevel =
1998 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1999 pSMB->Reserved4 = 0;
2000 pSMB->hdr.smb_buf_length += byte_count;
2001 pSMB->ByteCount = cpu_to_le16(byte_count);
2002 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002003 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002004 cifs_stats_inc(&pTcon->num_t2renames);
Steve Frenchad7a2922008-02-07 23:25:02 +00002005 if (rc)
Steve French790fe572007-07-07 19:25:05 +00002006 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Steve Frencha5a2b482005-08-20 21:42:53 -07002007
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 cifs_buf_release(pSMB);
2009
2010 /* Note: On -EAGAIN error only caller can retry on handle based calls
2011 since file handle passed in no longer valid */
2012
2013 return rc;
2014}
2015
2016int
Steve French50c2f752007-07-13 00:33:32 +00002017CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2018 const __u16 target_tid, const char *toName, const int flags,
2019 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020{
2021 int rc = 0;
2022 COPY_REQ *pSMB = NULL;
2023 COPY_RSP *pSMBr = NULL;
2024 int bytes_returned;
2025 int name_len, name_len2;
2026 __u16 count;
2027
2028 cFYI(1, ("In CIFSSMBCopy"));
2029copyRetry:
2030 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2031 (void **) &pSMBr);
2032 if (rc)
2033 return rc;
2034
2035 pSMB->BufferFormat = 0x04;
2036 pSMB->Tid2 = target_tid;
2037
2038 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2039
2040 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002041 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002042 fromName, PATH_MAX, nls_codepage,
2043 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 name_len++; /* trailing null */
2045 name_len *= 2;
2046 pSMB->OldFileName[name_len] = 0x04; /* pad */
2047 /* protocol requires ASCII signature byte on Unicode string */
2048 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002049 name_len2 =
2050 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002051 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2053 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002054 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 name_len = strnlen(fromName, PATH_MAX);
2056 name_len++; /* trailing null */
2057 strncpy(pSMB->OldFileName, fromName, name_len);
2058 name_len2 = strnlen(toName, PATH_MAX);
2059 name_len2++; /* trailing null */
2060 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2061 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2062 name_len2++; /* trailing null */
2063 name_len2++; /* signature byte */
2064 }
2065
2066 count = 1 /* 1st signature byte */ + name_len + name_len2;
2067 pSMB->hdr.smb_buf_length += count;
2068 pSMB->ByteCount = cpu_to_le16(count);
2069
2070 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2071 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2072 if (rc) {
2073 cFYI(1, ("Send error in copy = %d with %d files copied",
2074 rc, le16_to_cpu(pSMBr->CopyCount)));
2075 }
Steve French0d817bc2008-05-22 02:02:03 +00002076 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
2078 if (rc == -EAGAIN)
2079 goto copyRetry;
2080
2081 return rc;
2082}
2083
2084int
2085CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2086 const char *fromName, const char *toName,
2087 const struct nls_table *nls_codepage)
2088{
2089 TRANSACTION2_SPI_REQ *pSMB = NULL;
2090 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2091 char *data_offset;
2092 int name_len;
2093 int name_len_target;
2094 int rc = 0;
2095 int bytes_returned = 0;
2096 __u16 params, param_offset, offset, byte_count;
2097
2098 cFYI(1, ("In Symlink Unix style"));
2099createSymLinkRetry:
2100 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2101 (void **) &pSMBr);
2102 if (rc)
2103 return rc;
2104
2105 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2106 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002107 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 /* find define for this maxpathcomponent */
2109 , nls_codepage);
2110 name_len++; /* trailing null */
2111 name_len *= 2;
2112
Steve French50c2f752007-07-13 00:33:32 +00002113 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 name_len = strnlen(fromName, PATH_MAX);
2115 name_len++; /* trailing null */
2116 strncpy(pSMB->FileName, fromName, name_len);
2117 }
2118 params = 6 + name_len;
2119 pSMB->MaxSetupCount = 0;
2120 pSMB->Reserved = 0;
2121 pSMB->Flags = 0;
2122 pSMB->Timeout = 0;
2123 pSMB->Reserved2 = 0;
2124 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002125 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126 offset = param_offset + params;
2127
2128 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2129 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2130 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002131 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002132 /* find define for this maxpathcomponent */
2133 , nls_codepage);
2134 name_len_target++; /* trailing null */
2135 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002136 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002137 name_len_target = strnlen(toName, PATH_MAX);
2138 name_len_target++; /* trailing null */
2139 strncpy(data_offset, toName, name_len_target);
2140 }
2141
2142 pSMB->MaxParameterCount = cpu_to_le16(2);
2143 /* BB find exact max on data count below from sess */
2144 pSMB->MaxDataCount = cpu_to_le16(1000);
2145 pSMB->SetupCount = 1;
2146 pSMB->Reserved3 = 0;
2147 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2148 byte_count = 3 /* pad */ + params + name_len_target;
2149 pSMB->DataCount = cpu_to_le16(name_len_target);
2150 pSMB->ParameterCount = cpu_to_le16(params);
2151 pSMB->TotalDataCount = pSMB->DataCount;
2152 pSMB->TotalParameterCount = pSMB->ParameterCount;
2153 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2154 pSMB->DataOffset = cpu_to_le16(offset);
2155 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2156 pSMB->Reserved4 = 0;
2157 pSMB->hdr.smb_buf_length += byte_count;
2158 pSMB->ByteCount = cpu_to_le16(byte_count);
2159 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2160 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002161 cifs_stats_inc(&tcon->num_symlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002162 if (rc)
Steve French2d785a52007-07-15 01:48:57 +00002163 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164
Steve French0d817bc2008-05-22 02:02:03 +00002165 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166
2167 if (rc == -EAGAIN)
2168 goto createSymLinkRetry;
2169
2170 return rc;
2171}
2172
2173int
2174CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2175 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002176 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177{
2178 TRANSACTION2_SPI_REQ *pSMB = NULL;
2179 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2180 char *data_offset;
2181 int name_len;
2182 int name_len_target;
2183 int rc = 0;
2184 int bytes_returned = 0;
2185 __u16 params, param_offset, offset, byte_count;
2186
2187 cFYI(1, ("In Create Hard link Unix style"));
2188createHardLinkRetry:
2189 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2190 (void **) &pSMBr);
2191 if (rc)
2192 return rc;
2193
2194 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002195 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002196 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 name_len++; /* trailing null */
2198 name_len *= 2;
2199
Steve French50c2f752007-07-13 00:33:32 +00002200 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 name_len = strnlen(toName, PATH_MAX);
2202 name_len++; /* trailing null */
2203 strncpy(pSMB->FileName, toName, name_len);
2204 }
2205 params = 6 + name_len;
2206 pSMB->MaxSetupCount = 0;
2207 pSMB->Reserved = 0;
2208 pSMB->Flags = 0;
2209 pSMB->Timeout = 0;
2210 pSMB->Reserved2 = 0;
2211 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002212 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213 offset = param_offset + params;
2214
2215 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2216 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2217 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002218 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002219 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 name_len_target++; /* trailing null */
2221 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002222 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 name_len_target = strnlen(fromName, PATH_MAX);
2224 name_len_target++; /* trailing null */
2225 strncpy(data_offset, fromName, name_len_target);
2226 }
2227
2228 pSMB->MaxParameterCount = cpu_to_le16(2);
2229 /* BB find exact max on data count below from sess*/
2230 pSMB->MaxDataCount = cpu_to_le16(1000);
2231 pSMB->SetupCount = 1;
2232 pSMB->Reserved3 = 0;
2233 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2234 byte_count = 3 /* pad */ + params + name_len_target;
2235 pSMB->ParameterCount = cpu_to_le16(params);
2236 pSMB->TotalParameterCount = pSMB->ParameterCount;
2237 pSMB->DataCount = cpu_to_le16(name_len_target);
2238 pSMB->TotalDataCount = pSMB->DataCount;
2239 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2240 pSMB->DataOffset = cpu_to_le16(offset);
2241 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2242 pSMB->Reserved4 = 0;
2243 pSMB->hdr.smb_buf_length += byte_count;
2244 pSMB->ByteCount = cpu_to_le16(byte_count);
2245 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2246 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002247 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002248 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250
2251 cifs_buf_release(pSMB);
2252 if (rc == -EAGAIN)
2253 goto createHardLinkRetry;
2254
2255 return rc;
2256}
2257
2258int
2259CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2260 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002261 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262{
2263 int rc = 0;
2264 NT_RENAME_REQ *pSMB = NULL;
2265 RENAME_RSP *pSMBr = NULL;
2266 int bytes_returned;
2267 int name_len, name_len2;
2268 __u16 count;
2269
2270 cFYI(1, ("In CIFSCreateHardLink"));
2271winCreateHardLinkRetry:
2272
2273 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2274 (void **) &pSMBr);
2275 if (rc)
2276 return rc;
2277
2278 pSMB->SearchAttributes =
2279 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2280 ATTR_DIRECTORY);
2281 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2282 pSMB->ClusterCount = 0;
2283
2284 pSMB->BufferFormat = 0x04;
2285
2286 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2287 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002288 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002289 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 name_len++; /* trailing null */
2291 name_len *= 2;
Jeff Laytonfcc7c092009-02-28 12:59:03 -05002292
2293 /* protocol specifies ASCII buffer format (0x04) for unicode */
2294 pSMB->OldFileName[name_len] = 0x04;
2295 pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002297 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002298 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2300 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002301 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 name_len = strnlen(fromName, PATH_MAX);
2303 name_len++; /* trailing null */
2304 strncpy(pSMB->OldFileName, fromName, name_len);
2305 name_len2 = strnlen(toName, PATH_MAX);
2306 name_len2++; /* trailing null */
2307 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2308 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2309 name_len2++; /* trailing null */
2310 name_len2++; /* signature byte */
2311 }
2312
2313 count = 1 /* string type byte */ + name_len + name_len2;
2314 pSMB->hdr.smb_buf_length += count;
2315 pSMB->ByteCount = cpu_to_le16(count);
2316
2317 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2318 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002319 cifs_stats_inc(&tcon->num_hardlinks);
Steve Frenchad7a2922008-02-07 23:25:02 +00002320 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002321 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00002322
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 cifs_buf_release(pSMB);
2324 if (rc == -EAGAIN)
2325 goto winCreateHardLinkRetry;
2326
2327 return rc;
2328}
2329
2330int
2331CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
Jeff Layton460b9692009-04-30 07:17:56 -04002332 const unsigned char *searchName, char **symlinkinfo,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 const struct nls_table *nls_codepage)
2334{
2335/* SMB_QUERY_FILE_UNIX_LINK */
2336 TRANSACTION2_QPI_REQ *pSMB = NULL;
2337 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2338 int rc = 0;
2339 int bytes_returned;
2340 int name_len;
2341 __u16 params, byte_count;
Jeff Layton460b9692009-04-30 07:17:56 -04002342 char *data_start;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343
2344 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2345
2346querySymLinkRetry:
2347 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2348 (void **) &pSMBr);
2349 if (rc)
2350 return rc;
2351
2352 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2353 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002354 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2355 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 name_len++; /* trailing null */
2357 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002358 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 name_len = strnlen(searchName, PATH_MAX);
2360 name_len++; /* trailing null */
2361 strncpy(pSMB->FileName, searchName, name_len);
2362 }
2363
2364 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2365 pSMB->TotalDataCount = 0;
2366 pSMB->MaxParameterCount = cpu_to_le16(2);
Jeff Layton46a75742009-05-24 18:45:17 -04002367 pSMB->MaxDataCount = cpu_to_le16(CIFSMaxBufSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368 pSMB->MaxSetupCount = 0;
2369 pSMB->Reserved = 0;
2370 pSMB->Flags = 0;
2371 pSMB->Timeout = 0;
2372 pSMB->Reserved2 = 0;
2373 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002374 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 pSMB->DataCount = 0;
2376 pSMB->DataOffset = 0;
2377 pSMB->SetupCount = 1;
2378 pSMB->Reserved3 = 0;
2379 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2380 byte_count = params + 1 /* pad */ ;
2381 pSMB->TotalParameterCount = cpu_to_le16(params);
2382 pSMB->ParameterCount = pSMB->TotalParameterCount;
2383 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2384 pSMB->Reserved4 = 0;
2385 pSMB->hdr.smb_buf_length += byte_count;
2386 pSMB->ByteCount = cpu_to_le16(byte_count);
2387
2388 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2389 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2390 if (rc) {
2391 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2392 } else {
2393 /* decode response */
2394
2395 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396 /* BB also check enough total bytes returned */
Jeff Layton460b9692009-04-30 07:17:56 -04002397 if (rc || (pSMBr->ByteCount < 2))
2398 rc = -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 else {
Steve French0e0d2cf2009-05-01 05:27:32 +00002400 bool is_unicode;
Jeff Layton460b9692009-04-30 07:17:56 -04002401 u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402
Jeff Layton460b9692009-04-30 07:17:56 -04002403 data_start = ((char *) &pSMBr->hdr.Protocol) +
2404 le16_to_cpu(pSMBr->t2.DataOffset);
2405
Steve French0e0d2cf2009-05-01 05:27:32 +00002406 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2407 is_unicode = true;
2408 else
2409 is_unicode = false;
2410
Steve French737b7582005-04-28 22:41:06 -07002411 /* BB FIXME investigate remapping reserved chars here */
Steve Frenchd185cda2009-04-30 17:45:10 +00002412 *symlinkinfo = cifs_strndup_from_ucs(data_start, count,
Steve French0e0d2cf2009-05-01 05:27:32 +00002413 is_unicode, nls_codepage);
Jeff Layton8b6427a2009-05-19 09:57:03 -04002414 if (!*symlinkinfo)
Jeff Layton460b9692009-04-30 07:17:56 -04002415 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 }
2417 }
2418 cifs_buf_release(pSMB);
2419 if (rc == -EAGAIN)
2420 goto querySymLinkRetry;
2421 return rc;
2422}
2423
Parag Warudkarc9489772007-10-23 18:09:48 +00002424#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002425/* Initialize NT TRANSACT SMB into small smb request buffer.
2426 This assumes that all NT TRANSACTS that we init here have
2427 total parm and data under about 400 bytes (to fit in small cifs
2428 buffer size), which is the case so far, it easily fits. NB:
2429 Setup words themselves and ByteCount
2430 MaxSetupCount (size of returned setup area) and
2431 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002432static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002433smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002434 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002435 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002436{
2437 int rc;
2438 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002439 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002440
2441 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2442 (void **)&pSMB);
2443 if (rc)
2444 return rc;
2445 *ret_buf = (void *)pSMB;
2446 pSMB->Reserved = 0;
2447 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2448 pSMB->TotalDataCount = 0;
2449 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2450 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2451 pSMB->ParameterCount = pSMB->TotalParameterCount;
2452 pSMB->DataCount = pSMB->TotalDataCount;
2453 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2454 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2455 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2456 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2457 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2458 pSMB->SubCommand = cpu_to_le16(sub_command);
2459 return 0;
2460}
2461
2462static int
Steve French50c2f752007-07-13 00:33:32 +00002463validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002464 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002465{
Steve French50c2f752007-07-13 00:33:32 +00002466 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002467 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002468 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002469
Steve French630f3f0c2007-10-25 21:17:17 +00002470 *pdatalen = 0;
2471 *pparmlen = 0;
2472
Steve French790fe572007-07-07 19:25:05 +00002473 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002474 return -EINVAL;
2475
2476 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2477
2478 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002479 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002480 (char *)&pSMBr->ByteCount;
2481
Steve French0a4b92c2006-01-12 15:44:21 -08002482 data_offset = le32_to_cpu(pSMBr->DataOffset);
2483 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002484 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002485 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2486
2487 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2488 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2489
2490 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002491 if (*ppparm > end_of_smb) {
2492 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002493 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002494 } else if (parm_count + *ppparm > end_of_smb) {
2495 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002496 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002497 } else if (*ppdata > end_of_smb) {
2498 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002499 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002500 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002501 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002502 *ppdata, data_count, (data_count + *ppdata),
2503 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002504 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002505 } else if (parm_count + data_count > pSMBr->ByteCount) {
2506 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002507 return -EINVAL;
2508 }
Steve French630f3f0c2007-10-25 21:17:17 +00002509 *pdatalen = data_count;
2510 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002511 return 0;
2512}
2513
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514int
2515CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2516 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002517 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002518 const struct nls_table *nls_codepage)
2519{
2520 int rc = 0;
2521 int bytes_returned;
Steve French50c2f752007-07-13 00:33:32 +00002522 struct smb_com_transaction_ioctl_req *pSMB;
2523 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524
2525 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2526 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2527 (void **) &pSMBr);
2528 if (rc)
2529 return rc;
2530
2531 pSMB->TotalParameterCount = 0 ;
2532 pSMB->TotalDataCount = 0;
2533 pSMB->MaxParameterCount = cpu_to_le32(2);
2534 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002535 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2536 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 pSMB->MaxSetupCount = 4;
2538 pSMB->Reserved = 0;
2539 pSMB->ParameterOffset = 0;
2540 pSMB->DataCount = 0;
2541 pSMB->DataOffset = 0;
2542 pSMB->SetupCount = 4;
2543 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2544 pSMB->ParameterCount = pSMB->TotalParameterCount;
2545 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2546 pSMB->IsFsctl = 1; /* FSCTL */
2547 pSMB->IsRootFlag = 0;
2548 pSMB->Fid = fid; /* file handle always le */
2549 pSMB->ByteCount = 0;
2550
2551 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2552 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2553 if (rc) {
2554 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2555 } else { /* decode response */
2556 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2557 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
Steve Frenchafe48c32009-05-02 05:25:46 +00002558 if ((pSMBr->ByteCount < 2) || (data_offset > 512)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 /* BB also check enough total bytes returned */
2560 rc = -EIO; /* bad smb */
Steve Frenchafe48c32009-05-02 05:25:46 +00002561 goto qreparse_out;
2562 }
2563 if (data_count && (data_count < 2048)) {
2564 char *end_of_smb = 2 /* sizeof byte count */ +
2565 pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566
Steve Frenchafe48c32009-05-02 05:25:46 +00002567 struct reparse_data *reparse_buf =
Steve French50c2f752007-07-13 00:33:32 +00002568 (struct reparse_data *)
2569 ((char *)&pSMBr->hdr.Protocol
2570 + data_offset);
Steve Frenchafe48c32009-05-02 05:25:46 +00002571 if ((char *)reparse_buf >= end_of_smb) {
2572 rc = -EIO;
2573 goto qreparse_out;
2574 }
2575 if ((reparse_buf->LinkNamesBuf +
2576 reparse_buf->TargetNameOffset +
2577 reparse_buf->TargetNameLen) > end_of_smb) {
2578 cFYI(1, ("reparse buf beyond SMB"));
2579 rc = -EIO;
2580 goto qreparse_out;
2581 }
Steve French50c2f752007-07-13 00:33:32 +00002582
Steve Frenchafe48c32009-05-02 05:25:46 +00002583 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2584 cifs_from_ucs2(symlinkinfo, (__le16 *)
Steve French50c2f752007-07-13 00:33:32 +00002585 (reparse_buf->LinkNamesBuf +
2586 reparse_buf->TargetNameOffset),
Steve Frenchafe48c32009-05-02 05:25:46 +00002587 buflen,
2588 reparse_buf->TargetNameLen,
2589 nls_codepage, 0);
2590 } else { /* ASCII names */
2591 strncpy(symlinkinfo,
2592 reparse_buf->LinkNamesBuf +
2593 reparse_buf->TargetNameOffset,
2594 min_t(const int, buflen,
2595 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002597 } else {
2598 rc = -EIO;
2599 cFYI(1, ("Invalid return data count on "
2600 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601 }
Steve Frenchafe48c32009-05-02 05:25:46 +00002602 symlinkinfo[buflen] = 0; /* just in case so the caller
2603 does not go off the end of the buffer */
2604 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 }
Steve French989c7e52009-05-02 05:32:20 +00002606
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002608 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609
2610 /* Note: On -EAGAIN error only caller can retry on handle based calls
2611 since file handle passed in no longer valid */
2612
2613 return rc;
2614}
Steve Frenchafe48c32009-05-02 05:25:46 +00002615#endif /* CIFS_EXPERIMENTAL */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616
2617#ifdef CONFIG_CIFS_POSIX
2618
2619/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002620static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2621 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002622{
2623 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002624 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2625 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2626 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2628
2629 return;
2630}
2631
2632/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002633static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2634 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635{
2636 int size = 0;
2637 int i;
2638 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002639 struct cifs_posix_ace *pACE;
2640 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2641 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642
2643 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2644 return -EOPNOTSUPP;
2645
Steve French790fe572007-07-07 19:25:05 +00002646 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 count = le16_to_cpu(cifs_acl->access_entry_count);
2648 pACE = &cifs_acl->ace_array[0];
2649 size = sizeof(struct cifs_posix_acl);
2650 size += sizeof(struct cifs_posix_ace) * count;
2651 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002652 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002653 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2654 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 return -EINVAL;
2656 }
Steve French790fe572007-07-07 19:25:05 +00002657 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002658 count = le16_to_cpu(cifs_acl->access_entry_count);
2659 size = sizeof(struct cifs_posix_acl);
2660 size += sizeof(struct cifs_posix_ace) * count;
2661/* skip past access ACEs to get to default ACEs */
2662 pACE = &cifs_acl->ace_array[count];
2663 count = le16_to_cpu(cifs_acl->default_entry_count);
2664 size += sizeof(struct cifs_posix_ace) * count;
2665 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002666 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 return -EINVAL;
2668 } else {
2669 /* illegal type */
2670 return -EINVAL;
2671 }
2672
2673 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002674 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002675 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002676 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 return -ERANGE;
2678 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002679 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002680 for (i = 0; i < count ; i++) {
2681 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2682 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 }
2684 }
2685 return size;
2686}
2687
Steve French50c2f752007-07-13 00:33:32 +00002688static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2689 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690{
2691 __u16 rc = 0; /* 0 = ACL converted ok */
2692
Steve Frenchff7feac2005-11-15 16:45:16 -08002693 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2694 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002696 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 /* Probably no need to le convert -1 on any arch but can not hurt */
2698 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002699 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002700 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002701 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 return rc;
2703}
2704
2705/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002706static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2707 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708{
2709 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002710 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2711 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 int count;
2713 int i;
2714
Steve French790fe572007-07-07 19:25:05 +00002715 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 return 0;
2717
2718 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002719 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002720 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002721 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002722 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002723 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002724 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 return 0;
2726 }
2727 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002728 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002729 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002730 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002731 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 else {
Steve French50c2f752007-07-13 00:33:32 +00002733 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 return 0;
2735 }
Steve French50c2f752007-07-13 00:33:32 +00002736 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2738 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002739 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 /* ACE not converted */
2741 break;
2742 }
2743 }
Steve French790fe572007-07-07 19:25:05 +00002744 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2746 rc += sizeof(struct cifs_posix_acl);
2747 /* BB add check to make sure ACL does not overflow SMB */
2748 }
2749 return rc;
2750}
2751
2752int
2753CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002754 const unsigned char *searchName,
2755 char *acl_inf, const int buflen, const int acl_type,
2756 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757{
2758/* SMB_QUERY_POSIX_ACL */
2759 TRANSACTION2_QPI_REQ *pSMB = NULL;
2760 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2761 int rc = 0;
2762 int bytes_returned;
2763 int name_len;
2764 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002765
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2767
2768queryAclRetry:
2769 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2770 (void **) &pSMBr);
2771 if (rc)
2772 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002773
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2775 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002776 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002777 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 name_len++; /* trailing null */
2779 name_len *= 2;
2780 pSMB->FileName[name_len] = 0;
2781 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002782 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 name_len = strnlen(searchName, PATH_MAX);
2784 name_len++; /* trailing null */
2785 strncpy(pSMB->FileName, searchName, name_len);
2786 }
2787
2788 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2789 pSMB->TotalDataCount = 0;
2790 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002791 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 pSMB->MaxDataCount = cpu_to_le16(4000);
2793 pSMB->MaxSetupCount = 0;
2794 pSMB->Reserved = 0;
2795 pSMB->Flags = 0;
2796 pSMB->Timeout = 0;
2797 pSMB->Reserved2 = 0;
2798 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002799 offsetof(struct smb_com_transaction2_qpi_req,
2800 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801 pSMB->DataCount = 0;
2802 pSMB->DataOffset = 0;
2803 pSMB->SetupCount = 1;
2804 pSMB->Reserved3 = 0;
2805 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2806 byte_count = params + 1 /* pad */ ;
2807 pSMB->TotalParameterCount = cpu_to_le16(params);
2808 pSMB->ParameterCount = pSMB->TotalParameterCount;
2809 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2810 pSMB->Reserved4 = 0;
2811 pSMB->hdr.smb_buf_length += byte_count;
2812 pSMB->ByteCount = cpu_to_le16(byte_count);
2813
2814 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2815 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002816 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 if (rc) {
2818 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2819 } else {
2820 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002821
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2823 if (rc || (pSMBr->ByteCount < 2))
2824 /* BB also check enough total bytes returned */
2825 rc = -EIO; /* bad smb */
2826 else {
2827 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2828 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2829 rc = cifs_copy_posix_acl(acl_inf,
2830 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002831 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 }
2833 }
2834 cifs_buf_release(pSMB);
2835 if (rc == -EAGAIN)
2836 goto queryAclRetry;
2837 return rc;
2838}
2839
2840int
2841CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002842 const unsigned char *fileName,
2843 const char *local_acl, const int buflen,
2844 const int acl_type,
2845 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846{
2847 struct smb_com_transaction2_spi_req *pSMB = NULL;
2848 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2849 char *parm_data;
2850 int name_len;
2851 int rc = 0;
2852 int bytes_returned = 0;
2853 __u16 params, byte_count, data_count, param_offset, offset;
2854
2855 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2856setAclRetry:
2857 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002858 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 if (rc)
2860 return rc;
2861 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2862 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002863 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002864 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 name_len++; /* trailing null */
2866 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002867 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002868 name_len = strnlen(fileName, PATH_MAX);
2869 name_len++; /* trailing null */
2870 strncpy(pSMB->FileName, fileName, name_len);
2871 }
2872 params = 6 + name_len;
2873 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00002874 /* BB find max SMB size from sess */
2875 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 pSMB->MaxSetupCount = 0;
2877 pSMB->Reserved = 0;
2878 pSMB->Flags = 0;
2879 pSMB->Timeout = 0;
2880 pSMB->Reserved2 = 0;
2881 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002882 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 offset = param_offset + params;
2884 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2885 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2886
2887 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002888 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002889
Steve French790fe572007-07-07 19:25:05 +00002890 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 rc = -EOPNOTSUPP;
2892 goto setACLerrorExit;
2893 }
2894 pSMB->DataOffset = cpu_to_le16(offset);
2895 pSMB->SetupCount = 1;
2896 pSMB->Reserved3 = 0;
2897 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2898 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2899 byte_count = 3 /* pad */ + params + data_count;
2900 pSMB->DataCount = cpu_to_le16(data_count);
2901 pSMB->TotalDataCount = pSMB->DataCount;
2902 pSMB->ParameterCount = cpu_to_le16(params);
2903 pSMB->TotalParameterCount = pSMB->ParameterCount;
2904 pSMB->Reserved4 = 0;
2905 pSMB->hdr.smb_buf_length += byte_count;
2906 pSMB->ByteCount = cpu_to_le16(byte_count);
2907 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002908 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00002909 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 cFYI(1, ("Set POSIX ACL returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911
2912setACLerrorExit:
2913 cifs_buf_release(pSMB);
2914 if (rc == -EAGAIN)
2915 goto setAclRetry;
2916 return rc;
2917}
2918
Steve Frenchf654bac2005-04-28 22:41:04 -07002919/* BB fix tabs in this function FIXME BB */
2920int
2921CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve Frenchad7a2922008-02-07 23:25:02 +00002922 const int netfid, __u64 *pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002923{
Steve French50c2f752007-07-13 00:33:32 +00002924 int rc = 0;
2925 struct smb_t2_qfi_req *pSMB = NULL;
2926 struct smb_t2_qfi_rsp *pSMBr = NULL;
2927 int bytes_returned;
2928 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002929
Steve French790fe572007-07-07 19:25:05 +00002930 cFYI(1, ("In GetExtAttr"));
2931 if (tcon == NULL)
2932 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002933
2934GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002935 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2936 (void **) &pSMBr);
2937 if (rc)
2938 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002939
Steve Frenchad7a2922008-02-07 23:25:02 +00002940 params = 2 /* level */ + 2 /* fid */;
Steve French790fe572007-07-07 19:25:05 +00002941 pSMB->t2.TotalDataCount = 0;
2942 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2943 /* BB find exact max data count below from sess structure BB */
2944 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2945 pSMB->t2.MaxSetupCount = 0;
2946 pSMB->t2.Reserved = 0;
2947 pSMB->t2.Flags = 0;
2948 pSMB->t2.Timeout = 0;
2949 pSMB->t2.Reserved2 = 0;
2950 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2951 Fid) - 4);
2952 pSMB->t2.DataCount = 0;
2953 pSMB->t2.DataOffset = 0;
2954 pSMB->t2.SetupCount = 1;
2955 pSMB->t2.Reserved3 = 0;
2956 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2957 byte_count = params + 1 /* pad */ ;
2958 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2959 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2960 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2961 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07002962 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00002963 pSMB->hdr.smb_buf_length += byte_count;
2964 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07002965
Steve French790fe572007-07-07 19:25:05 +00002966 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2967 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2968 if (rc) {
2969 cFYI(1, ("error %d in GetExtAttr", rc));
2970 } else {
2971 /* decode response */
2972 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2973 if (rc || (pSMBr->ByteCount < 2))
2974 /* BB also check enough total bytes returned */
2975 /* If rc should we check for EOPNOSUPP and
2976 disable the srvino flag? or in caller? */
2977 rc = -EIO; /* bad smb */
2978 else {
2979 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2980 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2981 struct file_chattr_info *pfinfo;
2982 /* BB Do we need a cast or hash here ? */
2983 if (count != 16) {
2984 cFYI(1, ("Illegal size ret in GetExtAttr"));
2985 rc = -EIO;
2986 goto GetExtAttrOut;
2987 }
2988 pfinfo = (struct file_chattr_info *)
2989 (data_offset + (char *) &pSMBr->hdr.Protocol);
2990 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07002991 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00002992 }
2993 }
Steve Frenchf654bac2005-04-28 22:41:04 -07002994GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00002995 cifs_buf_release(pSMB);
2996 if (rc == -EAGAIN)
2997 goto GetExtAttrRetry;
2998 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002999}
3000
Steve Frenchf654bac2005-04-28 22:41:04 -07003001#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002
Steve French297647c2007-10-12 04:11:59 +00003003#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003004/* Get Security Descriptor (by handle) from remote server for a file or dir */
3005int
3006CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French630f3f0c2007-10-25 21:17:17 +00003007 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003008{
3009 int rc = 0;
3010 int buf_type = 0;
Steve Frenchad7a2922008-02-07 23:25:02 +00003011 QUERY_SEC_DESC_REQ *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08003012 struct kvec iov[1];
3013
3014 cFYI(1, ("GetCifsACL"));
3015
Steve French630f3f0c2007-10-25 21:17:17 +00003016 *pbuflen = 0;
3017 *acl_inf = NULL;
3018
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003019 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003020 8 /* parm len */, tcon, (void **) &pSMB);
3021 if (rc)
3022 return rc;
3023
3024 pSMB->MaxParameterCount = cpu_to_le32(4);
3025 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3026 pSMB->MaxSetupCount = 0;
3027 pSMB->Fid = fid; /* file handle always le */
3028 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3029 CIFS_ACL_DACL);
3030 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3031 pSMB->hdr.smb_buf_length += 11;
3032 iov[0].iov_base = (char *)pSMB;
3033 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3034
Steve Frencha761ac52007-10-18 21:45:27 +00003035 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003036 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003037 cifs_stats_inc(&tcon->num_acl_get);
3038 if (rc) {
3039 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3040 } else { /* decode response */
Steve Frenchad7a2922008-02-07 23:25:02 +00003041 __le32 *parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003042 __u32 parm_len;
3043 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003044 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003045 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003046
3047/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003048 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003049 &pdata, &parm_len, pbuflen);
Steve French790fe572007-07-07 19:25:05 +00003050 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003051 goto qsec_out;
3052 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3053
Steve French630f3f0c2007-10-25 21:17:17 +00003054 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003055
3056 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3057 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003058 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003059 goto qsec_out;
3060 }
3061
3062/* BB check that data area is minimum length and as big as acl_len */
3063
Steve Frenchaf6f4612007-10-16 18:40:37 +00003064 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003065 if (acl_len != *pbuflen) {
3066 cERROR(1, ("acl length %d does not match %d",
3067 acl_len, *pbuflen));
3068 if (*pbuflen > acl_len)
3069 *pbuflen = acl_len;
3070 }
Steve French0a4b92c2006-01-12 15:44:21 -08003071
Steve French630f3f0c2007-10-25 21:17:17 +00003072 /* check if buffer is big enough for the acl
3073 header followed by the smallest SID */
3074 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3075 (*pbuflen >= 64 * 1024)) {
3076 cERROR(1, ("bad acl length %d", *pbuflen));
3077 rc = -EINVAL;
3078 *pbuflen = 0;
3079 } else {
3080 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3081 if (*acl_inf == NULL) {
3082 *pbuflen = 0;
3083 rc = -ENOMEM;
3084 }
3085 memcpy(*acl_inf, pdata, *pbuflen);
3086 }
Steve French0a4b92c2006-01-12 15:44:21 -08003087 }
3088qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003089 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003090 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003091 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003092 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003093/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003094 return rc;
3095}
Steve French97837582007-12-31 07:47:21 +00003096
3097int
3098CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3099 struct cifs_ntsd *pntsd, __u32 acllen)
3100{
3101 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3102 int rc = 0;
3103 int bytes_returned = 0;
3104 SET_SEC_DESC_REQ *pSMB = NULL;
3105 NTRANSACT_RSP *pSMBr = NULL;
3106
3107setCifsAclRetry:
3108 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3109 (void **) &pSMBr);
3110 if (rc)
3111 return (rc);
3112
3113 pSMB->MaxSetupCount = 0;
3114 pSMB->Reserved = 0;
3115
3116 param_count = 8;
3117 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3118 data_count = acllen;
3119 data_offset = param_offset + param_count;
3120 byte_count = 3 /* pad */ + param_count;
3121
3122 pSMB->DataCount = cpu_to_le32(data_count);
3123 pSMB->TotalDataCount = pSMB->DataCount;
3124 pSMB->MaxParameterCount = cpu_to_le32(4);
3125 pSMB->MaxDataCount = cpu_to_le32(16384);
3126 pSMB->ParameterCount = cpu_to_le32(param_count);
3127 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3128 pSMB->TotalParameterCount = pSMB->ParameterCount;
3129 pSMB->DataOffset = cpu_to_le32(data_offset);
3130 pSMB->SetupCount = 0;
3131 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3132 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3133
3134 pSMB->Fid = fid; /* file handle always le */
3135 pSMB->Reserved2 = 0;
3136 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3137
3138 if (pntsd && acllen) {
3139 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3140 (char *) pntsd,
3141 acllen);
3142 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3143
3144 } else
3145 pSMB->hdr.smb_buf_length += byte_count;
3146
3147 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3148 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3149
3150 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3151 if (rc)
3152 cFYI(1, ("Set CIFS ACL returned %d", rc));
3153 cifs_buf_release(pSMB);
3154
3155 if (rc == -EAGAIN)
3156 goto setCifsAclRetry;
3157
3158 return (rc);
3159}
3160
Steve French297647c2007-10-12 04:11:59 +00003161#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003162
Steve French6b8edfe2005-08-23 20:26:03 -07003163/* Legacy Query Path Information call for lookup to old servers such
3164 as Win9x/WinME */
3165int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003166 const unsigned char *searchName,
3167 FILE_ALL_INFO *pFinfo,
3168 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003169{
Steve Frenchad7a2922008-02-07 23:25:02 +00003170 QUERY_INFORMATION_REQ *pSMB;
3171 QUERY_INFORMATION_RSP *pSMBr;
Steve French6b8edfe2005-08-23 20:26:03 -07003172 int rc = 0;
3173 int bytes_returned;
3174 int name_len;
3175
Steve French50c2f752007-07-13 00:33:32 +00003176 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003177QInfRetry:
3178 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003179 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003180 if (rc)
3181 return rc;
3182
3183 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3184 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003185 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3186 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003187 name_len++; /* trailing null */
3188 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003189 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003190 name_len = strnlen(searchName, PATH_MAX);
3191 name_len++; /* trailing null */
3192 strncpy(pSMB->FileName, searchName, name_len);
3193 }
3194 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003195 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003196 pSMB->hdr.smb_buf_length += (__u16) name_len;
3197 pSMB->ByteCount = cpu_to_le16(name_len);
3198
3199 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003200 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003201 if (rc) {
3202 cFYI(1, ("Send error in QueryInfo = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003203 } else if (pFinfo) {
Steve French1bd5bbc2006-09-28 03:35:57 +00003204 struct timespec ts;
3205 __u32 time = le32_to_cpu(pSMBr->last_write_time);
Steve Frenchad7a2922008-02-07 23:25:02 +00003206
3207 /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003208 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003209 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003210 ts.tv_nsec = 0;
3211 ts.tv_sec = time;
3212 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003213 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003214 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3215 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003216 pFinfo->AllocationSize =
3217 cpu_to_le64(le32_to_cpu(pSMBr->size));
3218 pFinfo->EndOfFile = pFinfo->AllocationSize;
3219 pFinfo->Attributes =
3220 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003221 } else
3222 rc = -EIO; /* bad buffer passed in */
3223
3224 cifs_buf_release(pSMB);
3225
3226 if (rc == -EAGAIN)
3227 goto QInfRetry;
3228
3229 return rc;
3230}
3231
3232
3233
3234
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235int
3236CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3237 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003238 FILE_ALL_INFO *pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003239 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003240 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241{
3242/* level 263 SMB_QUERY_FILE_ALL_INFO */
3243 TRANSACTION2_QPI_REQ *pSMB = NULL;
3244 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3245 int rc = 0;
3246 int bytes_returned;
3247 int name_len;
3248 __u16 params, byte_count;
3249
3250/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3251QPathInfoRetry:
3252 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3253 (void **) &pSMBr);
3254 if (rc)
3255 return rc;
3256
3257 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3258 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003259 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003260 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003261 name_len++; /* trailing null */
3262 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003263 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 name_len = strnlen(searchName, PATH_MAX);
3265 name_len++; /* trailing null */
3266 strncpy(pSMB->FileName, searchName, name_len);
3267 }
3268
Steve French50c2f752007-07-13 00:33:32 +00003269 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 pSMB->TotalDataCount = 0;
3271 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00003272 /* BB find exact max SMB PDU from sess structure BB */
3273 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 pSMB->MaxSetupCount = 0;
3275 pSMB->Reserved = 0;
3276 pSMB->Flags = 0;
3277 pSMB->Timeout = 0;
3278 pSMB->Reserved2 = 0;
3279 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003280 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 pSMB->DataCount = 0;
3282 pSMB->DataOffset = 0;
3283 pSMB->SetupCount = 1;
3284 pSMB->Reserved3 = 0;
3285 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3286 byte_count = params + 1 /* pad */ ;
3287 pSMB->TotalParameterCount = cpu_to_le16(params);
3288 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003289 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003290 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3291 else
3292 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293 pSMB->Reserved4 = 0;
3294 pSMB->hdr.smb_buf_length += byte_count;
3295 pSMB->ByteCount = cpu_to_le16(byte_count);
3296
3297 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3298 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3299 if (rc) {
3300 cFYI(1, ("Send error in QPathInfo = %d", rc));
3301 } else { /* decode response */
3302 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3303
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003304 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3305 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003306 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003308 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003309 rc = -EIO; /* 24 or 26 expected but we do not read
3310 last field */
3311 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003312 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003313 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve Frenchad7a2922008-02-07 23:25:02 +00003314
3315 /* On legacy responses we do not read the last field,
3316 EAsize, fortunately since it varies by subdialect and
3317 also note it differs on Set vs. Get, ie two bytes or 4
3318 bytes depending but we don't care here */
3319 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003320 size = sizeof(FILE_INFO_STANDARD);
3321 else
3322 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 memcpy((char *) pFindData,
3324 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003325 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 } else
3327 rc = -ENOMEM;
3328 }
3329 cifs_buf_release(pSMB);
3330 if (rc == -EAGAIN)
3331 goto QPathInfoRetry;
3332
3333 return rc;
3334}
3335
3336int
3337CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3338 const unsigned char *searchName,
Steve French582d21e2008-05-13 04:54:12 +00003339 FILE_UNIX_BASIC_INFO *pFindData,
Steve French737b7582005-04-28 22:41:06 -07003340 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341{
3342/* SMB_QUERY_FILE_UNIX_BASIC */
3343 TRANSACTION2_QPI_REQ *pSMB = NULL;
3344 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3345 int rc = 0;
3346 int bytes_returned = 0;
3347 int name_len;
3348 __u16 params, byte_count;
3349
3350 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3351UnixQPathInfoRetry:
3352 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3353 (void **) &pSMBr);
3354 if (rc)
3355 return rc;
3356
3357 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3358 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003359 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003360 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003361 name_len++; /* trailing null */
3362 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003363 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003364 name_len = strnlen(searchName, PATH_MAX);
3365 name_len++; /* trailing null */
3366 strncpy(pSMB->FileName, searchName, name_len);
3367 }
3368
Steve French50c2f752007-07-13 00:33:32 +00003369 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 pSMB->TotalDataCount = 0;
3371 pSMB->MaxParameterCount = cpu_to_le16(2);
3372 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003373 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003374 pSMB->MaxSetupCount = 0;
3375 pSMB->Reserved = 0;
3376 pSMB->Flags = 0;
3377 pSMB->Timeout = 0;
3378 pSMB->Reserved2 = 0;
3379 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003380 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 pSMB->DataCount = 0;
3382 pSMB->DataOffset = 0;
3383 pSMB->SetupCount = 1;
3384 pSMB->Reserved3 = 0;
3385 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3386 byte_count = params + 1 /* pad */ ;
3387 pSMB->TotalParameterCount = cpu_to_le16(params);
3388 pSMB->ParameterCount = pSMB->TotalParameterCount;
3389 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3390 pSMB->Reserved4 = 0;
3391 pSMB->hdr.smb_buf_length += byte_count;
3392 pSMB->ByteCount = cpu_to_le16(byte_count);
3393
3394 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3395 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3396 if (rc) {
3397 cFYI(1, ("Send error in QPathInfo = %d", rc));
3398 } else { /* decode response */
3399 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3400
3401 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003402 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3403 "Unix Extensions can be disabled on mount "
3404 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 rc = -EIO; /* bad smb */
3406 } else {
3407 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3408 memcpy((char *) pFindData,
3409 (char *) &pSMBr->hdr.Protocol +
3410 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003411 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 }
3413 }
3414 cifs_buf_release(pSMB);
3415 if (rc == -EAGAIN)
3416 goto UnixQPathInfoRetry;
3417
3418 return rc;
3419}
3420
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421/* xid, tcon, searchName and codepage are input parms, rest are returned */
3422int
3423CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003424 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003426 __u16 *pnetfid,
3427 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428{
3429/* level 257 SMB_ */
3430 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3431 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003432 T2_FFIRST_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003433 int rc = 0;
3434 int bytes_returned = 0;
3435 int name_len;
3436 __u16 params, byte_count;
3437
Steve French50c2f752007-07-13 00:33:32 +00003438 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439
3440findFirstRetry:
3441 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3442 (void **) &pSMBr);
3443 if (rc)
3444 return rc;
3445
3446 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3447 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003448 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003449 PATH_MAX, nls_codepage, remap);
3450 /* We can not add the asterik earlier in case
3451 it got remapped to 0xF03A as if it were part of the
3452 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003453 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003454 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003455 pSMB->FileName[name_len+1] = 0;
3456 pSMB->FileName[name_len+2] = '*';
3457 pSMB->FileName[name_len+3] = 0;
3458 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3460 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003461 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 } else { /* BB add check for overrun of SMB buf BB */
3463 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003465 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466 free buffer exit; BB */
3467 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003468 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003469 pSMB->FileName[name_len+1] = '*';
3470 pSMB->FileName[name_len+2] = 0;
3471 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 }
3473
3474 params = 12 + name_len /* includes null */ ;
3475 pSMB->TotalDataCount = 0; /* no EAs */
3476 pSMB->MaxParameterCount = cpu_to_le16(10);
3477 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3478 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3479 pSMB->MaxSetupCount = 0;
3480 pSMB->Reserved = 0;
3481 pSMB->Flags = 0;
3482 pSMB->Timeout = 0;
3483 pSMB->Reserved2 = 0;
3484 byte_count = params + 1 /* pad */ ;
3485 pSMB->TotalParameterCount = cpu_to_le16(params);
3486 pSMB->ParameterCount = pSMB->TotalParameterCount;
3487 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003488 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3489 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 pSMB->DataCount = 0;
3491 pSMB->DataOffset = 0;
3492 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3493 pSMB->Reserved3 = 0;
3494 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3495 pSMB->SearchAttributes =
3496 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3497 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003498 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3499 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 CIFS_SEARCH_RETURN_RESUME);
3501 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3502
3503 /* BB what should we set StorageType to? Does it matter? BB */
3504 pSMB->SearchStorageType = 0;
3505 pSMB->hdr.smb_buf_length += byte_count;
3506 pSMB->ByteCount = cpu_to_le16(byte_count);
3507
3508 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3509 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003510 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511
Steve French88274812006-03-09 22:21:45 +00003512 if (rc) {/* BB add logic to retry regular search if Unix search
3513 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 /* BB Add code to handle unsupported level rc */
3515 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003516
Steve French88274812006-03-09 22:21:45 +00003517 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518
3519 /* BB eventually could optimize out free and realloc of buf */
3520 /* for this case */
3521 if (rc == -EAGAIN)
3522 goto findFirstRetry;
3523 } else { /* decode response */
3524 /* BB remember to free buffer if error BB */
3525 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003526 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003527 unsigned int lnoff;
3528
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003530 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 else
Steve French4b18f2a2008-04-29 00:06:05 +00003532 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533
3534 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003535 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003536 psrch_inf->srch_entries_start =
3537 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003538 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003539 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3540 le16_to_cpu(pSMBr->t2.ParameterOffset));
3541
Steve French790fe572007-07-07 19:25:05 +00003542 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003543 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 else
Steve French4b18f2a2008-04-29 00:06:05 +00003545 psrch_inf->endOfSearch = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003546
Steve French50c2f752007-07-13 00:33:32 +00003547 psrch_inf->entries_in_buffer =
3548 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003549 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003551 lnoff = le16_to_cpu(parms->LastNameOffset);
3552 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3553 lnoff) {
3554 cERROR(1, ("ignoring corrupt resume name"));
3555 psrch_inf->last_entry = NULL;
3556 return rc;
3557 }
3558
Steve French0752f152008-10-07 20:03:33 +00003559 psrch_inf->last_entry = psrch_inf->srch_entries_start +
Steve Frenchb77d7532008-10-08 19:13:46 +00003560 lnoff;
3561
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 *pnetfid = parms->SearchHandle;
3563 } else {
3564 cifs_buf_release(pSMB);
3565 }
3566 }
3567
3568 return rc;
3569}
3570
3571int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003572 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003573{
3574 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3575 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
Steve Frenchad7a2922008-02-07 23:25:02 +00003576 T2_FNEXT_RSP_PARMS *parms;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 char *response_data;
3578 int rc = 0;
3579 int bytes_returned, name_len;
3580 __u16 params, byte_count;
3581
3582 cFYI(1, ("In FindNext"));
3583
Steve French4b18f2a2008-04-29 00:06:05 +00003584 if (psrch_inf->endOfSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 return -ENOENT;
3586
3587 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3588 (void **) &pSMBr);
3589 if (rc)
3590 return rc;
3591
Steve French50c2f752007-07-13 00:33:32 +00003592 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 byte_count = 0;
3594 pSMB->TotalDataCount = 0; /* no EAs */
3595 pSMB->MaxParameterCount = cpu_to_le16(8);
3596 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003597 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3598 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 pSMB->MaxSetupCount = 0;
3600 pSMB->Reserved = 0;
3601 pSMB->Flags = 0;
3602 pSMB->Timeout = 0;
3603 pSMB->Reserved2 = 0;
3604 pSMB->ParameterOffset = cpu_to_le16(
3605 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3606 pSMB->DataCount = 0;
3607 pSMB->DataOffset = 0;
3608 pSMB->SetupCount = 1;
3609 pSMB->Reserved3 = 0;
3610 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3611 pSMB->SearchHandle = searchHandle; /* always kept as le */
3612 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003613 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3615 pSMB->ResumeKey = psrch_inf->resume_key;
3616 pSMB->SearchFlags =
3617 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3618
3619 name_len = psrch_inf->resume_name_len;
3620 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003621 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3623 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003624 /* 14 byte parm len above enough for 2 byte null terminator */
3625 pSMB->ResumeFileName[name_len] = 0;
3626 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 } else {
3628 rc = -EINVAL;
3629 goto FNext2_err_exit;
3630 }
3631 byte_count = params + 1 /* pad */ ;
3632 pSMB->TotalParameterCount = cpu_to_le16(params);
3633 pSMB->ParameterCount = pSMB->TotalParameterCount;
3634 pSMB->hdr.smb_buf_length += byte_count;
3635 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003636
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3638 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003639 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 if (rc) {
3641 if (rc == -EBADF) {
Steve French4b18f2a2008-04-29 00:06:05 +00003642 psrch_inf->endOfSearch = true;
Jeff Layton63534502008-05-12 19:56:05 -07003643 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00003644 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 } else
3646 cFYI(1, ("FindNext returned = %d", rc));
3647 } else { /* decode response */
3648 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003649
Steve French790fe572007-07-07 19:25:05 +00003650 if (rc == 0) {
Steve Frenchb77d7532008-10-08 19:13:46 +00003651 unsigned int lnoff;
3652
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 /* BB fixme add lock for file (srch_info) struct here */
3654 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
Steve French4b18f2a2008-04-29 00:06:05 +00003655 psrch_inf->unicode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003656 else
Steve French4b18f2a2008-04-29 00:06:05 +00003657 psrch_inf->unicode = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 response_data = (char *) &pSMBr->hdr.Protocol +
3659 le16_to_cpu(pSMBr->t2.ParameterOffset);
3660 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3661 response_data = (char *)&pSMBr->hdr.Protocol +
3662 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003663 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003664 cifs_small_buf_release(
3665 psrch_inf->ntwrk_buf_start);
3666 else
3667 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 psrch_inf->srch_entries_start = response_data;
3669 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003670 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003671 if (parms->EndofSearch)
Steve French4b18f2a2008-04-29 00:06:05 +00003672 psrch_inf->endOfSearch = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 else
Steve French4b18f2a2008-04-29 00:06:05 +00003674 psrch_inf->endOfSearch = false;
Steve French50c2f752007-07-13 00:33:32 +00003675 psrch_inf->entries_in_buffer =
3676 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 psrch_inf->index_of_last_entry +=
3678 psrch_inf->entries_in_buffer;
Steve Frenchb77d7532008-10-08 19:13:46 +00003679 lnoff = le16_to_cpu(parms->LastNameOffset);
3680 if (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE <
3681 lnoff) {
3682 cERROR(1, ("ignoring corrupt resume name"));
3683 psrch_inf->last_entry = NULL;
3684 return rc;
3685 } else
3686 psrch_inf->last_entry =
3687 psrch_inf->srch_entries_start + lnoff;
3688
Steve French50c2f752007-07-13 00:33:32 +00003689/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3690 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691
3692 /* BB fixme add unlock here */
3693 }
3694
3695 }
3696
3697 /* BB On error, should we leave previous search buf (and count and
3698 last entry fields) intact or free the previous one? */
3699
3700 /* Note: On -EAGAIN error only caller can retry on handle based calls
3701 since file handle passed in no longer valid */
3702FNext2_err_exit:
3703 if (rc != 0)
3704 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 return rc;
3706}
3707
3708int
Steve French50c2f752007-07-13 00:33:32 +00003709CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3710 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711{
3712 int rc = 0;
3713 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714
3715 cFYI(1, ("In CIFSSMBFindClose"));
3716 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3717
3718 /* no sense returning error if session restarted
3719 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003720 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003721 return 0;
3722 if (rc)
3723 return rc;
3724
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725 pSMB->FileID = searchHandle;
3726 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003727 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00003728 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729 cERROR(1, ("Send error in FindClose = %d", rc));
Steve Frenchad7a2922008-02-07 23:25:02 +00003730
Steve Frencha4544342005-08-24 13:59:35 -07003731 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732
3733 /* Since session is dead, search handle closed on server already */
3734 if (rc == -EAGAIN)
3735 rc = 0;
3736
3737 return rc;
3738}
3739
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740int
3741CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003742 const unsigned char *searchName,
Steve Frenchad7a2922008-02-07 23:25:02 +00003743 __u64 *inode_number,
Steve French50c2f752007-07-13 00:33:32 +00003744 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003745{
3746 int rc = 0;
3747 TRANSACTION2_QPI_REQ *pSMB = NULL;
3748 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3749 int name_len, bytes_returned;
3750 __u16 params, byte_count;
3751
Steve French50c2f752007-07-13 00:33:32 +00003752 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003753 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003754 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755
3756GetInodeNumberRetry:
3757 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003758 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 if (rc)
3760 return rc;
3761
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3763 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003764 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003765 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766 name_len++; /* trailing null */
3767 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003768 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769 name_len = strnlen(searchName, PATH_MAX);
3770 name_len++; /* trailing null */
3771 strncpy(pSMB->FileName, searchName, name_len);
3772 }
3773
3774 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3775 pSMB->TotalDataCount = 0;
3776 pSMB->MaxParameterCount = cpu_to_le16(2);
3777 /* BB find exact max data count below from sess structure BB */
3778 pSMB->MaxDataCount = cpu_to_le16(4000);
3779 pSMB->MaxSetupCount = 0;
3780 pSMB->Reserved = 0;
3781 pSMB->Flags = 0;
3782 pSMB->Timeout = 0;
3783 pSMB->Reserved2 = 0;
3784 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003785 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786 pSMB->DataCount = 0;
3787 pSMB->DataOffset = 0;
3788 pSMB->SetupCount = 1;
3789 pSMB->Reserved3 = 0;
3790 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3791 byte_count = params + 1 /* pad */ ;
3792 pSMB->TotalParameterCount = cpu_to_le16(params);
3793 pSMB->ParameterCount = pSMB->TotalParameterCount;
3794 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3795 pSMB->Reserved4 = 0;
3796 pSMB->hdr.smb_buf_length += byte_count;
3797 pSMB->ByteCount = cpu_to_le16(byte_count);
3798
3799 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3800 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3801 if (rc) {
3802 cFYI(1, ("error %d in QueryInternalInfo", rc));
3803 } else {
3804 /* decode response */
3805 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3806 if (rc || (pSMBr->ByteCount < 2))
3807 /* BB also check enough total bytes returned */
3808 /* If rc should we check for EOPNOSUPP and
3809 disable the srvino flag? or in caller? */
3810 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003811 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3813 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003814 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003816 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3818 rc = -EIO;
3819 goto GetInodeNumOut;
3820 }
3821 pfinfo = (struct file_internal_info *)
3822 (data_offset + (char *) &pSMBr->hdr.Protocol);
Steve French85a6dac2009-04-01 05:22:00 +00003823 *inode_number = le64_to_cpu(pfinfo->UniqueId);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003824 }
3825 }
3826GetInodeNumOut:
3827 cifs_buf_release(pSMB);
3828 if (rc == -EAGAIN)
3829 goto GetInodeNumberRetry;
3830 return rc;
3831}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832
Igor Mammedovfec45852008-05-16 13:06:30 +04003833/* parses DFS refferal V3 structure
3834 * caller is responsible for freeing target_nodes
3835 * returns:
3836 * on success - 0
3837 * on failure - errno
3838 */
3839static int
Steve Frencha1fe78f2008-05-16 18:48:38 +00003840parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr,
Igor Mammedovfec45852008-05-16 13:06:30 +04003841 unsigned int *num_of_nodes,
3842 struct dfs_info3_param **target_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04003843 const struct nls_table *nls_codepage, int remap,
3844 const char *searchName)
Igor Mammedovfec45852008-05-16 13:06:30 +04003845{
3846 int i, rc = 0;
3847 char *data_end;
3848 bool is_unicode;
3849 struct dfs_referral_level_3 *ref;
3850
Harvey Harrison5ca33c62008-07-23 17:45:58 -07003851 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3852 is_unicode = true;
3853 else
3854 is_unicode = false;
Igor Mammedovfec45852008-05-16 13:06:30 +04003855 *num_of_nodes = le16_to_cpu(pSMBr->NumberOfReferrals);
3856
3857 if (*num_of_nodes < 1) {
3858 cERROR(1, ("num_referrals: must be at least > 0,"
3859 "but we get num_referrals = %d\n", *num_of_nodes));
3860 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003861 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003862 }
3863
3864 ref = (struct dfs_referral_level_3 *) &(pSMBr->referrals);
Al Viro1d92cfd2008-06-02 10:59:02 +01003865 if (ref->VersionNumber != cpu_to_le16(3)) {
Igor Mammedovfec45852008-05-16 13:06:30 +04003866 cERROR(1, ("Referrals of V%d version are not supported,"
Al Viro1d92cfd2008-06-02 10:59:02 +01003867 "should be V3", le16_to_cpu(ref->VersionNumber)));
Igor Mammedovfec45852008-05-16 13:06:30 +04003868 rc = -EINVAL;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003869 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003870 }
3871
3872 /* get the upper boundary of the resp buffer */
3873 data_end = (char *)(&(pSMBr->PathConsumed)) +
3874 le16_to_cpu(pSMBr->t2.DataCount);
3875
3876 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n",
3877 *num_of_nodes,
Steve French0e0d2cf2009-05-01 05:27:32 +00003878 le32_to_cpu(pSMBr->DFSFlags)));
Igor Mammedovfec45852008-05-16 13:06:30 +04003879
3880 *target_nodes = kzalloc(sizeof(struct dfs_info3_param) *
3881 *num_of_nodes, GFP_KERNEL);
3882 if (*target_nodes == NULL) {
3883 cERROR(1, ("Failed to allocate buffer for target_nodes\n"));
3884 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003885 goto parse_DFS_referrals_exit;
Igor Mammedovfec45852008-05-16 13:06:30 +04003886 }
3887
3888 /* collect neccessary data from referrals */
3889 for (i = 0; i < *num_of_nodes; i++) {
3890 char *temp;
3891 int max_len;
3892 struct dfs_info3_param *node = (*target_nodes)+i;
3893
Steve French0e0d2cf2009-05-01 05:27:32 +00003894 node->flags = le32_to_cpu(pSMBr->DFSFlags);
Igor Mammedov2c556082008-10-23 13:58:42 +04003895 if (is_unicode) {
Jeff Layton331c3132008-12-17 06:31:53 -05003896 __le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
3897 GFP_KERNEL);
Steve French2920ee22009-08-31 15:27:26 +00003898 if (tmp == NULL) {
3899 rc = -ENOMEM;
3900 goto parse_DFS_referrals_exit;
3901 }
Igor Mammedov2c556082008-10-23 13:58:42 +04003902 cifsConvertToUCS((__le16 *) tmp, searchName,
3903 PATH_MAX, nls_codepage, remap);
Jeff Layton69f801f2009-04-30 06:46:32 -04003904 node->path_consumed = cifs_ucs2_bytes(tmp,
3905 le16_to_cpu(pSMBr->PathConsumed),
Igor Mammedov2c556082008-10-23 13:58:42 +04003906 nls_codepage);
3907 kfree(tmp);
3908 } else
3909 node->path_consumed = le16_to_cpu(pSMBr->PathConsumed);
3910
Igor Mammedovfec45852008-05-16 13:06:30 +04003911 node->server_type = le16_to_cpu(ref->ServerType);
3912 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
3913
3914 /* copy DfsPath */
3915 temp = (char *)ref + le16_to_cpu(ref->DfsPathOffset);
3916 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00003917 node->path_name = cifs_strndup_from_ucs(temp, max_len,
3918 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04003919 if (!node->path_name) {
3920 rc = -ENOMEM;
Steve Frencha1fe78f2008-05-16 18:48:38 +00003921 goto parse_DFS_referrals_exit;
Jeff Layton066ce682009-04-30 07:16:14 -04003922 }
Igor Mammedovfec45852008-05-16 13:06:30 +04003923
3924 /* copy link target UNC */
3925 temp = (char *)ref + le16_to_cpu(ref->NetworkAddressOffset);
3926 max_len = data_end - temp;
Steve Frenchd185cda2009-04-30 17:45:10 +00003927 node->node_name = cifs_strndup_from_ucs(temp, max_len,
3928 is_unicode, nls_codepage);
Jeff Laytond8e2f532009-05-14 07:46:59 -04003929 if (!node->node_name)
3930 rc = -ENOMEM;
Igor Mammedovfec45852008-05-16 13:06:30 +04003931 }
3932
Steve Frencha1fe78f2008-05-16 18:48:38 +00003933parse_DFS_referrals_exit:
Igor Mammedovfec45852008-05-16 13:06:30 +04003934 if (rc) {
3935 free_dfs_info_array(*target_nodes, *num_of_nodes);
3936 *target_nodes = NULL;
3937 *num_of_nodes = 0;
3938 }
3939 return rc;
3940}
3941
Linus Torvalds1da177e2005-04-16 15:20:36 -07003942int
3943CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3944 const unsigned char *searchName,
Steve Frenchc2cf07d2008-05-15 06:20:02 +00003945 struct dfs_info3_param **target_nodes,
3946 unsigned int *num_of_nodes,
Steve French737b7582005-04-28 22:41:06 -07003947 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948{
3949/* TRANS2_GET_DFS_REFERRAL */
3950 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3951 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 int rc = 0;
3953 int bytes_returned;
3954 int name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 __u16 params, byte_count;
Steve Frenchc2cf07d2008-05-15 06:20:02 +00003956 *num_of_nodes = 0;
3957 *target_nodes = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958
3959 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3960 if (ses == NULL)
3961 return -ENODEV;
3962getDFSRetry:
3963 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3964 (void **) &pSMBr);
3965 if (rc)
3966 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003967
3968 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07003969 but should never be null here anyway */
3970 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 pSMB->hdr.Tid = ses->ipc_tid;
3972 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00003973 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003974 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00003975 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977
3978 if (ses->capabilities & CAP_UNICODE) {
3979 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3980 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003981 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003982 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003983 name_len++; /* trailing null */
3984 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003985 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 name_len = strnlen(searchName, PATH_MAX);
3987 name_len++; /* trailing null */
3988 strncpy(pSMB->RequestFileName, searchName, name_len);
3989 }
3990
Steve French790fe572007-07-07 19:25:05 +00003991 if (ses->server) {
3992 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00003993 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3994 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3995 }
3996
Steve French50c2f752007-07-13 00:33:32 +00003997 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00003998
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 params = 2 /* level */ + name_len /*includes null */ ;
4000 pSMB->TotalDataCount = 0;
4001 pSMB->DataCount = 0;
4002 pSMB->DataOffset = 0;
4003 pSMB->MaxParameterCount = 0;
Steve French582d21e2008-05-13 04:54:12 +00004004 /* BB find exact max SMB PDU from sess structure BB */
4005 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 pSMB->MaxSetupCount = 0;
4007 pSMB->Reserved = 0;
4008 pSMB->Flags = 0;
4009 pSMB->Timeout = 0;
4010 pSMB->Reserved2 = 0;
4011 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004012 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013 pSMB->SetupCount = 1;
4014 pSMB->Reserved3 = 0;
4015 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4016 byte_count = params + 3 /* pad */ ;
4017 pSMB->ParameterCount = cpu_to_le16(params);
4018 pSMB->TotalParameterCount = pSMB->ParameterCount;
4019 pSMB->MaxReferralLevel = cpu_to_le16(3);
4020 pSMB->hdr.smb_buf_length += byte_count;
4021 pSMB->ByteCount = cpu_to_le16(byte_count);
4022
4023 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4024 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4025 if (rc) {
4026 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004027 goto GetDFSRefExit;
4028 }
4029 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004031 /* BB Also check if enough total bytes returned? */
Igor Mammedovfec45852008-05-16 13:06:30 +04004032 if (rc || (pSMBr->ByteCount < 17)) {
Steve Frenchc2cf07d2008-05-15 06:20:02 +00004033 rc = -EIO; /* bad smb */
Igor Mammedovfec45852008-05-16 13:06:30 +04004034 goto GetDFSRefExit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004035 }
Igor Mammedovfec45852008-05-16 13:06:30 +04004036
4037 cFYI(1, ("Decoding GetDFSRefer response BCC: %d Offset %d",
4038 pSMBr->ByteCount,
4039 le16_to_cpu(pSMBr->t2.DataOffset)));
4040
4041 /* parse returned result into more usable form */
Steve Frencha1fe78f2008-05-16 18:48:38 +00004042 rc = parse_DFS_referrals(pSMBr, num_of_nodes,
Igor Mammedov2c556082008-10-23 13:58:42 +04004043 target_nodes, nls_codepage, remap,
4044 searchName);
Igor Mammedovfec45852008-05-16 13:06:30 +04004045
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046GetDFSRefExit:
Steve French0d817bc2008-05-22 02:02:03 +00004047 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048
4049 if (rc == -EAGAIN)
4050 goto getDFSRetry;
4051
4052 return rc;
4053}
4054
Steve French20962432005-09-21 22:05:57 -07004055/* Query File System Info such as free space to old servers such as Win 9x */
4056int
4057SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4058{
4059/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4060 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4061 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4062 FILE_SYSTEM_ALLOC_INFO *response_data;
4063 int rc = 0;
4064 int bytes_returned = 0;
4065 __u16 params, byte_count;
4066
4067 cFYI(1, ("OldQFSInfo"));
4068oldQFSInfoRetry:
4069 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4070 (void **) &pSMBr);
4071 if (rc)
4072 return rc;
Steve French20962432005-09-21 22:05:57 -07004073
4074 params = 2; /* level */
4075 pSMB->TotalDataCount = 0;
4076 pSMB->MaxParameterCount = cpu_to_le16(2);
4077 pSMB->MaxDataCount = cpu_to_le16(1000);
4078 pSMB->MaxSetupCount = 0;
4079 pSMB->Reserved = 0;
4080 pSMB->Flags = 0;
4081 pSMB->Timeout = 0;
4082 pSMB->Reserved2 = 0;
4083 byte_count = params + 1 /* pad */ ;
4084 pSMB->TotalParameterCount = cpu_to_le16(params);
4085 pSMB->ParameterCount = pSMB->TotalParameterCount;
4086 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4087 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4088 pSMB->DataCount = 0;
4089 pSMB->DataOffset = 0;
4090 pSMB->SetupCount = 1;
4091 pSMB->Reserved3 = 0;
4092 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4093 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4094 pSMB->hdr.smb_buf_length += byte_count;
4095 pSMB->ByteCount = cpu_to_le16(byte_count);
4096
4097 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4098 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4099 if (rc) {
4100 cFYI(1, ("Send error in QFSInfo = %d", rc));
4101 } else { /* decode response */
4102 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4103
4104 if (rc || (pSMBr->ByteCount < 18))
4105 rc = -EIO; /* bad smb */
4106 else {
4107 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004108 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004109 pSMBr->ByteCount, data_offset));
4110
Steve French50c2f752007-07-13 00:33:32 +00004111 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004112 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4113 FSData->f_bsize =
4114 le16_to_cpu(response_data->BytesPerSector) *
4115 le32_to_cpu(response_data->
4116 SectorsPerAllocationUnit);
4117 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004118 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004119 FSData->f_bfree = FSData->f_bavail =
4120 le32_to_cpu(response_data->FreeAllocationUnits);
4121 cFYI(1,
4122 ("Blocks: %lld Free: %lld Block size %ld",
4123 (unsigned long long)FSData->f_blocks,
4124 (unsigned long long)FSData->f_bfree,
4125 FSData->f_bsize));
4126 }
4127 }
4128 cifs_buf_release(pSMB);
4129
4130 if (rc == -EAGAIN)
4131 goto oldQFSInfoRetry;
4132
4133 return rc;
4134}
4135
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136int
Steve French737b7582005-04-28 22:41:06 -07004137CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138{
4139/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4140 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4141 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4142 FILE_SYSTEM_INFO *response_data;
4143 int rc = 0;
4144 int bytes_returned = 0;
4145 __u16 params, byte_count;
4146
4147 cFYI(1, ("In QFSInfo"));
4148QFSInfoRetry:
4149 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4150 (void **) &pSMBr);
4151 if (rc)
4152 return rc;
4153
4154 params = 2; /* level */
4155 pSMB->TotalDataCount = 0;
4156 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004157 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158 pSMB->MaxSetupCount = 0;
4159 pSMB->Reserved = 0;
4160 pSMB->Flags = 0;
4161 pSMB->Timeout = 0;
4162 pSMB->Reserved2 = 0;
4163 byte_count = params + 1 /* pad */ ;
4164 pSMB->TotalParameterCount = cpu_to_le16(params);
4165 pSMB->ParameterCount = pSMB->TotalParameterCount;
4166 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004167 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 pSMB->DataCount = 0;
4169 pSMB->DataOffset = 0;
4170 pSMB->SetupCount = 1;
4171 pSMB->Reserved3 = 0;
4172 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4173 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4174 pSMB->hdr.smb_buf_length += byte_count;
4175 pSMB->ByteCount = cpu_to_le16(byte_count);
4176
4177 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4178 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4179 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004180 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004182 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183
Steve French20962432005-09-21 22:05:57 -07004184 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 rc = -EIO; /* bad smb */
4186 else {
4187 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188
4189 response_data =
4190 (FILE_SYSTEM_INFO
4191 *) (((char *) &pSMBr->hdr.Protocol) +
4192 data_offset);
4193 FSData->f_bsize =
4194 le32_to_cpu(response_data->BytesPerSector) *
4195 le32_to_cpu(response_data->
4196 SectorsPerAllocationUnit);
4197 FSData->f_blocks =
4198 le64_to_cpu(response_data->TotalAllocationUnits);
4199 FSData->f_bfree = FSData->f_bavail =
4200 le64_to_cpu(response_data->FreeAllocationUnits);
4201 cFYI(1,
4202 ("Blocks: %lld Free: %lld Block size %ld",
4203 (unsigned long long)FSData->f_blocks,
4204 (unsigned long long)FSData->f_bfree,
4205 FSData->f_bsize));
4206 }
4207 }
4208 cifs_buf_release(pSMB);
4209
4210 if (rc == -EAGAIN)
4211 goto QFSInfoRetry;
4212
4213 return rc;
4214}
4215
4216int
Steve French737b7582005-04-28 22:41:06 -07004217CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218{
4219/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4220 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4221 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4222 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4223 int rc = 0;
4224 int bytes_returned = 0;
4225 __u16 params, byte_count;
4226
4227 cFYI(1, ("In QFSAttributeInfo"));
4228QFSAttributeRetry:
4229 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4230 (void **) &pSMBr);
4231 if (rc)
4232 return rc;
4233
4234 params = 2; /* level */
4235 pSMB->TotalDataCount = 0;
4236 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004237 /* BB find exact max SMB PDU from sess structure BB */
4238 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004239 pSMB->MaxSetupCount = 0;
4240 pSMB->Reserved = 0;
4241 pSMB->Flags = 0;
4242 pSMB->Timeout = 0;
4243 pSMB->Reserved2 = 0;
4244 byte_count = params + 1 /* pad */ ;
4245 pSMB->TotalParameterCount = cpu_to_le16(params);
4246 pSMB->ParameterCount = pSMB->TotalParameterCount;
4247 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004248 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249 pSMB->DataCount = 0;
4250 pSMB->DataOffset = 0;
4251 pSMB->SetupCount = 1;
4252 pSMB->Reserved3 = 0;
4253 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4254 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4255 pSMB->hdr.smb_buf_length += byte_count;
4256 pSMB->ByteCount = cpu_to_le16(byte_count);
4257
4258 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4259 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4260 if (rc) {
4261 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4262 } else { /* decode response */
4263 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4264
Steve French50c2f752007-07-13 00:33:32 +00004265 if (rc || (pSMBr->ByteCount < 13)) {
4266 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 rc = -EIO; /* bad smb */
4268 } else {
4269 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4270 response_data =
4271 (FILE_SYSTEM_ATTRIBUTE_INFO
4272 *) (((char *) &pSMBr->hdr.Protocol) +
4273 data_offset);
4274 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004275 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276 }
4277 }
4278 cifs_buf_release(pSMB);
4279
4280 if (rc == -EAGAIN)
4281 goto QFSAttributeRetry;
4282
4283 return rc;
4284}
4285
4286int
Steve French737b7582005-04-28 22:41:06 -07004287CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288{
4289/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4290 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4291 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4292 FILE_SYSTEM_DEVICE_INFO *response_data;
4293 int rc = 0;
4294 int bytes_returned = 0;
4295 __u16 params, byte_count;
4296
4297 cFYI(1, ("In QFSDeviceInfo"));
4298QFSDeviceRetry:
4299 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4300 (void **) &pSMBr);
4301 if (rc)
4302 return rc;
4303
4304 params = 2; /* level */
4305 pSMB->TotalDataCount = 0;
4306 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004307 /* BB find exact max SMB PDU from sess structure BB */
4308 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309 pSMB->MaxSetupCount = 0;
4310 pSMB->Reserved = 0;
4311 pSMB->Flags = 0;
4312 pSMB->Timeout = 0;
4313 pSMB->Reserved2 = 0;
4314 byte_count = params + 1 /* pad */ ;
4315 pSMB->TotalParameterCount = cpu_to_le16(params);
4316 pSMB->ParameterCount = pSMB->TotalParameterCount;
4317 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004318 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319
4320 pSMB->DataCount = 0;
4321 pSMB->DataOffset = 0;
4322 pSMB->SetupCount = 1;
4323 pSMB->Reserved3 = 0;
4324 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4325 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4326 pSMB->hdr.smb_buf_length += byte_count;
4327 pSMB->ByteCount = cpu_to_le16(byte_count);
4328
4329 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4330 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4331 if (rc) {
4332 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4333 } else { /* decode response */
4334 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4335
Steve French630f3f0c2007-10-25 21:17:17 +00004336 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337 rc = -EIO; /* bad smb */
4338 else {
4339 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4340 response_data =
Steve French737b7582005-04-28 22:41:06 -07004341 (FILE_SYSTEM_DEVICE_INFO *)
4342 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 data_offset);
4344 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004345 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 }
4347 }
4348 cifs_buf_release(pSMB);
4349
4350 if (rc == -EAGAIN)
4351 goto QFSDeviceRetry;
4352
4353 return rc;
4354}
4355
4356int
Steve French737b7582005-04-28 22:41:06 -07004357CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358{
4359/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4360 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4361 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4362 FILE_SYSTEM_UNIX_INFO *response_data;
4363 int rc = 0;
4364 int bytes_returned = 0;
4365 __u16 params, byte_count;
4366
4367 cFYI(1, ("In QFSUnixInfo"));
4368QFSUnixRetry:
4369 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4370 (void **) &pSMBr);
4371 if (rc)
4372 return rc;
4373
4374 params = 2; /* level */
4375 pSMB->TotalDataCount = 0;
4376 pSMB->DataCount = 0;
4377 pSMB->DataOffset = 0;
4378 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004379 /* BB find exact max SMB PDU from sess structure BB */
4380 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381 pSMB->MaxSetupCount = 0;
4382 pSMB->Reserved = 0;
4383 pSMB->Flags = 0;
4384 pSMB->Timeout = 0;
4385 pSMB->Reserved2 = 0;
4386 byte_count = params + 1 /* pad */ ;
4387 pSMB->ParameterCount = cpu_to_le16(params);
4388 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004389 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4390 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391 pSMB->SetupCount = 1;
4392 pSMB->Reserved3 = 0;
4393 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4394 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4395 pSMB->hdr.smb_buf_length += byte_count;
4396 pSMB->ByteCount = cpu_to_le16(byte_count);
4397
4398 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4399 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4400 if (rc) {
4401 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4402 } else { /* decode response */
4403 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4404
4405 if (rc || (pSMBr->ByteCount < 13)) {
4406 rc = -EIO; /* bad smb */
4407 } else {
4408 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4409 response_data =
4410 (FILE_SYSTEM_UNIX_INFO
4411 *) (((char *) &pSMBr->hdr.Protocol) +
4412 data_offset);
4413 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004414 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 }
4416 }
4417 cifs_buf_release(pSMB);
4418
4419 if (rc == -EAGAIN)
4420 goto QFSUnixRetry;
4421
4422
4423 return rc;
4424}
4425
Jeremy Allisonac670552005-06-22 17:26:35 -07004426int
Steve French45abc6e2005-06-23 13:42:03 -05004427CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004428{
4429/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4430 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4431 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4432 int rc = 0;
4433 int bytes_returned = 0;
4434 __u16 params, param_offset, offset, byte_count;
4435
4436 cFYI(1, ("In SETFSUnixInfo"));
4437SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004438 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004439 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4440 (void **) &pSMBr);
4441 if (rc)
4442 return rc;
4443
4444 params = 4; /* 2 bytes zero followed by info level. */
4445 pSMB->MaxSetupCount = 0;
4446 pSMB->Reserved = 0;
4447 pSMB->Flags = 0;
4448 pSMB->Timeout = 0;
4449 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004450 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4451 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004452 offset = param_offset + params;
4453
4454 pSMB->MaxParameterCount = cpu_to_le16(4);
Steve French582d21e2008-05-13 04:54:12 +00004455 /* BB find exact max SMB PDU from sess structure BB */
4456 pSMB->MaxDataCount = cpu_to_le16(100);
Jeremy Allisonac670552005-06-22 17:26:35 -07004457 pSMB->SetupCount = 1;
4458 pSMB->Reserved3 = 0;
4459 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4460 byte_count = 1 /* pad */ + params + 12;
4461
4462 pSMB->DataCount = cpu_to_le16(12);
4463 pSMB->ParameterCount = cpu_to_le16(params);
4464 pSMB->TotalDataCount = pSMB->DataCount;
4465 pSMB->TotalParameterCount = pSMB->ParameterCount;
4466 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4467 pSMB->DataOffset = cpu_to_le16(offset);
4468
4469 /* Params. */
4470 pSMB->FileNum = 0;
4471 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4472
4473 /* Data. */
4474 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4475 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4476 pSMB->ClientUnixCap = cpu_to_le64(cap);
4477
4478 pSMB->hdr.smb_buf_length += byte_count;
4479 pSMB->ByteCount = cpu_to_le16(byte_count);
4480
4481 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4482 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4483 if (rc) {
4484 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4485 } else { /* decode response */
4486 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve Frenchad7a2922008-02-07 23:25:02 +00004487 if (rc)
Jeremy Allisonac670552005-06-22 17:26:35 -07004488 rc = -EIO; /* bad smb */
Jeremy Allisonac670552005-06-22 17:26:35 -07004489 }
4490 cifs_buf_release(pSMB);
4491
4492 if (rc == -EAGAIN)
4493 goto SETFSUnixRetry;
4494
4495 return rc;
4496}
4497
4498
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499
4500int
4501CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004502 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503{
4504/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4505 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4506 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4507 FILE_SYSTEM_POSIX_INFO *response_data;
4508 int rc = 0;
4509 int bytes_returned = 0;
4510 __u16 params, byte_count;
4511
4512 cFYI(1, ("In QFSPosixInfo"));
4513QFSPosixRetry:
4514 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4515 (void **) &pSMBr);
4516 if (rc)
4517 return rc;
4518
4519 params = 2; /* level */
4520 pSMB->TotalDataCount = 0;
4521 pSMB->DataCount = 0;
4522 pSMB->DataOffset = 0;
4523 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004524 /* BB find exact max SMB PDU from sess structure BB */
4525 pSMB->MaxDataCount = cpu_to_le16(100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526 pSMB->MaxSetupCount = 0;
4527 pSMB->Reserved = 0;
4528 pSMB->Flags = 0;
4529 pSMB->Timeout = 0;
4530 pSMB->Reserved2 = 0;
4531 byte_count = params + 1 /* pad */ ;
4532 pSMB->ParameterCount = cpu_to_le16(params);
4533 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004534 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4535 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536 pSMB->SetupCount = 1;
4537 pSMB->Reserved3 = 0;
4538 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4539 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4540 pSMB->hdr.smb_buf_length += byte_count;
4541 pSMB->ByteCount = cpu_to_le16(byte_count);
4542
4543 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4544 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4545 if (rc) {
4546 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4547 } else { /* decode response */
4548 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4549
4550 if (rc || (pSMBr->ByteCount < 13)) {
4551 rc = -EIO; /* bad smb */
4552 } else {
4553 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4554 response_data =
4555 (FILE_SYSTEM_POSIX_INFO
4556 *) (((char *) &pSMBr->hdr.Protocol) +
4557 data_offset);
4558 FSData->f_bsize =
4559 le32_to_cpu(response_data->BlockSize);
4560 FSData->f_blocks =
4561 le64_to_cpu(response_data->TotalBlocks);
4562 FSData->f_bfree =
4563 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004564 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 FSData->f_bavail = FSData->f_bfree;
4566 } else {
4567 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004568 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 }
Steve French790fe572007-07-07 19:25:05 +00004570 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004572 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004573 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004575 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 }
4577 }
4578 cifs_buf_release(pSMB);
4579
4580 if (rc == -EAGAIN)
4581 goto QFSPosixRetry;
4582
4583 return rc;
4584}
4585
4586
Steve French50c2f752007-07-13 00:33:32 +00004587/* We can not use write of zero bytes trick to
4588 set file size due to need for large file support. Also note that
4589 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 routine which is only needed to work around a sharing violation bug
4591 in Samba which this routine can run into */
4592
4593int
4594CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French4b18f2a2008-04-29 00:06:05 +00004595 __u64 size, bool SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004596 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597{
4598 struct smb_com_transaction2_spi_req *pSMB = NULL;
4599 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4600 struct file_end_of_file_info *parm_data;
4601 int name_len;
4602 int rc = 0;
4603 int bytes_returned = 0;
4604 __u16 params, byte_count, data_count, param_offset, offset;
4605
4606 cFYI(1, ("In SetEOF"));
4607SetEOFRetry:
4608 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4609 (void **) &pSMBr);
4610 if (rc)
4611 return rc;
4612
4613 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4614 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004615 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004616 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617 name_len++; /* trailing null */
4618 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004619 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 name_len = strnlen(fileName, PATH_MAX);
4621 name_len++; /* trailing null */
4622 strncpy(pSMB->FileName, fileName, name_len);
4623 }
4624 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004625 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004627 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004628 pSMB->MaxSetupCount = 0;
4629 pSMB->Reserved = 0;
4630 pSMB->Flags = 0;
4631 pSMB->Timeout = 0;
4632 pSMB->Reserved2 = 0;
4633 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004634 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004636 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004637 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4638 pSMB->InformationLevel =
4639 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4640 else
4641 pSMB->InformationLevel =
4642 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4643 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4645 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004646 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 else
4648 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004649 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 }
4651
4652 parm_data =
4653 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4654 offset);
4655 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4656 pSMB->DataOffset = cpu_to_le16(offset);
4657 pSMB->SetupCount = 1;
4658 pSMB->Reserved3 = 0;
4659 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4660 byte_count = 3 /* pad */ + params + data_count;
4661 pSMB->DataCount = cpu_to_le16(data_count);
4662 pSMB->TotalDataCount = pSMB->DataCount;
4663 pSMB->ParameterCount = cpu_to_le16(params);
4664 pSMB->TotalParameterCount = pSMB->ParameterCount;
4665 pSMB->Reserved4 = 0;
4666 pSMB->hdr.smb_buf_length += byte_count;
4667 parm_data->FileSize = cpu_to_le64(size);
4668 pSMB->ByteCount = cpu_to_le16(byte_count);
4669 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4670 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004671 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673
4674 cifs_buf_release(pSMB);
4675
4676 if (rc == -EAGAIN)
4677 goto SetEOFRetry;
4678
4679 return rc;
4680}
4681
4682int
Steve French50c2f752007-07-13 00:33:32 +00004683CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
Steve French4b18f2a2008-04-29 00:06:05 +00004684 __u16 fid, __u32 pid_of_opener, bool SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004685{
4686 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687 char *data_offset;
4688 struct file_end_of_file_info *parm_data;
4689 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690 __u16 params, param_offset, offset, byte_count, count;
4691
4692 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4693 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004694 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4695
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696 if (rc)
4697 return rc;
4698
4699 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4700 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004701
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702 params = 6;
4703 pSMB->MaxSetupCount = 0;
4704 pSMB->Reserved = 0;
4705 pSMB->Flags = 0;
4706 pSMB->Timeout = 0;
4707 pSMB->Reserved2 = 0;
4708 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4709 offset = param_offset + params;
4710
Steve French50c2f752007-07-13 00:33:32 +00004711 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712
4713 count = sizeof(struct file_end_of_file_info);
4714 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004715 /* BB find exact max SMB PDU from sess structure BB */
4716 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004717 pSMB->SetupCount = 1;
4718 pSMB->Reserved3 = 0;
4719 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4720 byte_count = 3 /* pad */ + params + count;
4721 pSMB->DataCount = cpu_to_le16(count);
4722 pSMB->ParameterCount = cpu_to_le16(params);
4723 pSMB->TotalDataCount = pSMB->DataCount;
4724 pSMB->TotalParameterCount = pSMB->ParameterCount;
4725 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4726 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004727 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4728 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 pSMB->DataOffset = cpu_to_le16(offset);
4730 parm_data->FileSize = cpu_to_le64(size);
4731 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004732 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4734 pSMB->InformationLevel =
4735 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4736 else
4737 pSMB->InformationLevel =
4738 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004739 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4741 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004742 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743 else
4744 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004745 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746 }
4747 pSMB->Reserved4 = 0;
4748 pSMB->hdr.smb_buf_length += byte_count;
4749 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004750 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751 if (rc) {
4752 cFYI(1,
4753 ("Send error in SetFileInfo (SetFileSize) = %d",
4754 rc));
4755 }
4756
Steve French50c2f752007-07-13 00:33:32 +00004757 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 since file handle passed in no longer valid */
4759
4760 return rc;
4761}
4762
Steve French50c2f752007-07-13 00:33:32 +00004763/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764 an open handle, rather than by pathname - this is awkward due to
4765 potential access conflicts on the open, but it is unavoidable for these
4766 old servers since the only other choice is to go from 100 nanosecond DCE
4767 time and resort to the original setpathinfo level which takes the ancient
4768 DOS time format with 2 second granularity */
4769int
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004770CIFSSMBSetFileInfo(const int xid, struct cifsTconInfo *tcon,
4771 const FILE_BASIC_INFO *data, __u16 fid, __u32 pid_of_opener)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772{
4773 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774 char *data_offset;
4775 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776 __u16 params, param_offset, offset, byte_count, count;
4777
4778 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004779 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4780
Linus Torvalds1da177e2005-04-16 15:20:36 -07004781 if (rc)
4782 return rc;
4783
Jeff Layton2dd2dfa2008-08-02 07:26:12 -04004784 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4785 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004786
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787 params = 6;
4788 pSMB->MaxSetupCount = 0;
4789 pSMB->Reserved = 0;
4790 pSMB->Flags = 0;
4791 pSMB->Timeout = 0;
4792 pSMB->Reserved2 = 0;
4793 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4794 offset = param_offset + params;
4795
Steve French50c2f752007-07-13 00:33:32 +00004796 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004797
Steve French26f57362007-08-30 22:09:15 +00004798 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004799 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004800 /* BB find max SMB PDU from sess */
4801 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 pSMB->SetupCount = 1;
4803 pSMB->Reserved3 = 0;
4804 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4805 byte_count = 3 /* pad */ + params + count;
4806 pSMB->DataCount = cpu_to_le16(count);
4807 pSMB->ParameterCount = cpu_to_le16(params);
4808 pSMB->TotalDataCount = pSMB->DataCount;
4809 pSMB->TotalParameterCount = pSMB->ParameterCount;
4810 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4811 pSMB->DataOffset = cpu_to_le16(offset);
4812 pSMB->Fid = fid;
4813 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4814 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4815 else
4816 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4817 pSMB->Reserved4 = 0;
4818 pSMB->hdr.smb_buf_length += byte_count;
4819 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004820 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004821 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004822 if (rc)
Steve French50c2f752007-07-13 00:33:32 +00004823 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004824
Steve French50c2f752007-07-13 00:33:32 +00004825 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826 since file handle passed in no longer valid */
4827
4828 return rc;
4829}
4830
Jeff Layton6d22f092008-09-23 11:48:35 -04004831int
4832CIFSSMBSetFileDisposition(const int xid, struct cifsTconInfo *tcon,
4833 bool delete_file, __u16 fid, __u32 pid_of_opener)
4834{
4835 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4836 char *data_offset;
4837 int rc = 0;
4838 __u16 params, param_offset, offset, byte_count, count;
4839
4840 cFYI(1, ("Set File Disposition (via SetFileInfo)"));
4841 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4842
4843 if (rc)
4844 return rc;
4845
4846 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4847 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4848
4849 params = 6;
4850 pSMB->MaxSetupCount = 0;
4851 pSMB->Reserved = 0;
4852 pSMB->Flags = 0;
4853 pSMB->Timeout = 0;
4854 pSMB->Reserved2 = 0;
4855 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4856 offset = param_offset + params;
4857
4858 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4859
4860 count = 1;
4861 pSMB->MaxParameterCount = cpu_to_le16(2);
4862 /* BB find max SMB PDU from sess */
4863 pSMB->MaxDataCount = cpu_to_le16(1000);
4864 pSMB->SetupCount = 1;
4865 pSMB->Reserved3 = 0;
4866 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4867 byte_count = 3 /* pad */ + params + count;
4868 pSMB->DataCount = cpu_to_le16(count);
4869 pSMB->ParameterCount = cpu_to_le16(params);
4870 pSMB->TotalDataCount = pSMB->DataCount;
4871 pSMB->TotalParameterCount = pSMB->ParameterCount;
4872 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4873 pSMB->DataOffset = cpu_to_le16(offset);
4874 pSMB->Fid = fid;
4875 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_DISPOSITION_INFO);
4876 pSMB->Reserved4 = 0;
4877 pSMB->hdr.smb_buf_length += byte_count;
4878 pSMB->ByteCount = cpu_to_le16(byte_count);
4879 *data_offset = delete_file ? 1 : 0;
4880 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
4881 if (rc)
4882 cFYI(1, ("Send error in SetFileDisposition = %d", rc));
4883
4884 return rc;
4885}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886
4887int
Jeff Layton6fc000e2008-08-02 07:26:12 -04004888CIFSSMBSetPathInfo(const int xid, struct cifsTconInfo *tcon,
4889 const char *fileName, const FILE_BASIC_INFO *data,
4890 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004891{
4892 TRANSACTION2_SPI_REQ *pSMB = NULL;
4893 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4894 int name_len;
4895 int rc = 0;
4896 int bytes_returned = 0;
4897 char *data_offset;
4898 __u16 params, param_offset, offset, byte_count, count;
4899
4900 cFYI(1, ("In SetTimes"));
4901
4902SetTimesRetry:
4903 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4904 (void **) &pSMBr);
4905 if (rc)
4906 return rc;
4907
4908 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4909 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004910 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004911 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 name_len++; /* trailing null */
4913 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004914 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915 name_len = strnlen(fileName, PATH_MAX);
4916 name_len++; /* trailing null */
4917 strncpy(pSMB->FileName, fileName, name_len);
4918 }
4919
4920 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004921 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00004923 /* BB find max SMB PDU from sess structure BB */
4924 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004925 pSMB->MaxSetupCount = 0;
4926 pSMB->Reserved = 0;
4927 pSMB->Flags = 0;
4928 pSMB->Timeout = 0;
4929 pSMB->Reserved2 = 0;
4930 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004931 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932 offset = param_offset + params;
4933 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4934 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4935 pSMB->DataOffset = cpu_to_le16(offset);
4936 pSMB->SetupCount = 1;
4937 pSMB->Reserved3 = 0;
4938 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4939 byte_count = 3 /* pad */ + params + count;
4940
4941 pSMB->DataCount = cpu_to_le16(count);
4942 pSMB->ParameterCount = cpu_to_le16(params);
4943 pSMB->TotalDataCount = pSMB->DataCount;
4944 pSMB->TotalParameterCount = pSMB->ParameterCount;
4945 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4946 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4947 else
4948 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4949 pSMB->Reserved4 = 0;
4950 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00004951 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 pSMB->ByteCount = cpu_to_le16(byte_count);
4953 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4954 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00004955 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004956 cFYI(1, ("SetPathInfo (times) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957
4958 cifs_buf_release(pSMB);
4959
4960 if (rc == -EAGAIN)
4961 goto SetTimesRetry;
4962
4963 return rc;
4964}
4965
4966/* Can not be used to set time stamps yet (due to old DOS time format) */
4967/* Can be used to set attributes */
4968#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4969 handling it anyway and NT4 was what we thought it would be needed for
4970 Do not delete it until we prove whether needed for Win9x though */
4971int
4972CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4973 __u16 dos_attrs, const struct nls_table *nls_codepage)
4974{
4975 SETATTR_REQ *pSMB = NULL;
4976 SETATTR_RSP *pSMBr = NULL;
4977 int rc = 0;
4978 int bytes_returned;
4979 int name_len;
4980
4981 cFYI(1, ("In SetAttrLegacy"));
4982
4983SetAttrLgcyRetry:
4984 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4985 (void **) &pSMBr);
4986 if (rc)
4987 return rc;
4988
4989 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4990 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004991 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992 PATH_MAX, nls_codepage);
4993 name_len++; /* trailing null */
4994 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004995 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996 name_len = strnlen(fileName, PATH_MAX);
4997 name_len++; /* trailing null */
4998 strncpy(pSMB->fileName, fileName, name_len);
4999 }
5000 pSMB->attr = cpu_to_le16(dos_attrs);
5001 pSMB->BufferFormat = 0x04;
5002 pSMB->hdr.smb_buf_length += name_len + 1;
5003 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5004 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5005 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005006 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007 cFYI(1, ("Error in LegacySetAttr = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008
5009 cifs_buf_release(pSMB);
5010
5011 if (rc == -EAGAIN)
5012 goto SetAttrLgcyRetry;
5013
5014 return rc;
5015}
5016#endif /* temporarily unneeded SetAttr legacy function */
5017
Jeff Layton654cf142009-07-09 20:02:49 -04005018static void
5019cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset,
5020 const struct cifs_unix_set_info_args *args)
5021{
5022 u64 mode = args->mode;
5023
5024 /*
5025 * Samba server ignores set of file size to zero due to bugs in some
5026 * older clients, but we should be precise - we use SetFileSize to
5027 * set file size and do not want to truncate file size to zero
5028 * accidently as happened on one Samba server beta by putting
5029 * zero instead of -1 here
5030 */
5031 data_offset->EndOfFile = cpu_to_le64(NO_CHANGE_64);
5032 data_offset->NumOfBytes = cpu_to_le64(NO_CHANGE_64);
5033 data_offset->LastStatusChange = cpu_to_le64(args->ctime);
5034 data_offset->LastAccessTime = cpu_to_le64(args->atime);
5035 data_offset->LastModificationTime = cpu_to_le64(args->mtime);
5036 data_offset->Uid = cpu_to_le64(args->uid);
5037 data_offset->Gid = cpu_to_le64(args->gid);
5038 /* better to leave device as zero when it is */
5039 data_offset->DevMajor = cpu_to_le64(MAJOR(args->device));
5040 data_offset->DevMinor = cpu_to_le64(MINOR(args->device));
5041 data_offset->Permissions = cpu_to_le64(mode);
5042
5043 if (S_ISREG(mode))
5044 data_offset->Type = cpu_to_le32(UNIX_FILE);
5045 else if (S_ISDIR(mode))
5046 data_offset->Type = cpu_to_le32(UNIX_DIR);
5047 else if (S_ISLNK(mode))
5048 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
5049 else if (S_ISCHR(mode))
5050 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
5051 else if (S_ISBLK(mode))
5052 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
5053 else if (S_ISFIFO(mode))
5054 data_offset->Type = cpu_to_le32(UNIX_FIFO);
5055 else if (S_ISSOCK(mode))
5056 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5057}
5058
Linus Torvalds1da177e2005-04-16 15:20:36 -07005059int
Jeff Layton3bbeeb32009-07-09 20:02:50 -04005060CIFSSMBUnixSetFileInfo(const int xid, struct cifsTconInfo *tcon,
5061 const struct cifs_unix_set_info_args *args,
5062 u16 fid, u32 pid_of_opener)
5063{
5064 struct smb_com_transaction2_sfi_req *pSMB = NULL;
5065 FILE_UNIX_BASIC_INFO *data_offset;
5066 int rc = 0;
5067 u16 params, param_offset, offset, byte_count, count;
5068
5069 cFYI(1, ("Set Unix Info (via SetFileInfo)"));
5070 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
5071
5072 if (rc)
5073 return rc;
5074
5075 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
5076 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
5077
5078 params = 6;
5079 pSMB->MaxSetupCount = 0;
5080 pSMB->Reserved = 0;
5081 pSMB->Flags = 0;
5082 pSMB->Timeout = 0;
5083 pSMB->Reserved2 = 0;
5084 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
5085 offset = param_offset + params;
5086
5087 data_offset = (FILE_UNIX_BASIC_INFO *)
5088 ((char *)(&pSMB->hdr.Protocol) + offset);
5089 count = sizeof(FILE_UNIX_BASIC_INFO);
5090
5091 pSMB->MaxParameterCount = cpu_to_le16(2);
5092 /* BB find max SMB PDU from sess */
5093 pSMB->MaxDataCount = cpu_to_le16(1000);
5094 pSMB->SetupCount = 1;
5095 pSMB->Reserved3 = 0;
5096 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
5097 byte_count = 3 /* pad */ + params + count;
5098 pSMB->DataCount = cpu_to_le16(count);
5099 pSMB->ParameterCount = cpu_to_le16(params);
5100 pSMB->TotalDataCount = pSMB->DataCount;
5101 pSMB->TotalParameterCount = pSMB->ParameterCount;
5102 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5103 pSMB->DataOffset = cpu_to_le16(offset);
5104 pSMB->Fid = fid;
5105 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5106 pSMB->Reserved4 = 0;
5107 pSMB->hdr.smb_buf_length += byte_count;
5108 pSMB->ByteCount = cpu_to_le16(byte_count);
5109
5110 cifs_fill_unix_set_info(data_offset, args);
5111
5112 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
5113 if (rc)
5114 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
5115
5116 /* Note: On -EAGAIN error only caller can retry on handle based calls
5117 since file handle passed in no longer valid */
5118
5119 return rc;
5120}
5121
5122int
Jeff Layton01ea95e2009-07-09 20:02:49 -04005123CIFSSMBUnixSetPathInfo(const int xid, struct cifsTconInfo *tcon, char *fileName,
5124 const struct cifs_unix_set_info_args *args,
5125 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005126{
5127 TRANSACTION2_SPI_REQ *pSMB = NULL;
5128 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5129 int name_len;
5130 int rc = 0;
5131 int bytes_returned = 0;
5132 FILE_UNIX_BASIC_INFO *data_offset;
5133 __u16 params, param_offset, offset, count, byte_count;
5134
5135 cFYI(1, ("In SetUID/GID/Mode"));
5136setPermsRetry:
5137 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5138 (void **) &pSMBr);
5139 if (rc)
5140 return rc;
5141
5142 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5143 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005144 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005145 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 name_len++; /* trailing null */
5147 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005148 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149 name_len = strnlen(fileName, PATH_MAX);
5150 name_len++; /* trailing null */
5151 strncpy(pSMB->FileName, fileName, name_len);
5152 }
5153
5154 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005155 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005157 /* BB find max SMB PDU from sess structure BB */
5158 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159 pSMB->MaxSetupCount = 0;
5160 pSMB->Reserved = 0;
5161 pSMB->Flags = 0;
5162 pSMB->Timeout = 0;
5163 pSMB->Reserved2 = 0;
5164 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005165 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166 offset = param_offset + params;
5167 data_offset =
5168 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5169 offset);
5170 memset(data_offset, 0, count);
5171 pSMB->DataOffset = cpu_to_le16(offset);
5172 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5173 pSMB->SetupCount = 1;
5174 pSMB->Reserved3 = 0;
5175 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5176 byte_count = 3 /* pad */ + params + count;
5177 pSMB->ParameterCount = cpu_to_le16(params);
5178 pSMB->DataCount = cpu_to_le16(count);
5179 pSMB->TotalParameterCount = pSMB->ParameterCount;
5180 pSMB->TotalDataCount = pSMB->DataCount;
5181 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5182 pSMB->Reserved4 = 0;
5183 pSMB->hdr.smb_buf_length += byte_count;
Steve French50c2f752007-07-13 00:33:32 +00005184
Jeff Layton654cf142009-07-09 20:02:49 -04005185 cifs_fill_unix_set_info(data_offset, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186
5187 pSMB->ByteCount = cpu_to_le16(byte_count);
5188 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5189 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005190 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005191 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005192
Steve French0d817bc2008-05-22 02:02:03 +00005193 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005194 if (rc == -EAGAIN)
5195 goto setPermsRetry;
5196 return rc;
5197}
5198
Steve French50c2f752007-07-13 00:33:32 +00005199int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005200 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005201 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005202 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203{
5204 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005205 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5206 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005207 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005208 int bytes_returned;
5209
Steve French50c2f752007-07-13 00:33:32 +00005210 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005211 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005212 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005213 if (rc)
5214 return rc;
5215
5216 pSMB->TotalParameterCount = 0 ;
5217 pSMB->TotalDataCount = 0;
5218 pSMB->MaxParameterCount = cpu_to_le32(2);
5219 /* BB find exact data count max from sess structure BB */
5220 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005221/* BB VERIFY verify which is correct for above BB */
5222 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5223 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5224
Linus Torvalds1da177e2005-04-16 15:20:36 -07005225 pSMB->MaxSetupCount = 4;
5226 pSMB->Reserved = 0;
5227 pSMB->ParameterOffset = 0;
5228 pSMB->DataCount = 0;
5229 pSMB->DataOffset = 0;
5230 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5231 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5232 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005233 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5235 pSMB->Reserved2 = 0;
5236 pSMB->CompletionFilter = cpu_to_le32(filter);
5237 pSMB->Fid = netfid; /* file handle always le */
5238 pSMB->ByteCount = 0;
5239
5240 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005241 (struct smb_hdr *)pSMBr, &bytes_returned,
5242 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 if (rc) {
5244 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005245 } else {
5246 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005247 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005248 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005249 sizeof(struct dir_notify_req),
5250 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005251 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005252 dnotify_req->Pid = pSMB->hdr.Pid;
5253 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5254 dnotify_req->Mid = pSMB->hdr.Mid;
5255 dnotify_req->Tid = pSMB->hdr.Tid;
5256 dnotify_req->Uid = pSMB->hdr.Uid;
5257 dnotify_req->netfid = netfid;
5258 dnotify_req->pfile = pfile;
5259 dnotify_req->filter = filter;
5260 dnotify_req->multishot = multishot;
5261 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005262 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005263 &GlobalDnotifyReqList);
5264 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005265 } else
Steve French47c786e2005-10-11 20:03:18 -07005266 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267 }
5268 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005269 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005270}
5271#ifdef CONFIG_CIFS_XATTR
5272ssize_t
5273CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5274 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005275 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005276 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277{
5278 /* BB assumes one setup word */
5279 TRANSACTION2_QPI_REQ *pSMB = NULL;
5280 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5281 int rc = 0;
5282 int bytes_returned;
5283 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005284 struct fea *temp_fea;
5285 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 __u16 params, byte_count;
5287
5288 cFYI(1, ("In Query All EAs path %s", searchName));
5289QAllEAsRetry:
5290 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5291 (void **) &pSMBr);
5292 if (rc)
5293 return rc;
5294
5295 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5296 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005297 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005298 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005299 name_len++; /* trailing null */
5300 name_len *= 2;
5301 } else { /* BB improve the check for buffer overruns BB */
5302 name_len = strnlen(searchName, PATH_MAX);
5303 name_len++; /* trailing null */
5304 strncpy(pSMB->FileName, searchName, name_len);
5305 }
5306
Steve French50c2f752007-07-13 00:33:32 +00005307 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308 pSMB->TotalDataCount = 0;
5309 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005310 /* BB find exact max SMB PDU from sess structure BB */
5311 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005312 pSMB->MaxSetupCount = 0;
5313 pSMB->Reserved = 0;
5314 pSMB->Flags = 0;
5315 pSMB->Timeout = 0;
5316 pSMB->Reserved2 = 0;
5317 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005318 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005319 pSMB->DataCount = 0;
5320 pSMB->DataOffset = 0;
5321 pSMB->SetupCount = 1;
5322 pSMB->Reserved3 = 0;
5323 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5324 byte_count = params + 1 /* pad */ ;
5325 pSMB->TotalParameterCount = cpu_to_le16(params);
5326 pSMB->ParameterCount = pSMB->TotalParameterCount;
5327 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5328 pSMB->Reserved4 = 0;
5329 pSMB->hdr.smb_buf_length += byte_count;
5330 pSMB->ByteCount = cpu_to_le16(byte_count);
5331
5332 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5333 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5334 if (rc) {
5335 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5336 } else { /* decode response */
5337 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5338
5339 /* BB also check enough total bytes returned */
5340 /* BB we need to improve the validity checking
5341 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005342 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343 rc = -EIO; /* bad smb */
5344 /* else if (pFindData){
5345 memcpy((char *) pFindData,
5346 (char *) &pSMBr->hdr.Protocol +
5347 data_offset, kl);
5348 }*/ else {
5349 /* check that length of list is not more than bcc */
5350 /* check that each entry does not go beyond length
5351 of list */
5352 /* check that each element of each entry does not
5353 go beyond end of list */
5354 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005355 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005356 rc = 0;
5357 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005358 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005359 ea_response_data = (struct fealist *)
5360 (((char *) &pSMBr->hdr.Protocol) +
5361 data_offset);
5362 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005363 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005364 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005366 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005367 } else {
5368 /* account for ea list len */
5369 name_len -= 4;
5370 temp_fea = ea_response_data->list;
5371 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005372 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373 __u16 value_len;
5374 name_len -= 4;
5375 temp_ptr += 4;
5376 rc += temp_fea->name_len;
5377 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005378 rc = rc + 5 + 1;
5379 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005380 memcpy(EAData, "user.", 5);
5381 EAData += 5;
5382 memcpy(EAData, temp_ptr,
5383 temp_fea->name_len);
5384 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385 /* null terminate name */
5386 *EAData = 0;
5387 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005388 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005389 /* skip copy - calc size only */
5390 } else {
5391 /* stop before overrun buffer */
5392 rc = -ERANGE;
5393 break;
5394 }
5395 name_len -= temp_fea->name_len;
5396 temp_ptr += temp_fea->name_len;
5397 /* account for trailing null */
5398 name_len--;
5399 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005400 value_len =
5401 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005402 name_len -= value_len;
5403 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005404 /* BB check that temp_ptr is still
5405 within the SMB BB*/
5406
5407 /* no trailing null to account for
5408 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 /* go on to next EA */
5410 temp_fea = (struct fea *)temp_ptr;
5411 }
5412 }
5413 }
5414 }
Steve French0d817bc2008-05-22 02:02:03 +00005415 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416 if (rc == -EAGAIN)
5417 goto QAllEAsRetry;
5418
5419 return (ssize_t)rc;
5420}
5421
Steve French50c2f752007-07-13 00:33:32 +00005422ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5423 const unsigned char *searchName, const unsigned char *ea_name,
5424 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005425 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005426{
5427 TRANSACTION2_QPI_REQ *pSMB = NULL;
5428 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5429 int rc = 0;
5430 int bytes_returned;
5431 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005432 struct fea *temp_fea;
5433 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 __u16 params, byte_count;
5435
5436 cFYI(1, ("In Query EA path %s", searchName));
5437QEARetry:
5438 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5439 (void **) &pSMBr);
5440 if (rc)
5441 return rc;
5442
5443 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5444 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005445 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005446 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 name_len++; /* trailing null */
5448 name_len *= 2;
5449 } else { /* BB improve the check for buffer overruns BB */
5450 name_len = strnlen(searchName, PATH_MAX);
5451 name_len++; /* trailing null */
5452 strncpy(pSMB->FileName, searchName, name_len);
5453 }
5454
Steve French50c2f752007-07-13 00:33:32 +00005455 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 pSMB->TotalDataCount = 0;
5457 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005458 /* BB find exact max SMB PDU from sess structure BB */
5459 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005460 pSMB->MaxSetupCount = 0;
5461 pSMB->Reserved = 0;
5462 pSMB->Flags = 0;
5463 pSMB->Timeout = 0;
5464 pSMB->Reserved2 = 0;
5465 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005466 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 pSMB->DataCount = 0;
5468 pSMB->DataOffset = 0;
5469 pSMB->SetupCount = 1;
5470 pSMB->Reserved3 = 0;
5471 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5472 byte_count = params + 1 /* pad */ ;
5473 pSMB->TotalParameterCount = cpu_to_le16(params);
5474 pSMB->ParameterCount = pSMB->TotalParameterCount;
5475 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5476 pSMB->Reserved4 = 0;
5477 pSMB->hdr.smb_buf_length += byte_count;
5478 pSMB->ByteCount = cpu_to_le16(byte_count);
5479
5480 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5481 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5482 if (rc) {
5483 cFYI(1, ("Send error in Query EA = %d", rc));
5484 } else { /* decode response */
5485 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5486
5487 /* BB also check enough total bytes returned */
5488 /* BB we need to improve the validity checking
5489 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005490 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005491 rc = -EIO; /* bad smb */
5492 /* else if (pFindData){
5493 memcpy((char *) pFindData,
5494 (char *) &pSMBr->hdr.Protocol +
5495 data_offset, kl);
5496 }*/ else {
5497 /* check that length of list is not more than bcc */
5498 /* check that each entry does not go beyond length
5499 of list */
5500 /* check that each element of each entry does not
5501 go beyond end of list */
5502 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005503 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005504 rc = -ENODATA;
5505 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005506 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005507 ea_response_data = (struct fealist *)
5508 (((char *) &pSMBr->hdr.Protocol) +
5509 data_offset);
5510 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005511 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005512 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005514 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515 } else {
5516 /* account for ea list len */
5517 name_len -= 4;
5518 temp_fea = ea_response_data->list;
5519 temp_ptr = (char *)temp_fea;
5520 /* loop through checking if we have a matching
5521 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005522 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 __u16 value_len;
5524 name_len -= 4;
5525 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005526 value_len =
5527 le16_to_cpu(temp_fea->value_len);
5528 /* BB validate that value_len falls within SMB,
5529 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005530 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 temp_fea->name_len) == 0) {
5532 /* found a match */
5533 rc = value_len;
5534 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005535 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005536 memcpy(ea_value,
5537 temp_fea->name+temp_fea->name_len+1,
5538 rc);
Steve French50c2f752007-07-13 00:33:32 +00005539 /* ea values, unlike ea
5540 names, are not null
5541 terminated */
Steve French790fe572007-07-07 19:25:05 +00005542 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 /* skip copy - calc size only */
5544 } else {
Steve French50c2f752007-07-13 00:33:32 +00005545 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546 rc = -ERANGE;
5547 }
5548 break;
5549 }
5550 name_len -= temp_fea->name_len;
5551 temp_ptr += temp_fea->name_len;
5552 /* account for trailing null */
5553 name_len--;
5554 temp_ptr++;
5555 name_len -= value_len;
5556 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005557 /* No trailing null to account for in
5558 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005559 temp_fea = (struct fea *)temp_ptr;
5560 }
Steve French50c2f752007-07-13 00:33:32 +00005561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005562 }
5563 }
Steve French0d817bc2008-05-22 02:02:03 +00005564 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005565 if (rc == -EAGAIN)
5566 goto QEARetry;
5567
5568 return (ssize_t)rc;
5569}
5570
5571int
5572CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005573 const char *ea_name, const void *ea_value,
5574 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5575 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005576{
5577 struct smb_com_transaction2_spi_req *pSMB = NULL;
5578 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5579 struct fealist *parm_data;
5580 int name_len;
5581 int rc = 0;
5582 int bytes_returned = 0;
5583 __u16 params, param_offset, byte_count, offset, count;
5584
5585 cFYI(1, ("In SetEA"));
5586SetEARetry:
5587 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5588 (void **) &pSMBr);
5589 if (rc)
5590 return rc;
5591
5592 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5593 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005594 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005595 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005596 name_len++; /* trailing null */
5597 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005598 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005599 name_len = strnlen(fileName, PATH_MAX);
5600 name_len++; /* trailing null */
5601 strncpy(pSMB->FileName, fileName, name_len);
5602 }
5603
5604 params = 6 + name_len;
5605
5606 /* done calculating parms using name_len of file name,
5607 now use name_len to calculate length of ea name
5608 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005609 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005610 name_len = 0;
5611 else
Steve French50c2f752007-07-13 00:33:32 +00005612 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005613
Steve Frenchdae5dbd2007-12-30 23:49:57 +00005614 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005615 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French582d21e2008-05-13 04:54:12 +00005616 /* BB find max SMB PDU from sess */
5617 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005618 pSMB->MaxSetupCount = 0;
5619 pSMB->Reserved = 0;
5620 pSMB->Flags = 0;
5621 pSMB->Timeout = 0;
5622 pSMB->Reserved2 = 0;
5623 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005624 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625 offset = param_offset + params;
5626 pSMB->InformationLevel =
5627 cpu_to_le16(SMB_SET_FILE_EA);
5628
5629 parm_data =
5630 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5631 offset);
5632 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5633 pSMB->DataOffset = cpu_to_le16(offset);
5634 pSMB->SetupCount = 1;
5635 pSMB->Reserved3 = 0;
5636 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5637 byte_count = 3 /* pad */ + params + count;
5638 pSMB->DataCount = cpu_to_le16(count);
5639 parm_data->list_len = cpu_to_le32(count);
5640 parm_data->list[0].EA_flags = 0;
5641 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005642 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005643 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005644 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005645 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005646 parm_data->list[0].name[name_len] = 0;
5647 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5648 /* caller ensures that ea_value_len is less than 64K but
5649 we need to ensure that it fits within the smb */
5650
Steve French50c2f752007-07-13 00:33:32 +00005651 /*BB add length check to see if it would fit in
5652 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005653 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5654 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005655 memcpy(parm_data->list[0].name+name_len+1,
5656 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005657
5658 pSMB->TotalDataCount = pSMB->DataCount;
5659 pSMB->ParameterCount = cpu_to_le16(params);
5660 pSMB->TotalParameterCount = pSMB->ParameterCount;
5661 pSMB->Reserved4 = 0;
5662 pSMB->hdr.smb_buf_length += byte_count;
5663 pSMB->ByteCount = cpu_to_le16(byte_count);
5664 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5665 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frenchad7a2922008-02-07 23:25:02 +00005666 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005667 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005668
5669 cifs_buf_release(pSMB);
5670
5671 if (rc == -EAGAIN)
5672 goto SetEARetry;
5673
5674 return rc;
5675}
5676
5677#endif