blob: fda8b2490263a8fd437974385fea980bf4dcddcd [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve French2dd29d32007-04-23 22:07:35 +00004 * Copyright (C) International Business Machines Corp., 2002,2007
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
33#include <linux/posix_acl_xattr.h>
34#include <asm/uaccess.h>
35#include "cifspdu.h"
36#include "cifsglob.h"
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
85/* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +000087static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070088{
89 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000090 struct list_head *tmp;
91 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
93/* list all files open on tree connection and mark them invalid */
94 write_lock(&GlobalSMBSeslock);
95 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000096 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve French26f57362007-08-30 22:09:15 +000097 if (open_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 open_file->invalidHandle = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 }
100 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700101 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
102 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103}
104
105/* If the return code is zero, this function must fill in request_buf pointer */
106static int
107small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
108 void **request_buf /* returned */)
109{
110 int rc = 0;
111
112 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
113 check for tcp and smb session status done differently
114 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000115 if (tcon) {
116 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800117 /* only tree disconnect, open, and write,
118 (and ulogoff which does not have tcon)
119 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000120 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French50c2f752007-07-13 00:33:32 +0000121 (smb_command != SMB_COM_OPEN_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800122 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000123 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800124 smb_command));
125 return -ENODEV;
126 }
127 }
Steve French790fe572007-07-07 19:25:05 +0000128 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000129 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 struct nls_table *nls_codepage;
Steve French50c2f752007-07-13 00:33:32 +0000131 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700132 reconnect, should be greater than cifs socket
133 timeout which is 7 seconds */
Steve Frenchc18c8422007-07-18 23:21:09 +0000134 while (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000135 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve Frenchc18c8422007-07-18 23:21:09 +0000137 (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000138 CifsGood), 10 * HZ);
139 if (tcon->ses->server->tcpStatus ==
140 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 /* on "soft" mounts we wait once */
Steve French790fe572007-07-07 19:25:05 +0000142 if ((tcon->retry == FALSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000144 cFYI(1, ("gave up waiting on "
145 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700147 } /* else "hard" mount - keep retrying
148 until process is killed or server
149 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 } else /* TCP session is reestablished now */
151 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 }
Steve French50c2f752007-07-13 00:33:32 +0000153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 nls_codepage = load_nls_default();
155 /* need to prevent multiple threads trying to
156 simultaneously reconnect the same SMB session */
157 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000158 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000159 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700160 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000161 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 mark_open_files_invalid(tcon);
Steve French50c2f752007-07-13 00:33:32 +0000163 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
Steve French8af18972007-02-14 04:42:51 +0000164 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 up(&tcon->ses->sesSem);
Steve French8af18972007-02-14 04:42:51 +0000166 /* tell server which Unix caps we support */
167 if (tcon->ses->capabilities & CAP_UNIX)
168 reset_cifs_unix_caps(0 /* no xid */,
Steve French50c2f752007-07-13 00:33:32 +0000169 tcon,
Steve French8af18972007-02-14 04:42:51 +0000170 NULL /* we do not know sb */,
Steve French50c2f752007-07-13 00:33:32 +0000171 NULL /* no vol info */);
Steve French3e844692005-10-03 13:37:24 -0700172 /* BB FIXME add code to check if wsize needs
173 update due to negotiated smb buffer size
174 shrinking */
Steve French790fe572007-07-07 19:25:05 +0000175 if (rc == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 atomic_inc(&tconInfoReconnectCount);
177
178 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000179 /* Removed call to reopen open files here.
180 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700181 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Steve French50c2f752007-07-13 00:33:32 +0000183 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700184 know whether we can continue or not without
185 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000186 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 case SMB_COM_READ_ANDX:
188 case SMB_COM_WRITE_ANDX:
189 case SMB_COM_CLOSE:
190 case SMB_COM_FIND_CLOSE2:
191 case SMB_COM_LOCKING_ANDX: {
192 unload_nls(nls_codepage);
193 return -EAGAIN;
194 }
195 }
196 } else {
197 up(&tcon->ses->sesSem);
198 }
199 unload_nls(nls_codepage);
200
201 } else {
202 return -EIO;
203 }
204 }
Steve French790fe572007-07-07 19:25:05 +0000205 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 return rc;
207
208 *request_buf = cifs_small_buf_get();
209 if (*request_buf == NULL) {
210 /* BB should we add a retry in here if not a writepage? */
211 return -ENOMEM;
212 }
213
Steve French63135e02007-07-17 17:34:02 +0000214 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000215 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
Steve French790fe572007-07-07 19:25:05 +0000217 if (tcon != NULL)
218 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700219
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000221}
222
Steve French12b3b8f2006-02-09 21:12:47 +0000223int
Steve French50c2f752007-07-13 00:33:32 +0000224small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000225 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000226{
227 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000228 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000229
Steve French5815449d2006-02-14 01:36:20 +0000230 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000231 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000232 return rc;
233
Steve French04fdabe2006-02-10 05:52:50 +0000234 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000235 buffer->Mid = GetNextMid(ses->server);
236 if (ses->capabilities & CAP_UNICODE)
237 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000238 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000239 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
240
241 /* uid, tid can stay at zero as set in header assemble */
242
Steve French50c2f752007-07-13 00:33:32 +0000243 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000244 this function is used after 1st of session setup requests */
245
246 return rc;
247}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
249/* If the return code is zero, this function must fill in request_buf pointer */
250static int
251smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
252 void **request_buf /* returned */ ,
253 void **response_buf /* returned */ )
254{
255 int rc = 0;
256
257 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
258 check for tcp and smb session status done differently
259 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000260 if (tcon) {
261 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800262 /* only tree disconnect, open, and write,
263 (and ulogoff which does not have tcon)
264 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000265 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800266 (smb_command != SMB_COM_OPEN_ANDX) &&
267 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000268 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800269 smb_command));
270 return -ENODEV;
271 }
272 }
273
Steve French790fe572007-07-07 19:25:05 +0000274 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000275 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700277 /* Give Demultiplex thread up to 10 seconds to
278 reconnect, should be greater than cifs socket
279 timeout which is 7 seconds */
Steve French63135e02007-07-17 17:34:02 +0000280 while (tcon->ses->server->tcpStatus ==
281 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000283 (tcon->ses->server->tcpStatus ==
284 CifsGood), 10 * HZ);
Steve French790fe572007-07-07 19:25:05 +0000285 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700286 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 /* on "soft" mounts we wait once */
Steve French790fe572007-07-07 19:25:05 +0000288 if ((tcon->retry == FALSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000290 cFYI(1, ("gave up waiting on "
291 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700293 } /* else "hard" mount - keep retrying
294 until process is killed or server
295 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 } else /* TCP session is reestablished now */
297 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 nls_codepage = load_nls_default();
300 /* need to prevent multiple threads trying to
301 simultaneously reconnect the same SMB session */
302 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000303 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000304 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700305 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000306 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700308 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
309 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 up(&tcon->ses->sesSem);
Steve French8af18972007-02-14 04:42:51 +0000311 /* tell server which Unix caps we support */
312 if (tcon->ses->capabilities & CAP_UNIX)
313 reset_cifs_unix_caps(0 /* no xid */,
Steve French50c2f752007-07-13 00:33:32 +0000314 tcon,
Steve French8af18972007-02-14 04:42:51 +0000315 NULL /* do not know sb */,
316 NULL /* no vol info */);
Steve French3e844692005-10-03 13:37:24 -0700317 /* BB FIXME add code to check if wsize needs
318 update due to negotiated smb buffer size
319 shrinking */
Steve French790fe572007-07-07 19:25:05 +0000320 if (rc == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 atomic_inc(&tconInfoReconnectCount);
322
323 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000324 /* Removed call to reopen open files here.
325 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700326 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
Steve French50c2f752007-07-13 00:33:32 +0000328 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700329 know whether we can continue or not without
330 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000331 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 case SMB_COM_READ_ANDX:
333 case SMB_COM_WRITE_ANDX:
334 case SMB_COM_CLOSE:
335 case SMB_COM_FIND_CLOSE2:
336 case SMB_COM_LOCKING_ANDX: {
337 unload_nls(nls_codepage);
338 return -EAGAIN;
339 }
340 }
341 } else {
342 up(&tcon->ses->sesSem);
343 }
344 unload_nls(nls_codepage);
345
346 } else {
347 return -EIO;
348 }
349 }
Steve French790fe572007-07-07 19:25:05 +0000350 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 return rc;
352
353 *request_buf = cifs_buf_get();
354 if (*request_buf == NULL) {
355 /* BB should we add a retry in here if not a writepage? */
356 return -ENOMEM;
357 }
358 /* Although the original thought was we needed the response buf for */
359 /* potential retries of smb operations it turns out we can determine */
360 /* from the mid flags when the request buffer can be resent without */
361 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000362 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000363 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
365 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
366 wct /*wct */ );
367
Steve French790fe572007-07-07 19:25:05 +0000368 if (tcon != NULL)
369 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700370
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 return rc;
372}
373
Steve French50c2f752007-07-13 00:33:32 +0000374static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375{
376 int rc = -EINVAL;
377 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000378 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380 /* check for plausible wct, bcc and t2 data and parm sizes */
381 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000382 if (pSMB->hdr.WordCount >= 10) {
383 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
385 /* check that bcc is at least as big as parms + data */
386 /* check that bcc is less than negotiated smb buffer */
387 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000388 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000389 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000390 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000392 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700393 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000395 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000396 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
398 return 0;
399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 }
401 }
402 }
Steve French50c2f752007-07-13 00:33:32 +0000403 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 sizeof(struct smb_t2_rsp) + 16);
405 return rc;
406}
407int
408CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
409{
410 NEGOTIATE_REQ *pSMB;
411 NEGOTIATE_RSP *pSMBr;
412 int rc = 0;
413 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000414 int i;
Steve French50c2f752007-07-13 00:33:32 +0000415 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000417 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100418 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Steve French790fe572007-07-07 19:25:05 +0000420 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 server = ses->server;
422 else {
423 rc = -EIO;
424 return rc;
425 }
426 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
427 (void **) &pSMB, (void **) &pSMBr);
428 if (rc)
429 return rc;
Steve French750d1152006-06-27 06:28:30 +0000430
431 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000432 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000433 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000434 else /* if override flags set only sign/seal OR them with global auth */
435 secFlags = extended_security | ses->overrideSecFlg;
436
Steve French762e5ab2007-06-28 18:41:42 +0000437 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000438
Steve French1982c342005-08-17 12:38:22 -0700439 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000440 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000441
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000442 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000443 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000444 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
445 cFYI(1, ("Kerberos only mechanism, enable extended security"));
446 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
447 }
Steve French50c2f752007-07-13 00:33:32 +0000448
Steve French39798772006-05-31 22:40:51 +0000449 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000450 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000451 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
452 count += strlen(protocols[i].name) + 1;
453 /* null at end of source and target buffers anyway */
454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 pSMB->hdr.smb_buf_length += count;
456 pSMB->ByteCount = cpu_to_le16(count);
457
458 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
459 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000460 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000461 goto neg_err_exit;
462
Al Viro733f99a2006-10-14 16:48:26 +0100463 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000464 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000465 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000466 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000467 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000468 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000469 could not negotiate a common dialect */
470 rc = -EOPNOTSUPP;
471 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000472#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000473 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100474 && ((dialect == LANMAN_PROT)
475 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000476 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000477 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000478
Steve French790fe572007-07-07 19:25:05 +0000479 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000480 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000481 server->secType = LANMAN;
482 else {
483 cERROR(1, ("mount failed weak security disabled"
484 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000485 rc = -EOPNOTSUPP;
486 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000487 }
Steve French254e55e2006-06-04 05:53:15 +0000488 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
489 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
490 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000491 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000492 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
493 /* even though we do not use raw we might as well set this
494 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000495 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve French254e55e2006-06-04 05:53:15 +0000496 server->maxRw = 0xFF00;
497 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
498 } else {
499 server->maxRw = 0;/* we do not need to use raw anyway */
500 server->capabilities = CAP_MPX_MODE;
501 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000502 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000503 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000504 /* OS/2 often does not set timezone therefore
505 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000506 * Could deviate slightly from the right zone.
507 * Smallest defined timezone difference is 15 minutes
508 * (i.e. Nepal). Rounding up/down is done to match
509 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000510 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000511 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000512 struct timespec ts, utc;
513 utc = CURRENT_TIME;
514 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
515 le16_to_cpu(rsp->SrvTime.Time));
Steve French50c2f752007-07-13 00:33:32 +0000516 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
517 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000518 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000519 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000520 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000521 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000522 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000523 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000524 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000525 if (val < 0)
Steve Frenchb815f1e52006-10-02 05:53:29 +0000526 result = - result;
527 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000528 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000529 server->timeAdj = (int)tmp;
530 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000531 }
Steve French790fe572007-07-07 19:25:05 +0000532 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000533
Steve French39798772006-05-31 22:40:51 +0000534
Steve French254e55e2006-06-04 05:53:15 +0000535 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000536 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000537
Steve French50c2f752007-07-13 00:33:32 +0000538 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000539 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000540 memcpy(server->cryptKey, rsp->EncryptionKey,
541 CIFS_CRYPTO_KEY_SIZE);
542 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
543 rc = -EIO; /* need cryptkey unless plain text */
544 goto neg_err_exit;
545 }
Steve French39798772006-05-31 22:40:51 +0000546
Steve French790fe572007-07-07 19:25:05 +0000547 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000548 /* we will not end up setting signing flags - as no signing
549 was in LANMAN and server did not return the flags on */
550 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000551#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000552 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000553 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000554 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000555 rc = -EOPNOTSUPP;
556#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000557 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000558 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000559 /* unknown wct */
560 rc = -EOPNOTSUPP;
561 goto neg_err_exit;
562 }
563 /* else wct == 17 NTLM */
564 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000565 if ((server->secMode & SECMODE_USER) == 0)
566 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000567
Steve French790fe572007-07-07 19:25:05 +0000568 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000569#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000570 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000571#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000572 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000573 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000574
Steve French790fe572007-07-07 19:25:05 +0000575 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000576 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000577 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000578 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000579 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000580 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000581 else if (secFlags & CIFSSEC_MAY_KRB5)
582 server->secType = Kerberos;
583 else if (secFlags & CIFSSEC_MAY_LANMAN)
584 server->secType = LANMAN;
585/* #ifdef CONFIG_CIFS_EXPERIMENTAL
586 else if (secFlags & CIFSSEC_MAY_PLNTXT)
587 server->secType = ??
588#endif */
589 else {
590 rc = -EOPNOTSUPP;
591 cERROR(1, ("Invalid security type"));
592 goto neg_err_exit;
593 }
594 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000595
Steve French254e55e2006-06-04 05:53:15 +0000596 /* one byte, so no need to convert this or EncryptionKeyLen from
597 little endian */
598 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
599 /* probably no need to store and check maxvcs */
600 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000602 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
603 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
604 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
605 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000606 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
607 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000608 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
609 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
610 CIFS_CRYPTO_KEY_SIZE);
611 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
612 && (pSMBr->EncryptionKeyLength == 0)) {
613 /* decode security blob */
614 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
615 rc = -EIO; /* no crypt key only if plain text pwd */
616 goto neg_err_exit;
617 }
618
619 /* BB might be helpful to save off the domain of server here */
620
Steve French50c2f752007-07-13 00:33:32 +0000621 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000622 (server->capabilities & CAP_EXTENDED_SECURITY)) {
623 count = pSMBr->ByteCount;
624 if (count < 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 rc = -EIO;
Steve French254e55e2006-06-04 05:53:15 +0000626 else if (count == 16) {
627 server->secType = RawNTLMSSP;
628 if (server->socketUseCount.counter > 1) {
629 if (memcmp(server->server_GUID,
630 pSMBr->u.extended_response.
631 GUID, 16) != 0) {
632 cFYI(1, ("server UID changed"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 memcpy(server->server_GUID,
Steve French254e55e2006-06-04 05:53:15 +0000634 pSMBr->u.extended_response.GUID,
635 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 }
Steve French254e55e2006-06-04 05:53:15 +0000637 } else
638 memcpy(server->server_GUID,
639 pSMBr->u.extended_response.GUID, 16);
640 } else {
641 rc = decode_negTokenInit(pSMBr->u.extended_response.
642 SecurityBlob,
643 count - 16,
644 &server->secType);
Steve French790fe572007-07-07 19:25:05 +0000645 if (rc == 1) {
Steve French254e55e2006-06-04 05:53:15 +0000646 /* BB Need to fill struct for sessetup here */
647 rc = -EOPNOTSUPP;
648 } else {
649 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 }
Steve French254e55e2006-06-04 05:53:15 +0000652 } else
653 server->capabilities &= ~CAP_EXTENDED_SECURITY;
654
Steve French6344a422006-06-12 04:18:35 +0000655#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000656signing_check:
Steve French6344a422006-06-12 04:18:35 +0000657#endif
Steve French762e5ab2007-06-28 18:41:42 +0000658 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
659 /* MUST_SIGN already includes the MAY_SIGN FLAG
660 so if this is zero it means that signing is disabled */
661 cFYI(1, ("Signing disabled"));
Steve French790fe572007-07-07 19:25:05 +0000662 if (server->secMode & SECMODE_SIGN_REQUIRED)
Steve French762e5ab2007-06-28 18:41:42 +0000663 cERROR(1, ("Server requires "
664 "/proc/fs/cifs/PacketSigningEnabled "
665 "to be on"));
Steve French50c2f752007-07-13 00:33:32 +0000666 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000667 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000668 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
669 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000670 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000671 if ((server->secMode &
672 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
673 cERROR(1,
674 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000675 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000676 } else
677 server->secMode |= SECMODE_SIGN_REQUIRED;
678 } else {
679 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000680 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000681 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000682 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 }
Steve French50c2f752007-07-13 00:33:32 +0000684
685neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700686 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000687
Steve French790fe572007-07-07 19:25:05 +0000688 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 return rc;
690}
691
692int
693CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
694{
695 struct smb_hdr *smb_buffer;
696 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
697 int rc = 0;
698 int length;
699
700 cFYI(1, ("In tree disconnect"));
701 /*
702 * If last user of the connection and
703 * connection alive - disconnect it
704 * If this is the last connection on the server session disconnect it
Steve French50c2f752007-07-13 00:33:32 +0000705 * (and inside session disconnect we should check if tcp socket needs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 * to be freed and kernel thread woken up).
707 */
708 if (tcon)
709 down(&tcon->tconSem);
710 else
711 return -EIO;
712
713 atomic_dec(&tcon->useCount);
714 if (atomic_read(&tcon->useCount) > 0) {
715 up(&tcon->tconSem);
716 return -EBUSY;
717 }
718
Steve French50c2f752007-07-13 00:33:32 +0000719 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 closed on server already e.g. due to tcp session crashing */
Steve French790fe572007-07-07 19:25:05 +0000721 if (tcon->tidStatus == CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 up(&tcon->tconSem);
Steve French50c2f752007-07-13 00:33:32 +0000723 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 }
725
Steve French790fe572007-07-07 19:25:05 +0000726 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 up(&tcon->tconSem);
728 return -EIO;
729 }
Steve French50c2f752007-07-13 00:33:32 +0000730 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700731 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 if (rc) {
733 up(&tcon->tconSem);
734 return rc;
735 } else {
736 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700737 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
739 &length, 0);
740 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700741 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
743 if (smb_buffer)
744 cifs_small_buf_release(smb_buffer);
745 up(&tcon->tconSem);
746
Steve French50c2f752007-07-13 00:33:32 +0000747 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 closed on server already e.g. due to tcp session crashing */
749 if (rc == -EAGAIN)
750 rc = 0;
751
752 return rc;
753}
754
755int
756CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
757{
758 struct smb_hdr *smb_buffer_response;
759 LOGOFF_ANDX_REQ *pSMB;
760 int rc = 0;
761 int length;
762
763 cFYI(1, ("In SMBLogoff for session disconnect"));
764 if (ses)
765 down(&ses->sesSem);
766 else
767 return -EIO;
768
769 atomic_dec(&ses->inUse);
770 if (atomic_read(&ses->inUse) > 0) {
771 up(&ses->sesSem);
772 return -EBUSY;
773 }
774 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
775 if (rc) {
776 up(&ses->sesSem);
777 return rc;
778 }
779
780 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
Steve French50c2f752007-07-13 00:33:32 +0000781
Steve French790fe572007-07-07 19:25:05 +0000782 if (ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700783 pSMB->hdr.Mid = GetNextMid(ses->server);
784
Steve French790fe572007-07-07 19:25:05 +0000785 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
787 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
788 }
789
790 pSMB->hdr.Uid = ses->Suid;
791
792 pSMB->AndXCommand = 0xFF;
793 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
794 smb_buffer_response, &length, 0);
795 if (ses->server) {
796 atomic_dec(&ses->server->socketUseCount);
797 if (atomic_read(&ses->server->socketUseCount) == 0) {
798 spin_lock(&GlobalMid_Lock);
799 ses->server->tcpStatus = CifsExiting;
800 spin_unlock(&GlobalMid_Lock);
801 rc = -ESHUTDOWN;
802 }
803 }
Steve Frencha59c6582005-08-17 12:12:19 -0700804 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700805 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806
807 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000808 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 error */
810 if (rc == -EAGAIN)
811 rc = 0;
812 return rc;
813}
814
815int
Steve French2d785a52007-07-15 01:48:57 +0000816CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
817 __u16 type, const struct nls_table *nls_codepage, int remap)
818{
819 TRANSACTION2_SPI_REQ *pSMB = NULL;
820 TRANSACTION2_SPI_RSP *pSMBr = NULL;
821 struct unlink_psx_rq *pRqD;
822 int name_len;
823 int rc = 0;
824 int bytes_returned = 0;
825 __u16 params, param_offset, offset, byte_count;
826
827 cFYI(1, ("In POSIX delete"));
828PsxDelete:
829 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
830 (void **) &pSMBr);
831 if (rc)
832 return rc;
833
834 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
835 name_len =
836 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
837 PATH_MAX, nls_codepage, remap);
838 name_len++; /* trailing null */
839 name_len *= 2;
840 } else { /* BB add path length overrun check */
841 name_len = strnlen(fileName, PATH_MAX);
842 name_len++; /* trailing null */
843 strncpy(pSMB->FileName, fileName, name_len);
844 }
845
846 params = 6 + name_len;
847 pSMB->MaxParameterCount = cpu_to_le16(2);
848 pSMB->MaxDataCount = 0; /* BB double check this with jra */
849 pSMB->MaxSetupCount = 0;
850 pSMB->Reserved = 0;
851 pSMB->Flags = 0;
852 pSMB->Timeout = 0;
853 pSMB->Reserved2 = 0;
854 param_offset = offsetof(struct smb_com_transaction2_spi_req,
855 InformationLevel) - 4;
856 offset = param_offset + params;
857
858 /* Setup pointer to Request Data (inode type) */
859 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
860 pRqD->type = cpu_to_le16(type);
861 pSMB->ParameterOffset = cpu_to_le16(param_offset);
862 pSMB->DataOffset = cpu_to_le16(offset);
863 pSMB->SetupCount = 1;
864 pSMB->Reserved3 = 0;
865 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
866 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
867
868 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
869 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
870 pSMB->ParameterCount = cpu_to_le16(params);
871 pSMB->TotalParameterCount = pSMB->ParameterCount;
872 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
873 pSMB->Reserved4 = 0;
874 pSMB->hdr.smb_buf_length += byte_count;
875 pSMB->ByteCount = cpu_to_le16(byte_count);
876 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
877 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
878 if (rc) {
879 cFYI(1, ("Posix delete returned %d", rc));
880 }
881 cifs_buf_release(pSMB);
882
883 cifs_stats_inc(&tcon->num_deletes);
884
885 if (rc == -EAGAIN)
886 goto PsxDelete;
887
888 return rc;
889}
890
891int
Steve French737b7582005-04-28 22:41:06 -0700892CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
893 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894{
895 DELETE_FILE_REQ *pSMB = NULL;
896 DELETE_FILE_RSP *pSMBr = NULL;
897 int rc = 0;
898 int bytes_returned;
899 int name_len;
900
901DelFileRetry:
902 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
903 (void **) &pSMBr);
904 if (rc)
905 return rc;
906
907 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
908 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000909 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700910 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 name_len++; /* trailing null */
912 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700913 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914 name_len = strnlen(fileName, PATH_MAX);
915 name_len++; /* trailing null */
916 strncpy(pSMB->fileName, fileName, name_len);
917 }
918 pSMB->SearchAttributes =
919 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
920 pSMB->BufferFormat = 0x04;
921 pSMB->hdr.smb_buf_length += name_len + 1;
922 pSMB->ByteCount = cpu_to_le16(name_len + 1);
923 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
924 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700925 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 if (rc) {
927 cFYI(1, ("Error in RMFile = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000928 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929
930 cifs_buf_release(pSMB);
931 if (rc == -EAGAIN)
932 goto DelFileRetry;
933
934 return rc;
935}
936
937int
Steve French50c2f752007-07-13 00:33:32 +0000938CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700939 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940{
941 DELETE_DIRECTORY_REQ *pSMB = NULL;
942 DELETE_DIRECTORY_RSP *pSMBr = NULL;
943 int rc = 0;
944 int bytes_returned;
945 int name_len;
946
947 cFYI(1, ("In CIFSSMBRmDir"));
948RmDirRetry:
949 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
950 (void **) &pSMBr);
951 if (rc)
952 return rc;
953
954 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700955 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
956 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 name_len++; /* trailing null */
958 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700959 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 name_len = strnlen(dirName, PATH_MAX);
961 name_len++; /* trailing null */
962 strncpy(pSMB->DirName, dirName, name_len);
963 }
964
965 pSMB->BufferFormat = 0x04;
966 pSMB->hdr.smb_buf_length += name_len + 1;
967 pSMB->ByteCount = cpu_to_le16(name_len + 1);
968 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
969 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700970 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 if (rc) {
972 cFYI(1, ("Error in RMDir = %d", rc));
973 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
975 cifs_buf_release(pSMB);
976 if (rc == -EAGAIN)
977 goto RmDirRetry;
978 return rc;
979}
980
981int
982CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700983 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984{
985 int rc = 0;
986 CREATE_DIRECTORY_REQ *pSMB = NULL;
987 CREATE_DIRECTORY_RSP *pSMBr = NULL;
988 int bytes_returned;
989 int name_len;
990
991 cFYI(1, ("In CIFSSMBMkDir"));
992MkDirRetry:
993 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
994 (void **) &pSMBr);
995 if (rc)
996 return rc;
997
998 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000999 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -07001000 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 name_len++; /* trailing null */
1002 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001003 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 name_len = strnlen(name, PATH_MAX);
1005 name_len++; /* trailing null */
1006 strncpy(pSMB->DirName, name, name_len);
1007 }
1008
1009 pSMB->BufferFormat = 0x04;
1010 pSMB->hdr.smb_buf_length += name_len + 1;
1011 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1012 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1013 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001014 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 if (rc) {
1016 cFYI(1, ("Error in Mkdir = %d", rc));
1017 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001018
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 cifs_buf_release(pSMB);
1020 if (rc == -EAGAIN)
1021 goto MkDirRetry;
1022 return rc;
1023}
1024
Steve French2dd29d32007-04-23 22:07:35 +00001025int
1026CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1027 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001028 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001029 const struct nls_table *nls_codepage, int remap)
1030{
1031 TRANSACTION2_SPI_REQ *pSMB = NULL;
1032 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1033 int name_len;
1034 int rc = 0;
1035 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001036 __u16 params, param_offset, offset, byte_count, count;
1037 OPEN_PSX_REQ * pdata;
1038 OPEN_PSX_RSP * psx_rsp;
1039
1040 cFYI(1, ("In POSIX Create"));
1041PsxCreat:
1042 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1043 (void **) &pSMBr);
1044 if (rc)
1045 return rc;
1046
1047 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1048 name_len =
1049 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1050 PATH_MAX, nls_codepage, remap);
1051 name_len++; /* trailing null */
1052 name_len *= 2;
1053 } else { /* BB improve the check for buffer overruns BB */
1054 name_len = strnlen(name, PATH_MAX);
1055 name_len++; /* trailing null */
1056 strncpy(pSMB->FileName, name, name_len);
1057 }
1058
1059 params = 6 + name_len;
1060 count = sizeof(OPEN_PSX_REQ);
1061 pSMB->MaxParameterCount = cpu_to_le16(2);
1062 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1063 pSMB->MaxSetupCount = 0;
1064 pSMB->Reserved = 0;
1065 pSMB->Flags = 0;
1066 pSMB->Timeout = 0;
1067 pSMB->Reserved2 = 0;
1068 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001069 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001070 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001071 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
1072 pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
1073 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001074 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001075 pdata->OpenFlags = cpu_to_le32(*pOplock);
1076 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1077 pSMB->DataOffset = cpu_to_le16(offset);
1078 pSMB->SetupCount = 1;
1079 pSMB->Reserved3 = 0;
1080 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1081 byte_count = 3 /* pad */ + params + count;
1082
1083 pSMB->DataCount = cpu_to_le16(count);
1084 pSMB->ParameterCount = cpu_to_le16(params);
1085 pSMB->TotalDataCount = pSMB->DataCount;
1086 pSMB->TotalParameterCount = pSMB->ParameterCount;
1087 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1088 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001089 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001090 pSMB->ByteCount = cpu_to_le16(byte_count);
1091 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1092 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1093 if (rc) {
1094 cFYI(1, ("Posix create returned %d", rc));
1095 goto psx_create_err;
1096 }
1097
Steve French790fe572007-07-07 19:25:05 +00001098 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001099 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1100
1101 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1102 rc = -EIO; /* bad smb */
1103 goto psx_create_err;
1104 }
1105
1106 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001107 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001108 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001109
Steve French2dd29d32007-04-23 22:07:35 +00001110 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001111 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001112 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1113 /* Let caller know file was created so we can set the mode. */
1114 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001115 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001116 *pOplock |= CIFS_CREATE_ACTION;
1117 /* check to make sure response data is there */
Steve French790fe572007-07-07 19:25:05 +00001118 if (psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) {
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001119 pRetData->Type = -1; /* unknown */
1120#ifdef CONFIG_CIFS_DEBUG2
Steve French790fe572007-07-07 19:25:05 +00001121 cFYI(1, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001122#endif
1123 } else {
Steve French790fe572007-07-07 19:25:05 +00001124 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001125 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001126 cERROR(1, ("Open response data too small"));
Steve French2dd29d32007-04-23 22:07:35 +00001127 pRetData->Type = -1;
1128 goto psx_create_err;
1129 }
Steve French50c2f752007-07-13 00:33:32 +00001130 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001131 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001132 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001133 }
Steve French2dd29d32007-04-23 22:07:35 +00001134
1135psx_create_err:
1136 cifs_buf_release(pSMB);
1137
1138 cifs_stats_inc(&tcon->num_mkdirs);
1139
1140 if (rc == -EAGAIN)
1141 goto PsxCreat;
1142
Steve French50c2f752007-07-13 00:33:32 +00001143 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001144}
1145
Steve Frencha9d02ad2005-08-24 23:06:05 -07001146static __u16 convert_disposition(int disposition)
1147{
1148 __u16 ofun = 0;
1149
1150 switch (disposition) {
1151 case FILE_SUPERSEDE:
1152 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1153 break;
1154 case FILE_OPEN:
1155 ofun = SMBOPEN_OAPPEND;
1156 break;
1157 case FILE_CREATE:
1158 ofun = SMBOPEN_OCREATE;
1159 break;
1160 case FILE_OPEN_IF:
1161 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1162 break;
1163 case FILE_OVERWRITE:
1164 ofun = SMBOPEN_OTRUNC;
1165 break;
1166 case FILE_OVERWRITE_IF:
1167 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1168 break;
1169 default:
Steve French790fe572007-07-07 19:25:05 +00001170 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001171 ofun = SMBOPEN_OAPPEND; /* regular open */
1172 }
1173 return ofun;
1174}
1175
1176int
1177SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1178 const char *fileName, const int openDisposition,
1179 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001180 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001181 const struct nls_table *nls_codepage, int remap)
1182{
1183 int rc = -EACCES;
1184 OPENX_REQ *pSMB = NULL;
1185 OPENX_RSP *pSMBr = NULL;
1186 int bytes_returned;
1187 int name_len;
1188 __u16 count;
1189
1190OldOpenRetry:
1191 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1192 (void **) &pSMBr);
1193 if (rc)
1194 return rc;
1195
1196 pSMB->AndXCommand = 0xFF; /* none */
1197
1198 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1199 count = 1; /* account for one byte pad to word boundary */
1200 name_len =
1201 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1202 fileName, PATH_MAX, nls_codepage, remap);
1203 name_len++; /* trailing null */
1204 name_len *= 2;
1205 } else { /* BB improve check for buffer overruns BB */
1206 count = 0; /* no pad */
1207 name_len = strnlen(fileName, PATH_MAX);
1208 name_len++; /* trailing null */
1209 strncpy(pSMB->fileName, fileName, name_len);
1210 }
1211 if (*pOplock & REQ_OPLOCK)
1212 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001213 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001214 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001215
Steve Frencha9d02ad2005-08-24 23:06:05 -07001216 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1217 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1218 /* 0 = read
1219 1 = write
1220 2 = rw
1221 3 = execute
Steve French50c2f752007-07-13 00:33:32 +00001222 */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001223 pSMB->Mode = cpu_to_le16(2);
1224 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1225 /* set file as system file if special file such
1226 as fifo and server expecting SFU style and
1227 no Unix extensions */
1228
Steve French790fe572007-07-07 19:25:05 +00001229 if (create_options & CREATE_OPTION_SPECIAL)
1230 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1231 else
Steve French3e87d802005-09-18 20:49:21 -07001232 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001233
1234 /* if ((omode & S_IWUGO) == 0)
1235 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1236 /* Above line causes problems due to vfs splitting create into two
1237 pieces - need to set mode after file created not while it is
1238 being created */
1239
1240 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001241/* pSMB->CreateOptions = cpu_to_le32(create_options &
1242 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001243 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001244
1245 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001246 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247 count += name_len;
1248 pSMB->hdr.smb_buf_length += count;
1249
1250 pSMB->ByteCount = cpu_to_le16(count);
1251 /* long_op set to 1 to allow for oplock break timeouts */
1252 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00001253 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001254 cifs_stats_inc(&tcon->num_opens);
1255 if (rc) {
1256 cFYI(1, ("Error in Open = %d", rc));
1257 } else {
1258 /* BB verify if wct == 15 */
1259
1260/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1261
1262 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1263 /* Let caller know file was created so we can set the mode. */
1264 /* Do we care about the CreateAction in any other cases? */
1265 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001266/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001267 *pOplock |= CIFS_CREATE_ACTION; */
1268 /* BB FIXME END */
1269
Steve French790fe572007-07-07 19:25:05 +00001270 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001271 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1272 pfile_info->LastAccessTime = 0; /* BB fixme */
1273 pfile_info->LastWriteTime = 0; /* BB fixme */
1274 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001275 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001276 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001277 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001278 pfile_info->AllocationSize =
1279 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1280 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001281 pfile_info->NumberOfLinks = cpu_to_le32(1);
1282 }
1283 }
1284
1285 cifs_buf_release(pSMB);
1286 if (rc == -EAGAIN)
1287 goto OldOpenRetry;
1288 return rc;
1289}
1290
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291int
1292CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1293 const char *fileName, const int openDisposition,
1294 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001295 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001296 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297{
1298 int rc = -EACCES;
1299 OPEN_REQ *pSMB = NULL;
1300 OPEN_RSP *pSMBr = NULL;
1301 int bytes_returned;
1302 int name_len;
1303 __u16 count;
1304
1305openRetry:
1306 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1307 (void **) &pSMBr);
1308 if (rc)
1309 return rc;
1310
1311 pSMB->AndXCommand = 0xFF; /* none */
1312
1313 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1314 count = 1; /* account for one byte pad to word boundary */
1315 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001316 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001317 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 name_len++; /* trailing null */
1319 name_len *= 2;
1320 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001321 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 count = 0; /* no pad */
1323 name_len = strnlen(fileName, PATH_MAX);
1324 name_len++; /* trailing null */
1325 pSMB->NameLength = cpu_to_le16(name_len);
1326 strncpy(pSMB->fileName, fileName, name_len);
1327 }
1328 if (*pOplock & REQ_OPLOCK)
1329 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001330 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1333 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001334 /* set file as system file if special file such
1335 as fifo and server expecting SFU style and
1336 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001337 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001338 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1339 else
1340 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341 /* XP does not handle ATTR_POSIX_SEMANTICS */
1342 /* but it helps speed up case sensitive checks for other
1343 servers such as Samba */
1344 if (tcon->ses->capabilities & CAP_UNIX)
1345 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1346
1347 /* if ((omode & S_IWUGO) == 0)
1348 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1349 /* Above line causes problems due to vfs splitting create into two
1350 pieces - need to set mode after file created not while it is
1351 being created */
1352 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1353 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001354 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001355 /* BB Expirement with various impersonation levels and verify */
1356 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357 pSMB->SecurityFlags =
1358 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1359
1360 count += name_len;
1361 pSMB->hdr.smb_buf_length += count;
1362
1363 pSMB->ByteCount = cpu_to_le16(count);
1364 /* long_op set to 1 to allow for oplock break timeouts */
1365 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1366 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001367 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 if (rc) {
1369 cFYI(1, ("Error in Open = %d", rc));
1370 } else {
Steve French09d1db52005-04-28 22:41:08 -07001371 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1373 /* Let caller know file was created so we can set the mode. */
1374 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001375 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001376 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001377 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001378 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 36 /* CreationTime to Attributes */);
1380 /* the file_info buf is endian converted by caller */
1381 pfile_info->AllocationSize = pSMBr->AllocationSize;
1382 pfile_info->EndOfFile = pSMBr->EndOfFile;
1383 pfile_info->NumberOfLinks = cpu_to_le32(1);
1384 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001386
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 cifs_buf_release(pSMB);
1388 if (rc == -EAGAIN)
1389 goto openRetry;
1390 return rc;
1391}
1392
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393int
Steve French50c2f752007-07-13 00:33:32 +00001394CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1395 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1396 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397{
1398 int rc = -EACCES;
1399 READ_REQ *pSMB = NULL;
1400 READ_RSP *pSMBr = NULL;
1401 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001402 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001403 int resp_buf_type = 0;
1404 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405
Steve French790fe572007-07-07 19:25:05 +00001406 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1407 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001408 wct = 12;
1409 else
1410 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
1412 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001413 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 if (rc)
1415 return rc;
1416
1417 /* tcon and ses pointer are checked in smb_init */
1418 if (tcon->ses->server == NULL)
1419 return -ECONNABORTED;
1420
Steve Frenchec637e32005-12-12 20:53:18 -08001421 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 pSMB->Fid = netfid;
1423 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001424 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001425 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001426 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001427 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001428
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 pSMB->Remaining = 0;
1430 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1431 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001432 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001433 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1434 else {
1435 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001436 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001437 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001438 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001439 }
Steve Frenchec637e32005-12-12 20:53:18 -08001440
1441 iov[0].iov_base = (char *)pSMB;
1442 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve French50c2f752007-07-13 00:33:32 +00001443 rc = SendReceive2(xid, tcon->ses, iov,
Steve Frenchec637e32005-12-12 20:53:18 -08001444 1 /* num iovecs */,
Steve French50c2f752007-07-13 00:33:32 +00001445 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001446 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001447 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 if (rc) {
1449 cERROR(1, ("Send error in read = %d", rc));
1450 } else {
1451 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1452 data_length = data_length << 16;
1453 data_length += le16_to_cpu(pSMBr->DataLength);
1454 *nbytes = data_length;
1455
1456 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001457 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001458 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001459 cFYI(1, ("bad length %d for count %d",
1460 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 rc = -EIO;
1462 *nbytes = 0;
1463 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001464 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001465 le16_to_cpu(pSMBr->DataOffset);
1466/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001467 cERROR(1,("Faulting on read rc = %d",rc));
1468 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001469 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001470 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001471 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 }
1473 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474
Steve French4b8f9302006-02-26 16:41:18 +00001475/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001476 if (*buf) {
1477 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001478 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001479 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001480 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001481 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001482 /* return buffer to caller to free */
1483 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001484 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001485 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001486 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001487 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001488 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001489
1490 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 since file handle passed in no longer valid */
1492 return rc;
1493}
1494
Steve Frenchec637e32005-12-12 20:53:18 -08001495
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496int
1497CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1498 const int netfid, const unsigned int count,
1499 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001500 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501{
1502 int rc = -EACCES;
1503 WRITE_REQ *pSMB = NULL;
1504 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001505 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 __u32 bytes_sent;
1507 __u16 byte_count;
1508
1509 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001510 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001511 return -ECONNABORTED;
1512
Steve French790fe572007-07-07 19:25:05 +00001513 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001514 wct = 14;
1515 else
1516 wct = 12;
1517
1518 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519 (void **) &pSMBr);
1520 if (rc)
1521 return rc;
1522 /* tcon and ses pointer are checked in smb_init */
1523 if (tcon->ses->server == NULL)
1524 return -ECONNABORTED;
1525
1526 pSMB->AndXCommand = 0xFF; /* none */
1527 pSMB->Fid = netfid;
1528 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001529 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001530 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001531 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001532 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001533
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534 pSMB->Reserved = 0xFFFFFFFF;
1535 pSMB->WriteMode = 0;
1536 pSMB->Remaining = 0;
1537
Steve French50c2f752007-07-13 00:33:32 +00001538 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 can send more if LARGE_WRITE_X capability returned by the server and if
1540 our buffer is big enough or if we convert to iovecs on socket writes
1541 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001542 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1544 } else {
1545 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1546 & ~0xFF;
1547 }
1548
1549 if (bytes_sent > count)
1550 bytes_sent = count;
1551 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001552 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001553 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001554 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001555 else if (ubuf) {
1556 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 cifs_buf_release(pSMB);
1558 return -EFAULT;
1559 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001560 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 /* No buffer */
1562 cifs_buf_release(pSMB);
1563 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001564 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001565 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001566 byte_count = bytes_sent + 1; /* pad */
1567 else /* wct == 12 */ {
1568 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1571 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001572 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001573
Steve French790fe572007-07-07 19:25:05 +00001574 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001575 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001576 else { /* old style write has byte count 4 bytes earlier
1577 so 4 bytes pad */
1578 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001579 (struct smb_com_writex_req *)pSMB;
1580 pSMBW->ByteCount = cpu_to_le16(byte_count);
1581 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001582
1583 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1584 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001585 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 if (rc) {
1587 cFYI(1, ("Send error in write = %d", rc));
1588 *nbytes = 0;
1589 } else {
1590 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1591 *nbytes = (*nbytes) << 16;
1592 *nbytes += le16_to_cpu(pSMBr->Count);
1593 }
1594
1595 cifs_buf_release(pSMB);
1596
Steve French50c2f752007-07-13 00:33:32 +00001597 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 since file handle passed in no longer valid */
1599
1600 return rc;
1601}
1602
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001603int
1604CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001606 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1607 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001608{
1609 int rc = -EACCES;
1610 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001611 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001612 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001613 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614
Steve French790fe572007-07-07 19:25:05 +00001615 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001616
Steve French790fe572007-07-07 19:25:05 +00001617 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001618 wct = 14;
1619 else
1620 wct = 12;
1621 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 if (rc)
1623 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 /* tcon and ses pointer are checked in smb_init */
1625 if (tcon->ses->server == NULL)
1626 return -ECONNABORTED;
1627
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001628 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 pSMB->Fid = netfid;
1630 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001631 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001632 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001633 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001634 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 pSMB->Reserved = 0xFFFFFFFF;
1636 pSMB->WriteMode = 0;
1637 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001638
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001640 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641
Steve French3e844692005-10-03 13:37:24 -07001642 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1643 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001644 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001645 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001646 pSMB->hdr.smb_buf_length += count+1;
1647 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001648 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1649 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001650 pSMB->ByteCount = cpu_to_le16(count + 1);
1651 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001652 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001653 (struct smb_com_writex_req *)pSMB;
1654 pSMBW->ByteCount = cpu_to_le16(count + 5);
1655 }
Steve French3e844692005-10-03 13:37:24 -07001656 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001657 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001658 iov[0].iov_len = smb_hdr_len + 4;
1659 else /* wct == 12 pad bigger by four bytes */
1660 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001661
Steve French3e844692005-10-03 13:37:24 -07001662
Steve Frenchec637e32005-12-12 20:53:18 -08001663 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001664 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001665 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001667 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001669 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001670 /* presumably this can not happen, but best to be safe */
1671 rc = -EIO;
1672 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001673 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001674 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001675 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1676 *nbytes = (*nbytes) << 16;
1677 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001678 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679
Steve French4b8f9302006-02-26 16:41:18 +00001680/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001681 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001682 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001683 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001684 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685
Steve French50c2f752007-07-13 00:33:32 +00001686 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687 since file handle passed in no longer valid */
1688
1689 return rc;
1690}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001691
1692
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693int
1694CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1695 const __u16 smb_file_id, const __u64 len,
1696 const __u64 offset, const __u32 numUnlock,
1697 const __u32 numLock, const __u8 lockType, const int waitFlag)
1698{
1699 int rc = 0;
1700 LOCK_REQ *pSMB = NULL;
1701 LOCK_RSP *pSMBr = NULL;
1702 int bytes_returned;
1703 int timeout = 0;
1704 __u16 count;
1705
Steve French50c2f752007-07-13 00:33:32 +00001706 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001707 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1708
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 if (rc)
1710 return rc;
1711
Steve French46810cb2005-04-28 22:41:09 -07001712 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1713
Steve French790fe572007-07-07 19:25:05 +00001714 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001715 timeout = -1; /* no response expected */
1716 pSMB->Timeout = 0;
1717 } else if (waitFlag == TRUE) {
1718 timeout = 3; /* blocking operation, no timeout */
1719 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1720 } else {
1721 pSMB->Timeout = 0;
1722 }
1723
1724 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1725 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1726 pSMB->LockType = lockType;
1727 pSMB->AndXCommand = 0xFF; /* none */
1728 pSMB->Fid = smb_file_id; /* netfid stays le */
1729
Steve French790fe572007-07-07 19:25:05 +00001730 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1732 /* BB where to store pid high? */
1733 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1734 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1735 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1736 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1737 count = sizeof(LOCKING_ANDX_RANGE);
1738 } else {
1739 /* oplock break */
1740 count = 0;
1741 }
1742 pSMB->hdr.smb_buf_length += count;
1743 pSMB->ByteCount = cpu_to_le16(count);
1744
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001745 if (waitFlag) {
1746 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1747 (struct smb_hdr *) pSMBr, &bytes_returned);
1748 } else {
1749 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001751 }
Steve Frencha4544342005-08-24 13:59:35 -07001752 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001753 if (rc) {
1754 cFYI(1, ("Send error in Lock = %d", rc));
1755 }
Steve French46810cb2005-04-28 22:41:09 -07001756 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757
Steve French50c2f752007-07-13 00:33:32 +00001758 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 since file handle passed in no longer valid */
1760 return rc;
1761}
1762
1763int
Steve French08547b02006-02-28 22:39:25 +00001764CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1765 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001766 struct file_lock *pLockData, const __u16 lock_type,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001767 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001768{
1769 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1770 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001771 struct cifs_posix_lock *parm_data;
1772 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001773 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001774 int bytes_returned = 0;
1775 __u16 params, param_offset, offset, byte_count, count;
1776
1777 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001778
Steve French790fe572007-07-07 19:25:05 +00001779 if (pLockData == NULL)
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001780 return EINVAL;
1781
Steve French08547b02006-02-28 22:39:25 +00001782 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1783
1784 if (rc)
1785 return rc;
1786
1787 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1788
Steve French50c2f752007-07-13 00:33:32 +00001789 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001790 pSMB->MaxSetupCount = 0;
1791 pSMB->Reserved = 0;
1792 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001793 pSMB->Reserved2 = 0;
1794 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1795 offset = param_offset + params;
1796
Steve French08547b02006-02-28 22:39:25 +00001797 count = sizeof(struct cifs_posix_lock);
1798 pSMB->MaxParameterCount = cpu_to_le16(2);
1799 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1800 pSMB->SetupCount = 1;
1801 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001802 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001803 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1804 else
1805 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1806 byte_count = 3 /* pad */ + params + count;
1807 pSMB->DataCount = cpu_to_le16(count);
1808 pSMB->ParameterCount = cpu_to_le16(params);
1809 pSMB->TotalDataCount = pSMB->DataCount;
1810 pSMB->TotalParameterCount = pSMB->ParameterCount;
1811 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001812 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001813 (((char *) &pSMB->hdr.Protocol) + offset);
1814
1815 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001816 if (waitFlag) {
Steve French3a5ff612006-07-14 22:37:11 +00001817 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001818 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001819 pSMB->Timeout = cpu_to_le32(-1);
1820 } else
1821 pSMB->Timeout = 0;
1822
Steve French08547b02006-02-28 22:39:25 +00001823 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001824 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001825 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001826
1827 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001828 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001829 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1830 pSMB->Reserved4 = 0;
1831 pSMB->hdr.smb_buf_length += byte_count;
1832 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001833 if (waitFlag) {
1834 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1835 (struct smb_hdr *) pSMBr, &bytes_returned);
1836 } else {
1837 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001838 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001839 }
1840
Steve French08547b02006-02-28 22:39:25 +00001841 if (rc) {
1842 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001843 } else if (get_flag) {
1844 /* lock structure can be returned on get */
1845 __u16 data_offset;
1846 __u16 data_count;
1847 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001848
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001849 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1850 rc = -EIO; /* bad smb */
1851 goto plk_err_exit;
1852 }
Steve French790fe572007-07-07 19:25:05 +00001853 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001854 rc = -EINVAL;
1855 goto plk_err_exit;
1856 }
1857 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1858 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001859 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001860 rc = -EIO;
1861 goto plk_err_exit;
1862 }
1863 parm_data = (struct cifs_posix_lock *)
1864 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001865 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001866 pLockData->fl_type = F_UNLCK;
1867 }
Steve French50c2f752007-07-13 00:33:32 +00001868
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001869plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001870 if (pSMB)
1871 cifs_small_buf_release(pSMB);
1872
1873 /* Note: On -EAGAIN error only caller can retry on handle based calls
1874 since file handle passed in no longer valid */
1875
1876 return rc;
1877}
1878
1879
1880int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1882{
1883 int rc = 0;
1884 CLOSE_REQ *pSMB = NULL;
1885 CLOSE_RSP *pSMBr = NULL;
1886 int bytes_returned;
1887 cFYI(1, ("In CIFSSMBClose"));
1888
1889/* do not retry on dead session on close */
1890 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001891 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 return 0;
1893 if (rc)
1894 return rc;
1895
1896 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1897
1898 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001899 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 pSMB->ByteCount = 0;
1901 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1902 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001903 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001905 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 /* EINTR is expected when user ctl-c to kill app */
1907 cERROR(1, ("Send error in Close = %d", rc));
1908 }
1909 }
1910
1911 cifs_small_buf_release(pSMB);
1912
1913 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001914 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915 rc = 0;
1916
1917 return rc;
1918}
1919
1920int
1921CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1922 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001923 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924{
1925 int rc = 0;
1926 RENAME_REQ *pSMB = NULL;
1927 RENAME_RSP *pSMBr = NULL;
1928 int bytes_returned;
1929 int name_len, name_len2;
1930 __u16 count;
1931
1932 cFYI(1, ("In CIFSSMBRename"));
1933renameRetry:
1934 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1935 (void **) &pSMBr);
1936 if (rc)
1937 return rc;
1938
1939 pSMB->BufferFormat = 0x04;
1940 pSMB->SearchAttributes =
1941 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1942 ATTR_DIRECTORY);
1943
1944 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1945 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001946 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001947 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 name_len++; /* trailing null */
1949 name_len *= 2;
1950 pSMB->OldFileName[name_len] = 0x04; /* pad */
1951 /* protocol requires ASCII signature byte on Unicode string */
1952 pSMB->OldFileName[name_len + 1] = 0x00;
1953 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001954 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001955 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1957 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001958 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 name_len = strnlen(fromName, PATH_MAX);
1960 name_len++; /* trailing null */
1961 strncpy(pSMB->OldFileName, fromName, name_len);
1962 name_len2 = strnlen(toName, PATH_MAX);
1963 name_len2++; /* trailing null */
1964 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1965 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1966 name_len2++; /* trailing null */
1967 name_len2++; /* signature byte */
1968 }
1969
1970 count = 1 /* 1st signature byte */ + name_len + name_len2;
1971 pSMB->hdr.smb_buf_length += count;
1972 pSMB->ByteCount = cpu_to_le16(count);
1973
1974 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1975 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001976 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 if (rc) {
1978 cFYI(1, ("Send error in rename = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +00001979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 cifs_buf_release(pSMB);
1982
1983 if (rc == -EAGAIN)
1984 goto renameRetry;
1985
1986 return rc;
1987}
1988
Steve French50c2f752007-07-13 00:33:32 +00001989int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1990 int netfid, char *target_name,
1991 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992{
1993 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1994 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001995 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 char *data_offset;
1997 char dummy_string[30];
1998 int rc = 0;
1999 int bytes_returned = 0;
2000 int len_of_str;
2001 __u16 params, param_offset, offset, count, byte_count;
2002
2003 cFYI(1, ("Rename to File by handle"));
2004 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2005 (void **) &pSMBr);
2006 if (rc)
2007 return rc;
2008
2009 params = 6;
2010 pSMB->MaxSetupCount = 0;
2011 pSMB->Reserved = 0;
2012 pSMB->Flags = 0;
2013 pSMB->Timeout = 0;
2014 pSMB->Reserved2 = 0;
2015 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2016 offset = param_offset + params;
2017
2018 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2019 rename_info = (struct set_file_rename *) data_offset;
2020 pSMB->MaxParameterCount = cpu_to_le16(2);
2021 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
2022 pSMB->SetupCount = 1;
2023 pSMB->Reserved3 = 0;
2024 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2025 byte_count = 3 /* pad */ + params;
2026 pSMB->ParameterCount = cpu_to_le16(params);
2027 pSMB->TotalParameterCount = pSMB->ParameterCount;
2028 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2029 pSMB->DataOffset = cpu_to_le16(offset);
2030 /* construct random name ".cifs_tmp<inodenum><mid>" */
2031 rename_info->overwrite = cpu_to_le32(1);
2032 rename_info->root_fid = 0;
2033 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002034 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002035 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2036 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002037 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002039 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002040 target_name, PATH_MAX, nls_codepage,
2041 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 }
2043 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2044 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2045 byte_count += count;
2046 pSMB->DataCount = cpu_to_le16(count);
2047 pSMB->TotalDataCount = pSMB->DataCount;
2048 pSMB->Fid = netfid;
2049 pSMB->InformationLevel =
2050 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2051 pSMB->Reserved4 = 0;
2052 pSMB->hdr.smb_buf_length += byte_count;
2053 pSMB->ByteCount = cpu_to_le16(byte_count);
2054 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002055 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002056 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002058 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 }
Steve Frencha5a2b482005-08-20 21:42:53 -07002060
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 cifs_buf_release(pSMB);
2062
2063 /* Note: On -EAGAIN error only caller can retry on handle based calls
2064 since file handle passed in no longer valid */
2065
2066 return rc;
2067}
2068
2069int
Steve French50c2f752007-07-13 00:33:32 +00002070CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2071 const __u16 target_tid, const char *toName, const int flags,
2072 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073{
2074 int rc = 0;
2075 COPY_REQ *pSMB = NULL;
2076 COPY_RSP *pSMBr = NULL;
2077 int bytes_returned;
2078 int name_len, name_len2;
2079 __u16 count;
2080
2081 cFYI(1, ("In CIFSSMBCopy"));
2082copyRetry:
2083 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2084 (void **) &pSMBr);
2085 if (rc)
2086 return rc;
2087
2088 pSMB->BufferFormat = 0x04;
2089 pSMB->Tid2 = target_tid;
2090
2091 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2092
2093 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002094 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002095 fromName, PATH_MAX, nls_codepage,
2096 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 name_len++; /* trailing null */
2098 name_len *= 2;
2099 pSMB->OldFileName[name_len] = 0x04; /* pad */
2100 /* protocol requires ASCII signature byte on Unicode string */
2101 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002102 name_len2 =
2103 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002104 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2106 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002107 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 name_len = strnlen(fromName, PATH_MAX);
2109 name_len++; /* trailing null */
2110 strncpy(pSMB->OldFileName, fromName, name_len);
2111 name_len2 = strnlen(toName, PATH_MAX);
2112 name_len2++; /* trailing null */
2113 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2114 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2115 name_len2++; /* trailing null */
2116 name_len2++; /* signature byte */
2117 }
2118
2119 count = 1 /* 1st signature byte */ + name_len + name_len2;
2120 pSMB->hdr.smb_buf_length += count;
2121 pSMB->ByteCount = cpu_to_le16(count);
2122
2123 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2124 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2125 if (rc) {
2126 cFYI(1, ("Send error in copy = %d with %d files copied",
2127 rc, le16_to_cpu(pSMBr->CopyCount)));
2128 }
2129 if (pSMB)
2130 cifs_buf_release(pSMB);
2131
2132 if (rc == -EAGAIN)
2133 goto copyRetry;
2134
2135 return rc;
2136}
2137
2138int
2139CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2140 const char *fromName, const char *toName,
2141 const struct nls_table *nls_codepage)
2142{
2143 TRANSACTION2_SPI_REQ *pSMB = NULL;
2144 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2145 char *data_offset;
2146 int name_len;
2147 int name_len_target;
2148 int rc = 0;
2149 int bytes_returned = 0;
2150 __u16 params, param_offset, offset, byte_count;
2151
2152 cFYI(1, ("In Symlink Unix style"));
2153createSymLinkRetry:
2154 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2155 (void **) &pSMBr);
2156 if (rc)
2157 return rc;
2158
2159 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2160 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002161 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162 /* find define for this maxpathcomponent */
2163 , nls_codepage);
2164 name_len++; /* trailing null */
2165 name_len *= 2;
2166
Steve French50c2f752007-07-13 00:33:32 +00002167 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168 name_len = strnlen(fromName, PATH_MAX);
2169 name_len++; /* trailing null */
2170 strncpy(pSMB->FileName, fromName, name_len);
2171 }
2172 params = 6 + name_len;
2173 pSMB->MaxSetupCount = 0;
2174 pSMB->Reserved = 0;
2175 pSMB->Flags = 0;
2176 pSMB->Timeout = 0;
2177 pSMB->Reserved2 = 0;
2178 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002179 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180 offset = param_offset + params;
2181
2182 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2183 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2184 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002185 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 /* find define for this maxpathcomponent */
2187 , nls_codepage);
2188 name_len_target++; /* trailing null */
2189 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002190 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 name_len_target = strnlen(toName, PATH_MAX);
2192 name_len_target++; /* trailing null */
2193 strncpy(data_offset, toName, name_len_target);
2194 }
2195
2196 pSMB->MaxParameterCount = cpu_to_le16(2);
2197 /* BB find exact max on data count below from sess */
2198 pSMB->MaxDataCount = cpu_to_le16(1000);
2199 pSMB->SetupCount = 1;
2200 pSMB->Reserved3 = 0;
2201 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2202 byte_count = 3 /* pad */ + params + name_len_target;
2203 pSMB->DataCount = cpu_to_le16(name_len_target);
2204 pSMB->ParameterCount = cpu_to_le16(params);
2205 pSMB->TotalDataCount = pSMB->DataCount;
2206 pSMB->TotalParameterCount = pSMB->ParameterCount;
2207 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2208 pSMB->DataOffset = cpu_to_le16(offset);
2209 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2210 pSMB->Reserved4 = 0;
2211 pSMB->hdr.smb_buf_length += byte_count;
2212 pSMB->ByteCount = cpu_to_le16(byte_count);
2213 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2214 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002215 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 if (rc) {
Steve French2d785a52007-07-15 01:48:57 +00002217 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218 }
2219
2220 if (pSMB)
2221 cifs_buf_release(pSMB);
2222
2223 if (rc == -EAGAIN)
2224 goto createSymLinkRetry;
2225
2226 return rc;
2227}
2228
2229int
2230CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2231 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002232 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233{
2234 TRANSACTION2_SPI_REQ *pSMB = NULL;
2235 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2236 char *data_offset;
2237 int name_len;
2238 int name_len_target;
2239 int rc = 0;
2240 int bytes_returned = 0;
2241 __u16 params, param_offset, offset, byte_count;
2242
2243 cFYI(1, ("In Create Hard link Unix style"));
2244createHardLinkRetry:
2245 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2246 (void **) &pSMBr);
2247 if (rc)
2248 return rc;
2249
2250 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002251 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002252 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002253 name_len++; /* trailing null */
2254 name_len *= 2;
2255
Steve French50c2f752007-07-13 00:33:32 +00002256 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 name_len = strnlen(toName, PATH_MAX);
2258 name_len++; /* trailing null */
2259 strncpy(pSMB->FileName, toName, name_len);
2260 }
2261 params = 6 + name_len;
2262 pSMB->MaxSetupCount = 0;
2263 pSMB->Reserved = 0;
2264 pSMB->Flags = 0;
2265 pSMB->Timeout = 0;
2266 pSMB->Reserved2 = 0;
2267 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002268 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 offset = param_offset + params;
2270
2271 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2272 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2273 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002274 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002275 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 name_len_target++; /* trailing null */
2277 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002278 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 name_len_target = strnlen(fromName, PATH_MAX);
2280 name_len_target++; /* trailing null */
2281 strncpy(data_offset, fromName, name_len_target);
2282 }
2283
2284 pSMB->MaxParameterCount = cpu_to_le16(2);
2285 /* BB find exact max on data count below from sess*/
2286 pSMB->MaxDataCount = cpu_to_le16(1000);
2287 pSMB->SetupCount = 1;
2288 pSMB->Reserved3 = 0;
2289 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2290 byte_count = 3 /* pad */ + params + name_len_target;
2291 pSMB->ParameterCount = cpu_to_le16(params);
2292 pSMB->TotalParameterCount = pSMB->ParameterCount;
2293 pSMB->DataCount = cpu_to_le16(name_len_target);
2294 pSMB->TotalDataCount = pSMB->DataCount;
2295 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2296 pSMB->DataOffset = cpu_to_le16(offset);
2297 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2298 pSMB->Reserved4 = 0;
2299 pSMB->hdr.smb_buf_length += byte_count;
2300 pSMB->ByteCount = cpu_to_le16(byte_count);
2301 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2302 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002303 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 if (rc) {
2305 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2306 }
2307
2308 cifs_buf_release(pSMB);
2309 if (rc == -EAGAIN)
2310 goto createHardLinkRetry;
2311
2312 return rc;
2313}
2314
2315int
2316CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2317 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002318 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319{
2320 int rc = 0;
2321 NT_RENAME_REQ *pSMB = NULL;
2322 RENAME_RSP *pSMBr = NULL;
2323 int bytes_returned;
2324 int name_len, name_len2;
2325 __u16 count;
2326
2327 cFYI(1, ("In CIFSCreateHardLink"));
2328winCreateHardLinkRetry:
2329
2330 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2331 (void **) &pSMBr);
2332 if (rc)
2333 return rc;
2334
2335 pSMB->SearchAttributes =
2336 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2337 ATTR_DIRECTORY);
2338 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2339 pSMB->ClusterCount = 0;
2340
2341 pSMB->BufferFormat = 0x04;
2342
2343 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2344 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002345 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002346 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002347 name_len++; /* trailing null */
2348 name_len *= 2;
2349 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002350 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002352 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002353 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2355 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002356 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 name_len = strnlen(fromName, PATH_MAX);
2358 name_len++; /* trailing null */
2359 strncpy(pSMB->OldFileName, fromName, name_len);
2360 name_len2 = strnlen(toName, PATH_MAX);
2361 name_len2++; /* trailing null */
2362 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2363 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2364 name_len2++; /* trailing null */
2365 name_len2++; /* signature byte */
2366 }
2367
2368 count = 1 /* string type byte */ + name_len + name_len2;
2369 pSMB->hdr.smb_buf_length += count;
2370 pSMB->ByteCount = cpu_to_le16(count);
2371
2372 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2373 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002374 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375 if (rc) {
2376 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2377 }
2378 cifs_buf_release(pSMB);
2379 if (rc == -EAGAIN)
2380 goto winCreateHardLinkRetry;
2381
2382 return rc;
2383}
2384
2385int
2386CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2387 const unsigned char *searchName,
2388 char *symlinkinfo, const int buflen,
2389 const struct nls_table *nls_codepage)
2390{
2391/* SMB_QUERY_FILE_UNIX_LINK */
2392 TRANSACTION2_QPI_REQ *pSMB = NULL;
2393 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2394 int rc = 0;
2395 int bytes_returned;
2396 int name_len;
2397 __u16 params, byte_count;
2398
2399 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2400
2401querySymLinkRetry:
2402 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2403 (void **) &pSMBr);
2404 if (rc)
2405 return rc;
2406
2407 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2408 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002409 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2410 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002411 name_len++; /* trailing null */
2412 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002413 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 name_len = strnlen(searchName, PATH_MAX);
2415 name_len++; /* trailing null */
2416 strncpy(pSMB->FileName, searchName, name_len);
2417 }
2418
2419 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2420 pSMB->TotalDataCount = 0;
2421 pSMB->MaxParameterCount = cpu_to_le16(2);
2422 /* BB find exact max data count below from sess structure BB */
2423 pSMB->MaxDataCount = cpu_to_le16(4000);
2424 pSMB->MaxSetupCount = 0;
2425 pSMB->Reserved = 0;
2426 pSMB->Flags = 0;
2427 pSMB->Timeout = 0;
2428 pSMB->Reserved2 = 0;
2429 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002430 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 pSMB->DataCount = 0;
2432 pSMB->DataOffset = 0;
2433 pSMB->SetupCount = 1;
2434 pSMB->Reserved3 = 0;
2435 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2436 byte_count = params + 1 /* pad */ ;
2437 pSMB->TotalParameterCount = cpu_to_le16(params);
2438 pSMB->ParameterCount = pSMB->TotalParameterCount;
2439 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2440 pSMB->Reserved4 = 0;
2441 pSMB->hdr.smb_buf_length += byte_count;
2442 pSMB->ByteCount = cpu_to_le16(byte_count);
2443
2444 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2445 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2446 if (rc) {
2447 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2448 } else {
2449 /* decode response */
2450
2451 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2452 if (rc || (pSMBr->ByteCount < 2))
2453 /* BB also check enough total bytes returned */
2454 rc = -EIO; /* bad smb */
2455 else {
2456 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2457 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2458
2459 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2460 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002461 &pSMBr->hdr.Protocol + data_offset),
2462 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002463 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002465 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2466 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 name_len, nls_codepage);
2468 } else {
2469 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002470 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 data_offset,
2472 min_t(const int, buflen, count));
2473 }
2474 symlinkinfo[buflen] = 0;
2475 /* just in case so calling code does not go off the end of buffer */
2476 }
2477 }
2478 cifs_buf_release(pSMB);
2479 if (rc == -EAGAIN)
2480 goto querySymLinkRetry;
2481 return rc;
2482}
2483
Steve French0a4b92c2006-01-12 15:44:21 -08002484/* Initialize NT TRANSACT SMB into small smb request buffer.
2485 This assumes that all NT TRANSACTS that we init here have
2486 total parm and data under about 400 bytes (to fit in small cifs
2487 buffer size), which is the case so far, it easily fits. NB:
2488 Setup words themselves and ByteCount
2489 MaxSetupCount (size of returned setup area) and
2490 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002491static int
Steve French0a4b92c2006-01-12 15:44:21 -08002492smb_init_ntransact(const __u16 sub_command, const int setup_count,
2493 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002494 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002495{
2496 int rc;
2497 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002498 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002499
2500 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2501 (void **)&pSMB);
2502 if (rc)
2503 return rc;
2504 *ret_buf = (void *)pSMB;
2505 pSMB->Reserved = 0;
2506 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2507 pSMB->TotalDataCount = 0;
2508 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2509 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2510 pSMB->ParameterCount = pSMB->TotalParameterCount;
2511 pSMB->DataCount = pSMB->TotalDataCount;
2512 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2513 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2514 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2515 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2516 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2517 pSMB->SubCommand = cpu_to_le16(sub_command);
2518 return 0;
2519}
2520
2521static int
Steve French50c2f752007-07-13 00:33:32 +00002522validate_ntransact(char *buf, char **ppparm, char **ppdata,
2523 int *pdatalen, int *pparmlen)
Steve French0a4b92c2006-01-12 15:44:21 -08002524{
Steve French50c2f752007-07-13 00:33:32 +00002525 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002526 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002527 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002528
Steve French790fe572007-07-07 19:25:05 +00002529 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002530 return -EINVAL;
2531
2532 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2533
2534 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002535 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002536 (char *)&pSMBr->ByteCount;
2537
Steve French0a4b92c2006-01-12 15:44:21 -08002538 data_offset = le32_to_cpu(pSMBr->DataOffset);
2539 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002540 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002541 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2542
2543 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2544 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2545
2546 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002547 if (*ppparm > end_of_smb) {
2548 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002549 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002550 } else if (parm_count + *ppparm > end_of_smb) {
2551 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002552 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002553 } else if (*ppdata > end_of_smb) {
2554 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002555 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002556 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002557 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002558 *ppdata, data_count, (data_count + *ppdata),
2559 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002560 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002561 } else if (parm_count + data_count > pSMBr->ByteCount) {
2562 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002563 return -EINVAL;
2564 }
2565 return 0;
2566}
2567
Linus Torvalds1da177e2005-04-16 15:20:36 -07002568int
2569CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2570 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002571 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 const struct nls_table *nls_codepage)
2573{
2574 int rc = 0;
2575 int bytes_returned;
2576 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002577 struct smb_com_transaction_ioctl_req *pSMB;
2578 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579
2580 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2581 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2582 (void **) &pSMBr);
2583 if (rc)
2584 return rc;
2585
2586 pSMB->TotalParameterCount = 0 ;
2587 pSMB->TotalDataCount = 0;
2588 pSMB->MaxParameterCount = cpu_to_le32(2);
2589 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002590 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2591 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 pSMB->MaxSetupCount = 4;
2593 pSMB->Reserved = 0;
2594 pSMB->ParameterOffset = 0;
2595 pSMB->DataCount = 0;
2596 pSMB->DataOffset = 0;
2597 pSMB->SetupCount = 4;
2598 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2599 pSMB->ParameterCount = pSMB->TotalParameterCount;
2600 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2601 pSMB->IsFsctl = 1; /* FSCTL */
2602 pSMB->IsRootFlag = 0;
2603 pSMB->Fid = fid; /* file handle always le */
2604 pSMB->ByteCount = 0;
2605
2606 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2607 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2608 if (rc) {
2609 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2610 } else { /* decode response */
2611 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2612 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2613 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2614 /* BB also check enough total bytes returned */
2615 rc = -EIO; /* bad smb */
2616 else {
Steve French790fe572007-07-07 19:25:05 +00002617 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002618 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002619 pSMBr->ByteCount +
2620 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621
Steve French50c2f752007-07-13 00:33:32 +00002622 struct reparse_data *reparse_buf =
2623 (struct reparse_data *)
2624 ((char *)&pSMBr->hdr.Protocol
2625 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002626 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 rc = -EIO;
2628 goto qreparse_out;
2629 }
Steve French790fe572007-07-07 19:25:05 +00002630 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 reparse_buf->TargetNameOffset +
2632 reparse_buf->TargetNameLen) >
2633 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002634 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 rc = -EIO;
2636 goto qreparse_out;
2637 }
Steve French50c2f752007-07-13 00:33:32 +00002638
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2640 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002641 (reparse_buf->LinkNamesBuf +
2642 reparse_buf->TargetNameOffset),
2643 min(buflen/2,
2644 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002646 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 reparse_buf->TargetNameOffset),
2648 name_len, nls_codepage);
2649 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002650 strncpy(symlinkinfo,
2651 reparse_buf->LinkNamesBuf +
2652 reparse_buf->TargetNameOffset,
2653 min_t(const int, buflen,
2654 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 }
2656 } else {
2657 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002658 cFYI(1, ("Invalid return data count on "
2659 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 }
2661 symlinkinfo[buflen] = 0; /* just in case so the caller
2662 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002663 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 }
2665 }
2666qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002667 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668
2669 /* Note: On -EAGAIN error only caller can retry on handle based calls
2670 since file handle passed in no longer valid */
2671
2672 return rc;
2673}
2674
2675#ifdef CONFIG_CIFS_POSIX
2676
2677/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002678static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2679 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680{
2681 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002682 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2683 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2684 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2686
2687 return;
2688}
2689
2690/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002691static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2692 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693{
2694 int size = 0;
2695 int i;
2696 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002697 struct cifs_posix_ace *pACE;
2698 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2699 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700
2701 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2702 return -EOPNOTSUPP;
2703
Steve French790fe572007-07-07 19:25:05 +00002704 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705 count = le16_to_cpu(cifs_acl->access_entry_count);
2706 pACE = &cifs_acl->ace_array[0];
2707 size = sizeof(struct cifs_posix_acl);
2708 size += sizeof(struct cifs_posix_ace) * count;
2709 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002710 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002711 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2712 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002713 return -EINVAL;
2714 }
Steve French790fe572007-07-07 19:25:05 +00002715 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002716 count = le16_to_cpu(cifs_acl->access_entry_count);
2717 size = sizeof(struct cifs_posix_acl);
2718 size += sizeof(struct cifs_posix_ace) * count;
2719/* skip past access ACEs to get to default ACEs */
2720 pACE = &cifs_acl->ace_array[count];
2721 count = le16_to_cpu(cifs_acl->default_entry_count);
2722 size += sizeof(struct cifs_posix_ace) * count;
2723 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002724 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 return -EINVAL;
2726 } else {
2727 /* illegal type */
2728 return -EINVAL;
2729 }
2730
2731 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002732 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002733 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002734 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 return -ERANGE;
2736 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002737 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002738 for (i = 0; i < count ; i++) {
2739 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2740 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 }
2742 }
2743 return size;
2744}
2745
Steve French50c2f752007-07-13 00:33:32 +00002746static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2747 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748{
2749 __u16 rc = 0; /* 0 = ACL converted ok */
2750
Steve Frenchff7feac2005-11-15 16:45:16 -08002751 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2752 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002754 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 /* Probably no need to le convert -1 on any arch but can not hurt */
2756 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002757 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002758 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002759 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 return rc;
2761}
2762
2763/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002764static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2765 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766{
2767 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002768 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2769 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 int count;
2771 int i;
2772
Steve French790fe572007-07-07 19:25:05 +00002773 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 return 0;
2775
2776 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002777 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002778 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002779 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002780 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002781 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002782 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002783 return 0;
2784 }
2785 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002786 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002787 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002788 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002789 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 else {
Steve French50c2f752007-07-13 00:33:32 +00002791 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 return 0;
2793 }
Steve French50c2f752007-07-13 00:33:32 +00002794 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2796 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002797 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 /* ACE not converted */
2799 break;
2800 }
2801 }
Steve French790fe572007-07-07 19:25:05 +00002802 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2804 rc += sizeof(struct cifs_posix_acl);
2805 /* BB add check to make sure ACL does not overflow SMB */
2806 }
2807 return rc;
2808}
2809
2810int
2811CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002812 const unsigned char *searchName,
2813 char *acl_inf, const int buflen, const int acl_type,
2814 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002815{
2816/* SMB_QUERY_POSIX_ACL */
2817 TRANSACTION2_QPI_REQ *pSMB = NULL;
2818 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2819 int rc = 0;
2820 int bytes_returned;
2821 int name_len;
2822 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002823
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2825
2826queryAclRetry:
2827 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2828 (void **) &pSMBr);
2829 if (rc)
2830 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002831
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2833 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002834 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002835 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 name_len++; /* trailing null */
2837 name_len *= 2;
2838 pSMB->FileName[name_len] = 0;
2839 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002840 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 name_len = strnlen(searchName, PATH_MAX);
2842 name_len++; /* trailing null */
2843 strncpy(pSMB->FileName, searchName, name_len);
2844 }
2845
2846 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2847 pSMB->TotalDataCount = 0;
2848 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002849 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 pSMB->MaxDataCount = cpu_to_le16(4000);
2851 pSMB->MaxSetupCount = 0;
2852 pSMB->Reserved = 0;
2853 pSMB->Flags = 0;
2854 pSMB->Timeout = 0;
2855 pSMB->Reserved2 = 0;
2856 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002857 offsetof(struct smb_com_transaction2_qpi_req,
2858 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 pSMB->DataCount = 0;
2860 pSMB->DataOffset = 0;
2861 pSMB->SetupCount = 1;
2862 pSMB->Reserved3 = 0;
2863 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2864 byte_count = params + 1 /* pad */ ;
2865 pSMB->TotalParameterCount = cpu_to_le16(params);
2866 pSMB->ParameterCount = pSMB->TotalParameterCount;
2867 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2868 pSMB->Reserved4 = 0;
2869 pSMB->hdr.smb_buf_length += byte_count;
2870 pSMB->ByteCount = cpu_to_le16(byte_count);
2871
2872 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2873 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002874 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 if (rc) {
2876 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2877 } else {
2878 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002879
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2881 if (rc || (pSMBr->ByteCount < 2))
2882 /* BB also check enough total bytes returned */
2883 rc = -EIO; /* bad smb */
2884 else {
2885 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2886 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2887 rc = cifs_copy_posix_acl(acl_inf,
2888 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002889 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 }
2891 }
2892 cifs_buf_release(pSMB);
2893 if (rc == -EAGAIN)
2894 goto queryAclRetry;
2895 return rc;
2896}
2897
2898int
2899CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002900 const unsigned char *fileName,
2901 const char *local_acl, const int buflen,
2902 const int acl_type,
2903 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904{
2905 struct smb_com_transaction2_spi_req *pSMB = NULL;
2906 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2907 char *parm_data;
2908 int name_len;
2909 int rc = 0;
2910 int bytes_returned = 0;
2911 __u16 params, byte_count, data_count, param_offset, offset;
2912
2913 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2914setAclRetry:
2915 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002916 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 if (rc)
2918 return rc;
2919 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2920 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002921 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002922 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 name_len++; /* trailing null */
2924 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002925 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 name_len = strnlen(fileName, PATH_MAX);
2927 name_len++; /* trailing null */
2928 strncpy(pSMB->FileName, fileName, name_len);
2929 }
2930 params = 6 + name_len;
2931 pSMB->MaxParameterCount = cpu_to_le16(2);
2932 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2933 pSMB->MaxSetupCount = 0;
2934 pSMB->Reserved = 0;
2935 pSMB->Flags = 0;
2936 pSMB->Timeout = 0;
2937 pSMB->Reserved2 = 0;
2938 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002939 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940 offset = param_offset + params;
2941 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2942 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2943
2944 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002945 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946
Steve French790fe572007-07-07 19:25:05 +00002947 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 rc = -EOPNOTSUPP;
2949 goto setACLerrorExit;
2950 }
2951 pSMB->DataOffset = cpu_to_le16(offset);
2952 pSMB->SetupCount = 1;
2953 pSMB->Reserved3 = 0;
2954 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2955 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2956 byte_count = 3 /* pad */ + params + data_count;
2957 pSMB->DataCount = cpu_to_le16(data_count);
2958 pSMB->TotalDataCount = pSMB->DataCount;
2959 pSMB->ParameterCount = cpu_to_le16(params);
2960 pSMB->TotalParameterCount = pSMB->ParameterCount;
2961 pSMB->Reserved4 = 0;
2962 pSMB->hdr.smb_buf_length += byte_count;
2963 pSMB->ByteCount = cpu_to_le16(byte_count);
2964 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002965 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002966 if (rc) {
2967 cFYI(1, ("Set POSIX ACL returned %d", rc));
2968 }
2969
2970setACLerrorExit:
2971 cifs_buf_release(pSMB);
2972 if (rc == -EAGAIN)
2973 goto setAclRetry;
2974 return rc;
2975}
2976
Steve Frenchf654bac2005-04-28 22:41:04 -07002977/* BB fix tabs in this function FIXME BB */
2978int
2979CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002980 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002981{
Steve French50c2f752007-07-13 00:33:32 +00002982 int rc = 0;
2983 struct smb_t2_qfi_req *pSMB = NULL;
2984 struct smb_t2_qfi_rsp *pSMBr = NULL;
2985 int bytes_returned;
2986 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002987
Steve French790fe572007-07-07 19:25:05 +00002988 cFYI(1, ("In GetExtAttr"));
2989 if (tcon == NULL)
2990 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002991
2992GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002993 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2994 (void **) &pSMBr);
2995 if (rc)
2996 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07002997
Steve French790fe572007-07-07 19:25:05 +00002998 params = 2 /* level */ +2 /* fid */;
2999 pSMB->t2.TotalDataCount = 0;
3000 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3001 /* BB find exact max data count below from sess structure BB */
3002 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3003 pSMB->t2.MaxSetupCount = 0;
3004 pSMB->t2.Reserved = 0;
3005 pSMB->t2.Flags = 0;
3006 pSMB->t2.Timeout = 0;
3007 pSMB->t2.Reserved2 = 0;
3008 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3009 Fid) - 4);
3010 pSMB->t2.DataCount = 0;
3011 pSMB->t2.DataOffset = 0;
3012 pSMB->t2.SetupCount = 1;
3013 pSMB->t2.Reserved3 = 0;
3014 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3015 byte_count = params + 1 /* pad */ ;
3016 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3017 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3018 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3019 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003020 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003021 pSMB->hdr.smb_buf_length += byte_count;
3022 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003023
Steve French790fe572007-07-07 19:25:05 +00003024 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3025 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3026 if (rc) {
3027 cFYI(1, ("error %d in GetExtAttr", rc));
3028 } else {
3029 /* decode response */
3030 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3031 if (rc || (pSMBr->ByteCount < 2))
3032 /* BB also check enough total bytes returned */
3033 /* If rc should we check for EOPNOSUPP and
3034 disable the srvino flag? or in caller? */
3035 rc = -EIO; /* bad smb */
3036 else {
3037 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3038 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3039 struct file_chattr_info *pfinfo;
3040 /* BB Do we need a cast or hash here ? */
3041 if (count != 16) {
3042 cFYI(1, ("Illegal size ret in GetExtAttr"));
3043 rc = -EIO;
3044 goto GetExtAttrOut;
3045 }
3046 pfinfo = (struct file_chattr_info *)
3047 (data_offset + (char *) &pSMBr->hdr.Protocol);
3048 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003049 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003050 }
3051 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003052GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003053 cifs_buf_release(pSMB);
3054 if (rc == -EAGAIN)
3055 goto GetExtAttrRetry;
3056 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003057}
3058
Steve Frenchf654bac2005-04-28 22:41:04 -07003059#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060
Steve French0a4b92c2006-01-12 15:44:21 -08003061/* Get Security Descriptor (by handle) from remote server for a file or dir */
3062int
3063CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French50c2f752007-07-13 00:33:32 +00003064 /* BB fix up return info */ char *acl_inf, const int buflen,
Steve French442aa312007-09-24 20:25:46 +00003065 const int acl_type)
Steve French0a4b92c2006-01-12 15:44:21 -08003066{
3067 int rc = 0;
3068 int buf_type = 0;
3069 QUERY_SEC_DESC_REQ * pSMB;
3070 struct kvec iov[1];
3071
3072 cFYI(1, ("GetCifsACL"));
3073
Steve French50c2f752007-07-13 00:33:32 +00003074 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003075 8 /* parm len */, tcon, (void **) &pSMB);
3076 if (rc)
3077 return rc;
3078
3079 pSMB->MaxParameterCount = cpu_to_le32(4);
3080 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3081 pSMB->MaxSetupCount = 0;
3082 pSMB->Fid = fid; /* file handle always le */
3083 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3084 CIFS_ACL_DACL);
3085 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3086 pSMB->hdr.smb_buf_length += 11;
3087 iov[0].iov_base = (char *)pSMB;
3088 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3089
3090 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
3091 cifs_stats_inc(&tcon->num_acl_get);
3092 if (rc) {
3093 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3094 } else { /* decode response */
Steve French442aa312007-09-24 20:25:46 +00003095 struct cifs_ntsd *psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08003096 __le32 * parm;
3097 int parm_len;
3098 int data_len;
3099 int acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003100 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08003101
3102/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003103 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French0a4b92c2006-01-12 15:44:21 -08003104 (char **)&psec_desc,
3105 &parm_len, &data_len);
Steve French790fe572007-07-07 19:25:05 +00003106 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003107 goto qsec_out;
3108 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3109
Steve Frencha0136892007-10-04 20:05:09 +00003110 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, psec_desc));
Steve French0a4b92c2006-01-12 15:44:21 -08003111
3112 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3113 rc = -EIO; /* bad smb */
3114 goto qsec_out;
3115 }
3116
3117/* BB check that data area is minimum length and as big as acl_len */
3118
3119 acl_len = le32_to_cpu(*(__le32 *)parm);
Steve French790fe572007-07-07 19:25:05 +00003120 /* BB check if (acl_len > bufsize) */
Steve French0a4b92c2006-01-12 15:44:21 -08003121
3122 parse_sec_desc(psec_desc, acl_len);
3123 }
3124qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003125 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003126 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003127 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003128 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003129/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003130 return rc;
3131}
3132
Steve French6b8edfe2005-08-23 20:26:03 -07003133/* Legacy Query Path Information call for lookup to old servers such
3134 as Win9x/WinME */
3135int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003136 const unsigned char *searchName,
3137 FILE_ALL_INFO *pFinfo,
3138 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003139{
3140 QUERY_INFORMATION_REQ * pSMB;
3141 QUERY_INFORMATION_RSP * pSMBr;
3142 int rc = 0;
3143 int bytes_returned;
3144 int name_len;
3145
Steve French50c2f752007-07-13 00:33:32 +00003146 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003147QInfRetry:
3148 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003149 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003150 if (rc)
3151 return rc;
3152
3153 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3154 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003155 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3156 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003157 name_len++; /* trailing null */
3158 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003159 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003160 name_len = strnlen(searchName, PATH_MAX);
3161 name_len++; /* trailing null */
3162 strncpy(pSMB->FileName, searchName, name_len);
3163 }
3164 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003165 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003166 pSMB->hdr.smb_buf_length += (__u16) name_len;
3167 pSMB->ByteCount = cpu_to_le16(name_len);
3168
3169 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003170 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003171 if (rc) {
3172 cFYI(1, ("Send error in QueryInfo = %d", rc));
3173 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003174 struct timespec ts;
3175 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3176 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003177 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003178 ts.tv_nsec = 0;
3179 ts.tv_sec = time;
3180 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003181 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003182 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3183 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003184 pFinfo->AllocationSize =
3185 cpu_to_le64(le32_to_cpu(pSMBr->size));
3186 pFinfo->EndOfFile = pFinfo->AllocationSize;
3187 pFinfo->Attributes =
3188 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003189 } else
3190 rc = -EIO; /* bad buffer passed in */
3191
3192 cifs_buf_release(pSMB);
3193
3194 if (rc == -EAGAIN)
3195 goto QInfRetry;
3196
3197 return rc;
3198}
3199
3200
3201
3202
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203int
3204CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3205 const unsigned char *searchName,
3206 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003207 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003208 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209{
3210/* level 263 SMB_QUERY_FILE_ALL_INFO */
3211 TRANSACTION2_QPI_REQ *pSMB = NULL;
3212 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3213 int rc = 0;
3214 int bytes_returned;
3215 int name_len;
3216 __u16 params, byte_count;
3217
3218/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3219QPathInfoRetry:
3220 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3221 (void **) &pSMBr);
3222 if (rc)
3223 return rc;
3224
3225 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3226 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003227 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003228 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 name_len++; /* trailing null */
3230 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003231 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003232 name_len = strnlen(searchName, PATH_MAX);
3233 name_len++; /* trailing null */
3234 strncpy(pSMB->FileName, searchName, name_len);
3235 }
3236
Steve French50c2f752007-07-13 00:33:32 +00003237 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 pSMB->TotalDataCount = 0;
3239 pSMB->MaxParameterCount = cpu_to_le16(2);
3240 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3241 pSMB->MaxSetupCount = 0;
3242 pSMB->Reserved = 0;
3243 pSMB->Flags = 0;
3244 pSMB->Timeout = 0;
3245 pSMB->Reserved2 = 0;
3246 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003247 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 pSMB->DataCount = 0;
3249 pSMB->DataOffset = 0;
3250 pSMB->SetupCount = 1;
3251 pSMB->Reserved3 = 0;
3252 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3253 byte_count = params + 1 /* pad */ ;
3254 pSMB->TotalParameterCount = cpu_to_le16(params);
3255 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003256 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003257 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3258 else
3259 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 pSMB->Reserved4 = 0;
3261 pSMB->hdr.smb_buf_length += byte_count;
3262 pSMB->ByteCount = cpu_to_le16(byte_count);
3263
3264 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3265 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3266 if (rc) {
3267 cFYI(1, ("Send error in QPathInfo = %d", rc));
3268 } else { /* decode response */
3269 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3270
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003271 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3272 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003273 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003275 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003276 rc = -EIO; /* 24 or 26 expected but we do not read
3277 last field */
3278 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003279 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003281 if (legacy) /* we do not read the last field, EAsize,
3282 fortunately since it varies by subdialect
3283 and on Set vs. Get, is two bytes or 4
3284 bytes depending but we don't care here */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003285 size = sizeof(FILE_INFO_STANDARD);
3286 else
3287 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 memcpy((char *) pFindData,
3289 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003290 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003291 } else
3292 rc = -ENOMEM;
3293 }
3294 cifs_buf_release(pSMB);
3295 if (rc == -EAGAIN)
3296 goto QPathInfoRetry;
3297
3298 return rc;
3299}
3300
3301int
3302CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3303 const unsigned char *searchName,
3304 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003305 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306{
3307/* SMB_QUERY_FILE_UNIX_BASIC */
3308 TRANSACTION2_QPI_REQ *pSMB = NULL;
3309 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3310 int rc = 0;
3311 int bytes_returned = 0;
3312 int name_len;
3313 __u16 params, byte_count;
3314
3315 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3316UnixQPathInfoRetry:
3317 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3318 (void **) &pSMBr);
3319 if (rc)
3320 return rc;
3321
3322 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3323 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003324 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003325 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 name_len++; /* trailing null */
3327 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003328 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 name_len = strnlen(searchName, PATH_MAX);
3330 name_len++; /* trailing null */
3331 strncpy(pSMB->FileName, searchName, name_len);
3332 }
3333
Steve French50c2f752007-07-13 00:33:32 +00003334 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335 pSMB->TotalDataCount = 0;
3336 pSMB->MaxParameterCount = cpu_to_le16(2);
3337 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003338 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 pSMB->MaxSetupCount = 0;
3340 pSMB->Reserved = 0;
3341 pSMB->Flags = 0;
3342 pSMB->Timeout = 0;
3343 pSMB->Reserved2 = 0;
3344 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003345 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 pSMB->DataCount = 0;
3347 pSMB->DataOffset = 0;
3348 pSMB->SetupCount = 1;
3349 pSMB->Reserved3 = 0;
3350 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3351 byte_count = params + 1 /* pad */ ;
3352 pSMB->TotalParameterCount = cpu_to_le16(params);
3353 pSMB->ParameterCount = pSMB->TotalParameterCount;
3354 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3355 pSMB->Reserved4 = 0;
3356 pSMB->hdr.smb_buf_length += byte_count;
3357 pSMB->ByteCount = cpu_to_le16(byte_count);
3358
3359 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3360 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3361 if (rc) {
3362 cFYI(1, ("Send error in QPathInfo = %d", rc));
3363 } else { /* decode response */
3364 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3365
3366 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003367 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3368 "Unix Extensions can be disabled on mount "
3369 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003370 rc = -EIO; /* bad smb */
3371 } else {
3372 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3373 memcpy((char *) pFindData,
3374 (char *) &pSMBr->hdr.Protocol +
3375 data_offset,
3376 sizeof (FILE_UNIX_BASIC_INFO));
3377 }
3378 }
3379 cifs_buf_release(pSMB);
3380 if (rc == -EAGAIN)
3381 goto UnixQPathInfoRetry;
3382
3383 return rc;
3384}
3385
3386#if 0 /* function unused at present */
3387int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3388 const char *searchName, FILE_ALL_INFO * findData,
3389 const struct nls_table *nls_codepage)
3390{
3391/* level 257 SMB_ */
3392 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3393 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3394 int rc = 0;
3395 int bytes_returned;
3396 int name_len;
3397 __u16 params, byte_count;
3398
3399 cFYI(1, ("In FindUnique"));
3400findUniqueRetry:
3401 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3402 (void **) &pSMBr);
3403 if (rc)
3404 return rc;
3405
3406 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3407 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003408 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3409 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 name_len++; /* trailing null */
3411 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003412 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003413 name_len = strnlen(searchName, PATH_MAX);
3414 name_len++; /* trailing null */
3415 strncpy(pSMB->FileName, searchName, name_len);
3416 }
3417
3418 params = 12 + name_len /* includes null */ ;
3419 pSMB->TotalDataCount = 0; /* no EAs */
3420 pSMB->MaxParameterCount = cpu_to_le16(2);
3421 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3422 pSMB->MaxSetupCount = 0;
3423 pSMB->Reserved = 0;
3424 pSMB->Flags = 0;
3425 pSMB->Timeout = 0;
3426 pSMB->Reserved2 = 0;
3427 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003428 offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 pSMB->DataCount = 0;
3430 pSMB->DataOffset = 0;
3431 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3432 pSMB->Reserved3 = 0;
3433 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3434 byte_count = params + 1 /* pad */ ;
3435 pSMB->TotalParameterCount = cpu_to_le16(params);
3436 pSMB->ParameterCount = pSMB->TotalParameterCount;
3437 pSMB->SearchAttributes =
3438 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3439 ATTR_DIRECTORY);
3440 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3441 pSMB->SearchFlags = cpu_to_le16(1);
3442 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3443 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3444 pSMB->hdr.smb_buf_length += byte_count;
3445 pSMB->ByteCount = cpu_to_le16(byte_count);
3446
3447 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3448 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3449
3450 if (rc) {
3451 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3452 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003453 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003454 /* BB fill in */
3455 }
3456
3457 cifs_buf_release(pSMB);
3458 if (rc == -EAGAIN)
3459 goto findUniqueRetry;
3460
3461 return rc;
3462}
3463#endif /* end unused (temporarily) function */
3464
3465/* xid, tcon, searchName and codepage are input parms, rest are returned */
3466int
3467CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003468 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003470 __u16 *pnetfid,
3471 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472{
3473/* level 257 SMB_ */
3474 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3475 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3476 T2_FFIRST_RSP_PARMS * parms;
3477 int rc = 0;
3478 int bytes_returned = 0;
3479 int name_len;
3480 __u16 params, byte_count;
3481
Steve French50c2f752007-07-13 00:33:32 +00003482 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483
3484findFirstRetry:
3485 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3486 (void **) &pSMBr);
3487 if (rc)
3488 return rc;
3489
3490 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3491 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003492 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003493 PATH_MAX, nls_codepage, remap);
3494 /* We can not add the asterik earlier in case
3495 it got remapped to 0xF03A as if it were part of the
3496 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003498 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003499 pSMB->FileName[name_len+1] = 0;
3500 pSMB->FileName[name_len+2] = '*';
3501 pSMB->FileName[name_len+3] = 0;
3502 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3504 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003505 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 } else { /* BB add check for overrun of SMB buf BB */
3507 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003508/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003509 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510 free buffer exit; BB */
3511 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003512 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003513 pSMB->FileName[name_len+1] = '*';
3514 pSMB->FileName[name_len+2] = 0;
3515 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 }
3517
3518 params = 12 + name_len /* includes null */ ;
3519 pSMB->TotalDataCount = 0; /* no EAs */
3520 pSMB->MaxParameterCount = cpu_to_le16(10);
3521 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3522 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3523 pSMB->MaxSetupCount = 0;
3524 pSMB->Reserved = 0;
3525 pSMB->Flags = 0;
3526 pSMB->Timeout = 0;
3527 pSMB->Reserved2 = 0;
3528 byte_count = params + 1 /* pad */ ;
3529 pSMB->TotalParameterCount = cpu_to_le16(params);
3530 pSMB->ParameterCount = pSMB->TotalParameterCount;
3531 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003532 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3533 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534 pSMB->DataCount = 0;
3535 pSMB->DataOffset = 0;
3536 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3537 pSMB->Reserved3 = 0;
3538 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3539 pSMB->SearchAttributes =
3540 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3541 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003542 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3543 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 CIFS_SEARCH_RETURN_RESUME);
3545 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3546
3547 /* BB what should we set StorageType to? Does it matter? BB */
3548 pSMB->SearchStorageType = 0;
3549 pSMB->hdr.smb_buf_length += byte_count;
3550 pSMB->ByteCount = cpu_to_le16(byte_count);
3551
3552 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3553 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003554 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555
Steve French88274812006-03-09 22:21:45 +00003556 if (rc) {/* BB add logic to retry regular search if Unix search
3557 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558 /* BB Add code to handle unsupported level rc */
3559 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003560
Steve French88274812006-03-09 22:21:45 +00003561 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562
3563 /* BB eventually could optimize out free and realloc of buf */
3564 /* for this case */
3565 if (rc == -EAGAIN)
3566 goto findFirstRetry;
3567 } else { /* decode response */
3568 /* BB remember to free buffer if error BB */
3569 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003570 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3572 psrch_inf->unicode = TRUE;
3573 else
3574 psrch_inf->unicode = FALSE;
3575
3576 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003577 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003578 psrch_inf->srch_entries_start =
3579 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3582 le16_to_cpu(pSMBr->t2.ParameterOffset));
3583
Steve French790fe572007-07-07 19:25:05 +00003584 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 psrch_inf->endOfSearch = TRUE;
3586 else
3587 psrch_inf->endOfSearch = FALSE;
3588
Steve French50c2f752007-07-13 00:33:32 +00003589 psrch_inf->entries_in_buffer =
3590 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003591 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 *pnetfid = parms->SearchHandle;
3594 } else {
3595 cifs_buf_release(pSMB);
3596 }
3597 }
3598
3599 return rc;
3600}
3601
3602int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003603 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003604{
3605 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3606 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3607 T2_FNEXT_RSP_PARMS * parms;
3608 char *response_data;
3609 int rc = 0;
3610 int bytes_returned, name_len;
3611 __u16 params, byte_count;
3612
3613 cFYI(1, ("In FindNext"));
3614
Steve French790fe572007-07-07 19:25:05 +00003615 if (psrch_inf->endOfSearch == TRUE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003616 return -ENOENT;
3617
3618 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3619 (void **) &pSMBr);
3620 if (rc)
3621 return rc;
3622
Steve French50c2f752007-07-13 00:33:32 +00003623 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 byte_count = 0;
3625 pSMB->TotalDataCount = 0; /* no EAs */
3626 pSMB->MaxParameterCount = cpu_to_le16(8);
3627 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003628 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3629 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 pSMB->MaxSetupCount = 0;
3631 pSMB->Reserved = 0;
3632 pSMB->Flags = 0;
3633 pSMB->Timeout = 0;
3634 pSMB->Reserved2 = 0;
3635 pSMB->ParameterOffset = cpu_to_le16(
3636 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3637 pSMB->DataCount = 0;
3638 pSMB->DataOffset = 0;
3639 pSMB->SetupCount = 1;
3640 pSMB->Reserved3 = 0;
3641 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3642 pSMB->SearchHandle = searchHandle; /* always kept as le */
3643 pSMB->SearchCount =
3644 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003645 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3646 pSMB->ResumeKey = psrch_inf->resume_key;
3647 pSMB->SearchFlags =
3648 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3649
3650 name_len = psrch_inf->resume_name_len;
3651 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003652 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3654 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003655 /* 14 byte parm len above enough for 2 byte null terminator */
3656 pSMB->ResumeFileName[name_len] = 0;
3657 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003658 } else {
3659 rc = -EINVAL;
3660 goto FNext2_err_exit;
3661 }
3662 byte_count = params + 1 /* pad */ ;
3663 pSMB->TotalParameterCount = cpu_to_le16(params);
3664 pSMB->ParameterCount = pSMB->TotalParameterCount;
3665 pSMB->hdr.smb_buf_length += byte_count;
3666 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003667
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3669 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003670 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671 if (rc) {
3672 if (rc == -EBADF) {
3673 psrch_inf->endOfSearch = TRUE;
Steve French50c2f752007-07-13 00:33:32 +00003674 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003675 } else
3676 cFYI(1, ("FindNext returned = %d", rc));
3677 } else { /* decode response */
3678 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003679
Steve French790fe572007-07-07 19:25:05 +00003680 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 /* BB fixme add lock for file (srch_info) struct here */
3682 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3683 psrch_inf->unicode = TRUE;
3684 else
3685 psrch_inf->unicode = FALSE;
3686 response_data = (char *) &pSMBr->hdr.Protocol +
3687 le16_to_cpu(pSMBr->t2.ParameterOffset);
3688 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3689 response_data = (char *)&pSMBr->hdr.Protocol +
3690 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003691 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003692 cifs_small_buf_release(
3693 psrch_inf->ntwrk_buf_start);
3694 else
3695 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 psrch_inf->srch_entries_start = response_data;
3697 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003698 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003699 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003700 psrch_inf->endOfSearch = TRUE;
3701 else
3702 psrch_inf->endOfSearch = FALSE;
Steve French50c2f752007-07-13 00:33:32 +00003703 psrch_inf->entries_in_buffer =
3704 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 psrch_inf->index_of_last_entry +=
3706 psrch_inf->entries_in_buffer;
Steve French50c2f752007-07-13 00:33:32 +00003707/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3708 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709
3710 /* BB fixme add unlock here */
3711 }
3712
3713 }
3714
3715 /* BB On error, should we leave previous search buf (and count and
3716 last entry fields) intact or free the previous one? */
3717
3718 /* Note: On -EAGAIN error only caller can retry on handle based calls
3719 since file handle passed in no longer valid */
3720FNext2_err_exit:
3721 if (rc != 0)
3722 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 return rc;
3724}
3725
3726int
Steve French50c2f752007-07-13 00:33:32 +00003727CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3728 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729{
3730 int rc = 0;
3731 FINDCLOSE_REQ *pSMB = NULL;
3732 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3733 int bytes_returned;
3734
3735 cFYI(1, ("In CIFSSMBFindClose"));
3736 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3737
3738 /* no sense returning error if session restarted
3739 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003740 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741 return 0;
3742 if (rc)
3743 return rc;
3744
3745 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3746 pSMB->FileID = searchHandle;
3747 pSMB->ByteCount = 0;
3748 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3749 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3750 if (rc) {
3751 cERROR(1, ("Send error in FindClose = %d", rc));
3752 }
Steve Frencha4544342005-08-24 13:59:35 -07003753 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 cifs_small_buf_release(pSMB);
3755
3756 /* Since session is dead, search handle closed on server already */
3757 if (rc == -EAGAIN)
3758 rc = 0;
3759
3760 return rc;
3761}
3762
Linus Torvalds1da177e2005-04-16 15:20:36 -07003763int
3764CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003765 const unsigned char *searchName,
3766 __u64 * inode_number,
3767 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768{
3769 int rc = 0;
3770 TRANSACTION2_QPI_REQ *pSMB = NULL;
3771 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3772 int name_len, bytes_returned;
3773 __u16 params, byte_count;
3774
Steve French50c2f752007-07-13 00:33:32 +00003775 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003776 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003777 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778
3779GetInodeNumberRetry:
3780 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003781 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003782 if (rc)
3783 return rc;
3784
Linus Torvalds1da177e2005-04-16 15:20:36 -07003785 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3786 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003787 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003788 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 name_len++; /* trailing null */
3790 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003791 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 name_len = strnlen(searchName, PATH_MAX);
3793 name_len++; /* trailing null */
3794 strncpy(pSMB->FileName, searchName, name_len);
3795 }
3796
3797 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3798 pSMB->TotalDataCount = 0;
3799 pSMB->MaxParameterCount = cpu_to_le16(2);
3800 /* BB find exact max data count below from sess structure BB */
3801 pSMB->MaxDataCount = cpu_to_le16(4000);
3802 pSMB->MaxSetupCount = 0;
3803 pSMB->Reserved = 0;
3804 pSMB->Flags = 0;
3805 pSMB->Timeout = 0;
3806 pSMB->Reserved2 = 0;
3807 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003808 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809 pSMB->DataCount = 0;
3810 pSMB->DataOffset = 0;
3811 pSMB->SetupCount = 1;
3812 pSMB->Reserved3 = 0;
3813 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3814 byte_count = params + 1 /* pad */ ;
3815 pSMB->TotalParameterCount = cpu_to_le16(params);
3816 pSMB->ParameterCount = pSMB->TotalParameterCount;
3817 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3818 pSMB->Reserved4 = 0;
3819 pSMB->hdr.smb_buf_length += byte_count;
3820 pSMB->ByteCount = cpu_to_le16(byte_count);
3821
3822 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3823 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3824 if (rc) {
3825 cFYI(1, ("error %d in QueryInternalInfo", rc));
3826 } else {
3827 /* decode response */
3828 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3829 if (rc || (pSMBr->ByteCount < 2))
3830 /* BB also check enough total bytes returned */
3831 /* If rc should we check for EOPNOSUPP and
3832 disable the srvino flag? or in caller? */
3833 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003834 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003835 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3836 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003837 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003838 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003839 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003840 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3841 rc = -EIO;
3842 goto GetInodeNumOut;
3843 }
3844 pfinfo = (struct file_internal_info *)
3845 (data_offset + (char *) &pSMBr->hdr.Protocol);
3846 *inode_number = pfinfo->UniqueId;
3847 }
3848 }
3849GetInodeNumOut:
3850 cifs_buf_release(pSMB);
3851 if (rc == -EAGAIN)
3852 goto GetInodeNumberRetry;
3853 return rc;
3854}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855
3856int
3857CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3858 const unsigned char *searchName,
3859 unsigned char **targetUNCs,
3860 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003861 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862{
3863/* TRANS2_GET_DFS_REFERRAL */
3864 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3865 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003866 struct dfs_referral_level_3 *referrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867 int rc = 0;
3868 int bytes_returned;
3869 int name_len;
3870 unsigned int i;
Steve French50c2f752007-07-13 00:33:32 +00003871 char *temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 __u16 params, byte_count;
3873 *number_of_UNC_in_array = 0;
3874 *targetUNCs = NULL;
3875
3876 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3877 if (ses == NULL)
3878 return -ENODEV;
3879getDFSRetry:
3880 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3881 (void **) &pSMBr);
3882 if (rc)
3883 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003884
3885 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07003886 but should never be null here anyway */
3887 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888 pSMB->hdr.Tid = ses->ipc_tid;
3889 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00003890 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00003892 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003893 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894
3895 if (ses->capabilities & CAP_UNICODE) {
3896 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3897 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003898 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003899 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900 name_len++; /* trailing null */
3901 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003902 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 name_len = strnlen(searchName, PATH_MAX);
3904 name_len++; /* trailing null */
3905 strncpy(pSMB->RequestFileName, searchName, name_len);
3906 }
3907
Steve French790fe572007-07-07 19:25:05 +00003908 if (ses->server) {
3909 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00003910 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3911 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3912 }
3913
Steve French50c2f752007-07-13 00:33:32 +00003914 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00003915
Linus Torvalds1da177e2005-04-16 15:20:36 -07003916 params = 2 /* level */ + name_len /*includes null */ ;
3917 pSMB->TotalDataCount = 0;
3918 pSMB->DataCount = 0;
3919 pSMB->DataOffset = 0;
3920 pSMB->MaxParameterCount = 0;
3921 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3922 pSMB->MaxSetupCount = 0;
3923 pSMB->Reserved = 0;
3924 pSMB->Flags = 0;
3925 pSMB->Timeout = 0;
3926 pSMB->Reserved2 = 0;
3927 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003928 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003929 pSMB->SetupCount = 1;
3930 pSMB->Reserved3 = 0;
3931 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3932 byte_count = params + 3 /* pad */ ;
3933 pSMB->ParameterCount = cpu_to_le16(params);
3934 pSMB->TotalParameterCount = pSMB->ParameterCount;
3935 pSMB->MaxReferralLevel = cpu_to_le16(3);
3936 pSMB->hdr.smb_buf_length += byte_count;
3937 pSMB->ByteCount = cpu_to_le16(byte_count);
3938
3939 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3940 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3941 if (rc) {
3942 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3943 } else { /* decode response */
3944/* BB Add logic to parse referrals here */
3945 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3946
Steve French50c2f752007-07-13 00:33:32 +00003947 /* BB Also check if enough total bytes returned? */
3948 if (rc || (pSMBr->ByteCount < 17))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003949 rc = -EIO; /* bad smb */
3950 else {
Steve French50c2f752007-07-13 00:33:32 +00003951 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003952 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3953
3954 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003955 ("Decoding GetDFSRefer response BCC: %d Offset %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 pSMBr->ByteCount, data_offset));
Steve French50c2f752007-07-13 00:33:32 +00003957 referrals =
3958 (struct dfs_referral_level_3 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 (8 /* sizeof start of data block */ +
3960 data_offset +
Steve French50c2f752007-07-13 00:33:32 +00003961 (char *) &pSMBr->hdr.Protocol);
Steve Frenchc18c8422007-07-18 23:21:09 +00003962 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
Steve French63135e02007-07-17 17:34:02 +00003963 "for referral one refer size: 0x%x srv "
3964 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
Steve French50c2f752007-07-13 00:33:32 +00003965 le16_to_cpu(pSMBr->NumberOfReferrals),
3966 le16_to_cpu(pSMBr->DFSFlags),
3967 le16_to_cpu(referrals->ReferralSize),
3968 le16_to_cpu(referrals->ServerType),
3969 le16_to_cpu(referrals->ReferralFlags),
3970 le16_to_cpu(referrals->TimeToLive)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003971 /* BB This field is actually two bytes in from start of
3972 data block so we could do safety check that DataBlock
3973 begins at address of pSMBr->NumberOfReferrals */
Steve French50c2f752007-07-13 00:33:32 +00003974 *number_of_UNC_in_array =
3975 le16_to_cpu(pSMBr->NumberOfReferrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976
3977 /* BB Fix below so can return more than one referral */
Steve French790fe572007-07-07 19:25:05 +00003978 if (*number_of_UNC_in_array > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 *number_of_UNC_in_array = 1;
3980
3981 /* get the length of the strings describing refs */
3982 name_len = 0;
Steve French50c2f752007-07-13 00:33:32 +00003983 for (i = 0; i < *number_of_UNC_in_array; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984 /* make sure that DfsPathOffset not past end */
Steve French50c2f752007-07-13 00:33:32 +00003985 __u16 offset =
3986 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 if (offset > data_count) {
Steve French50c2f752007-07-13 00:33:32 +00003988 /* if invalid referral, stop here and do
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 not try to copy any more */
3990 *number_of_UNC_in_array = i;
3991 break;
Steve French50c2f752007-07-13 00:33:32 +00003992 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 temp = ((char *)referrals) + offset;
3994
3995 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00003996 name_len += UniStrnlen((wchar_t *)temp,
3997 data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 } else {
Steve French50c2f752007-07-13 00:33:32 +00003999 name_len += strnlen(temp, data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004000 }
4001 referrals++;
Steve French50c2f752007-07-13 00:33:32 +00004002 /* BB add check that referral pointer does
4003 not fall off end PDU */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 }
4005 /* BB add check for name_len bigger than bcc */
Steve French50c2f752007-07-13 00:33:32 +00004006 *targetUNCs =
4007 kmalloc(name_len+1+(*number_of_UNC_in_array),
4008 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00004009 if (*targetUNCs == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 rc = -ENOMEM;
4011 goto GetDFSRefExit;
4012 }
4013 /* copy the ref strings */
Steve French50c2f752007-07-13 00:33:32 +00004014 referrals = (struct dfs_referral_level_3 *)
4015 (8 /* sizeof data hdr */ + data_offset +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 (char *) &pSMBr->hdr.Protocol);
4017
Steve French50c2f752007-07-13 00:33:32 +00004018 for (i = 0; i < *number_of_UNC_in_array; i++) {
4019 temp = ((char *)referrals) +
4020 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4022 cifs_strfromUCS_le(*targetUNCs,
Steve French50c2f752007-07-13 00:33:32 +00004023 (__le16 *) temp,
4024 name_len,
4025 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 } else {
Steve French50c2f752007-07-13 00:33:32 +00004027 strncpy(*targetUNCs, temp, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 }
4029 /* BB update target_uncs pointers */
4030 referrals++;
4031 }
4032 temp = *targetUNCs;
4033 temp[name_len] = 0;
4034 }
4035
4036 }
4037GetDFSRefExit:
4038 if (pSMB)
4039 cifs_buf_release(pSMB);
4040
4041 if (rc == -EAGAIN)
4042 goto getDFSRetry;
4043
4044 return rc;
4045}
4046
Steve French20962432005-09-21 22:05:57 -07004047/* Query File System Info such as free space to old servers such as Win 9x */
4048int
4049SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4050{
4051/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4052 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4053 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4054 FILE_SYSTEM_ALLOC_INFO *response_data;
4055 int rc = 0;
4056 int bytes_returned = 0;
4057 __u16 params, byte_count;
4058
4059 cFYI(1, ("OldQFSInfo"));
4060oldQFSInfoRetry:
4061 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4062 (void **) &pSMBr);
4063 if (rc)
4064 return rc;
Steve French20962432005-09-21 22:05:57 -07004065
4066 params = 2; /* level */
4067 pSMB->TotalDataCount = 0;
4068 pSMB->MaxParameterCount = cpu_to_le16(2);
4069 pSMB->MaxDataCount = cpu_to_le16(1000);
4070 pSMB->MaxSetupCount = 0;
4071 pSMB->Reserved = 0;
4072 pSMB->Flags = 0;
4073 pSMB->Timeout = 0;
4074 pSMB->Reserved2 = 0;
4075 byte_count = params + 1 /* pad */ ;
4076 pSMB->TotalParameterCount = cpu_to_le16(params);
4077 pSMB->ParameterCount = pSMB->TotalParameterCount;
4078 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4079 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4080 pSMB->DataCount = 0;
4081 pSMB->DataOffset = 0;
4082 pSMB->SetupCount = 1;
4083 pSMB->Reserved3 = 0;
4084 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4085 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4086 pSMB->hdr.smb_buf_length += byte_count;
4087 pSMB->ByteCount = cpu_to_le16(byte_count);
4088
4089 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4090 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4091 if (rc) {
4092 cFYI(1, ("Send error in QFSInfo = %d", rc));
4093 } else { /* decode response */
4094 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4095
4096 if (rc || (pSMBr->ByteCount < 18))
4097 rc = -EIO; /* bad smb */
4098 else {
4099 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004100 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004101 pSMBr->ByteCount, data_offset));
4102
Steve French50c2f752007-07-13 00:33:32 +00004103 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004104 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4105 FSData->f_bsize =
4106 le16_to_cpu(response_data->BytesPerSector) *
4107 le32_to_cpu(response_data->
4108 SectorsPerAllocationUnit);
4109 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004110 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004111 FSData->f_bfree = FSData->f_bavail =
4112 le32_to_cpu(response_data->FreeAllocationUnits);
4113 cFYI(1,
4114 ("Blocks: %lld Free: %lld Block size %ld",
4115 (unsigned long long)FSData->f_blocks,
4116 (unsigned long long)FSData->f_bfree,
4117 FSData->f_bsize));
4118 }
4119 }
4120 cifs_buf_release(pSMB);
4121
4122 if (rc == -EAGAIN)
4123 goto oldQFSInfoRetry;
4124
4125 return rc;
4126}
4127
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128int
Steve French737b7582005-04-28 22:41:06 -07004129CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130{
4131/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4132 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4133 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4134 FILE_SYSTEM_INFO *response_data;
4135 int rc = 0;
4136 int bytes_returned = 0;
4137 __u16 params, byte_count;
4138
4139 cFYI(1, ("In QFSInfo"));
4140QFSInfoRetry:
4141 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4142 (void **) &pSMBr);
4143 if (rc)
4144 return rc;
4145
4146 params = 2; /* level */
4147 pSMB->TotalDataCount = 0;
4148 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004149 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 pSMB->MaxSetupCount = 0;
4151 pSMB->Reserved = 0;
4152 pSMB->Flags = 0;
4153 pSMB->Timeout = 0;
4154 pSMB->Reserved2 = 0;
4155 byte_count = params + 1 /* pad */ ;
4156 pSMB->TotalParameterCount = cpu_to_le16(params);
4157 pSMB->ParameterCount = pSMB->TotalParameterCount;
4158 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004159 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 pSMB->DataCount = 0;
4161 pSMB->DataOffset = 0;
4162 pSMB->SetupCount = 1;
4163 pSMB->Reserved3 = 0;
4164 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4165 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4166 pSMB->hdr.smb_buf_length += byte_count;
4167 pSMB->ByteCount = cpu_to_le16(byte_count);
4168
4169 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4170 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4171 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004172 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004174 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175
Steve French20962432005-09-21 22:05:57 -07004176 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177 rc = -EIO; /* bad smb */
4178 else {
4179 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180
4181 response_data =
4182 (FILE_SYSTEM_INFO
4183 *) (((char *) &pSMBr->hdr.Protocol) +
4184 data_offset);
4185 FSData->f_bsize =
4186 le32_to_cpu(response_data->BytesPerSector) *
4187 le32_to_cpu(response_data->
4188 SectorsPerAllocationUnit);
4189 FSData->f_blocks =
4190 le64_to_cpu(response_data->TotalAllocationUnits);
4191 FSData->f_bfree = FSData->f_bavail =
4192 le64_to_cpu(response_data->FreeAllocationUnits);
4193 cFYI(1,
4194 ("Blocks: %lld Free: %lld Block size %ld",
4195 (unsigned long long)FSData->f_blocks,
4196 (unsigned long long)FSData->f_bfree,
4197 FSData->f_bsize));
4198 }
4199 }
4200 cifs_buf_release(pSMB);
4201
4202 if (rc == -EAGAIN)
4203 goto QFSInfoRetry;
4204
4205 return rc;
4206}
4207
4208int
Steve French737b7582005-04-28 22:41:06 -07004209CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210{
4211/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4212 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4213 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4214 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4215 int rc = 0;
4216 int bytes_returned = 0;
4217 __u16 params, byte_count;
4218
4219 cFYI(1, ("In QFSAttributeInfo"));
4220QFSAttributeRetry:
4221 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4222 (void **) &pSMBr);
4223 if (rc)
4224 return rc;
4225
4226 params = 2; /* level */
4227 pSMB->TotalDataCount = 0;
4228 pSMB->MaxParameterCount = cpu_to_le16(2);
4229 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4230 pSMB->MaxSetupCount = 0;
4231 pSMB->Reserved = 0;
4232 pSMB->Flags = 0;
4233 pSMB->Timeout = 0;
4234 pSMB->Reserved2 = 0;
4235 byte_count = params + 1 /* pad */ ;
4236 pSMB->TotalParameterCount = cpu_to_le16(params);
4237 pSMB->ParameterCount = pSMB->TotalParameterCount;
4238 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004239 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004240 pSMB->DataCount = 0;
4241 pSMB->DataOffset = 0;
4242 pSMB->SetupCount = 1;
4243 pSMB->Reserved3 = 0;
4244 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4245 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4246 pSMB->hdr.smb_buf_length += byte_count;
4247 pSMB->ByteCount = cpu_to_le16(byte_count);
4248
4249 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4250 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4251 if (rc) {
4252 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4253 } else { /* decode response */
4254 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4255
Steve French50c2f752007-07-13 00:33:32 +00004256 if (rc || (pSMBr->ByteCount < 13)) {
4257 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 rc = -EIO; /* bad smb */
4259 } else {
4260 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4261 response_data =
4262 (FILE_SYSTEM_ATTRIBUTE_INFO
4263 *) (((char *) &pSMBr->hdr.Protocol) +
4264 data_offset);
4265 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004266 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004267 }
4268 }
4269 cifs_buf_release(pSMB);
4270
4271 if (rc == -EAGAIN)
4272 goto QFSAttributeRetry;
4273
4274 return rc;
4275}
4276
4277int
Steve French737b7582005-04-28 22:41:06 -07004278CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279{
4280/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4281 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4282 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4283 FILE_SYSTEM_DEVICE_INFO *response_data;
4284 int rc = 0;
4285 int bytes_returned = 0;
4286 __u16 params, byte_count;
4287
4288 cFYI(1, ("In QFSDeviceInfo"));
4289QFSDeviceRetry:
4290 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4291 (void **) &pSMBr);
4292 if (rc)
4293 return rc;
4294
4295 params = 2; /* level */
4296 pSMB->TotalDataCount = 0;
4297 pSMB->MaxParameterCount = cpu_to_le16(2);
4298 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4299 pSMB->MaxSetupCount = 0;
4300 pSMB->Reserved = 0;
4301 pSMB->Flags = 0;
4302 pSMB->Timeout = 0;
4303 pSMB->Reserved2 = 0;
4304 byte_count = params + 1 /* pad */ ;
4305 pSMB->TotalParameterCount = cpu_to_le16(params);
4306 pSMB->ParameterCount = pSMB->TotalParameterCount;
4307 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004308 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004309
4310 pSMB->DataCount = 0;
4311 pSMB->DataOffset = 0;
4312 pSMB->SetupCount = 1;
4313 pSMB->Reserved3 = 0;
4314 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4315 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4316 pSMB->hdr.smb_buf_length += byte_count;
4317 pSMB->ByteCount = cpu_to_le16(byte_count);
4318
4319 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4320 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4321 if (rc) {
4322 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4323 } else { /* decode response */
4324 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4325
4326 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4327 rc = -EIO; /* bad smb */
4328 else {
4329 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4330 response_data =
Steve French737b7582005-04-28 22:41:06 -07004331 (FILE_SYSTEM_DEVICE_INFO *)
4332 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333 data_offset);
4334 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004335 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004336 }
4337 }
4338 cifs_buf_release(pSMB);
4339
4340 if (rc == -EAGAIN)
4341 goto QFSDeviceRetry;
4342
4343 return rc;
4344}
4345
4346int
Steve French737b7582005-04-28 22:41:06 -07004347CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348{
4349/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4350 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4351 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4352 FILE_SYSTEM_UNIX_INFO *response_data;
4353 int rc = 0;
4354 int bytes_returned = 0;
4355 __u16 params, byte_count;
4356
4357 cFYI(1, ("In QFSUnixInfo"));
4358QFSUnixRetry:
4359 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4360 (void **) &pSMBr);
4361 if (rc)
4362 return rc;
4363
4364 params = 2; /* level */
4365 pSMB->TotalDataCount = 0;
4366 pSMB->DataCount = 0;
4367 pSMB->DataOffset = 0;
4368 pSMB->MaxParameterCount = cpu_to_le16(2);
4369 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4370 pSMB->MaxSetupCount = 0;
4371 pSMB->Reserved = 0;
4372 pSMB->Flags = 0;
4373 pSMB->Timeout = 0;
4374 pSMB->Reserved2 = 0;
4375 byte_count = params + 1 /* pad */ ;
4376 pSMB->ParameterCount = cpu_to_le16(params);
4377 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004378 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4379 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380 pSMB->SetupCount = 1;
4381 pSMB->Reserved3 = 0;
4382 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4383 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4384 pSMB->hdr.smb_buf_length += byte_count;
4385 pSMB->ByteCount = cpu_to_le16(byte_count);
4386
4387 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4388 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4389 if (rc) {
4390 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4391 } else { /* decode response */
4392 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4393
4394 if (rc || (pSMBr->ByteCount < 13)) {
4395 rc = -EIO; /* bad smb */
4396 } else {
4397 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4398 response_data =
4399 (FILE_SYSTEM_UNIX_INFO
4400 *) (((char *) &pSMBr->hdr.Protocol) +
4401 data_offset);
4402 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004403 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 }
4405 }
4406 cifs_buf_release(pSMB);
4407
4408 if (rc == -EAGAIN)
4409 goto QFSUnixRetry;
4410
4411
4412 return rc;
4413}
4414
Jeremy Allisonac670552005-06-22 17:26:35 -07004415int
Steve French45abc6e2005-06-23 13:42:03 -05004416CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004417{
4418/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4419 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4420 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4421 int rc = 0;
4422 int bytes_returned = 0;
4423 __u16 params, param_offset, offset, byte_count;
4424
4425 cFYI(1, ("In SETFSUnixInfo"));
4426SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004427 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004428 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4429 (void **) &pSMBr);
4430 if (rc)
4431 return rc;
4432
4433 params = 4; /* 2 bytes zero followed by info level. */
4434 pSMB->MaxSetupCount = 0;
4435 pSMB->Reserved = 0;
4436 pSMB->Flags = 0;
4437 pSMB->Timeout = 0;
4438 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004439 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4440 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004441 offset = param_offset + params;
4442
4443 pSMB->MaxParameterCount = cpu_to_le16(4);
4444 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4445 pSMB->SetupCount = 1;
4446 pSMB->Reserved3 = 0;
4447 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4448 byte_count = 1 /* pad */ + params + 12;
4449
4450 pSMB->DataCount = cpu_to_le16(12);
4451 pSMB->ParameterCount = cpu_to_le16(params);
4452 pSMB->TotalDataCount = pSMB->DataCount;
4453 pSMB->TotalParameterCount = pSMB->ParameterCount;
4454 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4455 pSMB->DataOffset = cpu_to_le16(offset);
4456
4457 /* Params. */
4458 pSMB->FileNum = 0;
4459 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4460
4461 /* Data. */
4462 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4463 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4464 pSMB->ClientUnixCap = cpu_to_le64(cap);
4465
4466 pSMB->hdr.smb_buf_length += byte_count;
4467 pSMB->ByteCount = cpu_to_le16(byte_count);
4468
4469 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4470 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4471 if (rc) {
4472 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4473 } else { /* decode response */
4474 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4475 if (rc) {
4476 rc = -EIO; /* bad smb */
4477 }
4478 }
4479 cifs_buf_release(pSMB);
4480
4481 if (rc == -EAGAIN)
4482 goto SETFSUnixRetry;
4483
4484 return rc;
4485}
4486
4487
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488
4489int
4490CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004491 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492{
4493/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4494 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4495 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4496 FILE_SYSTEM_POSIX_INFO *response_data;
4497 int rc = 0;
4498 int bytes_returned = 0;
4499 __u16 params, byte_count;
4500
4501 cFYI(1, ("In QFSPosixInfo"));
4502QFSPosixRetry:
4503 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4504 (void **) &pSMBr);
4505 if (rc)
4506 return rc;
4507
4508 params = 2; /* level */
4509 pSMB->TotalDataCount = 0;
4510 pSMB->DataCount = 0;
4511 pSMB->DataOffset = 0;
4512 pSMB->MaxParameterCount = cpu_to_le16(2);
4513 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4514 pSMB->MaxSetupCount = 0;
4515 pSMB->Reserved = 0;
4516 pSMB->Flags = 0;
4517 pSMB->Timeout = 0;
4518 pSMB->Reserved2 = 0;
4519 byte_count = params + 1 /* pad */ ;
4520 pSMB->ParameterCount = cpu_to_le16(params);
4521 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004522 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4523 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524 pSMB->SetupCount = 1;
4525 pSMB->Reserved3 = 0;
4526 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4527 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4528 pSMB->hdr.smb_buf_length += byte_count;
4529 pSMB->ByteCount = cpu_to_le16(byte_count);
4530
4531 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4532 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4533 if (rc) {
4534 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4535 } else { /* decode response */
4536 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4537
4538 if (rc || (pSMBr->ByteCount < 13)) {
4539 rc = -EIO; /* bad smb */
4540 } else {
4541 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4542 response_data =
4543 (FILE_SYSTEM_POSIX_INFO
4544 *) (((char *) &pSMBr->hdr.Protocol) +
4545 data_offset);
4546 FSData->f_bsize =
4547 le32_to_cpu(response_data->BlockSize);
4548 FSData->f_blocks =
4549 le64_to_cpu(response_data->TotalBlocks);
4550 FSData->f_bfree =
4551 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004552 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553 FSData->f_bavail = FSData->f_bfree;
4554 } else {
4555 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004556 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004557 }
Steve French790fe572007-07-07 19:25:05 +00004558 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004560 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004561 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004562 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004563 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 }
4565 }
4566 cifs_buf_release(pSMB);
4567
4568 if (rc == -EAGAIN)
4569 goto QFSPosixRetry;
4570
4571 return rc;
4572}
4573
4574
Steve French50c2f752007-07-13 00:33:32 +00004575/* We can not use write of zero bytes trick to
4576 set file size due to need for large file support. Also note that
4577 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578 routine which is only needed to work around a sharing violation bug
4579 in Samba which this routine can run into */
4580
4581int
4582CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004583 __u64 size, int SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004584 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004585{
4586 struct smb_com_transaction2_spi_req *pSMB = NULL;
4587 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4588 struct file_end_of_file_info *parm_data;
4589 int name_len;
4590 int rc = 0;
4591 int bytes_returned = 0;
4592 __u16 params, byte_count, data_count, param_offset, offset;
4593
4594 cFYI(1, ("In SetEOF"));
4595SetEOFRetry:
4596 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4597 (void **) &pSMBr);
4598 if (rc)
4599 return rc;
4600
4601 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4602 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004603 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004604 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 name_len++; /* trailing null */
4606 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004607 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608 name_len = strnlen(fileName, PATH_MAX);
4609 name_len++; /* trailing null */
4610 strncpy(pSMB->FileName, fileName, name_len);
4611 }
4612 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004613 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004615 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 pSMB->MaxSetupCount = 0;
4617 pSMB->Reserved = 0;
4618 pSMB->Flags = 0;
4619 pSMB->Timeout = 0;
4620 pSMB->Reserved2 = 0;
4621 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004622 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004624 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004625 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4626 pSMB->InformationLevel =
4627 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4628 else
4629 pSMB->InformationLevel =
4630 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4631 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4633 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004634 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635 else
4636 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004637 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 }
4639
4640 parm_data =
4641 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4642 offset);
4643 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4644 pSMB->DataOffset = cpu_to_le16(offset);
4645 pSMB->SetupCount = 1;
4646 pSMB->Reserved3 = 0;
4647 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4648 byte_count = 3 /* pad */ + params + data_count;
4649 pSMB->DataCount = cpu_to_le16(data_count);
4650 pSMB->TotalDataCount = pSMB->DataCount;
4651 pSMB->ParameterCount = cpu_to_le16(params);
4652 pSMB->TotalParameterCount = pSMB->ParameterCount;
4653 pSMB->Reserved4 = 0;
4654 pSMB->hdr.smb_buf_length += byte_count;
4655 parm_data->FileSize = cpu_to_le64(size);
4656 pSMB->ByteCount = cpu_to_le16(byte_count);
4657 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4658 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4659 if (rc) {
4660 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4661 }
4662
4663 cifs_buf_release(pSMB);
4664
4665 if (rc == -EAGAIN)
4666 goto SetEOFRetry;
4667
4668 return rc;
4669}
4670
4671int
Steve French50c2f752007-07-13 00:33:32 +00004672CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4673 __u16 fid, __u32 pid_of_opener, int SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674{
4675 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4676 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4677 char *data_offset;
4678 struct file_end_of_file_info *parm_data;
4679 int rc = 0;
4680 int bytes_returned = 0;
4681 __u16 params, param_offset, offset, byte_count, count;
4682
4683 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4684 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004685 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4686
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687 if (rc)
4688 return rc;
4689
Steve Frenchcd634992005-04-28 22:41:10 -07004690 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4691
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4693 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004694
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695 params = 6;
4696 pSMB->MaxSetupCount = 0;
4697 pSMB->Reserved = 0;
4698 pSMB->Flags = 0;
4699 pSMB->Timeout = 0;
4700 pSMB->Reserved2 = 0;
4701 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4702 offset = param_offset + params;
4703
Steve French50c2f752007-07-13 00:33:32 +00004704 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705
4706 count = sizeof(struct file_end_of_file_info);
4707 pSMB->MaxParameterCount = cpu_to_le16(2);
4708 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4709 pSMB->SetupCount = 1;
4710 pSMB->Reserved3 = 0;
4711 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4712 byte_count = 3 /* pad */ + params + count;
4713 pSMB->DataCount = cpu_to_le16(count);
4714 pSMB->ParameterCount = cpu_to_le16(params);
4715 pSMB->TotalDataCount = pSMB->DataCount;
4716 pSMB->TotalParameterCount = pSMB->ParameterCount;
4717 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4718 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004719 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4720 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004721 pSMB->DataOffset = cpu_to_le16(offset);
4722 parm_data->FileSize = cpu_to_le64(size);
4723 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004724 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4726 pSMB->InformationLevel =
4727 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4728 else
4729 pSMB->InformationLevel =
4730 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004731 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4733 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004734 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735 else
4736 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004737 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738 }
4739 pSMB->Reserved4 = 0;
4740 pSMB->hdr.smb_buf_length += byte_count;
4741 pSMB->ByteCount = cpu_to_le16(byte_count);
4742 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4743 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4744 if (rc) {
4745 cFYI(1,
4746 ("Send error in SetFileInfo (SetFileSize) = %d",
4747 rc));
4748 }
4749
4750 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004751 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752
Steve French50c2f752007-07-13 00:33:32 +00004753 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004754 since file handle passed in no longer valid */
4755
4756 return rc;
4757}
4758
Steve French50c2f752007-07-13 00:33:32 +00004759/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 an open handle, rather than by pathname - this is awkward due to
4761 potential access conflicts on the open, but it is unavoidable for these
4762 old servers since the only other choice is to go from 100 nanosecond DCE
4763 time and resort to the original setpathinfo level which takes the ancient
4764 DOS time format with 2 second granularity */
4765int
Steve French50c2f752007-07-13 00:33:32 +00004766CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4767 const FILE_BASIC_INFO *data, __u16 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768{
4769 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4770 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4771 char *data_offset;
4772 int rc = 0;
4773 int bytes_returned = 0;
4774 __u16 params, param_offset, offset, byte_count, count;
4775
4776 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004777 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4778
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 if (rc)
4780 return rc;
4781
Steve Frenchcd634992005-04-28 22:41:10 -07004782 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4783
Linus Torvalds1da177e2005-04-16 15:20:36 -07004784 /* At this point there is no need to override the current pid
4785 with the pid of the opener, but that could change if we someday
4786 use an existing handle (rather than opening one on the fly) */
4787 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4788 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
Steve French50c2f752007-07-13 00:33:32 +00004789
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 params = 6;
4791 pSMB->MaxSetupCount = 0;
4792 pSMB->Reserved = 0;
4793 pSMB->Flags = 0;
4794 pSMB->Timeout = 0;
4795 pSMB->Reserved2 = 0;
4796 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4797 offset = param_offset + params;
4798
Steve French50c2f752007-07-13 00:33:32 +00004799 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800
Steve French26f57362007-08-30 22:09:15 +00004801 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802 pSMB->MaxParameterCount = cpu_to_le16(2);
4803 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4804 pSMB->SetupCount = 1;
4805 pSMB->Reserved3 = 0;
4806 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4807 byte_count = 3 /* pad */ + params + count;
4808 pSMB->DataCount = cpu_to_le16(count);
4809 pSMB->ParameterCount = cpu_to_le16(params);
4810 pSMB->TotalDataCount = pSMB->DataCount;
4811 pSMB->TotalParameterCount = pSMB->ParameterCount;
4812 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4813 pSMB->DataOffset = cpu_to_le16(offset);
4814 pSMB->Fid = fid;
4815 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4816 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4817 else
4818 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4819 pSMB->Reserved4 = 0;
4820 pSMB->hdr.smb_buf_length += byte_count;
4821 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004822 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004823 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4824 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4825 if (rc) {
Steve French50c2f752007-07-13 00:33:32 +00004826 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 }
4828
Steve Frenchcd634992005-04-28 22:41:10 -07004829 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830
Steve French50c2f752007-07-13 00:33:32 +00004831 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004832 since file handle passed in no longer valid */
4833
4834 return rc;
4835}
4836
4837
4838int
4839CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004840 const FILE_BASIC_INFO *data,
Steve French737b7582005-04-28 22:41:06 -07004841 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842{
4843 TRANSACTION2_SPI_REQ *pSMB = NULL;
4844 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4845 int name_len;
4846 int rc = 0;
4847 int bytes_returned = 0;
4848 char *data_offset;
4849 __u16 params, param_offset, offset, byte_count, count;
4850
4851 cFYI(1, ("In SetTimes"));
4852
4853SetTimesRetry:
4854 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4855 (void **) &pSMBr);
4856 if (rc)
4857 return rc;
4858
4859 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4860 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004861 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004862 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863 name_len++; /* trailing null */
4864 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004865 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 name_len = strnlen(fileName, PATH_MAX);
4867 name_len++; /* trailing null */
4868 strncpy(pSMB->FileName, fileName, name_len);
4869 }
4870
4871 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004872 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 pSMB->MaxParameterCount = cpu_to_le16(2);
4874 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4875 pSMB->MaxSetupCount = 0;
4876 pSMB->Reserved = 0;
4877 pSMB->Flags = 0;
4878 pSMB->Timeout = 0;
4879 pSMB->Reserved2 = 0;
4880 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004881 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882 offset = param_offset + params;
4883 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4884 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4885 pSMB->DataOffset = cpu_to_le16(offset);
4886 pSMB->SetupCount = 1;
4887 pSMB->Reserved3 = 0;
4888 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4889 byte_count = 3 /* pad */ + params + count;
4890
4891 pSMB->DataCount = cpu_to_le16(count);
4892 pSMB->ParameterCount = cpu_to_le16(params);
4893 pSMB->TotalDataCount = pSMB->DataCount;
4894 pSMB->TotalParameterCount = pSMB->ParameterCount;
4895 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4896 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4897 else
4898 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4899 pSMB->Reserved4 = 0;
4900 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00004901 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902 pSMB->ByteCount = cpu_to_le16(byte_count);
4903 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4904 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4905 if (rc) {
4906 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4907 }
4908
4909 cifs_buf_release(pSMB);
4910
4911 if (rc == -EAGAIN)
4912 goto SetTimesRetry;
4913
4914 return rc;
4915}
4916
4917/* Can not be used to set time stamps yet (due to old DOS time format) */
4918/* Can be used to set attributes */
4919#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4920 handling it anyway and NT4 was what we thought it would be needed for
4921 Do not delete it until we prove whether needed for Win9x though */
4922int
4923CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4924 __u16 dos_attrs, const struct nls_table *nls_codepage)
4925{
4926 SETATTR_REQ *pSMB = NULL;
4927 SETATTR_RSP *pSMBr = NULL;
4928 int rc = 0;
4929 int bytes_returned;
4930 int name_len;
4931
4932 cFYI(1, ("In SetAttrLegacy"));
4933
4934SetAttrLgcyRetry:
4935 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4936 (void **) &pSMBr);
4937 if (rc)
4938 return rc;
4939
4940 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4941 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004942 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004943 PATH_MAX, nls_codepage);
4944 name_len++; /* trailing null */
4945 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004946 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004947 name_len = strnlen(fileName, PATH_MAX);
4948 name_len++; /* trailing null */
4949 strncpy(pSMB->fileName, fileName, name_len);
4950 }
4951 pSMB->attr = cpu_to_le16(dos_attrs);
4952 pSMB->BufferFormat = 0x04;
4953 pSMB->hdr.smb_buf_length += name_len + 1;
4954 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4955 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4956 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4957 if (rc) {
4958 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4959 }
4960
4961 cifs_buf_release(pSMB);
4962
4963 if (rc == -EAGAIN)
4964 goto SetAttrLgcyRetry;
4965
4966 return rc;
4967}
4968#endif /* temporarily unneeded SetAttr legacy function */
4969
4970int
4971CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004972 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4973 dev_t device, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07004974 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975{
4976 TRANSACTION2_SPI_REQ *pSMB = NULL;
4977 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4978 int name_len;
4979 int rc = 0;
4980 int bytes_returned = 0;
4981 FILE_UNIX_BASIC_INFO *data_offset;
4982 __u16 params, param_offset, offset, count, byte_count;
4983
4984 cFYI(1, ("In SetUID/GID/Mode"));
4985setPermsRetry:
4986 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4987 (void **) &pSMBr);
4988 if (rc)
4989 return rc;
4990
4991 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4992 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004993 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004994 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004995 name_len++; /* trailing null */
4996 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004997 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998 name_len = strnlen(fileName, PATH_MAX);
4999 name_len++; /* trailing null */
5000 strncpy(pSMB->FileName, fileName, name_len);
5001 }
5002
5003 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005004 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005005 pSMB->MaxParameterCount = cpu_to_le16(2);
5006 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
5007 pSMB->MaxSetupCount = 0;
5008 pSMB->Reserved = 0;
5009 pSMB->Flags = 0;
5010 pSMB->Timeout = 0;
5011 pSMB->Reserved2 = 0;
5012 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005013 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 offset = param_offset + params;
5015 data_offset =
5016 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5017 offset);
5018 memset(data_offset, 0, count);
5019 pSMB->DataOffset = cpu_to_le16(offset);
5020 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5021 pSMB->SetupCount = 1;
5022 pSMB->Reserved3 = 0;
5023 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5024 byte_count = 3 /* pad */ + params + count;
5025 pSMB->ParameterCount = cpu_to_le16(params);
5026 pSMB->DataCount = cpu_to_le16(count);
5027 pSMB->TotalParameterCount = pSMB->ParameterCount;
5028 pSMB->TotalDataCount = pSMB->DataCount;
5029 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5030 pSMB->Reserved4 = 0;
5031 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005032 /* Samba server ignores set of file size to zero due to bugs in some
5033 older clients, but we should be precise - we use SetFileSize to
5034 set file size and do not want to truncate file size to zero
5035 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005036 zero instead of -1 here */
Steve Frenchc7af1852007-03-01 04:11:22 +00005037 data_offset->EndOfFile = NO_CHANGE_64;
5038 data_offset->NumOfBytes = NO_CHANGE_64;
5039 data_offset->LastStatusChange = NO_CHANGE_64;
5040 data_offset->LastAccessTime = NO_CHANGE_64;
5041 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005042 data_offset->Uid = cpu_to_le64(uid);
5043 data_offset->Gid = cpu_to_le64(gid);
5044 /* better to leave device as zero when it is */
5045 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5046 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5047 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005048
Steve French790fe572007-07-07 19:25:05 +00005049 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005051 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005053 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005055 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005057 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005059 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005061 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5063
5064
5065 pSMB->ByteCount = cpu_to_le16(byte_count);
5066 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5067 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5068 if (rc) {
5069 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5070 }
5071
5072 if (pSMB)
5073 cifs_buf_release(pSMB);
5074 if (rc == -EAGAIN)
5075 goto setPermsRetry;
5076 return rc;
5077}
5078
Steve French50c2f752007-07-13 00:33:32 +00005079int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005080 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005081 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005082 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005083{
5084 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005085 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5086 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005087 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005088 int bytes_returned;
5089
Steve French50c2f752007-07-13 00:33:32 +00005090 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005092 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093 if (rc)
5094 return rc;
5095
5096 pSMB->TotalParameterCount = 0 ;
5097 pSMB->TotalDataCount = 0;
5098 pSMB->MaxParameterCount = cpu_to_le32(2);
5099 /* BB find exact data count max from sess structure BB */
5100 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005101/* BB VERIFY verify which is correct for above BB */
5102 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5103 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5104
Linus Torvalds1da177e2005-04-16 15:20:36 -07005105 pSMB->MaxSetupCount = 4;
5106 pSMB->Reserved = 0;
5107 pSMB->ParameterOffset = 0;
5108 pSMB->DataCount = 0;
5109 pSMB->DataOffset = 0;
5110 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5111 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5112 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005113 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005114 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5115 pSMB->Reserved2 = 0;
5116 pSMB->CompletionFilter = cpu_to_le32(filter);
5117 pSMB->Fid = netfid; /* file handle always le */
5118 pSMB->ByteCount = 0;
5119
5120 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5121 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
5122 if (rc) {
5123 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005124 } else {
5125 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005126 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005127 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005128 sizeof(struct dir_notify_req),
5129 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005130 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005131 dnotify_req->Pid = pSMB->hdr.Pid;
5132 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5133 dnotify_req->Mid = pSMB->hdr.Mid;
5134 dnotify_req->Tid = pSMB->hdr.Tid;
5135 dnotify_req->Uid = pSMB->hdr.Uid;
5136 dnotify_req->netfid = netfid;
5137 dnotify_req->pfile = pfile;
5138 dnotify_req->filter = filter;
5139 dnotify_req->multishot = multishot;
5140 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005141 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005142 &GlobalDnotifyReqList);
5143 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005144 } else
Steve French47c786e2005-10-11 20:03:18 -07005145 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005146 }
5147 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005148 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005149}
5150#ifdef CONFIG_CIFS_XATTR
5151ssize_t
5152CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5153 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005154 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005155 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156{
5157 /* BB assumes one setup word */
5158 TRANSACTION2_QPI_REQ *pSMB = NULL;
5159 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5160 int rc = 0;
5161 int bytes_returned;
5162 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005163 struct fea *temp_fea;
5164 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005165 __u16 params, byte_count;
5166
5167 cFYI(1, ("In Query All EAs path %s", searchName));
5168QAllEAsRetry:
5169 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5170 (void **) &pSMBr);
5171 if (rc)
5172 return rc;
5173
5174 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5175 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005176 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005177 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 name_len++; /* trailing null */
5179 name_len *= 2;
5180 } else { /* BB improve the check for buffer overruns BB */
5181 name_len = strnlen(searchName, PATH_MAX);
5182 name_len++; /* trailing null */
5183 strncpy(pSMB->FileName, searchName, name_len);
5184 }
5185
Steve French50c2f752007-07-13 00:33:32 +00005186 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187 pSMB->TotalDataCount = 0;
5188 pSMB->MaxParameterCount = cpu_to_le16(2);
5189 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5190 pSMB->MaxSetupCount = 0;
5191 pSMB->Reserved = 0;
5192 pSMB->Flags = 0;
5193 pSMB->Timeout = 0;
5194 pSMB->Reserved2 = 0;
5195 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005196 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 pSMB->DataCount = 0;
5198 pSMB->DataOffset = 0;
5199 pSMB->SetupCount = 1;
5200 pSMB->Reserved3 = 0;
5201 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5202 byte_count = params + 1 /* pad */ ;
5203 pSMB->TotalParameterCount = cpu_to_le16(params);
5204 pSMB->ParameterCount = pSMB->TotalParameterCount;
5205 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5206 pSMB->Reserved4 = 0;
5207 pSMB->hdr.smb_buf_length += byte_count;
5208 pSMB->ByteCount = cpu_to_le16(byte_count);
5209
5210 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5211 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5212 if (rc) {
5213 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5214 } else { /* decode response */
5215 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5216
5217 /* BB also check enough total bytes returned */
5218 /* BB we need to improve the validity checking
5219 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005220 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 rc = -EIO; /* bad smb */
5222 /* else if (pFindData){
5223 memcpy((char *) pFindData,
5224 (char *) &pSMBr->hdr.Protocol +
5225 data_offset, kl);
5226 }*/ else {
5227 /* check that length of list is not more than bcc */
5228 /* check that each entry does not go beyond length
5229 of list */
5230 /* check that each element of each entry does not
5231 go beyond end of list */
5232 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005233 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005234 rc = 0;
5235 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005236 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005237 ea_response_data = (struct fealist *)
5238 (((char *) &pSMBr->hdr.Protocol) +
5239 data_offset);
5240 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005241 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005242 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005244 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 } else {
5246 /* account for ea list len */
5247 name_len -= 4;
5248 temp_fea = ea_response_data->list;
5249 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005250 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 __u16 value_len;
5252 name_len -= 4;
5253 temp_ptr += 4;
5254 rc += temp_fea->name_len;
5255 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005256 rc = rc + 5 + 1;
5257 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005258 memcpy(EAData, "user.", 5);
5259 EAData += 5;
5260 memcpy(EAData, temp_ptr,
5261 temp_fea->name_len);
5262 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263 /* null terminate name */
5264 *EAData = 0;
5265 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005266 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005267 /* skip copy - calc size only */
5268 } else {
5269 /* stop before overrun buffer */
5270 rc = -ERANGE;
5271 break;
5272 }
5273 name_len -= temp_fea->name_len;
5274 temp_ptr += temp_fea->name_len;
5275 /* account for trailing null */
5276 name_len--;
5277 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005278 value_len =
5279 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280 name_len -= value_len;
5281 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005282 /* BB check that temp_ptr is still
5283 within the SMB BB*/
5284
5285 /* no trailing null to account for
5286 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005287 /* go on to next EA */
5288 temp_fea = (struct fea *)temp_ptr;
5289 }
5290 }
5291 }
5292 }
5293 if (pSMB)
5294 cifs_buf_release(pSMB);
5295 if (rc == -EAGAIN)
5296 goto QAllEAsRetry;
5297
5298 return (ssize_t)rc;
5299}
5300
Steve French50c2f752007-07-13 00:33:32 +00005301ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5302 const unsigned char *searchName, const unsigned char *ea_name,
5303 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005304 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005305{
5306 TRANSACTION2_QPI_REQ *pSMB = NULL;
5307 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5308 int rc = 0;
5309 int bytes_returned;
5310 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005311 struct fea *temp_fea;
5312 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313 __u16 params, byte_count;
5314
5315 cFYI(1, ("In Query EA path %s", searchName));
5316QEARetry:
5317 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5318 (void **) &pSMBr);
5319 if (rc)
5320 return rc;
5321
5322 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5323 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005324 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005325 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005326 name_len++; /* trailing null */
5327 name_len *= 2;
5328 } else { /* BB improve the check for buffer overruns BB */
5329 name_len = strnlen(searchName, PATH_MAX);
5330 name_len++; /* trailing null */
5331 strncpy(pSMB->FileName, searchName, name_len);
5332 }
5333
Steve French50c2f752007-07-13 00:33:32 +00005334 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005335 pSMB->TotalDataCount = 0;
5336 pSMB->MaxParameterCount = cpu_to_le16(2);
5337 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5338 pSMB->MaxSetupCount = 0;
5339 pSMB->Reserved = 0;
5340 pSMB->Flags = 0;
5341 pSMB->Timeout = 0;
5342 pSMB->Reserved2 = 0;
5343 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005344 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345 pSMB->DataCount = 0;
5346 pSMB->DataOffset = 0;
5347 pSMB->SetupCount = 1;
5348 pSMB->Reserved3 = 0;
5349 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5350 byte_count = params + 1 /* pad */ ;
5351 pSMB->TotalParameterCount = cpu_to_le16(params);
5352 pSMB->ParameterCount = pSMB->TotalParameterCount;
5353 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5354 pSMB->Reserved4 = 0;
5355 pSMB->hdr.smb_buf_length += byte_count;
5356 pSMB->ByteCount = cpu_to_le16(byte_count);
5357
5358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5359 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5360 if (rc) {
5361 cFYI(1, ("Send error in Query EA = %d", rc));
5362 } else { /* decode response */
5363 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5364
5365 /* BB also check enough total bytes returned */
5366 /* BB we need to improve the validity checking
5367 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005368 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005369 rc = -EIO; /* bad smb */
5370 /* else if (pFindData){
5371 memcpy((char *) pFindData,
5372 (char *) &pSMBr->hdr.Protocol +
5373 data_offset, kl);
5374 }*/ else {
5375 /* check that length of list is not more than bcc */
5376 /* check that each entry does not go beyond length
5377 of list */
5378 /* check that each element of each entry does not
5379 go beyond end of list */
5380 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005381 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005382 rc = -ENODATA;
5383 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005384 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005385 ea_response_data = (struct fealist *)
5386 (((char *) &pSMBr->hdr.Protocol) +
5387 data_offset);
5388 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005389 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005390 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005392 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393 } else {
5394 /* account for ea list len */
5395 name_len -= 4;
5396 temp_fea = ea_response_data->list;
5397 temp_ptr = (char *)temp_fea;
5398 /* loop through checking if we have a matching
5399 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005400 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401 __u16 value_len;
5402 name_len -= 4;
5403 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005404 value_len =
5405 le16_to_cpu(temp_fea->value_len);
5406 /* BB validate that value_len falls within SMB,
5407 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005408 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 temp_fea->name_len) == 0) {
5410 /* found a match */
5411 rc = value_len;
5412 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005413 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005414 memcpy(ea_value,
5415 temp_fea->name+temp_fea->name_len+1,
5416 rc);
Steve French50c2f752007-07-13 00:33:32 +00005417 /* ea values, unlike ea
5418 names, are not null
5419 terminated */
Steve French790fe572007-07-07 19:25:05 +00005420 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005421 /* skip copy - calc size only */
5422 } else {
Steve French50c2f752007-07-13 00:33:32 +00005423 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 rc = -ERANGE;
5425 }
5426 break;
5427 }
5428 name_len -= temp_fea->name_len;
5429 temp_ptr += temp_fea->name_len;
5430 /* account for trailing null */
5431 name_len--;
5432 temp_ptr++;
5433 name_len -= value_len;
5434 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005435 /* No trailing null to account for in
5436 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005437 temp_fea = (struct fea *)temp_ptr;
5438 }
Steve French50c2f752007-07-13 00:33:32 +00005439 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005440 }
5441 }
5442 if (pSMB)
5443 cifs_buf_release(pSMB);
5444 if (rc == -EAGAIN)
5445 goto QEARetry;
5446
5447 return (ssize_t)rc;
5448}
5449
5450int
5451CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005452 const char *ea_name, const void *ea_value,
5453 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5454 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005455{
5456 struct smb_com_transaction2_spi_req *pSMB = NULL;
5457 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5458 struct fealist *parm_data;
5459 int name_len;
5460 int rc = 0;
5461 int bytes_returned = 0;
5462 __u16 params, param_offset, byte_count, offset, count;
5463
5464 cFYI(1, ("In SetEA"));
5465SetEARetry:
5466 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5467 (void **) &pSMBr);
5468 if (rc)
5469 return rc;
5470
5471 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5472 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005473 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005474 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 name_len++; /* trailing null */
5476 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005477 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478 name_len = strnlen(fileName, PATH_MAX);
5479 name_len++; /* trailing null */
5480 strncpy(pSMB->FileName, fileName, name_len);
5481 }
5482
5483 params = 6 + name_len;
5484
5485 /* done calculating parms using name_len of file name,
5486 now use name_len to calculate length of ea name
5487 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005488 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005489 name_len = 0;
5490 else
Steve French50c2f752007-07-13 00:33:32 +00005491 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492
5493 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5494 pSMB->MaxParameterCount = cpu_to_le16(2);
5495 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5496 pSMB->MaxSetupCount = 0;
5497 pSMB->Reserved = 0;
5498 pSMB->Flags = 0;
5499 pSMB->Timeout = 0;
5500 pSMB->Reserved2 = 0;
5501 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005502 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503 offset = param_offset + params;
5504 pSMB->InformationLevel =
5505 cpu_to_le16(SMB_SET_FILE_EA);
5506
5507 parm_data =
5508 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5509 offset);
5510 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5511 pSMB->DataOffset = cpu_to_le16(offset);
5512 pSMB->SetupCount = 1;
5513 pSMB->Reserved3 = 0;
5514 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5515 byte_count = 3 /* pad */ + params + count;
5516 pSMB->DataCount = cpu_to_le16(count);
5517 parm_data->list_len = cpu_to_le32(count);
5518 parm_data->list[0].EA_flags = 0;
5519 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005520 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005521 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005522 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005523 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005524 parm_data->list[0].name[name_len] = 0;
5525 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5526 /* caller ensures that ea_value_len is less than 64K but
5527 we need to ensure that it fits within the smb */
5528
Steve French50c2f752007-07-13 00:33:32 +00005529 /*BB add length check to see if it would fit in
5530 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005531 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5532 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005533 memcpy(parm_data->list[0].name+name_len+1,
5534 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005535
5536 pSMB->TotalDataCount = pSMB->DataCount;
5537 pSMB->ParameterCount = cpu_to_le16(params);
5538 pSMB->TotalParameterCount = pSMB->ParameterCount;
5539 pSMB->Reserved4 = 0;
5540 pSMB->hdr.smb_buf_length += byte_count;
5541 pSMB->ByteCount = cpu_to_le16(byte_count);
5542 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5543 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5544 if (rc) {
5545 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5546 }
5547
5548 cifs_buf_release(pSMB);
5549
5550 if (rc == -EAGAIN)
5551 goto SetEARetry;
5552
5553 return rc;
5554}
5555
5556#endif