blob: d22af63e8f1facd7b9513293e810bf05a053956e [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;
Jeff Laytone187e442007-10-16 17:10:44 +0000624 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000626 goto neg_err_exit;
627 }
628
629 if (server->socketUseCount.counter > 1) {
630 if (memcmp(server->server_GUID,
631 pSMBr->u.extended_response.
632 GUID, 16) != 0) {
633 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000634 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000635 pSMBr->u.extended_response.GUID,
636 16);
637 }
638 } else
639 memcpy(server->server_GUID,
640 pSMBr->u.extended_response.GUID, 16);
641
642 if (count == 16) {
643 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000644 } else {
645 rc = decode_negTokenInit(pSMBr->u.extended_response.
646 SecurityBlob,
647 count - 16,
648 &server->secType);
Steve French790fe572007-07-07 19:25:05 +0000649 if (rc == 1) {
Steve French254e55e2006-06-04 05:53:15 +0000650 /* BB Need to fill struct for sessetup here */
651 rc = -EOPNOTSUPP;
652 } else {
653 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 }
Steve French254e55e2006-06-04 05:53:15 +0000656 } else
657 server->capabilities &= ~CAP_EXTENDED_SECURITY;
658
Steve French6344a422006-06-12 04:18:35 +0000659#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000660signing_check:
Steve French6344a422006-06-12 04:18:35 +0000661#endif
Steve French762e5ab2007-06-28 18:41:42 +0000662 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
663 /* MUST_SIGN already includes the MAY_SIGN FLAG
664 so if this is zero it means that signing is disabled */
665 cFYI(1, ("Signing disabled"));
Steve French790fe572007-07-07 19:25:05 +0000666 if (server->secMode & SECMODE_SIGN_REQUIRED)
Steve French762e5ab2007-06-28 18:41:42 +0000667 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000668 "packet signing to be enabled in "
669 "/proc/fs/cifs/SecurityFlags."));
Steve French50c2f752007-07-13 00:33:32 +0000670 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000671 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000672 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
673 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000674 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000675 if ((server->secMode &
676 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
677 cERROR(1,
678 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000679 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000680 } else
681 server->secMode |= SECMODE_SIGN_REQUIRED;
682 } else {
683 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000684 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000685 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000686 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 }
Steve French50c2f752007-07-13 00:33:32 +0000688
689neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700690 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000691
Steve French790fe572007-07-07 19:25:05 +0000692 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 return rc;
694}
695
696int
697CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
698{
699 struct smb_hdr *smb_buffer;
700 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
701 int rc = 0;
702 int length;
703
704 cFYI(1, ("In tree disconnect"));
705 /*
706 * If last user of the connection and
707 * connection alive - disconnect it
708 * If this is the last connection on the server session disconnect it
Steve French50c2f752007-07-13 00:33:32 +0000709 * (and inside session disconnect we should check if tcp socket needs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 * to be freed and kernel thread woken up).
711 */
712 if (tcon)
713 down(&tcon->tconSem);
714 else
715 return -EIO;
716
717 atomic_dec(&tcon->useCount);
718 if (atomic_read(&tcon->useCount) > 0) {
719 up(&tcon->tconSem);
720 return -EBUSY;
721 }
722
Steve French50c2f752007-07-13 00:33:32 +0000723 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 closed on server already e.g. due to tcp session crashing */
Steve French790fe572007-07-07 19:25:05 +0000725 if (tcon->tidStatus == CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 up(&tcon->tconSem);
Steve French50c2f752007-07-13 00:33:32 +0000727 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 }
729
Steve French790fe572007-07-07 19:25:05 +0000730 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 up(&tcon->tconSem);
732 return -EIO;
733 }
Steve French50c2f752007-07-13 00:33:32 +0000734 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700735 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 if (rc) {
737 up(&tcon->tconSem);
738 return rc;
739 } else {
740 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700741 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
743 &length, 0);
744 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700745 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
747 if (smb_buffer)
748 cifs_small_buf_release(smb_buffer);
749 up(&tcon->tconSem);
750
Steve French50c2f752007-07-13 00:33:32 +0000751 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 closed on server already e.g. due to tcp session crashing */
753 if (rc == -EAGAIN)
754 rc = 0;
755
756 return rc;
757}
758
759int
760CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
761{
762 struct smb_hdr *smb_buffer_response;
763 LOGOFF_ANDX_REQ *pSMB;
764 int rc = 0;
765 int length;
766
767 cFYI(1, ("In SMBLogoff for session disconnect"));
768 if (ses)
769 down(&ses->sesSem);
770 else
771 return -EIO;
772
773 atomic_dec(&ses->inUse);
774 if (atomic_read(&ses->inUse) > 0) {
775 up(&ses->sesSem);
776 return -EBUSY;
777 }
778 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
779 if (rc) {
780 up(&ses->sesSem);
781 return rc;
782 }
783
784 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
Steve French50c2f752007-07-13 00:33:32 +0000785
Steve French790fe572007-07-07 19:25:05 +0000786 if (ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700787 pSMB->hdr.Mid = GetNextMid(ses->server);
788
Steve French790fe572007-07-07 19:25:05 +0000789 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
791 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
792 }
793
794 pSMB->hdr.Uid = ses->Suid;
795
796 pSMB->AndXCommand = 0xFF;
797 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
798 smb_buffer_response, &length, 0);
799 if (ses->server) {
800 atomic_dec(&ses->server->socketUseCount);
801 if (atomic_read(&ses->server->socketUseCount) == 0) {
802 spin_lock(&GlobalMid_Lock);
803 ses->server->tcpStatus = CifsExiting;
804 spin_unlock(&GlobalMid_Lock);
805 rc = -ESHUTDOWN;
806 }
807 }
Steve Frencha59c6582005-08-17 12:12:19 -0700808 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700809 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
811 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000812 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 error */
814 if (rc == -EAGAIN)
815 rc = 0;
816 return rc;
817}
818
819int
Steve French2d785a52007-07-15 01:48:57 +0000820CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
821 __u16 type, const struct nls_table *nls_codepage, int remap)
822{
823 TRANSACTION2_SPI_REQ *pSMB = NULL;
824 TRANSACTION2_SPI_RSP *pSMBr = NULL;
825 struct unlink_psx_rq *pRqD;
826 int name_len;
827 int rc = 0;
828 int bytes_returned = 0;
829 __u16 params, param_offset, offset, byte_count;
830
831 cFYI(1, ("In POSIX delete"));
832PsxDelete:
833 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
834 (void **) &pSMBr);
835 if (rc)
836 return rc;
837
838 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
839 name_len =
840 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
841 PATH_MAX, nls_codepage, remap);
842 name_len++; /* trailing null */
843 name_len *= 2;
844 } else { /* BB add path length overrun check */
845 name_len = strnlen(fileName, PATH_MAX);
846 name_len++; /* trailing null */
847 strncpy(pSMB->FileName, fileName, name_len);
848 }
849
850 params = 6 + name_len;
851 pSMB->MaxParameterCount = cpu_to_le16(2);
852 pSMB->MaxDataCount = 0; /* BB double check this with jra */
853 pSMB->MaxSetupCount = 0;
854 pSMB->Reserved = 0;
855 pSMB->Flags = 0;
856 pSMB->Timeout = 0;
857 pSMB->Reserved2 = 0;
858 param_offset = offsetof(struct smb_com_transaction2_spi_req,
859 InformationLevel) - 4;
860 offset = param_offset + params;
861
862 /* Setup pointer to Request Data (inode type) */
863 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
864 pRqD->type = cpu_to_le16(type);
865 pSMB->ParameterOffset = cpu_to_le16(param_offset);
866 pSMB->DataOffset = cpu_to_le16(offset);
867 pSMB->SetupCount = 1;
868 pSMB->Reserved3 = 0;
869 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
870 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
871
872 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
873 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
874 pSMB->ParameterCount = cpu_to_le16(params);
875 pSMB->TotalParameterCount = pSMB->ParameterCount;
876 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
877 pSMB->Reserved4 = 0;
878 pSMB->hdr.smb_buf_length += byte_count;
879 pSMB->ByteCount = cpu_to_le16(byte_count);
880 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
881 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
882 if (rc) {
883 cFYI(1, ("Posix delete returned %d", rc));
884 }
885 cifs_buf_release(pSMB);
886
887 cifs_stats_inc(&tcon->num_deletes);
888
889 if (rc == -EAGAIN)
890 goto PsxDelete;
891
892 return rc;
893}
894
895int
Steve French737b7582005-04-28 22:41:06 -0700896CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
897 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898{
899 DELETE_FILE_REQ *pSMB = NULL;
900 DELETE_FILE_RSP *pSMBr = NULL;
901 int rc = 0;
902 int bytes_returned;
903 int name_len;
904
905DelFileRetry:
906 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
907 (void **) &pSMBr);
908 if (rc)
909 return rc;
910
911 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
912 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000913 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700914 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 name_len++; /* trailing null */
916 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700917 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 name_len = strnlen(fileName, PATH_MAX);
919 name_len++; /* trailing null */
920 strncpy(pSMB->fileName, fileName, name_len);
921 }
922 pSMB->SearchAttributes =
923 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
924 pSMB->BufferFormat = 0x04;
925 pSMB->hdr.smb_buf_length += name_len + 1;
926 pSMB->ByteCount = cpu_to_le16(name_len + 1);
927 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
928 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700929 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700930 if (rc) {
931 cFYI(1, ("Error in RMFile = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000932 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933
934 cifs_buf_release(pSMB);
935 if (rc == -EAGAIN)
936 goto DelFileRetry;
937
938 return rc;
939}
940
941int
Steve French50c2f752007-07-13 00:33:32 +0000942CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700943 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944{
945 DELETE_DIRECTORY_REQ *pSMB = NULL;
946 DELETE_DIRECTORY_RSP *pSMBr = NULL;
947 int rc = 0;
948 int bytes_returned;
949 int name_len;
950
951 cFYI(1, ("In CIFSSMBRmDir"));
952RmDirRetry:
953 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
954 (void **) &pSMBr);
955 if (rc)
956 return rc;
957
958 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700959 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
960 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961 name_len++; /* trailing null */
962 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700963 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 name_len = strnlen(dirName, PATH_MAX);
965 name_len++; /* trailing null */
966 strncpy(pSMB->DirName, dirName, name_len);
967 }
968
969 pSMB->BufferFormat = 0x04;
970 pSMB->hdr.smb_buf_length += name_len + 1;
971 pSMB->ByteCount = cpu_to_le16(name_len + 1);
972 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
973 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700974 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 if (rc) {
976 cFYI(1, ("Error in RMDir = %d", rc));
977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
979 cifs_buf_release(pSMB);
980 if (rc == -EAGAIN)
981 goto RmDirRetry;
982 return rc;
983}
984
985int
986CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700987 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988{
989 int rc = 0;
990 CREATE_DIRECTORY_REQ *pSMB = NULL;
991 CREATE_DIRECTORY_RSP *pSMBr = NULL;
992 int bytes_returned;
993 int name_len;
994
995 cFYI(1, ("In CIFSSMBMkDir"));
996MkDirRetry:
997 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
998 (void **) &pSMBr);
999 if (rc)
1000 return rc;
1001
1002 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00001003 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -07001004 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 name_len++; /* trailing null */
1006 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001007 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 name_len = strnlen(name, PATH_MAX);
1009 name_len++; /* trailing null */
1010 strncpy(pSMB->DirName, name, name_len);
1011 }
1012
1013 pSMB->BufferFormat = 0x04;
1014 pSMB->hdr.smb_buf_length += name_len + 1;
1015 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1016 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1017 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001018 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 if (rc) {
1020 cFYI(1, ("Error in Mkdir = %d", rc));
1021 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001022
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 cifs_buf_release(pSMB);
1024 if (rc == -EAGAIN)
1025 goto MkDirRetry;
1026 return rc;
1027}
1028
Steve French2dd29d32007-04-23 22:07:35 +00001029int
1030CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1031 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001032 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001033 const struct nls_table *nls_codepage, int remap)
1034{
1035 TRANSACTION2_SPI_REQ *pSMB = NULL;
1036 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1037 int name_len;
1038 int rc = 0;
1039 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001040 __u16 params, param_offset, offset, byte_count, count;
1041 OPEN_PSX_REQ * pdata;
1042 OPEN_PSX_RSP * psx_rsp;
1043
1044 cFYI(1, ("In POSIX Create"));
1045PsxCreat:
1046 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1047 (void **) &pSMBr);
1048 if (rc)
1049 return rc;
1050
1051 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1052 name_len =
1053 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1054 PATH_MAX, nls_codepage, remap);
1055 name_len++; /* trailing null */
1056 name_len *= 2;
1057 } else { /* BB improve the check for buffer overruns BB */
1058 name_len = strnlen(name, PATH_MAX);
1059 name_len++; /* trailing null */
1060 strncpy(pSMB->FileName, name, name_len);
1061 }
1062
1063 params = 6 + name_len;
1064 count = sizeof(OPEN_PSX_REQ);
1065 pSMB->MaxParameterCount = cpu_to_le16(2);
1066 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1067 pSMB->MaxSetupCount = 0;
1068 pSMB->Reserved = 0;
1069 pSMB->Flags = 0;
1070 pSMB->Timeout = 0;
1071 pSMB->Reserved2 = 0;
1072 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001073 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001074 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001075 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001076 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001077 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001078 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001079 pdata->OpenFlags = cpu_to_le32(*pOplock);
1080 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1081 pSMB->DataOffset = cpu_to_le16(offset);
1082 pSMB->SetupCount = 1;
1083 pSMB->Reserved3 = 0;
1084 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1085 byte_count = 3 /* pad */ + params + count;
1086
1087 pSMB->DataCount = cpu_to_le16(count);
1088 pSMB->ParameterCount = cpu_to_le16(params);
1089 pSMB->TotalDataCount = pSMB->DataCount;
1090 pSMB->TotalParameterCount = pSMB->ParameterCount;
1091 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1092 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001093 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001094 pSMB->ByteCount = cpu_to_le16(byte_count);
1095 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1096 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1097 if (rc) {
1098 cFYI(1, ("Posix create returned %d", rc));
1099 goto psx_create_err;
1100 }
1101
Steve French790fe572007-07-07 19:25:05 +00001102 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001103 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1104
1105 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1106 rc = -EIO; /* bad smb */
1107 goto psx_create_err;
1108 }
1109
1110 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001111 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001112 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001113
Steve French2dd29d32007-04-23 22:07:35 +00001114 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001115 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001116 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1117 /* Let caller know file was created so we can set the mode. */
1118 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001119 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001120 *pOplock |= CIFS_CREATE_ACTION;
1121 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001122 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1123 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001124#ifdef CONFIG_CIFS_DEBUG2
Steve French790fe572007-07-07 19:25:05 +00001125 cFYI(1, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001126#endif
1127 } else {
Steve French790fe572007-07-07 19:25:05 +00001128 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001129 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001130 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001131 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001132 goto psx_create_err;
1133 }
Steve French50c2f752007-07-13 00:33:32 +00001134 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001135 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001136 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001137 }
Steve French2dd29d32007-04-23 22:07:35 +00001138
1139psx_create_err:
1140 cifs_buf_release(pSMB);
1141
1142 cifs_stats_inc(&tcon->num_mkdirs);
1143
1144 if (rc == -EAGAIN)
1145 goto PsxCreat;
1146
Steve French50c2f752007-07-13 00:33:32 +00001147 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001148}
1149
Steve Frencha9d02ad2005-08-24 23:06:05 -07001150static __u16 convert_disposition(int disposition)
1151{
1152 __u16 ofun = 0;
1153
1154 switch (disposition) {
1155 case FILE_SUPERSEDE:
1156 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1157 break;
1158 case FILE_OPEN:
1159 ofun = SMBOPEN_OAPPEND;
1160 break;
1161 case FILE_CREATE:
1162 ofun = SMBOPEN_OCREATE;
1163 break;
1164 case FILE_OPEN_IF:
1165 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1166 break;
1167 case FILE_OVERWRITE:
1168 ofun = SMBOPEN_OTRUNC;
1169 break;
1170 case FILE_OVERWRITE_IF:
1171 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1172 break;
1173 default:
Steve French790fe572007-07-07 19:25:05 +00001174 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001175 ofun = SMBOPEN_OAPPEND; /* regular open */
1176 }
1177 return ofun;
1178}
1179
1180int
1181SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1182 const char *fileName, const int openDisposition,
1183 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001184 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001185 const struct nls_table *nls_codepage, int remap)
1186{
1187 int rc = -EACCES;
1188 OPENX_REQ *pSMB = NULL;
1189 OPENX_RSP *pSMBr = NULL;
1190 int bytes_returned;
1191 int name_len;
1192 __u16 count;
1193
1194OldOpenRetry:
1195 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1196 (void **) &pSMBr);
1197 if (rc)
1198 return rc;
1199
1200 pSMB->AndXCommand = 0xFF; /* none */
1201
1202 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1203 count = 1; /* account for one byte pad to word boundary */
1204 name_len =
1205 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1206 fileName, PATH_MAX, nls_codepage, remap);
1207 name_len++; /* trailing null */
1208 name_len *= 2;
1209 } else { /* BB improve check for buffer overruns BB */
1210 count = 0; /* no pad */
1211 name_len = strnlen(fileName, PATH_MAX);
1212 name_len++; /* trailing null */
1213 strncpy(pSMB->fileName, fileName, name_len);
1214 }
1215 if (*pOplock & REQ_OPLOCK)
1216 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001217 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001218 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001219
Steve Frencha9d02ad2005-08-24 23:06:05 -07001220 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1221 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1222 /* 0 = read
1223 1 = write
1224 2 = rw
1225 3 = execute
Steve French50c2f752007-07-13 00:33:32 +00001226 */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001227 pSMB->Mode = cpu_to_le16(2);
1228 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1229 /* set file as system file if special file such
1230 as fifo and server expecting SFU style and
1231 no Unix extensions */
1232
Steve French790fe572007-07-07 19:25:05 +00001233 if (create_options & CREATE_OPTION_SPECIAL)
1234 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1235 else
Steve French3e87d802005-09-18 20:49:21 -07001236 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001237
1238 /* if ((omode & S_IWUGO) == 0)
1239 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1240 /* Above line causes problems due to vfs splitting create into two
1241 pieces - need to set mode after file created not while it is
1242 being created */
1243
1244 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001245/* pSMB->CreateOptions = cpu_to_le32(create_options &
1246 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001248
1249 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001250 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001251 count += name_len;
1252 pSMB->hdr.smb_buf_length += count;
1253
1254 pSMB->ByteCount = cpu_to_le16(count);
1255 /* long_op set to 1 to allow for oplock break timeouts */
1256 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00001257 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001258 cifs_stats_inc(&tcon->num_opens);
1259 if (rc) {
1260 cFYI(1, ("Error in Open = %d", rc));
1261 } else {
1262 /* BB verify if wct == 15 */
1263
1264/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1265
1266 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1267 /* Let caller know file was created so we can set the mode. */
1268 /* Do we care about the CreateAction in any other cases? */
1269 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001270/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001271 *pOplock |= CIFS_CREATE_ACTION; */
1272 /* BB FIXME END */
1273
Steve French790fe572007-07-07 19:25:05 +00001274 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001275 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1276 pfile_info->LastAccessTime = 0; /* BB fixme */
1277 pfile_info->LastWriteTime = 0; /* BB fixme */
1278 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001279 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001280 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001281 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001282 pfile_info->AllocationSize =
1283 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1284 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001285 pfile_info->NumberOfLinks = cpu_to_le32(1);
1286 }
1287 }
1288
1289 cifs_buf_release(pSMB);
1290 if (rc == -EAGAIN)
1291 goto OldOpenRetry;
1292 return rc;
1293}
1294
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295int
1296CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1297 const char *fileName, const int openDisposition,
1298 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001299 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001300 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301{
1302 int rc = -EACCES;
1303 OPEN_REQ *pSMB = NULL;
1304 OPEN_RSP *pSMBr = NULL;
1305 int bytes_returned;
1306 int name_len;
1307 __u16 count;
1308
1309openRetry:
1310 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1311 (void **) &pSMBr);
1312 if (rc)
1313 return rc;
1314
1315 pSMB->AndXCommand = 0xFF; /* none */
1316
1317 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1318 count = 1; /* account for one byte pad to word boundary */
1319 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001320 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001321 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 name_len++; /* trailing null */
1323 name_len *= 2;
1324 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001325 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 count = 0; /* no pad */
1327 name_len = strnlen(fileName, PATH_MAX);
1328 name_len++; /* trailing null */
1329 pSMB->NameLength = cpu_to_le16(name_len);
1330 strncpy(pSMB->fileName, fileName, name_len);
1331 }
1332 if (*pOplock & REQ_OPLOCK)
1333 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001334 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001335 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1337 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001338 /* set file as system file if special file such
1339 as fifo and server expecting SFU style and
1340 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001341 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001342 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1343 else
1344 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 /* XP does not handle ATTR_POSIX_SEMANTICS */
1346 /* but it helps speed up case sensitive checks for other
1347 servers such as Samba */
1348 if (tcon->ses->capabilities & CAP_UNIX)
1349 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1350
1351 /* if ((omode & S_IWUGO) == 0)
1352 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1353 /* Above line causes problems due to vfs splitting create into two
1354 pieces - need to set mode after file created not while it is
1355 being created */
1356 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1357 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001358 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001359 /* BB Expirement with various impersonation levels and verify */
1360 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 pSMB->SecurityFlags =
1362 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1363
1364 count += name_len;
1365 pSMB->hdr.smb_buf_length += count;
1366
1367 pSMB->ByteCount = cpu_to_le16(count);
1368 /* long_op set to 1 to allow for oplock break timeouts */
1369 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1370 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001371 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 if (rc) {
1373 cFYI(1, ("Error in Open = %d", rc));
1374 } else {
Steve French09d1db52005-04-28 22:41:08 -07001375 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1377 /* Let caller know file was created so we can set the mode. */
1378 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001379 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001380 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001381 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001382 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 36 /* CreationTime to Attributes */);
1384 /* the file_info buf is endian converted by caller */
1385 pfile_info->AllocationSize = pSMBr->AllocationSize;
1386 pfile_info->EndOfFile = pSMBr->EndOfFile;
1387 pfile_info->NumberOfLinks = cpu_to_le32(1);
1388 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001390
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 cifs_buf_release(pSMB);
1392 if (rc == -EAGAIN)
1393 goto openRetry;
1394 return rc;
1395}
1396
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397int
Steve French50c2f752007-07-13 00:33:32 +00001398CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1399 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1400 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401{
1402 int rc = -EACCES;
1403 READ_REQ *pSMB = NULL;
1404 READ_RSP *pSMBr = NULL;
1405 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001406 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001407 int resp_buf_type = 0;
1408 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409
Steve French790fe572007-07-07 19:25:05 +00001410 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1411 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001412 wct = 12;
1413 else
1414 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415
1416 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001417 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418 if (rc)
1419 return rc;
1420
1421 /* tcon and ses pointer are checked in smb_init */
1422 if (tcon->ses->server == NULL)
1423 return -ECONNABORTED;
1424
Steve Frenchec637e32005-12-12 20:53:18 -08001425 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001426 pSMB->Fid = netfid;
1427 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001428 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001429 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001430 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001431 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001432
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433 pSMB->Remaining = 0;
1434 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1435 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001436 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001437 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1438 else {
1439 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001440 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001441 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001442 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001443 }
Steve Frenchec637e32005-12-12 20:53:18 -08001444
1445 iov[0].iov_base = (char *)pSMB;
1446 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve French50c2f752007-07-13 00:33:32 +00001447 rc = SendReceive2(xid, tcon->ses, iov,
Steve Frenchec637e32005-12-12 20:53:18 -08001448 1 /* num iovecs */,
Steve French50c2f752007-07-13 00:33:32 +00001449 &resp_buf_type, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001450 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001451 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 if (rc) {
1453 cERROR(1, ("Send error in read = %d", rc));
1454 } else {
1455 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1456 data_length = data_length << 16;
1457 data_length += le16_to_cpu(pSMBr->DataLength);
1458 *nbytes = data_length;
1459
1460 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001461 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001463 cFYI(1, ("bad length %d for count %d",
1464 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 rc = -EIO;
1466 *nbytes = 0;
1467 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001468 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001469 le16_to_cpu(pSMBr->DataOffset);
1470/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001471 cERROR(1,("Faulting on read rc = %d",rc));
1472 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001473 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001474 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001475 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 }
1477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001478
Steve French4b8f9302006-02-26 16:41:18 +00001479/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001480 if (*buf) {
1481 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001482 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001483 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001484 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001485 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001486 /* return buffer to caller to free */
1487 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001488 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001489 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001490 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001491 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001492 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001493
1494 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 since file handle passed in no longer valid */
1496 return rc;
1497}
1498
Steve Frenchec637e32005-12-12 20:53:18 -08001499
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500int
1501CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1502 const int netfid, const unsigned int count,
1503 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001504 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505{
1506 int rc = -EACCES;
1507 WRITE_REQ *pSMB = NULL;
1508 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001509 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 __u32 bytes_sent;
1511 __u16 byte_count;
1512
1513 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001514 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001515 return -ECONNABORTED;
1516
Steve French790fe572007-07-07 19:25:05 +00001517 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001518 wct = 14;
1519 else
1520 wct = 12;
1521
1522 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 (void **) &pSMBr);
1524 if (rc)
1525 return rc;
1526 /* tcon and ses pointer are checked in smb_init */
1527 if (tcon->ses->server == NULL)
1528 return -ECONNABORTED;
1529
1530 pSMB->AndXCommand = 0xFF; /* none */
1531 pSMB->Fid = netfid;
1532 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001533 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001534 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001535 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001536 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001537
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 pSMB->Reserved = 0xFFFFFFFF;
1539 pSMB->WriteMode = 0;
1540 pSMB->Remaining = 0;
1541
Steve French50c2f752007-07-13 00:33:32 +00001542 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 can send more if LARGE_WRITE_X capability returned by the server and if
1544 our buffer is big enough or if we convert to iovecs on socket writes
1545 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001546 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1548 } else {
1549 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1550 & ~0xFF;
1551 }
1552
1553 if (bytes_sent > count)
1554 bytes_sent = count;
1555 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001556 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001557 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001558 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001559 else if (ubuf) {
1560 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 cifs_buf_release(pSMB);
1562 return -EFAULT;
1563 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001564 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 /* No buffer */
1566 cifs_buf_release(pSMB);
1567 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001568 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001569 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001570 byte_count = bytes_sent + 1; /* pad */
1571 else /* wct == 12 */ {
1572 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1575 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001576 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001577
Steve French790fe572007-07-07 19:25:05 +00001578 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001579 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001580 else { /* old style write has byte count 4 bytes earlier
1581 so 4 bytes pad */
1582 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001583 (struct smb_com_writex_req *)pSMB;
1584 pSMBW->ByteCount = cpu_to_le16(byte_count);
1585 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586
1587 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1588 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001589 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 if (rc) {
1591 cFYI(1, ("Send error in write = %d", rc));
1592 *nbytes = 0;
1593 } else {
1594 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1595 *nbytes = (*nbytes) << 16;
1596 *nbytes += le16_to_cpu(pSMBr->Count);
1597 }
1598
1599 cifs_buf_release(pSMB);
1600
Steve French50c2f752007-07-13 00:33:32 +00001601 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 since file handle passed in no longer valid */
1603
1604 return rc;
1605}
1606
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001607int
1608CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001609 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001610 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1611 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612{
1613 int rc = -EACCES;
1614 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001615 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001616 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001617 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618
Steve French790fe572007-07-07 19:25:05 +00001619 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001620
Steve French790fe572007-07-07 19:25:05 +00001621 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001622 wct = 14;
1623 else
1624 wct = 12;
1625 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 if (rc)
1627 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 /* tcon and ses pointer are checked in smb_init */
1629 if (tcon->ses->server == NULL)
1630 return -ECONNABORTED;
1631
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001632 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 pSMB->Fid = netfid;
1634 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001635 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001636 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001637 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001638 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 pSMB->Reserved = 0xFFFFFFFF;
1640 pSMB->WriteMode = 0;
1641 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001642
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001644 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
Steve French3e844692005-10-03 13:37:24 -07001646 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1647 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001648 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001649 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001650 pSMB->hdr.smb_buf_length += count+1;
1651 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001652 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1653 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001654 pSMB->ByteCount = cpu_to_le16(count + 1);
1655 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001656 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001657 (struct smb_com_writex_req *)pSMB;
1658 pSMBW->ByteCount = cpu_to_le16(count + 5);
1659 }
Steve French3e844692005-10-03 13:37:24 -07001660 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001661 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001662 iov[0].iov_len = smb_hdr_len + 4;
1663 else /* wct == 12 pad bigger by four bytes */
1664 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001665
Steve French3e844692005-10-03 13:37:24 -07001666
Steve Frenchec637e32005-12-12 20:53:18 -08001667 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French3e844692005-10-03 13:37:24 -07001668 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001669 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001671 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001673 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001674 /* presumably this can not happen, but best to be safe */
1675 rc = -EIO;
1676 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001677 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001678 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001679 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1680 *nbytes = (*nbytes) << 16;
1681 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001682 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683
Steve French4b8f9302006-02-26 16:41:18 +00001684/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001685 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001686 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001687 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001688 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689
Steve French50c2f752007-07-13 00:33:32 +00001690 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 since file handle passed in no longer valid */
1692
1693 return rc;
1694}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001695
1696
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697int
1698CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1699 const __u16 smb_file_id, const __u64 len,
1700 const __u64 offset, const __u32 numUnlock,
1701 const __u32 numLock, const __u8 lockType, const int waitFlag)
1702{
1703 int rc = 0;
1704 LOCK_REQ *pSMB = NULL;
1705 LOCK_RSP *pSMBr = NULL;
1706 int bytes_returned;
1707 int timeout = 0;
1708 __u16 count;
1709
Steve French50c2f752007-07-13 00:33:32 +00001710 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001711 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1712
Linus Torvalds1da177e2005-04-16 15:20:36 -07001713 if (rc)
1714 return rc;
1715
Steve French46810cb2005-04-28 22:41:09 -07001716 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1717
Steve French790fe572007-07-07 19:25:05 +00001718 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719 timeout = -1; /* no response expected */
1720 pSMB->Timeout = 0;
1721 } else if (waitFlag == TRUE) {
1722 timeout = 3; /* blocking operation, no timeout */
1723 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1724 } else {
1725 pSMB->Timeout = 0;
1726 }
1727
1728 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1729 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1730 pSMB->LockType = lockType;
1731 pSMB->AndXCommand = 0xFF; /* none */
1732 pSMB->Fid = smb_file_id; /* netfid stays le */
1733
Steve French790fe572007-07-07 19:25:05 +00001734 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1736 /* BB where to store pid high? */
1737 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1738 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1739 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1740 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1741 count = sizeof(LOCKING_ANDX_RANGE);
1742 } else {
1743 /* oplock break */
1744 count = 0;
1745 }
1746 pSMB->hdr.smb_buf_length += count;
1747 pSMB->ByteCount = cpu_to_le16(count);
1748
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001749 if (waitFlag) {
1750 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1751 (struct smb_hdr *) pSMBr, &bytes_returned);
1752 } else {
1753 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001755 }
Steve Frencha4544342005-08-24 13:59:35 -07001756 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 if (rc) {
1758 cFYI(1, ("Send error in Lock = %d", rc));
1759 }
Steve French46810cb2005-04-28 22:41:09 -07001760 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761
Steve French50c2f752007-07-13 00:33:32 +00001762 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001763 since file handle passed in no longer valid */
1764 return rc;
1765}
1766
1767int
Steve French08547b02006-02-28 22:39:25 +00001768CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1769 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001770 struct file_lock *pLockData, const __u16 lock_type,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001771 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001772{
1773 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1774 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001775 struct cifs_posix_lock *parm_data;
1776 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001777 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001778 int bytes_returned = 0;
1779 __u16 params, param_offset, offset, byte_count, count;
1780
1781 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001782
Steve French790fe572007-07-07 19:25:05 +00001783 if (pLockData == NULL)
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001784 return EINVAL;
1785
Steve French08547b02006-02-28 22:39:25 +00001786 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1787
1788 if (rc)
1789 return rc;
1790
1791 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1792
Steve French50c2f752007-07-13 00:33:32 +00001793 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001794 pSMB->MaxSetupCount = 0;
1795 pSMB->Reserved = 0;
1796 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001797 pSMB->Reserved2 = 0;
1798 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1799 offset = param_offset + params;
1800
Steve French08547b02006-02-28 22:39:25 +00001801 count = sizeof(struct cifs_posix_lock);
1802 pSMB->MaxParameterCount = cpu_to_le16(2);
1803 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1804 pSMB->SetupCount = 1;
1805 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001806 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001807 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1808 else
1809 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1810 byte_count = 3 /* pad */ + params + count;
1811 pSMB->DataCount = cpu_to_le16(count);
1812 pSMB->ParameterCount = cpu_to_le16(params);
1813 pSMB->TotalDataCount = pSMB->DataCount;
1814 pSMB->TotalParameterCount = pSMB->ParameterCount;
1815 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001816 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001817 (((char *) &pSMB->hdr.Protocol) + offset);
1818
1819 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001820 if (waitFlag) {
Steve French3a5ff612006-07-14 22:37:11 +00001821 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001822 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001823 pSMB->Timeout = cpu_to_le32(-1);
1824 } else
1825 pSMB->Timeout = 0;
1826
Steve French08547b02006-02-28 22:39:25 +00001827 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001828 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001829 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001830
1831 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001832 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001833 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1834 pSMB->Reserved4 = 0;
1835 pSMB->hdr.smb_buf_length += byte_count;
1836 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001837 if (waitFlag) {
1838 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1839 (struct smb_hdr *) pSMBr, &bytes_returned);
1840 } else {
1841 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001842 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001843 }
1844
Steve French08547b02006-02-28 22:39:25 +00001845 if (rc) {
1846 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001847 } else if (get_flag) {
1848 /* lock structure can be returned on get */
1849 __u16 data_offset;
1850 __u16 data_count;
1851 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001852
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001853 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1854 rc = -EIO; /* bad smb */
1855 goto plk_err_exit;
1856 }
Steve French790fe572007-07-07 19:25:05 +00001857 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001858 rc = -EINVAL;
1859 goto plk_err_exit;
1860 }
1861 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1862 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001863 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001864 rc = -EIO;
1865 goto plk_err_exit;
1866 }
1867 parm_data = (struct cifs_posix_lock *)
1868 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001869 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001870 pLockData->fl_type = F_UNLCK;
1871 }
Steve French50c2f752007-07-13 00:33:32 +00001872
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001873plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001874 if (pSMB)
1875 cifs_small_buf_release(pSMB);
1876
1877 /* Note: On -EAGAIN error only caller can retry on handle based calls
1878 since file handle passed in no longer valid */
1879
1880 return rc;
1881}
1882
1883
1884int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1886{
1887 int rc = 0;
1888 CLOSE_REQ *pSMB = NULL;
1889 CLOSE_RSP *pSMBr = NULL;
1890 int bytes_returned;
1891 cFYI(1, ("In CIFSSMBClose"));
1892
1893/* do not retry on dead session on close */
1894 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001895 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 return 0;
1897 if (rc)
1898 return rc;
1899
1900 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1901
1902 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001903 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 pSMB->ByteCount = 0;
1905 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1906 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001907 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001909 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 /* EINTR is expected when user ctl-c to kill app */
1911 cERROR(1, ("Send error in Close = %d", rc));
1912 }
1913 }
1914
1915 cifs_small_buf_release(pSMB);
1916
1917 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001918 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919 rc = 0;
1920
1921 return rc;
1922}
1923
1924int
1925CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1926 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001927 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928{
1929 int rc = 0;
1930 RENAME_REQ *pSMB = NULL;
1931 RENAME_RSP *pSMBr = NULL;
1932 int bytes_returned;
1933 int name_len, name_len2;
1934 __u16 count;
1935
1936 cFYI(1, ("In CIFSSMBRename"));
1937renameRetry:
1938 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1939 (void **) &pSMBr);
1940 if (rc)
1941 return rc;
1942
1943 pSMB->BufferFormat = 0x04;
1944 pSMB->SearchAttributes =
1945 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1946 ATTR_DIRECTORY);
1947
1948 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1949 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001950 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001951 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 name_len++; /* trailing null */
1953 name_len *= 2;
1954 pSMB->OldFileName[name_len] = 0x04; /* pad */
1955 /* protocol requires ASCII signature byte on Unicode string */
1956 pSMB->OldFileName[name_len + 1] = 0x00;
1957 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001958 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001959 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1961 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001962 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 name_len = strnlen(fromName, PATH_MAX);
1964 name_len++; /* trailing null */
1965 strncpy(pSMB->OldFileName, fromName, name_len);
1966 name_len2 = strnlen(toName, PATH_MAX);
1967 name_len2++; /* trailing null */
1968 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1969 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1970 name_len2++; /* trailing null */
1971 name_len2++; /* signature byte */
1972 }
1973
1974 count = 1 /* 1st signature byte */ + name_len + name_len2;
1975 pSMB->hdr.smb_buf_length += count;
1976 pSMB->ByteCount = cpu_to_le16(count);
1977
1978 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1979 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001980 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981 if (rc) {
1982 cFYI(1, ("Send error in rename = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +00001983 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 cifs_buf_release(pSMB);
1986
1987 if (rc == -EAGAIN)
1988 goto renameRetry;
1989
1990 return rc;
1991}
1992
Steve French50c2f752007-07-13 00:33:32 +00001993int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1994 int netfid, char *target_name,
1995 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996{
1997 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1998 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001999 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000 char *data_offset;
2001 char dummy_string[30];
2002 int rc = 0;
2003 int bytes_returned = 0;
2004 int len_of_str;
2005 __u16 params, param_offset, offset, count, byte_count;
2006
2007 cFYI(1, ("Rename to File by handle"));
2008 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2009 (void **) &pSMBr);
2010 if (rc)
2011 return rc;
2012
2013 params = 6;
2014 pSMB->MaxSetupCount = 0;
2015 pSMB->Reserved = 0;
2016 pSMB->Flags = 0;
2017 pSMB->Timeout = 0;
2018 pSMB->Reserved2 = 0;
2019 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2020 offset = param_offset + params;
2021
2022 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2023 rename_info = (struct set_file_rename *) data_offset;
2024 pSMB->MaxParameterCount = cpu_to_le16(2);
2025 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
2026 pSMB->SetupCount = 1;
2027 pSMB->Reserved3 = 0;
2028 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2029 byte_count = 3 /* pad */ + params;
2030 pSMB->ParameterCount = cpu_to_le16(params);
2031 pSMB->TotalParameterCount = pSMB->ParameterCount;
2032 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2033 pSMB->DataOffset = cpu_to_le16(offset);
2034 /* construct random name ".cifs_tmp<inodenum><mid>" */
2035 rename_info->overwrite = cpu_to_le32(1);
2036 rename_info->root_fid = 0;
2037 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002038 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002039 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2040 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002041 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002042 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002043 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002044 target_name, PATH_MAX, nls_codepage,
2045 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 }
2047 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2048 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2049 byte_count += count;
2050 pSMB->DataCount = cpu_to_le16(count);
2051 pSMB->TotalDataCount = pSMB->DataCount;
2052 pSMB->Fid = netfid;
2053 pSMB->InformationLevel =
2054 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2055 pSMB->Reserved4 = 0;
2056 pSMB->hdr.smb_buf_length += byte_count;
2057 pSMB->ByteCount = cpu_to_le16(byte_count);
2058 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002059 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002060 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002062 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 }
Steve Frencha5a2b482005-08-20 21:42:53 -07002064
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065 cifs_buf_release(pSMB);
2066
2067 /* Note: On -EAGAIN error only caller can retry on handle based calls
2068 since file handle passed in no longer valid */
2069
2070 return rc;
2071}
2072
2073int
Steve French50c2f752007-07-13 00:33:32 +00002074CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2075 const __u16 target_tid, const char *toName, const int flags,
2076 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077{
2078 int rc = 0;
2079 COPY_REQ *pSMB = NULL;
2080 COPY_RSP *pSMBr = NULL;
2081 int bytes_returned;
2082 int name_len, name_len2;
2083 __u16 count;
2084
2085 cFYI(1, ("In CIFSSMBCopy"));
2086copyRetry:
2087 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2088 (void **) &pSMBr);
2089 if (rc)
2090 return rc;
2091
2092 pSMB->BufferFormat = 0x04;
2093 pSMB->Tid2 = target_tid;
2094
2095 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2096
2097 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002098 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002099 fromName, PATH_MAX, nls_codepage,
2100 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101 name_len++; /* trailing null */
2102 name_len *= 2;
2103 pSMB->OldFileName[name_len] = 0x04; /* pad */
2104 /* protocol requires ASCII signature byte on Unicode string */
2105 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002106 name_len2 =
2107 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002108 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2110 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002111 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112 name_len = strnlen(fromName, PATH_MAX);
2113 name_len++; /* trailing null */
2114 strncpy(pSMB->OldFileName, fromName, name_len);
2115 name_len2 = strnlen(toName, PATH_MAX);
2116 name_len2++; /* trailing null */
2117 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2118 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2119 name_len2++; /* trailing null */
2120 name_len2++; /* signature byte */
2121 }
2122
2123 count = 1 /* 1st signature byte */ + name_len + name_len2;
2124 pSMB->hdr.smb_buf_length += count;
2125 pSMB->ByteCount = cpu_to_le16(count);
2126
2127 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2128 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2129 if (rc) {
2130 cFYI(1, ("Send error in copy = %d with %d files copied",
2131 rc, le16_to_cpu(pSMBr->CopyCount)));
2132 }
2133 if (pSMB)
2134 cifs_buf_release(pSMB);
2135
2136 if (rc == -EAGAIN)
2137 goto copyRetry;
2138
2139 return rc;
2140}
2141
2142int
2143CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2144 const char *fromName, const char *toName,
2145 const struct nls_table *nls_codepage)
2146{
2147 TRANSACTION2_SPI_REQ *pSMB = NULL;
2148 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2149 char *data_offset;
2150 int name_len;
2151 int name_len_target;
2152 int rc = 0;
2153 int bytes_returned = 0;
2154 __u16 params, param_offset, offset, byte_count;
2155
2156 cFYI(1, ("In Symlink Unix style"));
2157createSymLinkRetry:
2158 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2159 (void **) &pSMBr);
2160 if (rc)
2161 return rc;
2162
2163 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2164 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002165 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 /* find define for this maxpathcomponent */
2167 , nls_codepage);
2168 name_len++; /* trailing null */
2169 name_len *= 2;
2170
Steve French50c2f752007-07-13 00:33:32 +00002171 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 name_len = strnlen(fromName, PATH_MAX);
2173 name_len++; /* trailing null */
2174 strncpy(pSMB->FileName, fromName, name_len);
2175 }
2176 params = 6 + name_len;
2177 pSMB->MaxSetupCount = 0;
2178 pSMB->Reserved = 0;
2179 pSMB->Flags = 0;
2180 pSMB->Timeout = 0;
2181 pSMB->Reserved2 = 0;
2182 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002183 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 offset = param_offset + params;
2185
2186 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2187 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2188 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002189 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190 /* find define for this maxpathcomponent */
2191 , nls_codepage);
2192 name_len_target++; /* trailing null */
2193 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002194 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002195 name_len_target = strnlen(toName, PATH_MAX);
2196 name_len_target++; /* trailing null */
2197 strncpy(data_offset, toName, name_len_target);
2198 }
2199
2200 pSMB->MaxParameterCount = cpu_to_le16(2);
2201 /* BB find exact max on data count below from sess */
2202 pSMB->MaxDataCount = cpu_to_le16(1000);
2203 pSMB->SetupCount = 1;
2204 pSMB->Reserved3 = 0;
2205 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2206 byte_count = 3 /* pad */ + params + name_len_target;
2207 pSMB->DataCount = cpu_to_le16(name_len_target);
2208 pSMB->ParameterCount = cpu_to_le16(params);
2209 pSMB->TotalDataCount = pSMB->DataCount;
2210 pSMB->TotalParameterCount = pSMB->ParameterCount;
2211 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2212 pSMB->DataOffset = cpu_to_le16(offset);
2213 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2214 pSMB->Reserved4 = 0;
2215 pSMB->hdr.smb_buf_length += byte_count;
2216 pSMB->ByteCount = cpu_to_le16(byte_count);
2217 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2218 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002219 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 if (rc) {
Steve French2d785a52007-07-15 01:48:57 +00002221 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 }
2223
2224 if (pSMB)
2225 cifs_buf_release(pSMB);
2226
2227 if (rc == -EAGAIN)
2228 goto createSymLinkRetry;
2229
2230 return rc;
2231}
2232
2233int
2234CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2235 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002236 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002237{
2238 TRANSACTION2_SPI_REQ *pSMB = NULL;
2239 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2240 char *data_offset;
2241 int name_len;
2242 int name_len_target;
2243 int rc = 0;
2244 int bytes_returned = 0;
2245 __u16 params, param_offset, offset, byte_count;
2246
2247 cFYI(1, ("In Create Hard link Unix style"));
2248createHardLinkRetry:
2249 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2250 (void **) &pSMBr);
2251 if (rc)
2252 return rc;
2253
2254 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002255 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002256 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002257 name_len++; /* trailing null */
2258 name_len *= 2;
2259
Steve French50c2f752007-07-13 00:33:32 +00002260 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002261 name_len = strnlen(toName, PATH_MAX);
2262 name_len++; /* trailing null */
2263 strncpy(pSMB->FileName, toName, name_len);
2264 }
2265 params = 6 + name_len;
2266 pSMB->MaxSetupCount = 0;
2267 pSMB->Reserved = 0;
2268 pSMB->Flags = 0;
2269 pSMB->Timeout = 0;
2270 pSMB->Reserved2 = 0;
2271 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002272 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273 offset = param_offset + params;
2274
2275 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2276 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2277 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002278 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002279 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280 name_len_target++; /* trailing null */
2281 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002282 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002283 name_len_target = strnlen(fromName, PATH_MAX);
2284 name_len_target++; /* trailing null */
2285 strncpy(data_offset, fromName, name_len_target);
2286 }
2287
2288 pSMB->MaxParameterCount = cpu_to_le16(2);
2289 /* BB find exact max on data count below from sess*/
2290 pSMB->MaxDataCount = cpu_to_le16(1000);
2291 pSMB->SetupCount = 1;
2292 pSMB->Reserved3 = 0;
2293 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2294 byte_count = 3 /* pad */ + params + name_len_target;
2295 pSMB->ParameterCount = cpu_to_le16(params);
2296 pSMB->TotalParameterCount = pSMB->ParameterCount;
2297 pSMB->DataCount = cpu_to_le16(name_len_target);
2298 pSMB->TotalDataCount = pSMB->DataCount;
2299 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2300 pSMB->DataOffset = cpu_to_le16(offset);
2301 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2302 pSMB->Reserved4 = 0;
2303 pSMB->hdr.smb_buf_length += byte_count;
2304 pSMB->ByteCount = cpu_to_le16(byte_count);
2305 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2306 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002307 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002308 if (rc) {
2309 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2310 }
2311
2312 cifs_buf_release(pSMB);
2313 if (rc == -EAGAIN)
2314 goto createHardLinkRetry;
2315
2316 return rc;
2317}
2318
2319int
2320CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2321 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002322 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323{
2324 int rc = 0;
2325 NT_RENAME_REQ *pSMB = NULL;
2326 RENAME_RSP *pSMBr = NULL;
2327 int bytes_returned;
2328 int name_len, name_len2;
2329 __u16 count;
2330
2331 cFYI(1, ("In CIFSCreateHardLink"));
2332winCreateHardLinkRetry:
2333
2334 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2335 (void **) &pSMBr);
2336 if (rc)
2337 return rc;
2338
2339 pSMB->SearchAttributes =
2340 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2341 ATTR_DIRECTORY);
2342 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2343 pSMB->ClusterCount = 0;
2344
2345 pSMB->BufferFormat = 0x04;
2346
2347 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2348 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002349 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002350 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002351 name_len++; /* trailing null */
2352 name_len *= 2;
2353 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002354 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002356 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002357 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2359 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002360 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361 name_len = strnlen(fromName, PATH_MAX);
2362 name_len++; /* trailing null */
2363 strncpy(pSMB->OldFileName, fromName, name_len);
2364 name_len2 = strnlen(toName, PATH_MAX);
2365 name_len2++; /* trailing null */
2366 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2367 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2368 name_len2++; /* trailing null */
2369 name_len2++; /* signature byte */
2370 }
2371
2372 count = 1 /* string type byte */ + name_len + name_len2;
2373 pSMB->hdr.smb_buf_length += count;
2374 pSMB->ByteCount = cpu_to_le16(count);
2375
2376 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2377 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002378 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 if (rc) {
2380 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2381 }
2382 cifs_buf_release(pSMB);
2383 if (rc == -EAGAIN)
2384 goto winCreateHardLinkRetry;
2385
2386 return rc;
2387}
2388
2389int
2390CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2391 const unsigned char *searchName,
2392 char *symlinkinfo, const int buflen,
2393 const struct nls_table *nls_codepage)
2394{
2395/* SMB_QUERY_FILE_UNIX_LINK */
2396 TRANSACTION2_QPI_REQ *pSMB = NULL;
2397 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2398 int rc = 0;
2399 int bytes_returned;
2400 int name_len;
2401 __u16 params, byte_count;
2402
2403 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2404
2405querySymLinkRetry:
2406 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2407 (void **) &pSMBr);
2408 if (rc)
2409 return rc;
2410
2411 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2412 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002413 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2414 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002415 name_len++; /* trailing null */
2416 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002417 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418 name_len = strnlen(searchName, PATH_MAX);
2419 name_len++; /* trailing null */
2420 strncpy(pSMB->FileName, searchName, name_len);
2421 }
2422
2423 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2424 pSMB->TotalDataCount = 0;
2425 pSMB->MaxParameterCount = cpu_to_le16(2);
2426 /* BB find exact max data count below from sess structure BB */
2427 pSMB->MaxDataCount = cpu_to_le16(4000);
2428 pSMB->MaxSetupCount = 0;
2429 pSMB->Reserved = 0;
2430 pSMB->Flags = 0;
2431 pSMB->Timeout = 0;
2432 pSMB->Reserved2 = 0;
2433 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002434 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 pSMB->DataCount = 0;
2436 pSMB->DataOffset = 0;
2437 pSMB->SetupCount = 1;
2438 pSMB->Reserved3 = 0;
2439 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2440 byte_count = params + 1 /* pad */ ;
2441 pSMB->TotalParameterCount = cpu_to_le16(params);
2442 pSMB->ParameterCount = pSMB->TotalParameterCount;
2443 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2444 pSMB->Reserved4 = 0;
2445 pSMB->hdr.smb_buf_length += byte_count;
2446 pSMB->ByteCount = cpu_to_le16(byte_count);
2447
2448 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2449 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2450 if (rc) {
2451 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2452 } else {
2453 /* decode response */
2454
2455 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2456 if (rc || (pSMBr->ByteCount < 2))
2457 /* BB also check enough total bytes returned */
2458 rc = -EIO; /* bad smb */
2459 else {
2460 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2461 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2462
2463 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2464 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002465 &pSMBr->hdr.Protocol + data_offset),
2466 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002467 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002468 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002469 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2470 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 name_len, nls_codepage);
2472 } else {
2473 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002474 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 data_offset,
2476 min_t(const int, buflen, count));
2477 }
2478 symlinkinfo[buflen] = 0;
2479 /* just in case so calling code does not go off the end of buffer */
2480 }
2481 }
2482 cifs_buf_release(pSMB);
2483 if (rc == -EAGAIN)
2484 goto querySymLinkRetry;
2485 return rc;
2486}
2487
Steve French0a4b92c2006-01-12 15:44:21 -08002488/* Initialize NT TRANSACT SMB into small smb request buffer.
2489 This assumes that all NT TRANSACTS that we init here have
2490 total parm and data under about 400 bytes (to fit in small cifs
2491 buffer size), which is the case so far, it easily fits. NB:
2492 Setup words themselves and ByteCount
2493 MaxSetupCount (size of returned setup area) and
2494 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002495static int
Steve French0a4b92c2006-01-12 15:44:21 -08002496smb_init_ntransact(const __u16 sub_command, const int setup_count,
2497 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002498 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002499{
2500 int rc;
2501 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002502 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002503
2504 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2505 (void **)&pSMB);
2506 if (rc)
2507 return rc;
2508 *ret_buf = (void *)pSMB;
2509 pSMB->Reserved = 0;
2510 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2511 pSMB->TotalDataCount = 0;
2512 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2513 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2514 pSMB->ParameterCount = pSMB->TotalParameterCount;
2515 pSMB->DataCount = pSMB->TotalDataCount;
2516 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2517 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2518 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2519 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2520 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2521 pSMB->SubCommand = cpu_to_le16(sub_command);
2522 return 0;
2523}
2524
2525static int
Steve French50c2f752007-07-13 00:33:32 +00002526validate_ntransact(char *buf, char **ppparm, char **ppdata,
2527 int *pdatalen, int *pparmlen)
Steve French0a4b92c2006-01-12 15:44:21 -08002528{
Steve French50c2f752007-07-13 00:33:32 +00002529 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002530 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002531 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002532
Steve French790fe572007-07-07 19:25:05 +00002533 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002534 return -EINVAL;
2535
2536 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2537
2538 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002539 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002540 (char *)&pSMBr->ByteCount;
2541
Steve French0a4b92c2006-01-12 15:44:21 -08002542 data_offset = le32_to_cpu(pSMBr->DataOffset);
2543 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002544 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002545 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2546
2547 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2548 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2549
2550 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002551 if (*ppparm > end_of_smb) {
2552 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002553 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002554 } else if (parm_count + *ppparm > end_of_smb) {
2555 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002556 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002557 } else if (*ppdata > end_of_smb) {
2558 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002559 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002560 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002561 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002562 *ppdata, data_count, (data_count + *ppdata),
2563 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002564 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002565 } else if (parm_count + data_count > pSMBr->ByteCount) {
2566 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002567 return -EINVAL;
2568 }
2569 return 0;
2570}
2571
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572int
2573CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2574 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002575 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576 const struct nls_table *nls_codepage)
2577{
2578 int rc = 0;
2579 int bytes_returned;
2580 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002581 struct smb_com_transaction_ioctl_req *pSMB;
2582 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583
2584 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2585 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2586 (void **) &pSMBr);
2587 if (rc)
2588 return rc;
2589
2590 pSMB->TotalParameterCount = 0 ;
2591 pSMB->TotalDataCount = 0;
2592 pSMB->MaxParameterCount = cpu_to_le32(2);
2593 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002594 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2595 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 pSMB->MaxSetupCount = 4;
2597 pSMB->Reserved = 0;
2598 pSMB->ParameterOffset = 0;
2599 pSMB->DataCount = 0;
2600 pSMB->DataOffset = 0;
2601 pSMB->SetupCount = 4;
2602 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2603 pSMB->ParameterCount = pSMB->TotalParameterCount;
2604 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2605 pSMB->IsFsctl = 1; /* FSCTL */
2606 pSMB->IsRootFlag = 0;
2607 pSMB->Fid = fid; /* file handle always le */
2608 pSMB->ByteCount = 0;
2609
2610 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2611 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2612 if (rc) {
2613 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2614 } else { /* decode response */
2615 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2616 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2617 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2618 /* BB also check enough total bytes returned */
2619 rc = -EIO; /* bad smb */
2620 else {
Steve French790fe572007-07-07 19:25:05 +00002621 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002622 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002623 pSMBr->ByteCount +
2624 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625
Steve French50c2f752007-07-13 00:33:32 +00002626 struct reparse_data *reparse_buf =
2627 (struct reparse_data *)
2628 ((char *)&pSMBr->hdr.Protocol
2629 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002630 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 rc = -EIO;
2632 goto qreparse_out;
2633 }
Steve French790fe572007-07-07 19:25:05 +00002634 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 reparse_buf->TargetNameOffset +
2636 reparse_buf->TargetNameLen) >
2637 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002638 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 rc = -EIO;
2640 goto qreparse_out;
2641 }
Steve French50c2f752007-07-13 00:33:32 +00002642
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2644 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002645 (reparse_buf->LinkNamesBuf +
2646 reparse_buf->TargetNameOffset),
2647 min(buflen/2,
2648 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002650 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 reparse_buf->TargetNameOffset),
2652 name_len, nls_codepage);
2653 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002654 strncpy(symlinkinfo,
2655 reparse_buf->LinkNamesBuf +
2656 reparse_buf->TargetNameOffset,
2657 min_t(const int, buflen,
2658 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 }
2660 } else {
2661 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002662 cFYI(1, ("Invalid return data count on "
2663 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 }
2665 symlinkinfo[buflen] = 0; /* just in case so the caller
2666 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002667 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 }
2669 }
2670qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002671 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672
2673 /* Note: On -EAGAIN error only caller can retry on handle based calls
2674 since file handle passed in no longer valid */
2675
2676 return rc;
2677}
2678
2679#ifdef CONFIG_CIFS_POSIX
2680
2681/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002682static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2683 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684{
2685 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002686 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2687 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2688 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2690
2691 return;
2692}
2693
2694/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002695static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2696 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697{
2698 int size = 0;
2699 int i;
2700 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002701 struct cifs_posix_ace *pACE;
2702 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2703 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704
2705 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2706 return -EOPNOTSUPP;
2707
Steve French790fe572007-07-07 19:25:05 +00002708 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 count = le16_to_cpu(cifs_acl->access_entry_count);
2710 pACE = &cifs_acl->ace_array[0];
2711 size = sizeof(struct cifs_posix_acl);
2712 size += sizeof(struct cifs_posix_ace) * count;
2713 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002714 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002715 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2716 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 return -EINVAL;
2718 }
Steve French790fe572007-07-07 19:25:05 +00002719 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 count = le16_to_cpu(cifs_acl->access_entry_count);
2721 size = sizeof(struct cifs_posix_acl);
2722 size += sizeof(struct cifs_posix_ace) * count;
2723/* skip past access ACEs to get to default ACEs */
2724 pACE = &cifs_acl->ace_array[count];
2725 count = le16_to_cpu(cifs_acl->default_entry_count);
2726 size += sizeof(struct cifs_posix_ace) * count;
2727 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002728 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 return -EINVAL;
2730 } else {
2731 /* illegal type */
2732 return -EINVAL;
2733 }
2734
2735 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002736 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002737 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002738 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002739 return -ERANGE;
2740 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002741 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002742 for (i = 0; i < count ; i++) {
2743 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2744 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 }
2746 }
2747 return size;
2748}
2749
Steve French50c2f752007-07-13 00:33:32 +00002750static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2751 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752{
2753 __u16 rc = 0; /* 0 = ACL converted ok */
2754
Steve Frenchff7feac2005-11-15 16:45:16 -08002755 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2756 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002758 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 /* Probably no need to le convert -1 on any arch but can not hurt */
2760 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002761 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002762 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002763 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 return rc;
2765}
2766
2767/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002768static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2769 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770{
2771 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002772 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2773 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 int count;
2775 int i;
2776
Steve French790fe572007-07-07 19:25:05 +00002777 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 return 0;
2779
2780 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002781 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002782 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002783 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002784 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002785 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002786 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 return 0;
2788 }
2789 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002790 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002791 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002792 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002793 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 else {
Steve French50c2f752007-07-13 00:33:32 +00002795 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 return 0;
2797 }
Steve French50c2f752007-07-13 00:33:32 +00002798 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2800 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002801 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 /* ACE not converted */
2803 break;
2804 }
2805 }
Steve French790fe572007-07-07 19:25:05 +00002806 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2808 rc += sizeof(struct cifs_posix_acl);
2809 /* BB add check to make sure ACL does not overflow SMB */
2810 }
2811 return rc;
2812}
2813
2814int
2815CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002816 const unsigned char *searchName,
2817 char *acl_inf, const int buflen, const int acl_type,
2818 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819{
2820/* SMB_QUERY_POSIX_ACL */
2821 TRANSACTION2_QPI_REQ *pSMB = NULL;
2822 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2823 int rc = 0;
2824 int bytes_returned;
2825 int name_len;
2826 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002827
Linus Torvalds1da177e2005-04-16 15:20:36 -07002828 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2829
2830queryAclRetry:
2831 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2832 (void **) &pSMBr);
2833 if (rc)
2834 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002835
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2837 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002838 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002839 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002840 name_len++; /* trailing null */
2841 name_len *= 2;
2842 pSMB->FileName[name_len] = 0;
2843 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002844 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002845 name_len = strnlen(searchName, PATH_MAX);
2846 name_len++; /* trailing null */
2847 strncpy(pSMB->FileName, searchName, name_len);
2848 }
2849
2850 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2851 pSMB->TotalDataCount = 0;
2852 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002853 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 pSMB->MaxDataCount = cpu_to_le16(4000);
2855 pSMB->MaxSetupCount = 0;
2856 pSMB->Reserved = 0;
2857 pSMB->Flags = 0;
2858 pSMB->Timeout = 0;
2859 pSMB->Reserved2 = 0;
2860 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002861 offsetof(struct smb_com_transaction2_qpi_req,
2862 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 pSMB->DataCount = 0;
2864 pSMB->DataOffset = 0;
2865 pSMB->SetupCount = 1;
2866 pSMB->Reserved3 = 0;
2867 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2868 byte_count = params + 1 /* pad */ ;
2869 pSMB->TotalParameterCount = cpu_to_le16(params);
2870 pSMB->ParameterCount = pSMB->TotalParameterCount;
2871 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2872 pSMB->Reserved4 = 0;
2873 pSMB->hdr.smb_buf_length += byte_count;
2874 pSMB->ByteCount = cpu_to_le16(byte_count);
2875
2876 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2877 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002878 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002879 if (rc) {
2880 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2881 } else {
2882 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002883
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2885 if (rc || (pSMBr->ByteCount < 2))
2886 /* BB also check enough total bytes returned */
2887 rc = -EIO; /* bad smb */
2888 else {
2889 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2890 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2891 rc = cifs_copy_posix_acl(acl_inf,
2892 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002893 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 }
2895 }
2896 cifs_buf_release(pSMB);
2897 if (rc == -EAGAIN)
2898 goto queryAclRetry;
2899 return rc;
2900}
2901
2902int
2903CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002904 const unsigned char *fileName,
2905 const char *local_acl, const int buflen,
2906 const int acl_type,
2907 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908{
2909 struct smb_com_transaction2_spi_req *pSMB = NULL;
2910 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2911 char *parm_data;
2912 int name_len;
2913 int rc = 0;
2914 int bytes_returned = 0;
2915 __u16 params, byte_count, data_count, param_offset, offset;
2916
2917 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2918setAclRetry:
2919 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002920 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002921 if (rc)
2922 return rc;
2923 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2924 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002925 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002926 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 name_len++; /* trailing null */
2928 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002929 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 name_len = strnlen(fileName, PATH_MAX);
2931 name_len++; /* trailing null */
2932 strncpy(pSMB->FileName, fileName, name_len);
2933 }
2934 params = 6 + name_len;
2935 pSMB->MaxParameterCount = cpu_to_le16(2);
2936 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2937 pSMB->MaxSetupCount = 0;
2938 pSMB->Reserved = 0;
2939 pSMB->Flags = 0;
2940 pSMB->Timeout = 0;
2941 pSMB->Reserved2 = 0;
2942 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002943 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944 offset = param_offset + params;
2945 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2946 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2947
2948 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002949 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002950
Steve French790fe572007-07-07 19:25:05 +00002951 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952 rc = -EOPNOTSUPP;
2953 goto setACLerrorExit;
2954 }
2955 pSMB->DataOffset = cpu_to_le16(offset);
2956 pSMB->SetupCount = 1;
2957 pSMB->Reserved3 = 0;
2958 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2959 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2960 byte_count = 3 /* pad */ + params + data_count;
2961 pSMB->DataCount = cpu_to_le16(data_count);
2962 pSMB->TotalDataCount = pSMB->DataCount;
2963 pSMB->ParameterCount = cpu_to_le16(params);
2964 pSMB->TotalParameterCount = pSMB->ParameterCount;
2965 pSMB->Reserved4 = 0;
2966 pSMB->hdr.smb_buf_length += byte_count;
2967 pSMB->ByteCount = cpu_to_le16(byte_count);
2968 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002969 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 if (rc) {
2971 cFYI(1, ("Set POSIX ACL returned %d", rc));
2972 }
2973
2974setACLerrorExit:
2975 cifs_buf_release(pSMB);
2976 if (rc == -EAGAIN)
2977 goto setAclRetry;
2978 return rc;
2979}
2980
Steve Frenchf654bac2005-04-28 22:41:04 -07002981/* BB fix tabs in this function FIXME BB */
2982int
2983CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002984 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002985{
Steve French50c2f752007-07-13 00:33:32 +00002986 int rc = 0;
2987 struct smb_t2_qfi_req *pSMB = NULL;
2988 struct smb_t2_qfi_rsp *pSMBr = NULL;
2989 int bytes_returned;
2990 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002991
Steve French790fe572007-07-07 19:25:05 +00002992 cFYI(1, ("In GetExtAttr"));
2993 if (tcon == NULL)
2994 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002995
2996GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002997 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2998 (void **) &pSMBr);
2999 if (rc)
3000 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003001
Steve French790fe572007-07-07 19:25:05 +00003002 params = 2 /* level */ +2 /* fid */;
3003 pSMB->t2.TotalDataCount = 0;
3004 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3005 /* BB find exact max data count below from sess structure BB */
3006 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3007 pSMB->t2.MaxSetupCount = 0;
3008 pSMB->t2.Reserved = 0;
3009 pSMB->t2.Flags = 0;
3010 pSMB->t2.Timeout = 0;
3011 pSMB->t2.Reserved2 = 0;
3012 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3013 Fid) - 4);
3014 pSMB->t2.DataCount = 0;
3015 pSMB->t2.DataOffset = 0;
3016 pSMB->t2.SetupCount = 1;
3017 pSMB->t2.Reserved3 = 0;
3018 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3019 byte_count = params + 1 /* pad */ ;
3020 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3021 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3022 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3023 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003024 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003025 pSMB->hdr.smb_buf_length += byte_count;
3026 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003027
Steve French790fe572007-07-07 19:25:05 +00003028 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3029 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3030 if (rc) {
3031 cFYI(1, ("error %d in GetExtAttr", rc));
3032 } else {
3033 /* decode response */
3034 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3035 if (rc || (pSMBr->ByteCount < 2))
3036 /* BB also check enough total bytes returned */
3037 /* If rc should we check for EOPNOSUPP and
3038 disable the srvino flag? or in caller? */
3039 rc = -EIO; /* bad smb */
3040 else {
3041 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3042 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3043 struct file_chattr_info *pfinfo;
3044 /* BB Do we need a cast or hash here ? */
3045 if (count != 16) {
3046 cFYI(1, ("Illegal size ret in GetExtAttr"));
3047 rc = -EIO;
3048 goto GetExtAttrOut;
3049 }
3050 pfinfo = (struct file_chattr_info *)
3051 (data_offset + (char *) &pSMBr->hdr.Protocol);
3052 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003053 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003054 }
3055 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003056GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003057 cifs_buf_release(pSMB);
3058 if (rc == -EAGAIN)
3059 goto GetExtAttrRetry;
3060 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003061}
3062
Steve Frenchf654bac2005-04-28 22:41:04 -07003063#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064
Steve French297647c2007-10-12 04:11:59 +00003065#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003066/* Get Security Descriptor (by handle) from remote server for a file or dir */
3067int
3068CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French50c2f752007-07-13 00:33:32 +00003069 /* BB fix up return info */ char *acl_inf, const int buflen,
Steve French442aa312007-09-24 20:25:46 +00003070 const int acl_type)
Steve French0a4b92c2006-01-12 15:44:21 -08003071{
3072 int rc = 0;
3073 int buf_type = 0;
3074 QUERY_SEC_DESC_REQ * pSMB;
3075 struct kvec iov[1];
3076
3077 cFYI(1, ("GetCifsACL"));
3078
Steve French50c2f752007-07-13 00:33:32 +00003079 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003080 8 /* parm len */, tcon, (void **) &pSMB);
3081 if (rc)
3082 return rc;
3083
3084 pSMB->MaxParameterCount = cpu_to_le32(4);
3085 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3086 pSMB->MaxSetupCount = 0;
3087 pSMB->Fid = fid; /* file handle always le */
3088 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3089 CIFS_ACL_DACL);
3090 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3091 pSMB->hdr.smb_buf_length += 11;
3092 iov[0].iov_base = (char *)pSMB;
3093 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3094
3095 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
3096 cifs_stats_inc(&tcon->num_acl_get);
3097 if (rc) {
3098 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3099 } else { /* decode response */
Steve French442aa312007-09-24 20:25:46 +00003100 struct cifs_ntsd *psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08003101 __le32 * parm;
3102 int parm_len;
3103 int data_len;
3104 int acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003105 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08003106
3107/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003108 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French0a4b92c2006-01-12 15:44:21 -08003109 (char **)&psec_desc,
3110 &parm_len, &data_len);
Steve French790fe572007-07-07 19:25:05 +00003111 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003112 goto qsec_out;
3113 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3114
Steve Frencha0136892007-10-04 20:05:09 +00003115 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, psec_desc));
Steve French0a4b92c2006-01-12 15:44:21 -08003116
3117 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3118 rc = -EIO; /* bad smb */
3119 goto qsec_out;
3120 }
3121
3122/* BB check that data area is minimum length and as big as acl_len */
3123
Steve Frenchaf6f4612007-10-16 18:40:37 +00003124 acl_len = le32_to_cpu(*parm);
Steve French790fe572007-07-07 19:25:05 +00003125 /* BB check if (acl_len > bufsize) */
Steve French0a4b92c2006-01-12 15:44:21 -08003126
3127 parse_sec_desc(psec_desc, acl_len);
3128 }
3129qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003130 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003131 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003132 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003133 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003134/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003135 return rc;
3136}
Steve French297647c2007-10-12 04:11:59 +00003137#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003138
Steve French6b8edfe2005-08-23 20:26:03 -07003139/* Legacy Query Path Information call for lookup to old servers such
3140 as Win9x/WinME */
3141int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003142 const unsigned char *searchName,
3143 FILE_ALL_INFO *pFinfo,
3144 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003145{
3146 QUERY_INFORMATION_REQ * pSMB;
3147 QUERY_INFORMATION_RSP * pSMBr;
3148 int rc = 0;
3149 int bytes_returned;
3150 int name_len;
3151
Steve French50c2f752007-07-13 00:33:32 +00003152 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003153QInfRetry:
3154 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003155 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003156 if (rc)
3157 return rc;
3158
3159 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3160 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003161 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3162 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003163 name_len++; /* trailing null */
3164 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003165 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003166 name_len = strnlen(searchName, PATH_MAX);
3167 name_len++; /* trailing null */
3168 strncpy(pSMB->FileName, searchName, name_len);
3169 }
3170 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003171 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003172 pSMB->hdr.smb_buf_length += (__u16) name_len;
3173 pSMB->ByteCount = cpu_to_le16(name_len);
3174
3175 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003176 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003177 if (rc) {
3178 cFYI(1, ("Send error in QueryInfo = %d", rc));
3179 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003180 struct timespec ts;
3181 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3182 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003183 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003184 ts.tv_nsec = 0;
3185 ts.tv_sec = time;
3186 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003187 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003188 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3189 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003190 pFinfo->AllocationSize =
3191 cpu_to_le64(le32_to_cpu(pSMBr->size));
3192 pFinfo->EndOfFile = pFinfo->AllocationSize;
3193 pFinfo->Attributes =
3194 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003195 } else
3196 rc = -EIO; /* bad buffer passed in */
3197
3198 cifs_buf_release(pSMB);
3199
3200 if (rc == -EAGAIN)
3201 goto QInfRetry;
3202
3203 return rc;
3204}
3205
3206
3207
3208
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209int
3210CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3211 const unsigned char *searchName,
3212 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003213 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003214 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215{
3216/* level 263 SMB_QUERY_FILE_ALL_INFO */
3217 TRANSACTION2_QPI_REQ *pSMB = NULL;
3218 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3219 int rc = 0;
3220 int bytes_returned;
3221 int name_len;
3222 __u16 params, byte_count;
3223
3224/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3225QPathInfoRetry:
3226 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3227 (void **) &pSMBr);
3228 if (rc)
3229 return rc;
3230
3231 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3232 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003233 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003234 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 name_len++; /* trailing null */
3236 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003237 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 name_len = strnlen(searchName, PATH_MAX);
3239 name_len++; /* trailing null */
3240 strncpy(pSMB->FileName, searchName, name_len);
3241 }
3242
Steve French50c2f752007-07-13 00:33:32 +00003243 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 pSMB->TotalDataCount = 0;
3245 pSMB->MaxParameterCount = cpu_to_le16(2);
3246 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3247 pSMB->MaxSetupCount = 0;
3248 pSMB->Reserved = 0;
3249 pSMB->Flags = 0;
3250 pSMB->Timeout = 0;
3251 pSMB->Reserved2 = 0;
3252 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003253 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 pSMB->DataCount = 0;
3255 pSMB->DataOffset = 0;
3256 pSMB->SetupCount = 1;
3257 pSMB->Reserved3 = 0;
3258 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3259 byte_count = params + 1 /* pad */ ;
3260 pSMB->TotalParameterCount = cpu_to_le16(params);
3261 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003262 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003263 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3264 else
3265 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266 pSMB->Reserved4 = 0;
3267 pSMB->hdr.smb_buf_length += byte_count;
3268 pSMB->ByteCount = cpu_to_le16(byte_count);
3269
3270 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3271 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3272 if (rc) {
3273 cFYI(1, ("Send error in QPathInfo = %d", rc));
3274 } else { /* decode response */
3275 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3276
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003277 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3278 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003279 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003280 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003281 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003282 rc = -EIO; /* 24 or 26 expected but we do not read
3283 last field */
3284 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003285 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003287 if (legacy) /* we do not read the last field, EAsize,
3288 fortunately since it varies by subdialect
3289 and on Set vs. Get, is two bytes or 4
3290 bytes depending but we don't care here */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003291 size = sizeof(FILE_INFO_STANDARD);
3292 else
3293 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003294 memcpy((char *) pFindData,
3295 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003296 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003297 } else
3298 rc = -ENOMEM;
3299 }
3300 cifs_buf_release(pSMB);
3301 if (rc == -EAGAIN)
3302 goto QPathInfoRetry;
3303
3304 return rc;
3305}
3306
3307int
3308CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3309 const unsigned char *searchName,
3310 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003311 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312{
3313/* SMB_QUERY_FILE_UNIX_BASIC */
3314 TRANSACTION2_QPI_REQ *pSMB = NULL;
3315 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3316 int rc = 0;
3317 int bytes_returned = 0;
3318 int name_len;
3319 __u16 params, byte_count;
3320
3321 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3322UnixQPathInfoRetry:
3323 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3324 (void **) &pSMBr);
3325 if (rc)
3326 return rc;
3327
3328 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3329 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003330 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003331 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003332 name_len++; /* trailing null */
3333 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003334 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335 name_len = strnlen(searchName, PATH_MAX);
3336 name_len++; /* trailing null */
3337 strncpy(pSMB->FileName, searchName, name_len);
3338 }
3339
Steve French50c2f752007-07-13 00:33:32 +00003340 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 pSMB->TotalDataCount = 0;
3342 pSMB->MaxParameterCount = cpu_to_le16(2);
3343 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003344 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 pSMB->MaxSetupCount = 0;
3346 pSMB->Reserved = 0;
3347 pSMB->Flags = 0;
3348 pSMB->Timeout = 0;
3349 pSMB->Reserved2 = 0;
3350 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003351 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003352 pSMB->DataCount = 0;
3353 pSMB->DataOffset = 0;
3354 pSMB->SetupCount = 1;
3355 pSMB->Reserved3 = 0;
3356 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3357 byte_count = params + 1 /* pad */ ;
3358 pSMB->TotalParameterCount = cpu_to_le16(params);
3359 pSMB->ParameterCount = pSMB->TotalParameterCount;
3360 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3361 pSMB->Reserved4 = 0;
3362 pSMB->hdr.smb_buf_length += byte_count;
3363 pSMB->ByteCount = cpu_to_le16(byte_count);
3364
3365 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3366 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3367 if (rc) {
3368 cFYI(1, ("Send error in QPathInfo = %d", rc));
3369 } else { /* decode response */
3370 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3371
3372 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003373 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3374 "Unix Extensions can be disabled on mount "
3375 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003376 rc = -EIO; /* bad smb */
3377 } else {
3378 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3379 memcpy((char *) pFindData,
3380 (char *) &pSMBr->hdr.Protocol +
3381 data_offset,
3382 sizeof (FILE_UNIX_BASIC_INFO));
3383 }
3384 }
3385 cifs_buf_release(pSMB);
3386 if (rc == -EAGAIN)
3387 goto UnixQPathInfoRetry;
3388
3389 return rc;
3390}
3391
3392#if 0 /* function unused at present */
3393int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3394 const char *searchName, FILE_ALL_INFO * findData,
3395 const struct nls_table *nls_codepage)
3396{
3397/* level 257 SMB_ */
3398 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3399 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3400 int rc = 0;
3401 int bytes_returned;
3402 int name_len;
3403 __u16 params, byte_count;
3404
3405 cFYI(1, ("In FindUnique"));
3406findUniqueRetry:
3407 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3408 (void **) &pSMBr);
3409 if (rc)
3410 return rc;
3411
3412 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3413 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003414 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3415 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003416 name_len++; /* trailing null */
3417 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003418 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 name_len = strnlen(searchName, PATH_MAX);
3420 name_len++; /* trailing null */
3421 strncpy(pSMB->FileName, searchName, name_len);
3422 }
3423
3424 params = 12 + name_len /* includes null */ ;
3425 pSMB->TotalDataCount = 0; /* no EAs */
3426 pSMB->MaxParameterCount = cpu_to_le16(2);
3427 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3428 pSMB->MaxSetupCount = 0;
3429 pSMB->Reserved = 0;
3430 pSMB->Flags = 0;
3431 pSMB->Timeout = 0;
3432 pSMB->Reserved2 = 0;
3433 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003434 offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003435 pSMB->DataCount = 0;
3436 pSMB->DataOffset = 0;
3437 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3438 pSMB->Reserved3 = 0;
3439 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3440 byte_count = params + 1 /* pad */ ;
3441 pSMB->TotalParameterCount = cpu_to_le16(params);
3442 pSMB->ParameterCount = pSMB->TotalParameterCount;
3443 pSMB->SearchAttributes =
3444 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3445 ATTR_DIRECTORY);
3446 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3447 pSMB->SearchFlags = cpu_to_le16(1);
3448 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3449 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3450 pSMB->hdr.smb_buf_length += byte_count;
3451 pSMB->ByteCount = cpu_to_le16(byte_count);
3452
3453 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3454 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3455
3456 if (rc) {
3457 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3458 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003459 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460 /* BB fill in */
3461 }
3462
3463 cifs_buf_release(pSMB);
3464 if (rc == -EAGAIN)
3465 goto findUniqueRetry;
3466
3467 return rc;
3468}
3469#endif /* end unused (temporarily) function */
3470
3471/* xid, tcon, searchName and codepage are input parms, rest are returned */
3472int
3473CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003474 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003475 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003476 __u16 *pnetfid,
3477 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478{
3479/* level 257 SMB_ */
3480 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3481 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3482 T2_FFIRST_RSP_PARMS * parms;
3483 int rc = 0;
3484 int bytes_returned = 0;
3485 int name_len;
3486 __u16 params, byte_count;
3487
Steve French50c2f752007-07-13 00:33:32 +00003488 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489
3490findFirstRetry:
3491 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3492 (void **) &pSMBr);
3493 if (rc)
3494 return rc;
3495
3496 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3497 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003498 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003499 PATH_MAX, nls_codepage, remap);
3500 /* We can not add the asterik earlier in case
3501 it got remapped to 0xF03A as if it were part of the
3502 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003504 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003505 pSMB->FileName[name_len+1] = 0;
3506 pSMB->FileName[name_len+2] = '*';
3507 pSMB->FileName[name_len+3] = 0;
3508 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3510 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003511 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003512 } else { /* BB add check for overrun of SMB buf BB */
3513 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003515 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 free buffer exit; BB */
3517 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003518 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003519 pSMB->FileName[name_len+1] = '*';
3520 pSMB->FileName[name_len+2] = 0;
3521 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 }
3523
3524 params = 12 + name_len /* includes null */ ;
3525 pSMB->TotalDataCount = 0; /* no EAs */
3526 pSMB->MaxParameterCount = cpu_to_le16(10);
3527 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3528 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3529 pSMB->MaxSetupCount = 0;
3530 pSMB->Reserved = 0;
3531 pSMB->Flags = 0;
3532 pSMB->Timeout = 0;
3533 pSMB->Reserved2 = 0;
3534 byte_count = params + 1 /* pad */ ;
3535 pSMB->TotalParameterCount = cpu_to_le16(params);
3536 pSMB->ParameterCount = pSMB->TotalParameterCount;
3537 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003538 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3539 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003540 pSMB->DataCount = 0;
3541 pSMB->DataOffset = 0;
3542 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3543 pSMB->Reserved3 = 0;
3544 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3545 pSMB->SearchAttributes =
3546 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3547 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003548 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3549 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003550 CIFS_SEARCH_RETURN_RESUME);
3551 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3552
3553 /* BB what should we set StorageType to? Does it matter? BB */
3554 pSMB->SearchStorageType = 0;
3555 pSMB->hdr.smb_buf_length += byte_count;
3556 pSMB->ByteCount = cpu_to_le16(byte_count);
3557
3558 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3559 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003560 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003561
Steve French88274812006-03-09 22:21:45 +00003562 if (rc) {/* BB add logic to retry regular search if Unix search
3563 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564 /* BB Add code to handle unsupported level rc */
3565 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003566
Steve French88274812006-03-09 22:21:45 +00003567 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568
3569 /* BB eventually could optimize out free and realloc of buf */
3570 /* for this case */
3571 if (rc == -EAGAIN)
3572 goto findFirstRetry;
3573 } else { /* decode response */
3574 /* BB remember to free buffer if error BB */
3575 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003576 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3578 psrch_inf->unicode = TRUE;
3579 else
3580 psrch_inf->unicode = FALSE;
3581
3582 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003583 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003584 psrch_inf->srch_entries_start =
3585 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003587 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3588 le16_to_cpu(pSMBr->t2.ParameterOffset));
3589
Steve French790fe572007-07-07 19:25:05 +00003590 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 psrch_inf->endOfSearch = TRUE;
3592 else
3593 psrch_inf->endOfSearch = FALSE;
3594
Steve French50c2f752007-07-13 00:33:32 +00003595 psrch_inf->entries_in_buffer =
3596 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003597 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003598 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 *pnetfid = parms->SearchHandle;
3600 } else {
3601 cifs_buf_release(pSMB);
3602 }
3603 }
3604
3605 return rc;
3606}
3607
3608int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003609 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003610{
3611 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3612 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3613 T2_FNEXT_RSP_PARMS * parms;
3614 char *response_data;
3615 int rc = 0;
3616 int bytes_returned, name_len;
3617 __u16 params, byte_count;
3618
3619 cFYI(1, ("In FindNext"));
3620
Steve French790fe572007-07-07 19:25:05 +00003621 if (psrch_inf->endOfSearch == TRUE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003622 return -ENOENT;
3623
3624 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3625 (void **) &pSMBr);
3626 if (rc)
3627 return rc;
3628
Steve French50c2f752007-07-13 00:33:32 +00003629 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 byte_count = 0;
3631 pSMB->TotalDataCount = 0; /* no EAs */
3632 pSMB->MaxParameterCount = cpu_to_le16(8);
3633 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003634 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3635 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003636 pSMB->MaxSetupCount = 0;
3637 pSMB->Reserved = 0;
3638 pSMB->Flags = 0;
3639 pSMB->Timeout = 0;
3640 pSMB->Reserved2 = 0;
3641 pSMB->ParameterOffset = cpu_to_le16(
3642 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3643 pSMB->DataCount = 0;
3644 pSMB->DataOffset = 0;
3645 pSMB->SetupCount = 1;
3646 pSMB->Reserved3 = 0;
3647 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3648 pSMB->SearchHandle = searchHandle; /* always kept as le */
3649 pSMB->SearchCount =
3650 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3652 pSMB->ResumeKey = psrch_inf->resume_key;
3653 pSMB->SearchFlags =
3654 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3655
3656 name_len = psrch_inf->resume_name_len;
3657 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003658 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003659 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3660 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003661 /* 14 byte parm len above enough for 2 byte null terminator */
3662 pSMB->ResumeFileName[name_len] = 0;
3663 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 } else {
3665 rc = -EINVAL;
3666 goto FNext2_err_exit;
3667 }
3668 byte_count = params + 1 /* pad */ ;
3669 pSMB->TotalParameterCount = cpu_to_le16(params);
3670 pSMB->ParameterCount = pSMB->TotalParameterCount;
3671 pSMB->hdr.smb_buf_length += byte_count;
3672 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003673
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3675 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003676 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003677 if (rc) {
3678 if (rc == -EBADF) {
3679 psrch_inf->endOfSearch = TRUE;
Steve French50c2f752007-07-13 00:33:32 +00003680 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 } else
3682 cFYI(1, ("FindNext returned = %d", rc));
3683 } else { /* decode response */
3684 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003685
Steve French790fe572007-07-07 19:25:05 +00003686 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687 /* BB fixme add lock for file (srch_info) struct here */
3688 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3689 psrch_inf->unicode = TRUE;
3690 else
3691 psrch_inf->unicode = FALSE;
3692 response_data = (char *) &pSMBr->hdr.Protocol +
3693 le16_to_cpu(pSMBr->t2.ParameterOffset);
3694 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3695 response_data = (char *)&pSMBr->hdr.Protocol +
3696 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003697 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003698 cifs_small_buf_release(
3699 psrch_inf->ntwrk_buf_start);
3700 else
3701 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 psrch_inf->srch_entries_start = response_data;
3703 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003704 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003705 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 psrch_inf->endOfSearch = TRUE;
3707 else
3708 psrch_inf->endOfSearch = FALSE;
Steve French50c2f752007-07-13 00:33:32 +00003709 psrch_inf->entries_in_buffer =
3710 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003711 psrch_inf->index_of_last_entry +=
3712 psrch_inf->entries_in_buffer;
Steve French50c2f752007-07-13 00:33:32 +00003713/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3714 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715
3716 /* BB fixme add unlock here */
3717 }
3718
3719 }
3720
3721 /* BB On error, should we leave previous search buf (and count and
3722 last entry fields) intact or free the previous one? */
3723
3724 /* Note: On -EAGAIN error only caller can retry on handle based calls
3725 since file handle passed in no longer valid */
3726FNext2_err_exit:
3727 if (rc != 0)
3728 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729 return rc;
3730}
3731
3732int
Steve French50c2f752007-07-13 00:33:32 +00003733CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3734 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003735{
3736 int rc = 0;
3737 FINDCLOSE_REQ *pSMB = NULL;
3738 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3739 int bytes_returned;
3740
3741 cFYI(1, ("In CIFSSMBFindClose"));
3742 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3743
3744 /* no sense returning error if session restarted
3745 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003746 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747 return 0;
3748 if (rc)
3749 return rc;
3750
3751 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3752 pSMB->FileID = searchHandle;
3753 pSMB->ByteCount = 0;
3754 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3755 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3756 if (rc) {
3757 cERROR(1, ("Send error in FindClose = %d", rc));
3758 }
Steve Frencha4544342005-08-24 13:59:35 -07003759 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 cifs_small_buf_release(pSMB);
3761
3762 /* Since session is dead, search handle closed on server already */
3763 if (rc == -EAGAIN)
3764 rc = 0;
3765
3766 return rc;
3767}
3768
Linus Torvalds1da177e2005-04-16 15:20:36 -07003769int
3770CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003771 const unsigned char *searchName,
3772 __u64 * inode_number,
3773 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774{
3775 int rc = 0;
3776 TRANSACTION2_QPI_REQ *pSMB = NULL;
3777 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3778 int name_len, bytes_returned;
3779 __u16 params, byte_count;
3780
Steve French50c2f752007-07-13 00:33:32 +00003781 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003782 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003783 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784
3785GetInodeNumberRetry:
3786 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003787 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 if (rc)
3789 return rc;
3790
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3792 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003793 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003794 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795 name_len++; /* trailing null */
3796 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003797 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 name_len = strnlen(searchName, PATH_MAX);
3799 name_len++; /* trailing null */
3800 strncpy(pSMB->FileName, searchName, name_len);
3801 }
3802
3803 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3804 pSMB->TotalDataCount = 0;
3805 pSMB->MaxParameterCount = cpu_to_le16(2);
3806 /* BB find exact max data count below from sess structure BB */
3807 pSMB->MaxDataCount = cpu_to_le16(4000);
3808 pSMB->MaxSetupCount = 0;
3809 pSMB->Reserved = 0;
3810 pSMB->Flags = 0;
3811 pSMB->Timeout = 0;
3812 pSMB->Reserved2 = 0;
3813 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003814 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003815 pSMB->DataCount = 0;
3816 pSMB->DataOffset = 0;
3817 pSMB->SetupCount = 1;
3818 pSMB->Reserved3 = 0;
3819 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3820 byte_count = params + 1 /* pad */ ;
3821 pSMB->TotalParameterCount = cpu_to_le16(params);
3822 pSMB->ParameterCount = pSMB->TotalParameterCount;
3823 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3824 pSMB->Reserved4 = 0;
3825 pSMB->hdr.smb_buf_length += byte_count;
3826 pSMB->ByteCount = cpu_to_le16(byte_count);
3827
3828 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3829 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3830 if (rc) {
3831 cFYI(1, ("error %d in QueryInternalInfo", rc));
3832 } else {
3833 /* decode response */
3834 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3835 if (rc || (pSMBr->ByteCount < 2))
3836 /* BB also check enough total bytes returned */
3837 /* If rc should we check for EOPNOSUPP and
3838 disable the srvino flag? or in caller? */
3839 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003840 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3842 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003843 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003844 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003845 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3847 rc = -EIO;
3848 goto GetInodeNumOut;
3849 }
3850 pfinfo = (struct file_internal_info *)
3851 (data_offset + (char *) &pSMBr->hdr.Protocol);
3852 *inode_number = pfinfo->UniqueId;
3853 }
3854 }
3855GetInodeNumOut:
3856 cifs_buf_release(pSMB);
3857 if (rc == -EAGAIN)
3858 goto GetInodeNumberRetry;
3859 return rc;
3860}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861
3862int
3863CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3864 const unsigned char *searchName,
3865 unsigned char **targetUNCs,
3866 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003867 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003868{
3869/* TRANS2_GET_DFS_REFERRAL */
3870 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3871 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003872 struct dfs_referral_level_3 *referrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 int rc = 0;
3874 int bytes_returned;
3875 int name_len;
3876 unsigned int i;
Steve French50c2f752007-07-13 00:33:32 +00003877 char *temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 __u16 params, byte_count;
3879 *number_of_UNC_in_array = 0;
3880 *targetUNCs = NULL;
3881
3882 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3883 if (ses == NULL)
3884 return -ENODEV;
3885getDFSRetry:
3886 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3887 (void **) &pSMBr);
3888 if (rc)
3889 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003890
3891 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07003892 but should never be null here anyway */
3893 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003894 pSMB->hdr.Tid = ses->ipc_tid;
3895 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00003896 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00003898 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003900
3901 if (ses->capabilities & CAP_UNICODE) {
3902 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3903 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003904 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003905 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003906 name_len++; /* trailing null */
3907 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003908 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 name_len = strnlen(searchName, PATH_MAX);
3910 name_len++; /* trailing null */
3911 strncpy(pSMB->RequestFileName, searchName, name_len);
3912 }
3913
Steve French790fe572007-07-07 19:25:05 +00003914 if (ses->server) {
3915 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00003916 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3917 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3918 }
3919
Steve French50c2f752007-07-13 00:33:32 +00003920 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00003921
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922 params = 2 /* level */ + name_len /*includes null */ ;
3923 pSMB->TotalDataCount = 0;
3924 pSMB->DataCount = 0;
3925 pSMB->DataOffset = 0;
3926 pSMB->MaxParameterCount = 0;
3927 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3928 pSMB->MaxSetupCount = 0;
3929 pSMB->Reserved = 0;
3930 pSMB->Flags = 0;
3931 pSMB->Timeout = 0;
3932 pSMB->Reserved2 = 0;
3933 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003934 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003935 pSMB->SetupCount = 1;
3936 pSMB->Reserved3 = 0;
3937 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3938 byte_count = params + 3 /* pad */ ;
3939 pSMB->ParameterCount = cpu_to_le16(params);
3940 pSMB->TotalParameterCount = pSMB->ParameterCount;
3941 pSMB->MaxReferralLevel = cpu_to_le16(3);
3942 pSMB->hdr.smb_buf_length += byte_count;
3943 pSMB->ByteCount = cpu_to_le16(byte_count);
3944
3945 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3946 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3947 if (rc) {
3948 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3949 } else { /* decode response */
3950/* BB Add logic to parse referrals here */
3951 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3952
Steve French50c2f752007-07-13 00:33:32 +00003953 /* BB Also check if enough total bytes returned? */
3954 if (rc || (pSMBr->ByteCount < 17))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 rc = -EIO; /* bad smb */
3956 else {
Steve French50c2f752007-07-13 00:33:32 +00003957 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003958 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3959
3960 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003961 ("Decoding GetDFSRefer response BCC: %d Offset %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 pSMBr->ByteCount, data_offset));
Steve French50c2f752007-07-13 00:33:32 +00003963 referrals =
3964 (struct dfs_referral_level_3 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965 (8 /* sizeof start of data block */ +
3966 data_offset +
Steve French50c2f752007-07-13 00:33:32 +00003967 (char *) &pSMBr->hdr.Protocol);
Steve Frenchc18c8422007-07-18 23:21:09 +00003968 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
Steve French63135e02007-07-17 17:34:02 +00003969 "for referral one refer size: 0x%x srv "
3970 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
Steve French50c2f752007-07-13 00:33:32 +00003971 le16_to_cpu(pSMBr->NumberOfReferrals),
3972 le16_to_cpu(pSMBr->DFSFlags),
3973 le16_to_cpu(referrals->ReferralSize),
3974 le16_to_cpu(referrals->ServerType),
3975 le16_to_cpu(referrals->ReferralFlags),
3976 le16_to_cpu(referrals->TimeToLive)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 /* BB This field is actually two bytes in from start of
3978 data block so we could do safety check that DataBlock
3979 begins at address of pSMBr->NumberOfReferrals */
Steve French50c2f752007-07-13 00:33:32 +00003980 *number_of_UNC_in_array =
3981 le16_to_cpu(pSMBr->NumberOfReferrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982
3983 /* BB Fix below so can return more than one referral */
Steve French790fe572007-07-07 19:25:05 +00003984 if (*number_of_UNC_in_array > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003985 *number_of_UNC_in_array = 1;
3986
3987 /* get the length of the strings describing refs */
3988 name_len = 0;
Steve French50c2f752007-07-13 00:33:32 +00003989 for (i = 0; i < *number_of_UNC_in_array; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003990 /* make sure that DfsPathOffset not past end */
Steve French50c2f752007-07-13 00:33:32 +00003991 __u16 offset =
3992 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 if (offset > data_count) {
Steve French50c2f752007-07-13 00:33:32 +00003994 /* if invalid referral, stop here and do
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 not try to copy any more */
3996 *number_of_UNC_in_array = i;
3997 break;
Steve French50c2f752007-07-13 00:33:32 +00003998 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 temp = ((char *)referrals) + offset;
4000
4001 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00004002 name_len += UniStrnlen((wchar_t *)temp,
4003 data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 } else {
Steve French50c2f752007-07-13 00:33:32 +00004005 name_len += strnlen(temp, data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 }
4007 referrals++;
Steve French50c2f752007-07-13 00:33:32 +00004008 /* BB add check that referral pointer does
4009 not fall off end PDU */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 }
4011 /* BB add check for name_len bigger than bcc */
Steve French50c2f752007-07-13 00:33:32 +00004012 *targetUNCs =
4013 kmalloc(name_len+1+(*number_of_UNC_in_array),
4014 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00004015 if (*targetUNCs == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 rc = -ENOMEM;
4017 goto GetDFSRefExit;
4018 }
4019 /* copy the ref strings */
Steve French50c2f752007-07-13 00:33:32 +00004020 referrals = (struct dfs_referral_level_3 *)
4021 (8 /* sizeof data hdr */ + data_offset +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022 (char *) &pSMBr->hdr.Protocol);
4023
Steve French50c2f752007-07-13 00:33:32 +00004024 for (i = 0; i < *number_of_UNC_in_array; i++) {
4025 temp = ((char *)referrals) +
4026 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4028 cifs_strfromUCS_le(*targetUNCs,
Steve French50c2f752007-07-13 00:33:32 +00004029 (__le16 *) temp,
4030 name_len,
4031 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 } else {
Steve French50c2f752007-07-13 00:33:32 +00004033 strncpy(*targetUNCs, temp, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 }
4035 /* BB update target_uncs pointers */
4036 referrals++;
4037 }
4038 temp = *targetUNCs;
4039 temp[name_len] = 0;
4040 }
4041
4042 }
4043GetDFSRefExit:
4044 if (pSMB)
4045 cifs_buf_release(pSMB);
4046
4047 if (rc == -EAGAIN)
4048 goto getDFSRetry;
4049
4050 return rc;
4051}
4052
Steve French20962432005-09-21 22:05:57 -07004053/* Query File System Info such as free space to old servers such as Win 9x */
4054int
4055SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4056{
4057/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4058 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4059 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4060 FILE_SYSTEM_ALLOC_INFO *response_data;
4061 int rc = 0;
4062 int bytes_returned = 0;
4063 __u16 params, byte_count;
4064
4065 cFYI(1, ("OldQFSInfo"));
4066oldQFSInfoRetry:
4067 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4068 (void **) &pSMBr);
4069 if (rc)
4070 return rc;
Steve French20962432005-09-21 22:05:57 -07004071
4072 params = 2; /* level */
4073 pSMB->TotalDataCount = 0;
4074 pSMB->MaxParameterCount = cpu_to_le16(2);
4075 pSMB->MaxDataCount = cpu_to_le16(1000);
4076 pSMB->MaxSetupCount = 0;
4077 pSMB->Reserved = 0;
4078 pSMB->Flags = 0;
4079 pSMB->Timeout = 0;
4080 pSMB->Reserved2 = 0;
4081 byte_count = params + 1 /* pad */ ;
4082 pSMB->TotalParameterCount = cpu_to_le16(params);
4083 pSMB->ParameterCount = pSMB->TotalParameterCount;
4084 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4085 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4086 pSMB->DataCount = 0;
4087 pSMB->DataOffset = 0;
4088 pSMB->SetupCount = 1;
4089 pSMB->Reserved3 = 0;
4090 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4091 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4092 pSMB->hdr.smb_buf_length += byte_count;
4093 pSMB->ByteCount = cpu_to_le16(byte_count);
4094
4095 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4096 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4097 if (rc) {
4098 cFYI(1, ("Send error in QFSInfo = %d", rc));
4099 } else { /* decode response */
4100 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4101
4102 if (rc || (pSMBr->ByteCount < 18))
4103 rc = -EIO; /* bad smb */
4104 else {
4105 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004106 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004107 pSMBr->ByteCount, data_offset));
4108
Steve French50c2f752007-07-13 00:33:32 +00004109 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004110 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4111 FSData->f_bsize =
4112 le16_to_cpu(response_data->BytesPerSector) *
4113 le32_to_cpu(response_data->
4114 SectorsPerAllocationUnit);
4115 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004116 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004117 FSData->f_bfree = FSData->f_bavail =
4118 le32_to_cpu(response_data->FreeAllocationUnits);
4119 cFYI(1,
4120 ("Blocks: %lld Free: %lld Block size %ld",
4121 (unsigned long long)FSData->f_blocks,
4122 (unsigned long long)FSData->f_bfree,
4123 FSData->f_bsize));
4124 }
4125 }
4126 cifs_buf_release(pSMB);
4127
4128 if (rc == -EAGAIN)
4129 goto oldQFSInfoRetry;
4130
4131 return rc;
4132}
4133
Linus Torvalds1da177e2005-04-16 15:20:36 -07004134int
Steve French737b7582005-04-28 22:41:06 -07004135CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136{
4137/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4138 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4139 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4140 FILE_SYSTEM_INFO *response_data;
4141 int rc = 0;
4142 int bytes_returned = 0;
4143 __u16 params, byte_count;
4144
4145 cFYI(1, ("In QFSInfo"));
4146QFSInfoRetry:
4147 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4148 (void **) &pSMBr);
4149 if (rc)
4150 return rc;
4151
4152 params = 2; /* level */
4153 pSMB->TotalDataCount = 0;
4154 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004155 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 pSMB->MaxSetupCount = 0;
4157 pSMB->Reserved = 0;
4158 pSMB->Flags = 0;
4159 pSMB->Timeout = 0;
4160 pSMB->Reserved2 = 0;
4161 byte_count = params + 1 /* pad */ ;
4162 pSMB->TotalParameterCount = cpu_to_le16(params);
4163 pSMB->ParameterCount = pSMB->TotalParameterCount;
4164 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004165 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166 pSMB->DataCount = 0;
4167 pSMB->DataOffset = 0;
4168 pSMB->SetupCount = 1;
4169 pSMB->Reserved3 = 0;
4170 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4171 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4172 pSMB->hdr.smb_buf_length += byte_count;
4173 pSMB->ByteCount = cpu_to_le16(byte_count);
4174
4175 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4176 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4177 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004178 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004179 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004180 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181
Steve French20962432005-09-21 22:05:57 -07004182 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 rc = -EIO; /* bad smb */
4184 else {
4185 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186
4187 response_data =
4188 (FILE_SYSTEM_INFO
4189 *) (((char *) &pSMBr->hdr.Protocol) +
4190 data_offset);
4191 FSData->f_bsize =
4192 le32_to_cpu(response_data->BytesPerSector) *
4193 le32_to_cpu(response_data->
4194 SectorsPerAllocationUnit);
4195 FSData->f_blocks =
4196 le64_to_cpu(response_data->TotalAllocationUnits);
4197 FSData->f_bfree = FSData->f_bavail =
4198 le64_to_cpu(response_data->FreeAllocationUnits);
4199 cFYI(1,
4200 ("Blocks: %lld Free: %lld Block size %ld",
4201 (unsigned long long)FSData->f_blocks,
4202 (unsigned long long)FSData->f_bfree,
4203 FSData->f_bsize));
4204 }
4205 }
4206 cifs_buf_release(pSMB);
4207
4208 if (rc == -EAGAIN)
4209 goto QFSInfoRetry;
4210
4211 return rc;
4212}
4213
4214int
Steve French737b7582005-04-28 22:41:06 -07004215CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216{
4217/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4218 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4219 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4220 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4221 int rc = 0;
4222 int bytes_returned = 0;
4223 __u16 params, byte_count;
4224
4225 cFYI(1, ("In QFSAttributeInfo"));
4226QFSAttributeRetry:
4227 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4228 (void **) &pSMBr);
4229 if (rc)
4230 return rc;
4231
4232 params = 2; /* level */
4233 pSMB->TotalDataCount = 0;
4234 pSMB->MaxParameterCount = cpu_to_le16(2);
4235 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4236 pSMB->MaxSetupCount = 0;
4237 pSMB->Reserved = 0;
4238 pSMB->Flags = 0;
4239 pSMB->Timeout = 0;
4240 pSMB->Reserved2 = 0;
4241 byte_count = params + 1 /* pad */ ;
4242 pSMB->TotalParameterCount = cpu_to_le16(params);
4243 pSMB->ParameterCount = pSMB->TotalParameterCount;
4244 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004245 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 pSMB->DataCount = 0;
4247 pSMB->DataOffset = 0;
4248 pSMB->SetupCount = 1;
4249 pSMB->Reserved3 = 0;
4250 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4251 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4252 pSMB->hdr.smb_buf_length += byte_count;
4253 pSMB->ByteCount = cpu_to_le16(byte_count);
4254
4255 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4256 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4257 if (rc) {
4258 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4259 } else { /* decode response */
4260 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4261
Steve French50c2f752007-07-13 00:33:32 +00004262 if (rc || (pSMBr->ByteCount < 13)) {
4263 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004264 rc = -EIO; /* bad smb */
4265 } else {
4266 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4267 response_data =
4268 (FILE_SYSTEM_ATTRIBUTE_INFO
4269 *) (((char *) &pSMBr->hdr.Protocol) +
4270 data_offset);
4271 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004272 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 }
4274 }
4275 cifs_buf_release(pSMB);
4276
4277 if (rc == -EAGAIN)
4278 goto QFSAttributeRetry;
4279
4280 return rc;
4281}
4282
4283int
Steve French737b7582005-04-28 22:41:06 -07004284CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285{
4286/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4287 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4288 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4289 FILE_SYSTEM_DEVICE_INFO *response_data;
4290 int rc = 0;
4291 int bytes_returned = 0;
4292 __u16 params, byte_count;
4293
4294 cFYI(1, ("In QFSDeviceInfo"));
4295QFSDeviceRetry:
4296 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4297 (void **) &pSMBr);
4298 if (rc)
4299 return rc;
4300
4301 params = 2; /* level */
4302 pSMB->TotalDataCount = 0;
4303 pSMB->MaxParameterCount = cpu_to_le16(2);
4304 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4305 pSMB->MaxSetupCount = 0;
4306 pSMB->Reserved = 0;
4307 pSMB->Flags = 0;
4308 pSMB->Timeout = 0;
4309 pSMB->Reserved2 = 0;
4310 byte_count = params + 1 /* pad */ ;
4311 pSMB->TotalParameterCount = cpu_to_le16(params);
4312 pSMB->ParameterCount = pSMB->TotalParameterCount;
4313 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004314 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315
4316 pSMB->DataCount = 0;
4317 pSMB->DataOffset = 0;
4318 pSMB->SetupCount = 1;
4319 pSMB->Reserved3 = 0;
4320 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4321 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4322 pSMB->hdr.smb_buf_length += byte_count;
4323 pSMB->ByteCount = cpu_to_le16(byte_count);
4324
4325 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4326 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4327 if (rc) {
4328 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4329 } else { /* decode response */
4330 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4331
4332 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4333 rc = -EIO; /* bad smb */
4334 else {
4335 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4336 response_data =
Steve French737b7582005-04-28 22:41:06 -07004337 (FILE_SYSTEM_DEVICE_INFO *)
4338 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339 data_offset);
4340 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004341 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 }
4343 }
4344 cifs_buf_release(pSMB);
4345
4346 if (rc == -EAGAIN)
4347 goto QFSDeviceRetry;
4348
4349 return rc;
4350}
4351
4352int
Steve French737b7582005-04-28 22:41:06 -07004353CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354{
4355/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4356 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4357 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4358 FILE_SYSTEM_UNIX_INFO *response_data;
4359 int rc = 0;
4360 int bytes_returned = 0;
4361 __u16 params, byte_count;
4362
4363 cFYI(1, ("In QFSUnixInfo"));
4364QFSUnixRetry:
4365 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4366 (void **) &pSMBr);
4367 if (rc)
4368 return rc;
4369
4370 params = 2; /* level */
4371 pSMB->TotalDataCount = 0;
4372 pSMB->DataCount = 0;
4373 pSMB->DataOffset = 0;
4374 pSMB->MaxParameterCount = cpu_to_le16(2);
4375 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4376 pSMB->MaxSetupCount = 0;
4377 pSMB->Reserved = 0;
4378 pSMB->Flags = 0;
4379 pSMB->Timeout = 0;
4380 pSMB->Reserved2 = 0;
4381 byte_count = params + 1 /* pad */ ;
4382 pSMB->ParameterCount = cpu_to_le16(params);
4383 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004384 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4385 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 pSMB->SetupCount = 1;
4387 pSMB->Reserved3 = 0;
4388 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4389 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4390 pSMB->hdr.smb_buf_length += byte_count;
4391 pSMB->ByteCount = cpu_to_le16(byte_count);
4392
4393 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4394 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4395 if (rc) {
4396 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4397 } else { /* decode response */
4398 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4399
4400 if (rc || (pSMBr->ByteCount < 13)) {
4401 rc = -EIO; /* bad smb */
4402 } else {
4403 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4404 response_data =
4405 (FILE_SYSTEM_UNIX_INFO
4406 *) (((char *) &pSMBr->hdr.Protocol) +
4407 data_offset);
4408 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004409 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 }
4411 }
4412 cifs_buf_release(pSMB);
4413
4414 if (rc == -EAGAIN)
4415 goto QFSUnixRetry;
4416
4417
4418 return rc;
4419}
4420
Jeremy Allisonac670552005-06-22 17:26:35 -07004421int
Steve French45abc6e2005-06-23 13:42:03 -05004422CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004423{
4424/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4425 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4426 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4427 int rc = 0;
4428 int bytes_returned = 0;
4429 __u16 params, param_offset, offset, byte_count;
4430
4431 cFYI(1, ("In SETFSUnixInfo"));
4432SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004433 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004434 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4435 (void **) &pSMBr);
4436 if (rc)
4437 return rc;
4438
4439 params = 4; /* 2 bytes zero followed by info level. */
4440 pSMB->MaxSetupCount = 0;
4441 pSMB->Reserved = 0;
4442 pSMB->Flags = 0;
4443 pSMB->Timeout = 0;
4444 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004445 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4446 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004447 offset = param_offset + params;
4448
4449 pSMB->MaxParameterCount = cpu_to_le16(4);
4450 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4451 pSMB->SetupCount = 1;
4452 pSMB->Reserved3 = 0;
4453 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4454 byte_count = 1 /* pad */ + params + 12;
4455
4456 pSMB->DataCount = cpu_to_le16(12);
4457 pSMB->ParameterCount = cpu_to_le16(params);
4458 pSMB->TotalDataCount = pSMB->DataCount;
4459 pSMB->TotalParameterCount = pSMB->ParameterCount;
4460 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4461 pSMB->DataOffset = cpu_to_le16(offset);
4462
4463 /* Params. */
4464 pSMB->FileNum = 0;
4465 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4466
4467 /* Data. */
4468 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4469 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4470 pSMB->ClientUnixCap = cpu_to_le64(cap);
4471
4472 pSMB->hdr.smb_buf_length += byte_count;
4473 pSMB->ByteCount = cpu_to_le16(byte_count);
4474
4475 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4476 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4477 if (rc) {
4478 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4479 } else { /* decode response */
4480 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4481 if (rc) {
4482 rc = -EIO; /* bad smb */
4483 }
4484 }
4485 cifs_buf_release(pSMB);
4486
4487 if (rc == -EAGAIN)
4488 goto SETFSUnixRetry;
4489
4490 return rc;
4491}
4492
4493
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494
4495int
4496CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004497 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498{
4499/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4500 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4501 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4502 FILE_SYSTEM_POSIX_INFO *response_data;
4503 int rc = 0;
4504 int bytes_returned = 0;
4505 __u16 params, byte_count;
4506
4507 cFYI(1, ("In QFSPosixInfo"));
4508QFSPosixRetry:
4509 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4510 (void **) &pSMBr);
4511 if (rc)
4512 return rc;
4513
4514 params = 2; /* level */
4515 pSMB->TotalDataCount = 0;
4516 pSMB->DataCount = 0;
4517 pSMB->DataOffset = 0;
4518 pSMB->MaxParameterCount = cpu_to_le16(2);
4519 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4520 pSMB->MaxSetupCount = 0;
4521 pSMB->Reserved = 0;
4522 pSMB->Flags = 0;
4523 pSMB->Timeout = 0;
4524 pSMB->Reserved2 = 0;
4525 byte_count = params + 1 /* pad */ ;
4526 pSMB->ParameterCount = cpu_to_le16(params);
4527 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004528 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4529 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530 pSMB->SetupCount = 1;
4531 pSMB->Reserved3 = 0;
4532 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4533 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4534 pSMB->hdr.smb_buf_length += byte_count;
4535 pSMB->ByteCount = cpu_to_le16(byte_count);
4536
4537 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4538 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4539 if (rc) {
4540 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4541 } else { /* decode response */
4542 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4543
4544 if (rc || (pSMBr->ByteCount < 13)) {
4545 rc = -EIO; /* bad smb */
4546 } else {
4547 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4548 response_data =
4549 (FILE_SYSTEM_POSIX_INFO
4550 *) (((char *) &pSMBr->hdr.Protocol) +
4551 data_offset);
4552 FSData->f_bsize =
4553 le32_to_cpu(response_data->BlockSize);
4554 FSData->f_blocks =
4555 le64_to_cpu(response_data->TotalBlocks);
4556 FSData->f_bfree =
4557 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004558 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004559 FSData->f_bavail = FSData->f_bfree;
4560 } else {
4561 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004562 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 }
Steve French790fe572007-07-07 19:25:05 +00004564 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004566 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004567 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004569 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 }
4571 }
4572 cifs_buf_release(pSMB);
4573
4574 if (rc == -EAGAIN)
4575 goto QFSPosixRetry;
4576
4577 return rc;
4578}
4579
4580
Steve French50c2f752007-07-13 00:33:32 +00004581/* We can not use write of zero bytes trick to
4582 set file size due to need for large file support. Also note that
4583 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004584 routine which is only needed to work around a sharing violation bug
4585 in Samba which this routine can run into */
4586
4587int
4588CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004589 __u64 size, int SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004590 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591{
4592 struct smb_com_transaction2_spi_req *pSMB = NULL;
4593 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4594 struct file_end_of_file_info *parm_data;
4595 int name_len;
4596 int rc = 0;
4597 int bytes_returned = 0;
4598 __u16 params, byte_count, data_count, param_offset, offset;
4599
4600 cFYI(1, ("In SetEOF"));
4601SetEOFRetry:
4602 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4603 (void **) &pSMBr);
4604 if (rc)
4605 return rc;
4606
4607 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4608 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004609 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004610 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004611 name_len++; /* trailing null */
4612 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004613 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614 name_len = strnlen(fileName, PATH_MAX);
4615 name_len++; /* trailing null */
4616 strncpy(pSMB->FileName, fileName, name_len);
4617 }
4618 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004619 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004621 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 pSMB->MaxSetupCount = 0;
4623 pSMB->Reserved = 0;
4624 pSMB->Flags = 0;
4625 pSMB->Timeout = 0;
4626 pSMB->Reserved2 = 0;
4627 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004628 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004630 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004631 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4632 pSMB->InformationLevel =
4633 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4634 else
4635 pSMB->InformationLevel =
4636 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4637 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004638 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4639 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004640 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641 else
4642 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004643 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 }
4645
4646 parm_data =
4647 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4648 offset);
4649 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4650 pSMB->DataOffset = cpu_to_le16(offset);
4651 pSMB->SetupCount = 1;
4652 pSMB->Reserved3 = 0;
4653 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4654 byte_count = 3 /* pad */ + params + data_count;
4655 pSMB->DataCount = cpu_to_le16(data_count);
4656 pSMB->TotalDataCount = pSMB->DataCount;
4657 pSMB->ParameterCount = cpu_to_le16(params);
4658 pSMB->TotalParameterCount = pSMB->ParameterCount;
4659 pSMB->Reserved4 = 0;
4660 pSMB->hdr.smb_buf_length += byte_count;
4661 parm_data->FileSize = cpu_to_le64(size);
4662 pSMB->ByteCount = cpu_to_le16(byte_count);
4663 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4664 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4665 if (rc) {
4666 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4667 }
4668
4669 cifs_buf_release(pSMB);
4670
4671 if (rc == -EAGAIN)
4672 goto SetEOFRetry;
4673
4674 return rc;
4675}
4676
4677int
Steve French50c2f752007-07-13 00:33:32 +00004678CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4679 __u16 fid, __u32 pid_of_opener, int SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004680{
4681 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4682 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4683 char *data_offset;
4684 struct file_end_of_file_info *parm_data;
4685 int rc = 0;
4686 int bytes_returned = 0;
4687 __u16 params, param_offset, offset, byte_count, count;
4688
4689 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4690 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004691 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4692
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693 if (rc)
4694 return rc;
4695
Steve Frenchcd634992005-04-28 22:41:10 -07004696 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4697
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4699 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004700
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701 params = 6;
4702 pSMB->MaxSetupCount = 0;
4703 pSMB->Reserved = 0;
4704 pSMB->Flags = 0;
4705 pSMB->Timeout = 0;
4706 pSMB->Reserved2 = 0;
4707 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4708 offset = param_offset + params;
4709
Steve French50c2f752007-07-13 00:33:32 +00004710 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711
4712 count = sizeof(struct file_end_of_file_info);
4713 pSMB->MaxParameterCount = cpu_to_le16(2);
4714 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4715 pSMB->SetupCount = 1;
4716 pSMB->Reserved3 = 0;
4717 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4718 byte_count = 3 /* pad */ + params + count;
4719 pSMB->DataCount = cpu_to_le16(count);
4720 pSMB->ParameterCount = cpu_to_le16(params);
4721 pSMB->TotalDataCount = pSMB->DataCount;
4722 pSMB->TotalParameterCount = pSMB->ParameterCount;
4723 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4724 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004725 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4726 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727 pSMB->DataOffset = cpu_to_le16(offset);
4728 parm_data->FileSize = cpu_to_le64(size);
4729 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004730 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4732 pSMB->InformationLevel =
4733 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4734 else
4735 pSMB->InformationLevel =
4736 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004737 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4739 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004740 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741 else
4742 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004743 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 }
4745 pSMB->Reserved4 = 0;
4746 pSMB->hdr.smb_buf_length += byte_count;
4747 pSMB->ByteCount = cpu_to_le16(byte_count);
4748 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4749 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4750 if (rc) {
4751 cFYI(1,
4752 ("Send error in SetFileInfo (SetFileSize) = %d",
4753 rc));
4754 }
4755
4756 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004757 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758
Steve French50c2f752007-07-13 00:33:32 +00004759 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760 since file handle passed in no longer valid */
4761
4762 return rc;
4763}
4764
Steve French50c2f752007-07-13 00:33:32 +00004765/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 an open handle, rather than by pathname - this is awkward due to
4767 potential access conflicts on the open, but it is unavoidable for these
4768 old servers since the only other choice is to go from 100 nanosecond DCE
4769 time and resort to the original setpathinfo level which takes the ancient
4770 DOS time format with 2 second granularity */
4771int
Steve French50c2f752007-07-13 00:33:32 +00004772CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4773 const FILE_BASIC_INFO *data, __u16 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774{
4775 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4776 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4777 char *data_offset;
4778 int rc = 0;
4779 int bytes_returned = 0;
4780 __u16 params, param_offset, offset, byte_count, count;
4781
4782 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004783 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4784
Linus Torvalds1da177e2005-04-16 15:20:36 -07004785 if (rc)
4786 return rc;
4787
Steve Frenchcd634992005-04-28 22:41:10 -07004788 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4789
Linus Torvalds1da177e2005-04-16 15:20:36 -07004790 /* At this point there is no need to override the current pid
4791 with the pid of the opener, but that could change if we someday
4792 use an existing handle (rather than opening one on the fly) */
4793 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4794 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
Steve French50c2f752007-07-13 00:33:32 +00004795
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 params = 6;
4797 pSMB->MaxSetupCount = 0;
4798 pSMB->Reserved = 0;
4799 pSMB->Flags = 0;
4800 pSMB->Timeout = 0;
4801 pSMB->Reserved2 = 0;
4802 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4803 offset = param_offset + params;
4804
Steve French50c2f752007-07-13 00:33:32 +00004805 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806
Steve French26f57362007-08-30 22:09:15 +00004807 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808 pSMB->MaxParameterCount = cpu_to_le16(2);
4809 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4810 pSMB->SetupCount = 1;
4811 pSMB->Reserved3 = 0;
4812 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4813 byte_count = 3 /* pad */ + params + count;
4814 pSMB->DataCount = cpu_to_le16(count);
4815 pSMB->ParameterCount = cpu_to_le16(params);
4816 pSMB->TotalDataCount = pSMB->DataCount;
4817 pSMB->TotalParameterCount = pSMB->ParameterCount;
4818 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4819 pSMB->DataOffset = cpu_to_le16(offset);
4820 pSMB->Fid = fid;
4821 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4822 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4823 else
4824 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4825 pSMB->Reserved4 = 0;
4826 pSMB->hdr.smb_buf_length += byte_count;
4827 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004828 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4830 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4831 if (rc) {
Steve French50c2f752007-07-13 00:33:32 +00004832 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833 }
4834
Steve Frenchcd634992005-04-28 22:41:10 -07004835 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836
Steve French50c2f752007-07-13 00:33:32 +00004837 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838 since file handle passed in no longer valid */
4839
4840 return rc;
4841}
4842
4843
4844int
4845CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004846 const FILE_BASIC_INFO *data,
Steve French737b7582005-04-28 22:41:06 -07004847 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848{
4849 TRANSACTION2_SPI_REQ *pSMB = NULL;
4850 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4851 int name_len;
4852 int rc = 0;
4853 int bytes_returned = 0;
4854 char *data_offset;
4855 __u16 params, param_offset, offset, byte_count, count;
4856
4857 cFYI(1, ("In SetTimes"));
4858
4859SetTimesRetry:
4860 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4861 (void **) &pSMBr);
4862 if (rc)
4863 return rc;
4864
4865 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4866 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004867 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004868 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004869 name_len++; /* trailing null */
4870 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004871 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004872 name_len = strnlen(fileName, PATH_MAX);
4873 name_len++; /* trailing null */
4874 strncpy(pSMB->FileName, fileName, name_len);
4875 }
4876
4877 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004878 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 pSMB->MaxParameterCount = cpu_to_le16(2);
4880 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4881 pSMB->MaxSetupCount = 0;
4882 pSMB->Reserved = 0;
4883 pSMB->Flags = 0;
4884 pSMB->Timeout = 0;
4885 pSMB->Reserved2 = 0;
4886 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004887 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004888 offset = param_offset + params;
4889 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4890 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4891 pSMB->DataOffset = cpu_to_le16(offset);
4892 pSMB->SetupCount = 1;
4893 pSMB->Reserved3 = 0;
4894 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4895 byte_count = 3 /* pad */ + params + count;
4896
4897 pSMB->DataCount = cpu_to_le16(count);
4898 pSMB->ParameterCount = cpu_to_le16(params);
4899 pSMB->TotalDataCount = pSMB->DataCount;
4900 pSMB->TotalParameterCount = pSMB->ParameterCount;
4901 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4902 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4903 else
4904 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4905 pSMB->Reserved4 = 0;
4906 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00004907 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004908 pSMB->ByteCount = cpu_to_le16(byte_count);
4909 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4910 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4911 if (rc) {
4912 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4913 }
4914
4915 cifs_buf_release(pSMB);
4916
4917 if (rc == -EAGAIN)
4918 goto SetTimesRetry;
4919
4920 return rc;
4921}
4922
4923/* Can not be used to set time stamps yet (due to old DOS time format) */
4924/* Can be used to set attributes */
4925#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4926 handling it anyway and NT4 was what we thought it would be needed for
4927 Do not delete it until we prove whether needed for Win9x though */
4928int
4929CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4930 __u16 dos_attrs, const struct nls_table *nls_codepage)
4931{
4932 SETATTR_REQ *pSMB = NULL;
4933 SETATTR_RSP *pSMBr = NULL;
4934 int rc = 0;
4935 int bytes_returned;
4936 int name_len;
4937
4938 cFYI(1, ("In SetAttrLegacy"));
4939
4940SetAttrLgcyRetry:
4941 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4942 (void **) &pSMBr);
4943 if (rc)
4944 return rc;
4945
4946 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4947 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004948 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004949 PATH_MAX, nls_codepage);
4950 name_len++; /* trailing null */
4951 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004952 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953 name_len = strnlen(fileName, PATH_MAX);
4954 name_len++; /* trailing null */
4955 strncpy(pSMB->fileName, fileName, name_len);
4956 }
4957 pSMB->attr = cpu_to_le16(dos_attrs);
4958 pSMB->BufferFormat = 0x04;
4959 pSMB->hdr.smb_buf_length += name_len + 1;
4960 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4961 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4962 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4963 if (rc) {
4964 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4965 }
4966
4967 cifs_buf_release(pSMB);
4968
4969 if (rc == -EAGAIN)
4970 goto SetAttrLgcyRetry;
4971
4972 return rc;
4973}
4974#endif /* temporarily unneeded SetAttr legacy function */
4975
4976int
4977CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004978 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4979 dev_t device, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07004980 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981{
4982 TRANSACTION2_SPI_REQ *pSMB = NULL;
4983 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4984 int name_len;
4985 int rc = 0;
4986 int bytes_returned = 0;
4987 FILE_UNIX_BASIC_INFO *data_offset;
4988 __u16 params, param_offset, offset, count, byte_count;
4989
4990 cFYI(1, ("In SetUID/GID/Mode"));
4991setPermsRetry:
4992 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4993 (void **) &pSMBr);
4994 if (rc)
4995 return rc;
4996
4997 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4998 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004999 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005000 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005001 name_len++; /* trailing null */
5002 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005003 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005004 name_len = strnlen(fileName, PATH_MAX);
5005 name_len++; /* trailing null */
5006 strncpy(pSMB->FileName, fileName, name_len);
5007 }
5008
5009 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005010 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011 pSMB->MaxParameterCount = cpu_to_le16(2);
5012 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
5013 pSMB->MaxSetupCount = 0;
5014 pSMB->Reserved = 0;
5015 pSMB->Flags = 0;
5016 pSMB->Timeout = 0;
5017 pSMB->Reserved2 = 0;
5018 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005019 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 offset = param_offset + params;
5021 data_offset =
5022 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5023 offset);
5024 memset(data_offset, 0, count);
5025 pSMB->DataOffset = cpu_to_le16(offset);
5026 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5027 pSMB->SetupCount = 1;
5028 pSMB->Reserved3 = 0;
5029 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5030 byte_count = 3 /* pad */ + params + count;
5031 pSMB->ParameterCount = cpu_to_le16(params);
5032 pSMB->DataCount = cpu_to_le16(count);
5033 pSMB->TotalParameterCount = pSMB->ParameterCount;
5034 pSMB->TotalDataCount = pSMB->DataCount;
5035 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5036 pSMB->Reserved4 = 0;
5037 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005038 /* Samba server ignores set of file size to zero due to bugs in some
5039 older clients, but we should be precise - we use SetFileSize to
5040 set file size and do not want to truncate file size to zero
5041 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005042 zero instead of -1 here */
Steve Frenchc7af1852007-03-01 04:11:22 +00005043 data_offset->EndOfFile = NO_CHANGE_64;
5044 data_offset->NumOfBytes = NO_CHANGE_64;
5045 data_offset->LastStatusChange = NO_CHANGE_64;
5046 data_offset->LastAccessTime = NO_CHANGE_64;
5047 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048 data_offset->Uid = cpu_to_le64(uid);
5049 data_offset->Gid = cpu_to_le64(gid);
5050 /* better to leave device as zero when it is */
5051 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5052 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5053 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005054
Steve French790fe572007-07-07 19:25:05 +00005055 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005056 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005057 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005059 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005061 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005063 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005065 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005067 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5069
5070
5071 pSMB->ByteCount = cpu_to_le16(byte_count);
5072 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5073 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5074 if (rc) {
5075 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5076 }
5077
5078 if (pSMB)
5079 cifs_buf_release(pSMB);
5080 if (rc == -EAGAIN)
5081 goto setPermsRetry;
5082 return rc;
5083}
5084
Steve French50c2f752007-07-13 00:33:32 +00005085int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005086 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005087 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005088 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005089{
5090 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005091 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5092 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005093 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 int bytes_returned;
5095
Steve French50c2f752007-07-13 00:33:32 +00005096 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005097 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005098 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099 if (rc)
5100 return rc;
5101
5102 pSMB->TotalParameterCount = 0 ;
5103 pSMB->TotalDataCount = 0;
5104 pSMB->MaxParameterCount = cpu_to_le32(2);
5105 /* BB find exact data count max from sess structure BB */
5106 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005107/* BB VERIFY verify which is correct for above BB */
5108 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5109 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5110
Linus Torvalds1da177e2005-04-16 15:20:36 -07005111 pSMB->MaxSetupCount = 4;
5112 pSMB->Reserved = 0;
5113 pSMB->ParameterOffset = 0;
5114 pSMB->DataCount = 0;
5115 pSMB->DataOffset = 0;
5116 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5117 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5118 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005119 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005120 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5121 pSMB->Reserved2 = 0;
5122 pSMB->CompletionFilter = cpu_to_le32(filter);
5123 pSMB->Fid = netfid; /* file handle always le */
5124 pSMB->ByteCount = 0;
5125
5126 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5127 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
5128 if (rc) {
5129 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005130 } else {
5131 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005132 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005133 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005134 sizeof(struct dir_notify_req),
5135 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005136 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005137 dnotify_req->Pid = pSMB->hdr.Pid;
5138 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5139 dnotify_req->Mid = pSMB->hdr.Mid;
5140 dnotify_req->Tid = pSMB->hdr.Tid;
5141 dnotify_req->Uid = pSMB->hdr.Uid;
5142 dnotify_req->netfid = netfid;
5143 dnotify_req->pfile = pfile;
5144 dnotify_req->filter = filter;
5145 dnotify_req->multishot = multishot;
5146 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005147 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005148 &GlobalDnotifyReqList);
5149 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005150 } else
Steve French47c786e2005-10-11 20:03:18 -07005151 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005152 }
5153 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005154 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155}
5156#ifdef CONFIG_CIFS_XATTR
5157ssize_t
5158CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5159 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005160 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005161 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005162{
5163 /* BB assumes one setup word */
5164 TRANSACTION2_QPI_REQ *pSMB = NULL;
5165 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5166 int rc = 0;
5167 int bytes_returned;
5168 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005169 struct fea *temp_fea;
5170 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005171 __u16 params, byte_count;
5172
5173 cFYI(1, ("In Query All EAs path %s", searchName));
5174QAllEAsRetry:
5175 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5176 (void **) &pSMBr);
5177 if (rc)
5178 return rc;
5179
5180 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5181 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005182 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005183 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005184 name_len++; /* trailing null */
5185 name_len *= 2;
5186 } else { /* BB improve the check for buffer overruns BB */
5187 name_len = strnlen(searchName, PATH_MAX);
5188 name_len++; /* trailing null */
5189 strncpy(pSMB->FileName, searchName, name_len);
5190 }
5191
Steve French50c2f752007-07-13 00:33:32 +00005192 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193 pSMB->TotalDataCount = 0;
5194 pSMB->MaxParameterCount = cpu_to_le16(2);
5195 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5196 pSMB->MaxSetupCount = 0;
5197 pSMB->Reserved = 0;
5198 pSMB->Flags = 0;
5199 pSMB->Timeout = 0;
5200 pSMB->Reserved2 = 0;
5201 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005202 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203 pSMB->DataCount = 0;
5204 pSMB->DataOffset = 0;
5205 pSMB->SetupCount = 1;
5206 pSMB->Reserved3 = 0;
5207 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5208 byte_count = params + 1 /* pad */ ;
5209 pSMB->TotalParameterCount = cpu_to_le16(params);
5210 pSMB->ParameterCount = pSMB->TotalParameterCount;
5211 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5212 pSMB->Reserved4 = 0;
5213 pSMB->hdr.smb_buf_length += byte_count;
5214 pSMB->ByteCount = cpu_to_le16(byte_count);
5215
5216 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5217 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5218 if (rc) {
5219 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5220 } else { /* decode response */
5221 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5222
5223 /* BB also check enough total bytes returned */
5224 /* BB we need to improve the validity checking
5225 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005226 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005227 rc = -EIO; /* bad smb */
5228 /* else if (pFindData){
5229 memcpy((char *) pFindData,
5230 (char *) &pSMBr->hdr.Protocol +
5231 data_offset, kl);
5232 }*/ else {
5233 /* check that length of list is not more than bcc */
5234 /* check that each entry does not go beyond length
5235 of list */
5236 /* check that each element of each entry does not
5237 go beyond end of list */
5238 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005239 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005240 rc = 0;
5241 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005242 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005243 ea_response_data = (struct fealist *)
5244 (((char *) &pSMBr->hdr.Protocol) +
5245 data_offset);
5246 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005247 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005248 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005249 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005250 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 } else {
5252 /* account for ea list len */
5253 name_len -= 4;
5254 temp_fea = ea_response_data->list;
5255 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005256 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257 __u16 value_len;
5258 name_len -= 4;
5259 temp_ptr += 4;
5260 rc += temp_fea->name_len;
5261 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005262 rc = rc + 5 + 1;
5263 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005264 memcpy(EAData, "user.", 5);
5265 EAData += 5;
5266 memcpy(EAData, temp_ptr,
5267 temp_fea->name_len);
5268 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005269 /* null terminate name */
5270 *EAData = 0;
5271 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005272 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 /* skip copy - calc size only */
5274 } else {
5275 /* stop before overrun buffer */
5276 rc = -ERANGE;
5277 break;
5278 }
5279 name_len -= temp_fea->name_len;
5280 temp_ptr += temp_fea->name_len;
5281 /* account for trailing null */
5282 name_len--;
5283 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005284 value_len =
5285 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005286 name_len -= value_len;
5287 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005288 /* BB check that temp_ptr is still
5289 within the SMB BB*/
5290
5291 /* no trailing null to account for
5292 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005293 /* go on to next EA */
5294 temp_fea = (struct fea *)temp_ptr;
5295 }
5296 }
5297 }
5298 }
5299 if (pSMB)
5300 cifs_buf_release(pSMB);
5301 if (rc == -EAGAIN)
5302 goto QAllEAsRetry;
5303
5304 return (ssize_t)rc;
5305}
5306
Steve French50c2f752007-07-13 00:33:32 +00005307ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5308 const unsigned char *searchName, const unsigned char *ea_name,
5309 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005310 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311{
5312 TRANSACTION2_QPI_REQ *pSMB = NULL;
5313 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5314 int rc = 0;
5315 int bytes_returned;
5316 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005317 struct fea *temp_fea;
5318 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005319 __u16 params, byte_count;
5320
5321 cFYI(1, ("In Query EA path %s", searchName));
5322QEARetry:
5323 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5324 (void **) &pSMBr);
5325 if (rc)
5326 return rc;
5327
5328 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5329 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005330 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005331 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332 name_len++; /* trailing null */
5333 name_len *= 2;
5334 } else { /* BB improve the check for buffer overruns BB */
5335 name_len = strnlen(searchName, PATH_MAX);
5336 name_len++; /* trailing null */
5337 strncpy(pSMB->FileName, searchName, name_len);
5338 }
5339
Steve French50c2f752007-07-13 00:33:32 +00005340 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341 pSMB->TotalDataCount = 0;
5342 pSMB->MaxParameterCount = cpu_to_le16(2);
5343 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5344 pSMB->MaxSetupCount = 0;
5345 pSMB->Reserved = 0;
5346 pSMB->Flags = 0;
5347 pSMB->Timeout = 0;
5348 pSMB->Reserved2 = 0;
5349 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005350 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 pSMB->DataCount = 0;
5352 pSMB->DataOffset = 0;
5353 pSMB->SetupCount = 1;
5354 pSMB->Reserved3 = 0;
5355 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5356 byte_count = params + 1 /* pad */ ;
5357 pSMB->TotalParameterCount = cpu_to_le16(params);
5358 pSMB->ParameterCount = pSMB->TotalParameterCount;
5359 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5360 pSMB->Reserved4 = 0;
5361 pSMB->hdr.smb_buf_length += byte_count;
5362 pSMB->ByteCount = cpu_to_le16(byte_count);
5363
5364 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5365 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5366 if (rc) {
5367 cFYI(1, ("Send error in Query EA = %d", rc));
5368 } else { /* decode response */
5369 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5370
5371 /* BB also check enough total bytes returned */
5372 /* BB we need to improve the validity checking
5373 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005374 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005375 rc = -EIO; /* bad smb */
5376 /* else if (pFindData){
5377 memcpy((char *) pFindData,
5378 (char *) &pSMBr->hdr.Protocol +
5379 data_offset, kl);
5380 }*/ else {
5381 /* check that length of list is not more than bcc */
5382 /* check that each entry does not go beyond length
5383 of list */
5384 /* check that each element of each entry does not
5385 go beyond end of list */
5386 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005387 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005388 rc = -ENODATA;
5389 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005390 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005391 ea_response_data = (struct fealist *)
5392 (((char *) &pSMBr->hdr.Protocol) +
5393 data_offset);
5394 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005395 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005396 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005398 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 } else {
5400 /* account for ea list len */
5401 name_len -= 4;
5402 temp_fea = ea_response_data->list;
5403 temp_ptr = (char *)temp_fea;
5404 /* loop through checking if we have a matching
5405 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005406 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005407 __u16 value_len;
5408 name_len -= 4;
5409 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005410 value_len =
5411 le16_to_cpu(temp_fea->value_len);
5412 /* BB validate that value_len falls within SMB,
5413 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005414 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005415 temp_fea->name_len) == 0) {
5416 /* found a match */
5417 rc = value_len;
5418 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005419 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 memcpy(ea_value,
5421 temp_fea->name+temp_fea->name_len+1,
5422 rc);
Steve French50c2f752007-07-13 00:33:32 +00005423 /* ea values, unlike ea
5424 names, are not null
5425 terminated */
Steve French790fe572007-07-07 19:25:05 +00005426 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427 /* skip copy - calc size only */
5428 } else {
Steve French50c2f752007-07-13 00:33:32 +00005429 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005430 rc = -ERANGE;
5431 }
5432 break;
5433 }
5434 name_len -= temp_fea->name_len;
5435 temp_ptr += temp_fea->name_len;
5436 /* account for trailing null */
5437 name_len--;
5438 temp_ptr++;
5439 name_len -= value_len;
5440 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005441 /* No trailing null to account for in
5442 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 temp_fea = (struct fea *)temp_ptr;
5444 }
Steve French50c2f752007-07-13 00:33:32 +00005445 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446 }
5447 }
5448 if (pSMB)
5449 cifs_buf_release(pSMB);
5450 if (rc == -EAGAIN)
5451 goto QEARetry;
5452
5453 return (ssize_t)rc;
5454}
5455
5456int
5457CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005458 const char *ea_name, const void *ea_value,
5459 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5460 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461{
5462 struct smb_com_transaction2_spi_req *pSMB = NULL;
5463 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5464 struct fealist *parm_data;
5465 int name_len;
5466 int rc = 0;
5467 int bytes_returned = 0;
5468 __u16 params, param_offset, byte_count, offset, count;
5469
5470 cFYI(1, ("In SetEA"));
5471SetEARetry:
5472 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5473 (void **) &pSMBr);
5474 if (rc)
5475 return rc;
5476
5477 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5478 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005479 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005480 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005481 name_len++; /* trailing null */
5482 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005483 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 name_len = strnlen(fileName, PATH_MAX);
5485 name_len++; /* trailing null */
5486 strncpy(pSMB->FileName, fileName, name_len);
5487 }
5488
5489 params = 6 + name_len;
5490
5491 /* done calculating parms using name_len of file name,
5492 now use name_len to calculate length of ea name
5493 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005494 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 name_len = 0;
5496 else
Steve French50c2f752007-07-13 00:33:32 +00005497 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498
5499 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5500 pSMB->MaxParameterCount = cpu_to_le16(2);
5501 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5502 pSMB->MaxSetupCount = 0;
5503 pSMB->Reserved = 0;
5504 pSMB->Flags = 0;
5505 pSMB->Timeout = 0;
5506 pSMB->Reserved2 = 0;
5507 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005508 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 offset = param_offset + params;
5510 pSMB->InformationLevel =
5511 cpu_to_le16(SMB_SET_FILE_EA);
5512
5513 parm_data =
5514 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5515 offset);
5516 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5517 pSMB->DataOffset = cpu_to_le16(offset);
5518 pSMB->SetupCount = 1;
5519 pSMB->Reserved3 = 0;
5520 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5521 byte_count = 3 /* pad */ + params + count;
5522 pSMB->DataCount = cpu_to_le16(count);
5523 parm_data->list_len = cpu_to_le32(count);
5524 parm_data->list[0].EA_flags = 0;
5525 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005526 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005528 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005529 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005530 parm_data->list[0].name[name_len] = 0;
5531 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5532 /* caller ensures that ea_value_len is less than 64K but
5533 we need to ensure that it fits within the smb */
5534
Steve French50c2f752007-07-13 00:33:32 +00005535 /*BB add length check to see if it would fit in
5536 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005537 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5538 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005539 memcpy(parm_data->list[0].name+name_len+1,
5540 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005541
5542 pSMB->TotalDataCount = pSMB->DataCount;
5543 pSMB->ParameterCount = cpu_to_le16(params);
5544 pSMB->TotalParameterCount = pSMB->ParameterCount;
5545 pSMB->Reserved4 = 0;
5546 pSMB->hdr.smb_buf_length += byte_count;
5547 pSMB->ByteCount = cpu_to_le16(byte_count);
5548 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5549 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5550 if (rc) {
5551 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5552 }
5553
5554 cifs_buf_release(pSMB);
5555
5556 if (rc == -EAGAIN)
5557 goto SetEARetry;
5558
5559 return rc;
5560}
5561
5562#endif