blob: f0d9a485d0951f29c3f140ebda33391d7471a53d [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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchb815f1e2006-10-02 05:53:29 +0000524 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000525 if (val < 0)
Steve Frenchb815f1e2006-10-02 05:53:29 +0000526 result = - result;
527 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000528 } else {
Steve Frenchb815f1e2006-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 Frenchb815f1e2006-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 Frenchabb63d62007-10-18 02:58:40 +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 Frenchabb63d62007-10-18 02:58:40 +0000670 rc = -EOPNOTSUPP;
671 }
Steve French50c2f752007-07-13 00:33:32 +0000672 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000673 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000674 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
675 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000676 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000677 if ((server->secMode &
678 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
679 cERROR(1,
680 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000681 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000682 } else
683 server->secMode |= SECMODE_SIGN_REQUIRED;
684 } else {
685 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000686 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000687 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000688 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 }
Steve French50c2f752007-07-13 00:33:32 +0000690
691neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700692 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000693
Steve French790fe572007-07-07 19:25:05 +0000694 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 return rc;
696}
697
698int
699CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
700{
701 struct smb_hdr *smb_buffer;
702 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
703 int rc = 0;
704 int length;
705
706 cFYI(1, ("In tree disconnect"));
707 /*
708 * If last user of the connection and
709 * connection alive - disconnect it
710 * If this is the last connection on the server session disconnect it
Steve French50c2f752007-07-13 00:33:32 +0000711 * (and inside session disconnect we should check if tcp socket needs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 * to be freed and kernel thread woken up).
713 */
714 if (tcon)
715 down(&tcon->tconSem);
716 else
717 return -EIO;
718
719 atomic_dec(&tcon->useCount);
720 if (atomic_read(&tcon->useCount) > 0) {
721 up(&tcon->tconSem);
722 return -EBUSY;
723 }
724
Steve French50c2f752007-07-13 00:33:32 +0000725 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 closed on server already e.g. due to tcp session crashing */
Steve French790fe572007-07-07 19:25:05 +0000727 if (tcon->tidStatus == CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 up(&tcon->tconSem);
Steve French50c2f752007-07-13 00:33:32 +0000729 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 }
731
Steve French790fe572007-07-07 19:25:05 +0000732 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 up(&tcon->tconSem);
734 return -EIO;
735 }
Steve French50c2f752007-07-13 00:33:32 +0000736 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700737 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 if (rc) {
739 up(&tcon->tconSem);
740 return rc;
741 } else {
742 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700743 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
745 &length, 0);
746 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700747 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
749 if (smb_buffer)
750 cifs_small_buf_release(smb_buffer);
751 up(&tcon->tconSem);
752
Steve French50c2f752007-07-13 00:33:32 +0000753 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 closed on server already e.g. due to tcp session crashing */
755 if (rc == -EAGAIN)
756 rc = 0;
757
758 return rc;
759}
760
761int
762CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
763{
764 struct smb_hdr *smb_buffer_response;
765 LOGOFF_ANDX_REQ *pSMB;
766 int rc = 0;
767 int length;
768
769 cFYI(1, ("In SMBLogoff for session disconnect"));
770 if (ses)
771 down(&ses->sesSem);
772 else
773 return -EIO;
774
775 atomic_dec(&ses->inUse);
776 if (atomic_read(&ses->inUse) > 0) {
777 up(&ses->sesSem);
778 return -EBUSY;
779 }
780 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
781 if (rc) {
782 up(&ses->sesSem);
783 return rc;
784 }
785
786 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
Steve French50c2f752007-07-13 00:33:32 +0000787
Steve French790fe572007-07-07 19:25:05 +0000788 if (ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700789 pSMB->hdr.Mid = GetNextMid(ses->server);
790
Steve French790fe572007-07-07 19:25:05 +0000791 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
793 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
794 }
795
796 pSMB->hdr.Uid = ses->Suid;
797
798 pSMB->AndXCommand = 0xFF;
799 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
800 smb_buffer_response, &length, 0);
801 if (ses->server) {
802 atomic_dec(&ses->server->socketUseCount);
803 if (atomic_read(&ses->server->socketUseCount) == 0) {
804 spin_lock(&GlobalMid_Lock);
805 ses->server->tcpStatus = CifsExiting;
806 spin_unlock(&GlobalMid_Lock);
807 rc = -ESHUTDOWN;
808 }
809 }
Steve Frencha59c6582005-08-17 12:12:19 -0700810 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700811 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000814 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 error */
816 if (rc == -EAGAIN)
817 rc = 0;
818 return rc;
819}
820
821int
Steve French2d785a52007-07-15 01:48:57 +0000822CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
823 __u16 type, const struct nls_table *nls_codepage, int remap)
824{
825 TRANSACTION2_SPI_REQ *pSMB = NULL;
826 TRANSACTION2_SPI_RSP *pSMBr = NULL;
827 struct unlink_psx_rq *pRqD;
828 int name_len;
829 int rc = 0;
830 int bytes_returned = 0;
831 __u16 params, param_offset, offset, byte_count;
832
833 cFYI(1, ("In POSIX delete"));
834PsxDelete:
835 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
836 (void **) &pSMBr);
837 if (rc)
838 return rc;
839
840 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
841 name_len =
842 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
843 PATH_MAX, nls_codepage, remap);
844 name_len++; /* trailing null */
845 name_len *= 2;
846 } else { /* BB add path length overrun check */
847 name_len = strnlen(fileName, PATH_MAX);
848 name_len++; /* trailing null */
849 strncpy(pSMB->FileName, fileName, name_len);
850 }
851
852 params = 6 + name_len;
853 pSMB->MaxParameterCount = cpu_to_le16(2);
854 pSMB->MaxDataCount = 0; /* BB double check this with jra */
855 pSMB->MaxSetupCount = 0;
856 pSMB->Reserved = 0;
857 pSMB->Flags = 0;
858 pSMB->Timeout = 0;
859 pSMB->Reserved2 = 0;
860 param_offset = offsetof(struct smb_com_transaction2_spi_req,
861 InformationLevel) - 4;
862 offset = param_offset + params;
863
864 /* Setup pointer to Request Data (inode type) */
865 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
866 pRqD->type = cpu_to_le16(type);
867 pSMB->ParameterOffset = cpu_to_le16(param_offset);
868 pSMB->DataOffset = cpu_to_le16(offset);
869 pSMB->SetupCount = 1;
870 pSMB->Reserved3 = 0;
871 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
872 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
873
874 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
875 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
876 pSMB->ParameterCount = cpu_to_le16(params);
877 pSMB->TotalParameterCount = pSMB->ParameterCount;
878 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
879 pSMB->Reserved4 = 0;
880 pSMB->hdr.smb_buf_length += byte_count;
881 pSMB->ByteCount = cpu_to_le16(byte_count);
882 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
883 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
884 if (rc) {
885 cFYI(1, ("Posix delete returned %d", rc));
886 }
887 cifs_buf_release(pSMB);
888
889 cifs_stats_inc(&tcon->num_deletes);
890
891 if (rc == -EAGAIN)
892 goto PsxDelete;
893
894 return rc;
895}
896
897int
Steve French737b7582005-04-28 22:41:06 -0700898CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
899 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900{
901 DELETE_FILE_REQ *pSMB = NULL;
902 DELETE_FILE_RSP *pSMBr = NULL;
903 int rc = 0;
904 int bytes_returned;
905 int name_len;
906
907DelFileRetry:
908 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
909 (void **) &pSMBr);
910 if (rc)
911 return rc;
912
913 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
914 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000915 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700916 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 name_len++; /* trailing null */
918 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700919 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 name_len = strnlen(fileName, PATH_MAX);
921 name_len++; /* trailing null */
922 strncpy(pSMB->fileName, fileName, name_len);
923 }
924 pSMB->SearchAttributes =
925 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
926 pSMB->BufferFormat = 0x04;
927 pSMB->hdr.smb_buf_length += name_len + 1;
928 pSMB->ByteCount = cpu_to_le16(name_len + 1);
929 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
930 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700931 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 if (rc) {
933 cFYI(1, ("Error in RMFile = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000934 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
936 cifs_buf_release(pSMB);
937 if (rc == -EAGAIN)
938 goto DelFileRetry;
939
940 return rc;
941}
942
943int
Steve French50c2f752007-07-13 00:33:32 +0000944CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700945 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946{
947 DELETE_DIRECTORY_REQ *pSMB = NULL;
948 DELETE_DIRECTORY_RSP *pSMBr = NULL;
949 int rc = 0;
950 int bytes_returned;
951 int name_len;
952
953 cFYI(1, ("In CIFSSMBRmDir"));
954RmDirRetry:
955 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
956 (void **) &pSMBr);
957 if (rc)
958 return rc;
959
960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700961 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
962 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 name_len++; /* trailing null */
964 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700965 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 name_len = strnlen(dirName, PATH_MAX);
967 name_len++; /* trailing null */
968 strncpy(pSMB->DirName, dirName, name_len);
969 }
970
971 pSMB->BufferFormat = 0x04;
972 pSMB->hdr.smb_buf_length += name_len + 1;
973 pSMB->ByteCount = cpu_to_le16(name_len + 1);
974 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
975 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700976 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 if (rc) {
978 cFYI(1, ("Error in RMDir = %d", rc));
979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
981 cifs_buf_release(pSMB);
982 if (rc == -EAGAIN)
983 goto RmDirRetry;
984 return rc;
985}
986
987int
988CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700989 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990{
991 int rc = 0;
992 CREATE_DIRECTORY_REQ *pSMB = NULL;
993 CREATE_DIRECTORY_RSP *pSMBr = NULL;
994 int bytes_returned;
995 int name_len;
996
997 cFYI(1, ("In CIFSSMBMkDir"));
998MkDirRetry:
999 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1000 (void **) &pSMBr);
1001 if (rc)
1002 return rc;
1003
1004 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00001005 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -07001006 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 name_len++; /* trailing null */
1008 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001009 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 name_len = strnlen(name, PATH_MAX);
1011 name_len++; /* trailing null */
1012 strncpy(pSMB->DirName, name, name_len);
1013 }
1014
1015 pSMB->BufferFormat = 0x04;
1016 pSMB->hdr.smb_buf_length += name_len + 1;
1017 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1018 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1019 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001020 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 if (rc) {
1022 cFYI(1, ("Error in Mkdir = %d", rc));
1023 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001024
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 cifs_buf_release(pSMB);
1026 if (rc == -EAGAIN)
1027 goto MkDirRetry;
1028 return rc;
1029}
1030
Steve French2dd29d32007-04-23 22:07:35 +00001031int
1032CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1033 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001034 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001035 const struct nls_table *nls_codepage, int remap)
1036{
1037 TRANSACTION2_SPI_REQ *pSMB = NULL;
1038 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1039 int name_len;
1040 int rc = 0;
1041 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001042 __u16 params, param_offset, offset, byte_count, count;
1043 OPEN_PSX_REQ * pdata;
1044 OPEN_PSX_RSP * psx_rsp;
1045
1046 cFYI(1, ("In POSIX Create"));
1047PsxCreat:
1048 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1049 (void **) &pSMBr);
1050 if (rc)
1051 return rc;
1052
1053 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1054 name_len =
1055 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1056 PATH_MAX, nls_codepage, remap);
1057 name_len++; /* trailing null */
1058 name_len *= 2;
1059 } else { /* BB improve the check for buffer overruns BB */
1060 name_len = strnlen(name, PATH_MAX);
1061 name_len++; /* trailing null */
1062 strncpy(pSMB->FileName, name, name_len);
1063 }
1064
1065 params = 6 + name_len;
1066 count = sizeof(OPEN_PSX_REQ);
1067 pSMB->MaxParameterCount = cpu_to_le16(2);
1068 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1069 pSMB->MaxSetupCount = 0;
1070 pSMB->Reserved = 0;
1071 pSMB->Flags = 0;
1072 pSMB->Timeout = 0;
1073 pSMB->Reserved2 = 0;
1074 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001075 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001076 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001077 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001078 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001079 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001080 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001081 pdata->OpenFlags = cpu_to_le32(*pOplock);
1082 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1083 pSMB->DataOffset = cpu_to_le16(offset);
1084 pSMB->SetupCount = 1;
1085 pSMB->Reserved3 = 0;
1086 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1087 byte_count = 3 /* pad */ + params + count;
1088
1089 pSMB->DataCount = cpu_to_le16(count);
1090 pSMB->ParameterCount = cpu_to_le16(params);
1091 pSMB->TotalDataCount = pSMB->DataCount;
1092 pSMB->TotalParameterCount = pSMB->ParameterCount;
1093 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1094 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001095 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001096 pSMB->ByteCount = cpu_to_le16(byte_count);
1097 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1098 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1099 if (rc) {
1100 cFYI(1, ("Posix create returned %d", rc));
1101 goto psx_create_err;
1102 }
1103
Steve French790fe572007-07-07 19:25:05 +00001104 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001105 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1106
1107 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1108 rc = -EIO; /* bad smb */
1109 goto psx_create_err;
1110 }
1111
1112 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001113 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001114 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001115
Steve French2dd29d32007-04-23 22:07:35 +00001116 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001117 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001118 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1119 /* Let caller know file was created so we can set the mode. */
1120 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001121 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001122 *pOplock |= CIFS_CREATE_ACTION;
1123 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001124 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1125 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001126#ifdef CONFIG_CIFS_DEBUG2
Steve French790fe572007-07-07 19:25:05 +00001127 cFYI(1, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001128#endif
1129 } else {
Steve French790fe572007-07-07 19:25:05 +00001130 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001131 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001132 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001133 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001134 goto psx_create_err;
1135 }
Steve French50c2f752007-07-13 00:33:32 +00001136 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001137 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001138 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001139 }
Steve French2dd29d32007-04-23 22:07:35 +00001140
1141psx_create_err:
1142 cifs_buf_release(pSMB);
1143
1144 cifs_stats_inc(&tcon->num_mkdirs);
1145
1146 if (rc == -EAGAIN)
1147 goto PsxCreat;
1148
Steve French50c2f752007-07-13 00:33:32 +00001149 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001150}
1151
Steve Frencha9d02ad2005-08-24 23:06:05 -07001152static __u16 convert_disposition(int disposition)
1153{
1154 __u16 ofun = 0;
1155
1156 switch (disposition) {
1157 case FILE_SUPERSEDE:
1158 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1159 break;
1160 case FILE_OPEN:
1161 ofun = SMBOPEN_OAPPEND;
1162 break;
1163 case FILE_CREATE:
1164 ofun = SMBOPEN_OCREATE;
1165 break;
1166 case FILE_OPEN_IF:
1167 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1168 break;
1169 case FILE_OVERWRITE:
1170 ofun = SMBOPEN_OTRUNC;
1171 break;
1172 case FILE_OVERWRITE_IF:
1173 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1174 break;
1175 default:
Steve French790fe572007-07-07 19:25:05 +00001176 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001177 ofun = SMBOPEN_OAPPEND; /* regular open */
1178 }
1179 return ofun;
1180}
1181
1182int
1183SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1184 const char *fileName, const int openDisposition,
1185 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001186 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001187 const struct nls_table *nls_codepage, int remap)
1188{
1189 int rc = -EACCES;
1190 OPENX_REQ *pSMB = NULL;
1191 OPENX_RSP *pSMBr = NULL;
1192 int bytes_returned;
1193 int name_len;
1194 __u16 count;
1195
1196OldOpenRetry:
1197 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1198 (void **) &pSMBr);
1199 if (rc)
1200 return rc;
1201
1202 pSMB->AndXCommand = 0xFF; /* none */
1203
1204 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1205 count = 1; /* account for one byte pad to word boundary */
1206 name_len =
1207 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1208 fileName, PATH_MAX, nls_codepage, remap);
1209 name_len++; /* trailing null */
1210 name_len *= 2;
1211 } else { /* BB improve check for buffer overruns BB */
1212 count = 0; /* no pad */
1213 name_len = strnlen(fileName, PATH_MAX);
1214 name_len++; /* trailing null */
1215 strncpy(pSMB->fileName, fileName, name_len);
1216 }
1217 if (*pOplock & REQ_OPLOCK)
1218 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001219 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001220 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001221
Steve Frencha9d02ad2005-08-24 23:06:05 -07001222 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1223 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1224 /* 0 = read
1225 1 = write
1226 2 = rw
1227 3 = execute
Steve French50c2f752007-07-13 00:33:32 +00001228 */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001229 pSMB->Mode = cpu_to_le16(2);
1230 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1231 /* set file as system file if special file such
1232 as fifo and server expecting SFU style and
1233 no Unix extensions */
1234
Steve French790fe572007-07-07 19:25:05 +00001235 if (create_options & CREATE_OPTION_SPECIAL)
1236 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1237 else
Steve French3e87d802005-09-18 20:49:21 -07001238 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001239
1240 /* if ((omode & S_IWUGO) == 0)
1241 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1242 /* Above line causes problems due to vfs splitting create into two
1243 pieces - need to set mode after file created not while it is
1244 being created */
1245
1246 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001247/* pSMB->CreateOptions = cpu_to_le32(create_options &
1248 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001249 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001250
1251 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001252 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253 count += name_len;
1254 pSMB->hdr.smb_buf_length += count;
1255
1256 pSMB->ByteCount = cpu_to_le16(count);
1257 /* long_op set to 1 to allow for oplock break timeouts */
1258 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00001259 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 cifs_stats_inc(&tcon->num_opens);
1261 if (rc) {
1262 cFYI(1, ("Error in Open = %d", rc));
1263 } else {
1264 /* BB verify if wct == 15 */
1265
1266/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1267
1268 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1269 /* Let caller know file was created so we can set the mode. */
1270 /* Do we care about the CreateAction in any other cases? */
1271 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001272/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001273 *pOplock |= CIFS_CREATE_ACTION; */
1274 /* BB FIXME END */
1275
Steve French790fe572007-07-07 19:25:05 +00001276 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001277 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1278 pfile_info->LastAccessTime = 0; /* BB fixme */
1279 pfile_info->LastWriteTime = 0; /* BB fixme */
1280 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001281 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001282 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001283 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001284 pfile_info->AllocationSize =
1285 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1286 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001287 pfile_info->NumberOfLinks = cpu_to_le32(1);
1288 }
1289 }
1290
1291 cifs_buf_release(pSMB);
1292 if (rc == -EAGAIN)
1293 goto OldOpenRetry;
1294 return rc;
1295}
1296
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297int
1298CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1299 const char *fileName, const int openDisposition,
1300 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001301 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001302 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303{
1304 int rc = -EACCES;
1305 OPEN_REQ *pSMB = NULL;
1306 OPEN_RSP *pSMBr = NULL;
1307 int bytes_returned;
1308 int name_len;
1309 __u16 count;
1310
1311openRetry:
1312 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1313 (void **) &pSMBr);
1314 if (rc)
1315 return rc;
1316
1317 pSMB->AndXCommand = 0xFF; /* none */
1318
1319 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1320 count = 1; /* account for one byte pad to word boundary */
1321 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001322 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001323 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 name_len++; /* trailing null */
1325 name_len *= 2;
1326 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001327 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 count = 0; /* no pad */
1329 name_len = strnlen(fileName, PATH_MAX);
1330 name_len++; /* trailing null */
1331 pSMB->NameLength = cpu_to_le16(name_len);
1332 strncpy(pSMB->fileName, fileName, name_len);
1333 }
1334 if (*pOplock & REQ_OPLOCK)
1335 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001336 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1339 pSMB->AllocationSize = 0;
Steve Frencheda3c022005-07-21 15:20:28 -07001340 /* set file as system file if special file such
1341 as fifo and server expecting SFU style and
1342 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001343 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c022005-07-21 15:20:28 -07001344 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1345 else
1346 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 /* XP does not handle ATTR_POSIX_SEMANTICS */
1348 /* but it helps speed up case sensitive checks for other
1349 servers such as Samba */
1350 if (tcon->ses->capabilities & CAP_UNIX)
1351 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1352
1353 /* if ((omode & S_IWUGO) == 0)
1354 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1355 /* Above line causes problems due to vfs splitting create into two
1356 pieces - need to set mode after file created not while it is
1357 being created */
1358 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1359 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c022005-07-21 15:20:28 -07001360 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001361 /* BB Expirement with various impersonation levels and verify */
1362 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 pSMB->SecurityFlags =
1364 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1365
1366 count += name_len;
1367 pSMB->hdr.smb_buf_length += count;
1368
1369 pSMB->ByteCount = cpu_to_le16(count);
1370 /* long_op set to 1 to allow for oplock break timeouts */
1371 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1372 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001373 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 if (rc) {
1375 cFYI(1, ("Error in Open = %d", rc));
1376 } else {
Steve French09d1db52005-04-28 22:41:08 -07001377 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1379 /* Let caller know file was created so we can set the mode. */
1380 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001381 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001382 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001383 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001384 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 36 /* CreationTime to Attributes */);
1386 /* the file_info buf is endian converted by caller */
1387 pfile_info->AllocationSize = pSMBr->AllocationSize;
1388 pfile_info->EndOfFile = pSMBr->EndOfFile;
1389 pfile_info->NumberOfLinks = cpu_to_le32(1);
1390 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001392
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 cifs_buf_release(pSMB);
1394 if (rc == -EAGAIN)
1395 goto openRetry;
1396 return rc;
1397}
1398
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399int
Steve French50c2f752007-07-13 00:33:32 +00001400CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1401 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1402 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403{
1404 int rc = -EACCES;
1405 READ_REQ *pSMB = NULL;
1406 READ_RSP *pSMBr = NULL;
1407 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001408 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001409 int resp_buf_type = 0;
1410 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
Steve French790fe572007-07-07 19:25:05 +00001412 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1413 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001414 wct = 12;
1415 else
1416 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417
1418 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001419 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 if (rc)
1421 return rc;
1422
1423 /* tcon and ses pointer are checked in smb_init */
1424 if (tcon->ses->server == NULL)
1425 return -ECONNABORTED;
1426
Steve Frenchec637e32005-12-12 20:53:18 -08001427 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 pSMB->Fid = netfid;
1429 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001430 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001431 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001432 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001433 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001434
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 pSMB->Remaining = 0;
1436 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1437 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001438 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001439 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1440 else {
1441 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001442 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001443 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001444 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001445 }
Steve Frenchec637e32005-12-12 20:53:18 -08001446
1447 iov[0].iov_base = (char *)pSMB;
1448 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001449 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1450 &resp_buf_type, 0 /* not long op */, 1 /* log err */ );
Steve Frencha4544342005-08-24 13:59:35 -07001451 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001452 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 if (rc) {
1454 cERROR(1, ("Send error in read = %d", rc));
1455 } else {
1456 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1457 data_length = data_length << 16;
1458 data_length += le16_to_cpu(pSMBr->DataLength);
1459 *nbytes = data_length;
1460
1461 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001462 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001464 cFYI(1, ("bad length %d for count %d",
1465 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 rc = -EIO;
1467 *nbytes = 0;
1468 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001469 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001470 le16_to_cpu(pSMBr->DataOffset);
1471/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001472 cERROR(1,("Faulting on read rc = %d",rc));
1473 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001474 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001475 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001476 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 }
1478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
Steve French4b8f9302006-02-26 16:41:18 +00001480/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001481 if (*buf) {
1482 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001483 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001484 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001485 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001486 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001487 /* return buffer to caller to free */
1488 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001489 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001490 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001491 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001492 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001493 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001494
1495 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 since file handle passed in no longer valid */
1497 return rc;
1498}
1499
Steve Frenchec637e32005-12-12 20:53:18 -08001500
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501int
1502CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1503 const int netfid, const unsigned int count,
1504 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001505 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506{
1507 int rc = -EACCES;
1508 WRITE_REQ *pSMB = NULL;
1509 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001510 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 __u32 bytes_sent;
1512 __u16 byte_count;
1513
1514 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001515 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001516 return -ECONNABORTED;
1517
Steve French790fe572007-07-07 19:25:05 +00001518 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001519 wct = 14;
1520 else
1521 wct = 12;
1522
1523 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 (void **) &pSMBr);
1525 if (rc)
1526 return rc;
1527 /* tcon and ses pointer are checked in smb_init */
1528 if (tcon->ses->server == NULL)
1529 return -ECONNABORTED;
1530
1531 pSMB->AndXCommand = 0xFF; /* none */
1532 pSMB->Fid = netfid;
1533 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001534 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001535 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001536 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001537 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001538
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 pSMB->Reserved = 0xFFFFFFFF;
1540 pSMB->WriteMode = 0;
1541 pSMB->Remaining = 0;
1542
Steve French50c2f752007-07-13 00:33:32 +00001543 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 can send more if LARGE_WRITE_X capability returned by the server and if
1545 our buffer is big enough or if we convert to iovecs on socket writes
1546 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001547 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1549 } else {
1550 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1551 & ~0xFF;
1552 }
1553
1554 if (bytes_sent > count)
1555 bytes_sent = count;
1556 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001557 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001558 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001559 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001560 else if (ubuf) {
1561 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 cifs_buf_release(pSMB);
1563 return -EFAULT;
1564 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001565 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 /* No buffer */
1567 cifs_buf_release(pSMB);
1568 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001569 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001570 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001571 byte_count = bytes_sent + 1; /* pad */
1572 else /* wct == 12 */ {
1573 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1576 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001577 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001578
Steve French790fe572007-07-07 19:25:05 +00001579 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001580 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001581 else { /* old style write has byte count 4 bytes earlier
1582 so 4 bytes pad */
1583 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001584 (struct smb_com_writex_req *)pSMB;
1585 pSMBW->ByteCount = cpu_to_le16(byte_count);
1586 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587
1588 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1589 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001590 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 if (rc) {
1592 cFYI(1, ("Send error in write = %d", rc));
1593 *nbytes = 0;
1594 } else {
1595 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1596 *nbytes = (*nbytes) << 16;
1597 *nbytes += le16_to_cpu(pSMBr->Count);
1598 }
1599
1600 cifs_buf_release(pSMB);
1601
Steve French50c2f752007-07-13 00:33:32 +00001602 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 since file handle passed in no longer valid */
1604
1605 return rc;
1606}
1607
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001608int
1609CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001611 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1612 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613{
1614 int rc = -EACCES;
1615 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001616 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001617 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001618 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
Steve French790fe572007-07-07 19:25:05 +00001620 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001621
Steve French790fe572007-07-07 19:25:05 +00001622 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001623 wct = 14;
1624 else
1625 wct = 12;
1626 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 if (rc)
1628 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 /* tcon and ses pointer are checked in smb_init */
1630 if (tcon->ses->server == NULL)
1631 return -ECONNABORTED;
1632
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001633 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 pSMB->Fid = netfid;
1635 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001636 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001637 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001638 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001639 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 pSMB->Reserved = 0xFFFFFFFF;
1641 pSMB->WriteMode = 0;
1642 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001643
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001645 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
Steve French3e844692005-10-03 13:37:24 -07001647 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1648 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001649 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001650 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001651 pSMB->hdr.smb_buf_length += count+1;
1652 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001653 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1654 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001655 pSMB->ByteCount = cpu_to_le16(count + 1);
1656 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001657 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001658 (struct smb_com_writex_req *)pSMB;
1659 pSMBW->ByteCount = cpu_to_le16(count + 5);
1660 }
Steve French3e844692005-10-03 13:37:24 -07001661 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001662 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001663 iov[0].iov_len = smb_hdr_len + 4;
1664 else /* wct == 12 pad bigger by four bytes */
1665 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001666
Steve French3e844692005-10-03 13:37:24 -07001667
Steve Frenchec637e32005-12-12 20:53:18 -08001668 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve Frencha761ac52007-10-18 21:45:27 +00001669 long_op, 0 /* do not log STATUS code */ );
Steve Frencha4544342005-08-24 13:59:35 -07001670 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001672 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001674 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001675 /* presumably this can not happen, but best to be safe */
1676 rc = -EIO;
1677 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001678 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001679 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001680 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1681 *nbytes = (*nbytes) << 16;
1682 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
Steve French4b8f9302006-02-26 16:41:18 +00001685/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001686 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001687 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001688 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001689 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
Steve French50c2f752007-07-13 00:33:32 +00001691 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 since file handle passed in no longer valid */
1693
1694 return rc;
1695}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001696
1697
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698int
1699CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1700 const __u16 smb_file_id, const __u64 len,
1701 const __u64 offset, const __u32 numUnlock,
1702 const __u32 numLock, const __u8 lockType, const int waitFlag)
1703{
1704 int rc = 0;
1705 LOCK_REQ *pSMB = NULL;
1706 LOCK_RSP *pSMBr = NULL;
1707 int bytes_returned;
1708 int timeout = 0;
1709 __u16 count;
1710
Steve French50c2f752007-07-13 00:33:32 +00001711 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001712 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1713
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 if (rc)
1715 return rc;
1716
Steve French46810cb2005-04-28 22:41:09 -07001717 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1718
Steve French790fe572007-07-07 19:25:05 +00001719 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 timeout = -1; /* no response expected */
1721 pSMB->Timeout = 0;
1722 } else if (waitFlag == TRUE) {
1723 timeout = 3; /* blocking operation, no timeout */
1724 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1725 } else {
1726 pSMB->Timeout = 0;
1727 }
1728
1729 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1730 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1731 pSMB->LockType = lockType;
1732 pSMB->AndXCommand = 0xFF; /* none */
1733 pSMB->Fid = smb_file_id; /* netfid stays le */
1734
Steve French790fe572007-07-07 19:25:05 +00001735 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1737 /* BB where to store pid high? */
1738 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1739 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1740 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1741 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1742 count = sizeof(LOCKING_ANDX_RANGE);
1743 } else {
1744 /* oplock break */
1745 count = 0;
1746 }
1747 pSMB->hdr.smb_buf_length += count;
1748 pSMB->ByteCount = cpu_to_le16(count);
1749
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001750 if (waitFlag) {
1751 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1752 (struct smb_hdr *) pSMBr, &bytes_returned);
1753 } else {
1754 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001756 }
Steve Frencha4544342005-08-24 13:59:35 -07001757 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 if (rc) {
1759 cFYI(1, ("Send error in Lock = %d", rc));
1760 }
Steve French46810cb2005-04-28 22:41:09 -07001761 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762
Steve French50c2f752007-07-13 00:33:32 +00001763 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 since file handle passed in no longer valid */
1765 return rc;
1766}
1767
1768int
Steve French08547b02006-02-28 22:39:25 +00001769CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1770 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001771 struct file_lock *pLockData, const __u16 lock_type,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001772 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001773{
1774 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1775 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001776 struct cifs_posix_lock *parm_data;
1777 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001778 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001779 int bytes_returned = 0;
1780 __u16 params, param_offset, offset, byte_count, count;
1781
1782 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001783
Steve French790fe572007-07-07 19:25:05 +00001784 if (pLockData == NULL)
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001785 return EINVAL;
1786
Steve French08547b02006-02-28 22:39:25 +00001787 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1788
1789 if (rc)
1790 return rc;
1791
1792 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1793
Steve French50c2f752007-07-13 00:33:32 +00001794 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001795 pSMB->MaxSetupCount = 0;
1796 pSMB->Reserved = 0;
1797 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001798 pSMB->Reserved2 = 0;
1799 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1800 offset = param_offset + params;
1801
Steve French08547b02006-02-28 22:39:25 +00001802 count = sizeof(struct cifs_posix_lock);
1803 pSMB->MaxParameterCount = cpu_to_le16(2);
1804 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1805 pSMB->SetupCount = 1;
1806 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001807 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001808 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1809 else
1810 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1811 byte_count = 3 /* pad */ + params + count;
1812 pSMB->DataCount = cpu_to_le16(count);
1813 pSMB->ParameterCount = cpu_to_le16(params);
1814 pSMB->TotalDataCount = pSMB->DataCount;
1815 pSMB->TotalParameterCount = pSMB->ParameterCount;
1816 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001817 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001818 (((char *) &pSMB->hdr.Protocol) + offset);
1819
1820 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001821 if (waitFlag) {
Steve French3a5ff612006-07-14 22:37:11 +00001822 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001823 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001824 pSMB->Timeout = cpu_to_le32(-1);
1825 } else
1826 pSMB->Timeout = 0;
1827
Steve French08547b02006-02-28 22:39:25 +00001828 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001829 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001830 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001831
1832 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001833 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001834 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1835 pSMB->Reserved4 = 0;
1836 pSMB->hdr.smb_buf_length += byte_count;
1837 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001838 if (waitFlag) {
1839 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1840 (struct smb_hdr *) pSMBr, &bytes_returned);
1841 } else {
1842 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001843 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001844 }
1845
Steve French08547b02006-02-28 22:39:25 +00001846 if (rc) {
1847 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001848 } else if (get_flag) {
1849 /* lock structure can be returned on get */
1850 __u16 data_offset;
1851 __u16 data_count;
1852 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001853
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001854 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1855 rc = -EIO; /* bad smb */
1856 goto plk_err_exit;
1857 }
Steve French790fe572007-07-07 19:25:05 +00001858 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001859 rc = -EINVAL;
1860 goto plk_err_exit;
1861 }
1862 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1863 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001864 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001865 rc = -EIO;
1866 goto plk_err_exit;
1867 }
1868 parm_data = (struct cifs_posix_lock *)
1869 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001870 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001871 pLockData->fl_type = F_UNLCK;
1872 }
Steve French50c2f752007-07-13 00:33:32 +00001873
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001874plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001875 if (pSMB)
1876 cifs_small_buf_release(pSMB);
1877
1878 /* Note: On -EAGAIN error only caller can retry on handle based calls
1879 since file handle passed in no longer valid */
1880
1881 return rc;
1882}
1883
1884
1885int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1887{
1888 int rc = 0;
1889 CLOSE_REQ *pSMB = NULL;
1890 CLOSE_RSP *pSMBr = NULL;
1891 int bytes_returned;
1892 cFYI(1, ("In CIFSSMBClose"));
1893
1894/* do not retry on dead session on close */
1895 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001896 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 return 0;
1898 if (rc)
1899 return rc;
1900
1901 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1902
1903 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e2006-10-02 05:53:29 +00001904 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 pSMB->ByteCount = 0;
1906 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1907 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001908 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001910 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 /* EINTR is expected when user ctl-c to kill app */
1912 cERROR(1, ("Send error in Close = %d", rc));
1913 }
1914 }
1915
1916 cifs_small_buf_release(pSMB);
1917
1918 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001919 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 rc = 0;
1921
1922 return rc;
1923}
1924
1925int
1926CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1927 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001928 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929{
1930 int rc = 0;
1931 RENAME_REQ *pSMB = NULL;
1932 RENAME_RSP *pSMBr = NULL;
1933 int bytes_returned;
1934 int name_len, name_len2;
1935 __u16 count;
1936
1937 cFYI(1, ("In CIFSSMBRename"));
1938renameRetry:
1939 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1940 (void **) &pSMBr);
1941 if (rc)
1942 return rc;
1943
1944 pSMB->BufferFormat = 0x04;
1945 pSMB->SearchAttributes =
1946 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1947 ATTR_DIRECTORY);
1948
1949 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1950 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001951 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001952 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 name_len++; /* trailing null */
1954 name_len *= 2;
1955 pSMB->OldFileName[name_len] = 0x04; /* pad */
1956 /* protocol requires ASCII signature byte on Unicode string */
1957 pSMB->OldFileName[name_len + 1] = 0x00;
1958 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001959 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001960 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1962 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001963 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 name_len = strnlen(fromName, PATH_MAX);
1965 name_len++; /* trailing null */
1966 strncpy(pSMB->OldFileName, fromName, name_len);
1967 name_len2 = strnlen(toName, PATH_MAX);
1968 name_len2++; /* trailing null */
1969 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1970 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1971 name_len2++; /* trailing null */
1972 name_len2++; /* signature byte */
1973 }
1974
1975 count = 1 /* 1st signature byte */ + name_len + name_len2;
1976 pSMB->hdr.smb_buf_length += count;
1977 pSMB->ByteCount = cpu_to_le16(count);
1978
1979 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1980 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001981 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 if (rc) {
1983 cFYI(1, ("Send error in rename = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +00001984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 cifs_buf_release(pSMB);
1987
1988 if (rc == -EAGAIN)
1989 goto renameRetry;
1990
1991 return rc;
1992}
1993
Steve French50c2f752007-07-13 00:33:32 +00001994int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1995 int netfid, char *target_name,
1996 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997{
1998 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1999 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002000 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 char *data_offset;
2002 char dummy_string[30];
2003 int rc = 0;
2004 int bytes_returned = 0;
2005 int len_of_str;
2006 __u16 params, param_offset, offset, count, byte_count;
2007
2008 cFYI(1, ("Rename to File by handle"));
2009 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2010 (void **) &pSMBr);
2011 if (rc)
2012 return rc;
2013
2014 params = 6;
2015 pSMB->MaxSetupCount = 0;
2016 pSMB->Reserved = 0;
2017 pSMB->Flags = 0;
2018 pSMB->Timeout = 0;
2019 pSMB->Reserved2 = 0;
2020 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2021 offset = param_offset + params;
2022
2023 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2024 rename_info = (struct set_file_rename *) data_offset;
2025 pSMB->MaxParameterCount = cpu_to_le16(2);
2026 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
2027 pSMB->SetupCount = 1;
2028 pSMB->Reserved3 = 0;
2029 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2030 byte_count = 3 /* pad */ + params;
2031 pSMB->ParameterCount = cpu_to_le16(params);
2032 pSMB->TotalParameterCount = pSMB->ParameterCount;
2033 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2034 pSMB->DataOffset = cpu_to_le16(offset);
2035 /* construct random name ".cifs_tmp<inodenum><mid>" */
2036 rename_info->overwrite = cpu_to_le32(1);
2037 rename_info->root_fid = 0;
2038 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002039 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002040 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2041 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002042 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002044 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002045 target_name, PATH_MAX, nls_codepage,
2046 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 }
2048 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2049 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2050 byte_count += count;
2051 pSMB->DataCount = cpu_to_le16(count);
2052 pSMB->TotalDataCount = pSMB->DataCount;
2053 pSMB->Fid = netfid;
2054 pSMB->InformationLevel =
2055 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2056 pSMB->Reserved4 = 0;
2057 pSMB->hdr.smb_buf_length += byte_count;
2058 pSMB->ByteCount = cpu_to_le16(byte_count);
2059 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002060 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002061 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002063 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 }
Steve Frencha5a2b482005-08-20 21:42:53 -07002065
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 cifs_buf_release(pSMB);
2067
2068 /* Note: On -EAGAIN error only caller can retry on handle based calls
2069 since file handle passed in no longer valid */
2070
2071 return rc;
2072}
2073
2074int
Steve French50c2f752007-07-13 00:33:32 +00002075CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2076 const __u16 target_tid, const char *toName, const int flags,
2077 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078{
2079 int rc = 0;
2080 COPY_REQ *pSMB = NULL;
2081 COPY_RSP *pSMBr = NULL;
2082 int bytes_returned;
2083 int name_len, name_len2;
2084 __u16 count;
2085
2086 cFYI(1, ("In CIFSSMBCopy"));
2087copyRetry:
2088 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2089 (void **) &pSMBr);
2090 if (rc)
2091 return rc;
2092
2093 pSMB->BufferFormat = 0x04;
2094 pSMB->Tid2 = target_tid;
2095
2096 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2097
2098 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002099 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002100 fromName, PATH_MAX, nls_codepage,
2101 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 name_len++; /* trailing null */
2103 name_len *= 2;
2104 pSMB->OldFileName[name_len] = 0x04; /* pad */
2105 /* protocol requires ASCII signature byte on Unicode string */
2106 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002107 name_len2 =
2108 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002109 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2111 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002112 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 name_len = strnlen(fromName, PATH_MAX);
2114 name_len++; /* trailing null */
2115 strncpy(pSMB->OldFileName, fromName, name_len);
2116 name_len2 = strnlen(toName, PATH_MAX);
2117 name_len2++; /* trailing null */
2118 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2119 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2120 name_len2++; /* trailing null */
2121 name_len2++; /* signature byte */
2122 }
2123
2124 count = 1 /* 1st signature byte */ + name_len + name_len2;
2125 pSMB->hdr.smb_buf_length += count;
2126 pSMB->ByteCount = cpu_to_le16(count);
2127
2128 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2129 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2130 if (rc) {
2131 cFYI(1, ("Send error in copy = %d with %d files copied",
2132 rc, le16_to_cpu(pSMBr->CopyCount)));
2133 }
2134 if (pSMB)
2135 cifs_buf_release(pSMB);
2136
2137 if (rc == -EAGAIN)
2138 goto copyRetry;
2139
2140 return rc;
2141}
2142
2143int
2144CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2145 const char *fromName, const char *toName,
2146 const struct nls_table *nls_codepage)
2147{
2148 TRANSACTION2_SPI_REQ *pSMB = NULL;
2149 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2150 char *data_offset;
2151 int name_len;
2152 int name_len_target;
2153 int rc = 0;
2154 int bytes_returned = 0;
2155 __u16 params, param_offset, offset, byte_count;
2156
2157 cFYI(1, ("In Symlink Unix style"));
2158createSymLinkRetry:
2159 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2160 (void **) &pSMBr);
2161 if (rc)
2162 return rc;
2163
2164 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2165 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002166 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 /* find define for this maxpathcomponent */
2168 , nls_codepage);
2169 name_len++; /* trailing null */
2170 name_len *= 2;
2171
Steve French50c2f752007-07-13 00:33:32 +00002172 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 name_len = strnlen(fromName, PATH_MAX);
2174 name_len++; /* trailing null */
2175 strncpy(pSMB->FileName, fromName, name_len);
2176 }
2177 params = 6 + name_len;
2178 pSMB->MaxSetupCount = 0;
2179 pSMB->Reserved = 0;
2180 pSMB->Flags = 0;
2181 pSMB->Timeout = 0;
2182 pSMB->Reserved2 = 0;
2183 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002184 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 offset = param_offset + params;
2186
2187 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2188 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2189 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002190 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 /* find define for this maxpathcomponent */
2192 , nls_codepage);
2193 name_len_target++; /* trailing null */
2194 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002195 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 name_len_target = strnlen(toName, PATH_MAX);
2197 name_len_target++; /* trailing null */
2198 strncpy(data_offset, toName, name_len_target);
2199 }
2200
2201 pSMB->MaxParameterCount = cpu_to_le16(2);
2202 /* BB find exact max on data count below from sess */
2203 pSMB->MaxDataCount = cpu_to_le16(1000);
2204 pSMB->SetupCount = 1;
2205 pSMB->Reserved3 = 0;
2206 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2207 byte_count = 3 /* pad */ + params + name_len_target;
2208 pSMB->DataCount = cpu_to_le16(name_len_target);
2209 pSMB->ParameterCount = cpu_to_le16(params);
2210 pSMB->TotalDataCount = pSMB->DataCount;
2211 pSMB->TotalParameterCount = pSMB->ParameterCount;
2212 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2213 pSMB->DataOffset = cpu_to_le16(offset);
2214 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2215 pSMB->Reserved4 = 0;
2216 pSMB->hdr.smb_buf_length += byte_count;
2217 pSMB->ByteCount = cpu_to_le16(byte_count);
2218 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2219 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002220 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 if (rc) {
Steve French2d785a52007-07-15 01:48:57 +00002222 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 }
2224
2225 if (pSMB)
2226 cifs_buf_release(pSMB);
2227
2228 if (rc == -EAGAIN)
2229 goto createSymLinkRetry;
2230
2231 return rc;
2232}
2233
2234int
2235CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2236 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002237 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238{
2239 TRANSACTION2_SPI_REQ *pSMB = NULL;
2240 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2241 char *data_offset;
2242 int name_len;
2243 int name_len_target;
2244 int rc = 0;
2245 int bytes_returned = 0;
2246 __u16 params, param_offset, offset, byte_count;
2247
2248 cFYI(1, ("In Create Hard link Unix style"));
2249createHardLinkRetry:
2250 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2251 (void **) &pSMBr);
2252 if (rc)
2253 return rc;
2254
2255 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002256 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002257 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 name_len++; /* trailing null */
2259 name_len *= 2;
2260
Steve French50c2f752007-07-13 00:33:32 +00002261 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 name_len = strnlen(toName, PATH_MAX);
2263 name_len++; /* trailing null */
2264 strncpy(pSMB->FileName, toName, name_len);
2265 }
2266 params = 6 + name_len;
2267 pSMB->MaxSetupCount = 0;
2268 pSMB->Reserved = 0;
2269 pSMB->Flags = 0;
2270 pSMB->Timeout = 0;
2271 pSMB->Reserved2 = 0;
2272 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002273 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 offset = param_offset + params;
2275
2276 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2277 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2278 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002279 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002280 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 name_len_target++; /* trailing null */
2282 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002283 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 name_len_target = strnlen(fromName, PATH_MAX);
2285 name_len_target++; /* trailing null */
2286 strncpy(data_offset, fromName, name_len_target);
2287 }
2288
2289 pSMB->MaxParameterCount = cpu_to_le16(2);
2290 /* BB find exact max on data count below from sess*/
2291 pSMB->MaxDataCount = cpu_to_le16(1000);
2292 pSMB->SetupCount = 1;
2293 pSMB->Reserved3 = 0;
2294 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2295 byte_count = 3 /* pad */ + params + name_len_target;
2296 pSMB->ParameterCount = cpu_to_le16(params);
2297 pSMB->TotalParameterCount = pSMB->ParameterCount;
2298 pSMB->DataCount = cpu_to_le16(name_len_target);
2299 pSMB->TotalDataCount = pSMB->DataCount;
2300 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2301 pSMB->DataOffset = cpu_to_le16(offset);
2302 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2303 pSMB->Reserved4 = 0;
2304 pSMB->hdr.smb_buf_length += byte_count;
2305 pSMB->ByteCount = cpu_to_le16(byte_count);
2306 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2307 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002308 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 if (rc) {
2310 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2311 }
2312
2313 cifs_buf_release(pSMB);
2314 if (rc == -EAGAIN)
2315 goto createHardLinkRetry;
2316
2317 return rc;
2318}
2319
2320int
2321CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2322 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002323 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324{
2325 int rc = 0;
2326 NT_RENAME_REQ *pSMB = NULL;
2327 RENAME_RSP *pSMBr = NULL;
2328 int bytes_returned;
2329 int name_len, name_len2;
2330 __u16 count;
2331
2332 cFYI(1, ("In CIFSCreateHardLink"));
2333winCreateHardLinkRetry:
2334
2335 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2336 (void **) &pSMBr);
2337 if (rc)
2338 return rc;
2339
2340 pSMB->SearchAttributes =
2341 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2342 ATTR_DIRECTORY);
2343 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2344 pSMB->ClusterCount = 0;
2345
2346 pSMB->BufferFormat = 0x04;
2347
2348 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2349 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002350 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002351 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 name_len++; /* trailing null */
2353 name_len *= 2;
2354 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002355 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002357 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002358 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2360 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002361 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 name_len = strnlen(fromName, PATH_MAX);
2363 name_len++; /* trailing null */
2364 strncpy(pSMB->OldFileName, fromName, name_len);
2365 name_len2 = strnlen(toName, PATH_MAX);
2366 name_len2++; /* trailing null */
2367 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2368 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2369 name_len2++; /* trailing null */
2370 name_len2++; /* signature byte */
2371 }
2372
2373 count = 1 /* string type byte */ + name_len + name_len2;
2374 pSMB->hdr.smb_buf_length += count;
2375 pSMB->ByteCount = cpu_to_le16(count);
2376
2377 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2378 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002379 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 if (rc) {
2381 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2382 }
2383 cifs_buf_release(pSMB);
2384 if (rc == -EAGAIN)
2385 goto winCreateHardLinkRetry;
2386
2387 return rc;
2388}
2389
2390int
2391CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2392 const unsigned char *searchName,
2393 char *symlinkinfo, const int buflen,
2394 const struct nls_table *nls_codepage)
2395{
2396/* SMB_QUERY_FILE_UNIX_LINK */
2397 TRANSACTION2_QPI_REQ *pSMB = NULL;
2398 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2399 int rc = 0;
2400 int bytes_returned;
2401 int name_len;
2402 __u16 params, byte_count;
2403
2404 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2405
2406querySymLinkRetry:
2407 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2408 (void **) &pSMBr);
2409 if (rc)
2410 return rc;
2411
2412 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2413 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002414 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2415 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 name_len++; /* trailing null */
2417 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002418 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 name_len = strnlen(searchName, PATH_MAX);
2420 name_len++; /* trailing null */
2421 strncpy(pSMB->FileName, searchName, name_len);
2422 }
2423
2424 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2425 pSMB->TotalDataCount = 0;
2426 pSMB->MaxParameterCount = cpu_to_le16(2);
2427 /* BB find exact max data count below from sess structure BB */
2428 pSMB->MaxDataCount = cpu_to_le16(4000);
2429 pSMB->MaxSetupCount = 0;
2430 pSMB->Reserved = 0;
2431 pSMB->Flags = 0;
2432 pSMB->Timeout = 0;
2433 pSMB->Reserved2 = 0;
2434 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002435 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 pSMB->DataCount = 0;
2437 pSMB->DataOffset = 0;
2438 pSMB->SetupCount = 1;
2439 pSMB->Reserved3 = 0;
2440 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2441 byte_count = params + 1 /* pad */ ;
2442 pSMB->TotalParameterCount = cpu_to_le16(params);
2443 pSMB->ParameterCount = pSMB->TotalParameterCount;
2444 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2445 pSMB->Reserved4 = 0;
2446 pSMB->hdr.smb_buf_length += byte_count;
2447 pSMB->ByteCount = cpu_to_le16(byte_count);
2448
2449 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2450 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2451 if (rc) {
2452 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2453 } else {
2454 /* decode response */
2455
2456 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2457 if (rc || (pSMBr->ByteCount < 2))
2458 /* BB also check enough total bytes returned */
2459 rc = -EIO; /* bad smb */
2460 else {
2461 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2462 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2463
2464 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2465 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002466 &pSMBr->hdr.Protocol + data_offset),
2467 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002468 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002470 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2471 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 name_len, nls_codepage);
2473 } else {
2474 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002475 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 data_offset,
2477 min_t(const int, buflen, count));
2478 }
2479 symlinkinfo[buflen] = 0;
2480 /* just in case so calling code does not go off the end of buffer */
2481 }
2482 }
2483 cifs_buf_release(pSMB);
2484 if (rc == -EAGAIN)
2485 goto querySymLinkRetry;
2486 return rc;
2487}
2488
Steve French0a4b92c2006-01-12 15:44:21 -08002489/* Initialize NT TRANSACT SMB into small smb request buffer.
2490 This assumes that all NT TRANSACTS that we init here have
2491 total parm and data under about 400 bytes (to fit in small cifs
2492 buffer size), which is the case so far, it easily fits. NB:
2493 Setup words themselves and ByteCount
2494 MaxSetupCount (size of returned setup area) and
2495 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002496static int
Steve French0a4b92c2006-01-12 15:44:21 -08002497smb_init_ntransact(const __u16 sub_command, const int setup_count,
2498 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002499 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002500{
2501 int rc;
2502 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002503 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002504
2505 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2506 (void **)&pSMB);
2507 if (rc)
2508 return rc;
2509 *ret_buf = (void *)pSMB;
2510 pSMB->Reserved = 0;
2511 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2512 pSMB->TotalDataCount = 0;
2513 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2514 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2515 pSMB->ParameterCount = pSMB->TotalParameterCount;
2516 pSMB->DataCount = pSMB->TotalDataCount;
2517 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2518 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2519 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2520 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2521 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2522 pSMB->SubCommand = cpu_to_le16(sub_command);
2523 return 0;
2524}
2525
2526static int
Steve French50c2f752007-07-13 00:33:32 +00002527validate_ntransact(char *buf, char **ppparm, char **ppdata,
2528 int *pdatalen, int *pparmlen)
Steve French0a4b92c2006-01-12 15:44:21 -08002529{
Steve French50c2f752007-07-13 00:33:32 +00002530 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002531 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002532 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002533
Steve French790fe572007-07-07 19:25:05 +00002534 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002535 return -EINVAL;
2536
2537 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2538
2539 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002540 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002541 (char *)&pSMBr->ByteCount;
2542
Steve French0a4b92c2006-01-12 15:44:21 -08002543 data_offset = le32_to_cpu(pSMBr->DataOffset);
2544 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002545 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002546 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2547
2548 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2549 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2550
2551 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002552 if (*ppparm > end_of_smb) {
2553 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002554 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002555 } else if (parm_count + *ppparm > end_of_smb) {
2556 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002557 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002558 } else if (*ppdata > end_of_smb) {
2559 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002560 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002561 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002562 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002563 *ppdata, data_count, (data_count + *ppdata),
2564 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002565 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002566 } else if (parm_count + data_count > pSMBr->ByteCount) {
2567 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002568 return -EINVAL;
2569 }
2570 return 0;
2571}
2572
Linus Torvalds1da177e2005-04-16 15:20:36 -07002573int
2574CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2575 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002576 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577 const struct nls_table *nls_codepage)
2578{
2579 int rc = 0;
2580 int bytes_returned;
2581 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002582 struct smb_com_transaction_ioctl_req *pSMB;
2583 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584
2585 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2586 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2587 (void **) &pSMBr);
2588 if (rc)
2589 return rc;
2590
2591 pSMB->TotalParameterCount = 0 ;
2592 pSMB->TotalDataCount = 0;
2593 pSMB->MaxParameterCount = cpu_to_le32(2);
2594 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002595 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2596 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597 pSMB->MaxSetupCount = 4;
2598 pSMB->Reserved = 0;
2599 pSMB->ParameterOffset = 0;
2600 pSMB->DataCount = 0;
2601 pSMB->DataOffset = 0;
2602 pSMB->SetupCount = 4;
2603 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2604 pSMB->ParameterCount = pSMB->TotalParameterCount;
2605 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2606 pSMB->IsFsctl = 1; /* FSCTL */
2607 pSMB->IsRootFlag = 0;
2608 pSMB->Fid = fid; /* file handle always le */
2609 pSMB->ByteCount = 0;
2610
2611 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2612 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2613 if (rc) {
2614 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2615 } else { /* decode response */
2616 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2617 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2618 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2619 /* BB also check enough total bytes returned */
2620 rc = -EIO; /* bad smb */
2621 else {
Steve French790fe572007-07-07 19:25:05 +00002622 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002623 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002624 pSMBr->ByteCount +
2625 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626
Steve French50c2f752007-07-13 00:33:32 +00002627 struct reparse_data *reparse_buf =
2628 (struct reparse_data *)
2629 ((char *)&pSMBr->hdr.Protocol
2630 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002631 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002632 rc = -EIO;
2633 goto qreparse_out;
2634 }
Steve French790fe572007-07-07 19:25:05 +00002635 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 reparse_buf->TargetNameOffset +
2637 reparse_buf->TargetNameLen) >
2638 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002639 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 rc = -EIO;
2641 goto qreparse_out;
2642 }
Steve French50c2f752007-07-13 00:33:32 +00002643
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2645 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002646 (reparse_buf->LinkNamesBuf +
2647 reparse_buf->TargetNameOffset),
2648 min(buflen/2,
2649 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002650 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002651 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 reparse_buf->TargetNameOffset),
2653 name_len, nls_codepage);
2654 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002655 strncpy(symlinkinfo,
2656 reparse_buf->LinkNamesBuf +
2657 reparse_buf->TargetNameOffset,
2658 min_t(const int, buflen,
2659 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 }
2661 } else {
2662 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002663 cFYI(1, ("Invalid return data count on "
2664 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 }
2666 symlinkinfo[buflen] = 0; /* just in case so the caller
2667 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002668 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 }
2670 }
2671qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002672 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673
2674 /* Note: On -EAGAIN error only caller can retry on handle based calls
2675 since file handle passed in no longer valid */
2676
2677 return rc;
2678}
2679
2680#ifdef CONFIG_CIFS_POSIX
2681
2682/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002683static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2684 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685{
2686 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002687 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2688 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2689 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2691
2692 return;
2693}
2694
2695/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002696static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2697 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698{
2699 int size = 0;
2700 int i;
2701 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002702 struct cifs_posix_ace *pACE;
2703 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2704 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002705
2706 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2707 return -EOPNOTSUPP;
2708
Steve French790fe572007-07-07 19:25:05 +00002709 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 count = le16_to_cpu(cifs_acl->access_entry_count);
2711 pACE = &cifs_acl->ace_array[0];
2712 size = sizeof(struct cifs_posix_acl);
2713 size += sizeof(struct cifs_posix_ace) * count;
2714 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002715 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002716 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2717 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002718 return -EINVAL;
2719 }
Steve French790fe572007-07-07 19:25:05 +00002720 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 count = le16_to_cpu(cifs_acl->access_entry_count);
2722 size = sizeof(struct cifs_posix_acl);
2723 size += sizeof(struct cifs_posix_ace) * count;
2724/* skip past access ACEs to get to default ACEs */
2725 pACE = &cifs_acl->ace_array[count];
2726 count = le16_to_cpu(cifs_acl->default_entry_count);
2727 size += sizeof(struct cifs_posix_ace) * count;
2728 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002729 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 return -EINVAL;
2731 } else {
2732 /* illegal type */
2733 return -EINVAL;
2734 }
2735
2736 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002737 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002738 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002739 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 return -ERANGE;
2741 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002742 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002743 for (i = 0; i < count ; i++) {
2744 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2745 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 }
2747 }
2748 return size;
2749}
2750
Steve French50c2f752007-07-13 00:33:32 +00002751static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2752 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753{
2754 __u16 rc = 0; /* 0 = ACL converted ok */
2755
Steve Frenchff7feac2005-11-15 16:45:16 -08002756 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2757 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002759 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 /* Probably no need to le convert -1 on any arch but can not hurt */
2761 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002762 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002763 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002764 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 return rc;
2766}
2767
2768/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002769static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2770 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002771{
2772 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002773 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2774 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 int count;
2776 int i;
2777
Steve French790fe572007-07-07 19:25:05 +00002778 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002779 return 0;
2780
2781 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002782 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002783 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002784 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002785 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002786 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002787 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 return 0;
2789 }
2790 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002791 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002792 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002793 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002794 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 else {
Steve French50c2f752007-07-13 00:33:32 +00002796 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 return 0;
2798 }
Steve French50c2f752007-07-13 00:33:32 +00002799 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2801 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002802 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002803 /* ACE not converted */
2804 break;
2805 }
2806 }
Steve French790fe572007-07-07 19:25:05 +00002807 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2809 rc += sizeof(struct cifs_posix_acl);
2810 /* BB add check to make sure ACL does not overflow SMB */
2811 }
2812 return rc;
2813}
2814
2815int
2816CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002817 const unsigned char *searchName,
2818 char *acl_inf, const int buflen, const int acl_type,
2819 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002820{
2821/* SMB_QUERY_POSIX_ACL */
2822 TRANSACTION2_QPI_REQ *pSMB = NULL;
2823 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2824 int rc = 0;
2825 int bytes_returned;
2826 int name_len;
2827 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002828
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2830
2831queryAclRetry:
2832 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2833 (void **) &pSMBr);
2834 if (rc)
2835 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002836
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2838 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002839 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002840 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 name_len++; /* trailing null */
2842 name_len *= 2;
2843 pSMB->FileName[name_len] = 0;
2844 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002845 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846 name_len = strnlen(searchName, PATH_MAX);
2847 name_len++; /* trailing null */
2848 strncpy(pSMB->FileName, searchName, name_len);
2849 }
2850
2851 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2852 pSMB->TotalDataCount = 0;
2853 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002854 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 pSMB->MaxDataCount = cpu_to_le16(4000);
2856 pSMB->MaxSetupCount = 0;
2857 pSMB->Reserved = 0;
2858 pSMB->Flags = 0;
2859 pSMB->Timeout = 0;
2860 pSMB->Reserved2 = 0;
2861 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002862 offsetof(struct smb_com_transaction2_qpi_req,
2863 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 pSMB->DataCount = 0;
2865 pSMB->DataOffset = 0;
2866 pSMB->SetupCount = 1;
2867 pSMB->Reserved3 = 0;
2868 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2869 byte_count = params + 1 /* pad */ ;
2870 pSMB->TotalParameterCount = cpu_to_le16(params);
2871 pSMB->ParameterCount = pSMB->TotalParameterCount;
2872 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2873 pSMB->Reserved4 = 0;
2874 pSMB->hdr.smb_buf_length += byte_count;
2875 pSMB->ByteCount = cpu_to_le16(byte_count);
2876
2877 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2878 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002879 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 if (rc) {
2881 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2882 } else {
2883 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002884
Linus Torvalds1da177e2005-04-16 15:20:36 -07002885 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2886 if (rc || (pSMBr->ByteCount < 2))
2887 /* BB also check enough total bytes returned */
2888 rc = -EIO; /* bad smb */
2889 else {
2890 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2891 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2892 rc = cifs_copy_posix_acl(acl_inf,
2893 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002894 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 }
2896 }
2897 cifs_buf_release(pSMB);
2898 if (rc == -EAGAIN)
2899 goto queryAclRetry;
2900 return rc;
2901}
2902
2903int
2904CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002905 const unsigned char *fileName,
2906 const char *local_acl, const int buflen,
2907 const int acl_type,
2908 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909{
2910 struct smb_com_transaction2_spi_req *pSMB = NULL;
2911 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2912 char *parm_data;
2913 int name_len;
2914 int rc = 0;
2915 int bytes_returned = 0;
2916 __u16 params, byte_count, data_count, param_offset, offset;
2917
2918 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2919setAclRetry:
2920 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002921 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002922 if (rc)
2923 return rc;
2924 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2925 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002926 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002927 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 name_len++; /* trailing null */
2929 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002930 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931 name_len = strnlen(fileName, PATH_MAX);
2932 name_len++; /* trailing null */
2933 strncpy(pSMB->FileName, fileName, name_len);
2934 }
2935 params = 6 + name_len;
2936 pSMB->MaxParameterCount = cpu_to_le16(2);
2937 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2938 pSMB->MaxSetupCount = 0;
2939 pSMB->Reserved = 0;
2940 pSMB->Flags = 0;
2941 pSMB->Timeout = 0;
2942 pSMB->Reserved2 = 0;
2943 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002944 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945 offset = param_offset + params;
2946 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2947 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2948
2949 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002950 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951
Steve French790fe572007-07-07 19:25:05 +00002952 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 rc = -EOPNOTSUPP;
2954 goto setACLerrorExit;
2955 }
2956 pSMB->DataOffset = cpu_to_le16(offset);
2957 pSMB->SetupCount = 1;
2958 pSMB->Reserved3 = 0;
2959 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2960 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2961 byte_count = 3 /* pad */ + params + data_count;
2962 pSMB->DataCount = cpu_to_le16(data_count);
2963 pSMB->TotalDataCount = pSMB->DataCount;
2964 pSMB->ParameterCount = cpu_to_le16(params);
2965 pSMB->TotalParameterCount = pSMB->ParameterCount;
2966 pSMB->Reserved4 = 0;
2967 pSMB->hdr.smb_buf_length += byte_count;
2968 pSMB->ByteCount = cpu_to_le16(byte_count);
2969 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002970 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 if (rc) {
2972 cFYI(1, ("Set POSIX ACL returned %d", rc));
2973 }
2974
2975setACLerrorExit:
2976 cifs_buf_release(pSMB);
2977 if (rc == -EAGAIN)
2978 goto setAclRetry;
2979 return rc;
2980}
2981
Steve Frenchf654bac2005-04-28 22:41:04 -07002982/* BB fix tabs in this function FIXME BB */
2983int
2984CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002985 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002986{
Steve French50c2f752007-07-13 00:33:32 +00002987 int rc = 0;
2988 struct smb_t2_qfi_req *pSMB = NULL;
2989 struct smb_t2_qfi_rsp *pSMBr = NULL;
2990 int bytes_returned;
2991 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002992
Steve French790fe572007-07-07 19:25:05 +00002993 cFYI(1, ("In GetExtAttr"));
2994 if (tcon == NULL)
2995 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002996
2997GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00002998 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2999 (void **) &pSMBr);
3000 if (rc)
3001 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003002
Steve French790fe572007-07-07 19:25:05 +00003003 params = 2 /* level */ +2 /* fid */;
3004 pSMB->t2.TotalDataCount = 0;
3005 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3006 /* BB find exact max data count below from sess structure BB */
3007 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3008 pSMB->t2.MaxSetupCount = 0;
3009 pSMB->t2.Reserved = 0;
3010 pSMB->t2.Flags = 0;
3011 pSMB->t2.Timeout = 0;
3012 pSMB->t2.Reserved2 = 0;
3013 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3014 Fid) - 4);
3015 pSMB->t2.DataCount = 0;
3016 pSMB->t2.DataOffset = 0;
3017 pSMB->t2.SetupCount = 1;
3018 pSMB->t2.Reserved3 = 0;
3019 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3020 byte_count = params + 1 /* pad */ ;
3021 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3022 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3023 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3024 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003025 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003026 pSMB->hdr.smb_buf_length += byte_count;
3027 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003028
Steve French790fe572007-07-07 19:25:05 +00003029 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3030 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3031 if (rc) {
3032 cFYI(1, ("error %d in GetExtAttr", rc));
3033 } else {
3034 /* decode response */
3035 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3036 if (rc || (pSMBr->ByteCount < 2))
3037 /* BB also check enough total bytes returned */
3038 /* If rc should we check for EOPNOSUPP and
3039 disable the srvino flag? or in caller? */
3040 rc = -EIO; /* bad smb */
3041 else {
3042 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3043 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3044 struct file_chattr_info *pfinfo;
3045 /* BB Do we need a cast or hash here ? */
3046 if (count != 16) {
3047 cFYI(1, ("Illegal size ret in GetExtAttr"));
3048 rc = -EIO;
3049 goto GetExtAttrOut;
3050 }
3051 pfinfo = (struct file_chattr_info *)
3052 (data_offset + (char *) &pSMBr->hdr.Protocol);
3053 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003054 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003055 }
3056 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003057GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003058 cifs_buf_release(pSMB);
3059 if (rc == -EAGAIN)
3060 goto GetExtAttrRetry;
3061 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003062}
3063
Steve Frenchf654bac2005-04-28 22:41:04 -07003064#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065
Steve French297647c2007-10-12 04:11:59 +00003066#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003067/* Get Security Descriptor (by handle) from remote server for a file or dir */
3068int
3069CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French50c2f752007-07-13 00:33:32 +00003070 /* BB fix up return info */ char *acl_inf, const int buflen,
Steve French442aa312007-09-24 20:25:46 +00003071 const int acl_type)
Steve French0a4b92c2006-01-12 15:44:21 -08003072{
3073 int rc = 0;
3074 int buf_type = 0;
3075 QUERY_SEC_DESC_REQ * pSMB;
3076 struct kvec iov[1];
3077
3078 cFYI(1, ("GetCifsACL"));
3079
Steve French50c2f752007-07-13 00:33:32 +00003080 rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003081 8 /* parm len */, tcon, (void **) &pSMB);
3082 if (rc)
3083 return rc;
3084
3085 pSMB->MaxParameterCount = cpu_to_le32(4);
3086 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3087 pSMB->MaxSetupCount = 0;
3088 pSMB->Fid = fid; /* file handle always le */
3089 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3090 CIFS_ACL_DACL);
3091 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3092 pSMB->hdr.smb_buf_length += 11;
3093 iov[0].iov_base = (char *)pSMB;
3094 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3095
Steve Frencha761ac52007-10-18 21:45:27 +00003096 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
3097 0 /* not long op */, 0 /* do not log STATUS codes */ );
Steve French0a4b92c2006-01-12 15:44:21 -08003098 cifs_stats_inc(&tcon->num_acl_get);
3099 if (rc) {
3100 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3101 } else { /* decode response */
Steve French442aa312007-09-24 20:25:46 +00003102 struct cifs_ntsd *psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08003103 __le32 * parm;
3104 int parm_len;
3105 int data_len;
3106 int acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003107 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08003108
3109/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003110 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French0a4b92c2006-01-12 15:44:21 -08003111 (char **)&psec_desc,
3112 &parm_len, &data_len);
Steve French790fe572007-07-07 19:25:05 +00003113 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003114 goto qsec_out;
3115 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3116
Steve Frencha0136892007-10-04 20:05:09 +00003117 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, psec_desc));
Steve French0a4b92c2006-01-12 15:44:21 -08003118
3119 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3120 rc = -EIO; /* bad smb */
3121 goto qsec_out;
3122 }
3123
3124/* BB check that data area is minimum length and as big as acl_len */
3125
Steve Frenchaf6f4612007-10-16 18:40:37 +00003126 acl_len = le32_to_cpu(*parm);
Steve French790fe572007-07-07 19:25:05 +00003127 /* BB check if (acl_len > bufsize) */
Steve French0a4b92c2006-01-12 15:44:21 -08003128
3129 parse_sec_desc(psec_desc, acl_len);
3130 }
3131qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003132 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003133 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003134 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003135 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003136/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003137 return rc;
3138}
Steve French297647c2007-10-12 04:11:59 +00003139#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003140
Steve French6b8edfe2005-08-23 20:26:03 -07003141/* Legacy Query Path Information call for lookup to old servers such
3142 as Win9x/WinME */
3143int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003144 const unsigned char *searchName,
3145 FILE_ALL_INFO *pFinfo,
3146 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003147{
3148 QUERY_INFORMATION_REQ * pSMB;
3149 QUERY_INFORMATION_RSP * pSMBr;
3150 int rc = 0;
3151 int bytes_returned;
3152 int name_len;
3153
Steve French50c2f752007-07-13 00:33:32 +00003154 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003155QInfRetry:
3156 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003157 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003158 if (rc)
3159 return rc;
3160
3161 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3162 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003163 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3164 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003165 name_len++; /* trailing null */
3166 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003167 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003168 name_len = strnlen(searchName, PATH_MAX);
3169 name_len++; /* trailing null */
3170 strncpy(pSMB->FileName, searchName, name_len);
3171 }
3172 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003173 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003174 pSMB->hdr.smb_buf_length += (__u16) name_len;
3175 pSMB->ByteCount = cpu_to_le16(name_len);
3176
3177 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003178 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003179 if (rc) {
3180 cFYI(1, ("Send error in QueryInfo = %d", rc));
3181 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003182 struct timespec ts;
3183 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3184 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003185 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003186 ts.tv_nsec = 0;
3187 ts.tv_sec = time;
3188 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003189 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003190 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3191 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003192 pFinfo->AllocationSize =
3193 cpu_to_le64(le32_to_cpu(pSMBr->size));
3194 pFinfo->EndOfFile = pFinfo->AllocationSize;
3195 pFinfo->Attributes =
3196 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003197 } else
3198 rc = -EIO; /* bad buffer passed in */
3199
3200 cifs_buf_release(pSMB);
3201
3202 if (rc == -EAGAIN)
3203 goto QInfRetry;
3204
3205 return rc;
3206}
3207
3208
3209
3210
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211int
3212CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3213 const unsigned char *searchName,
3214 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003215 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003216 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217{
3218/* level 263 SMB_QUERY_FILE_ALL_INFO */
3219 TRANSACTION2_QPI_REQ *pSMB = NULL;
3220 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3221 int rc = 0;
3222 int bytes_returned;
3223 int name_len;
3224 __u16 params, byte_count;
3225
3226/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3227QPathInfoRetry:
3228 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3229 (void **) &pSMBr);
3230 if (rc)
3231 return rc;
3232
3233 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3234 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003235 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003236 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003237 name_len++; /* trailing null */
3238 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003239 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003240 name_len = strnlen(searchName, PATH_MAX);
3241 name_len++; /* trailing null */
3242 strncpy(pSMB->FileName, searchName, name_len);
3243 }
3244
Steve French50c2f752007-07-13 00:33:32 +00003245 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003246 pSMB->TotalDataCount = 0;
3247 pSMB->MaxParameterCount = cpu_to_le16(2);
3248 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3249 pSMB->MaxSetupCount = 0;
3250 pSMB->Reserved = 0;
3251 pSMB->Flags = 0;
3252 pSMB->Timeout = 0;
3253 pSMB->Reserved2 = 0;
3254 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003255 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 pSMB->DataCount = 0;
3257 pSMB->DataOffset = 0;
3258 pSMB->SetupCount = 1;
3259 pSMB->Reserved3 = 0;
3260 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3261 byte_count = params + 1 /* pad */ ;
3262 pSMB->TotalParameterCount = cpu_to_le16(params);
3263 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003264 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003265 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3266 else
3267 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 pSMB->Reserved4 = 0;
3269 pSMB->hdr.smb_buf_length += byte_count;
3270 pSMB->ByteCount = cpu_to_le16(byte_count);
3271
3272 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3273 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3274 if (rc) {
3275 cFYI(1, ("Send error in QPathInfo = %d", rc));
3276 } else { /* decode response */
3277 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3278
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003279 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3280 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003281 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003283 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003284 rc = -EIO; /* 24 or 26 expected but we do not read
3285 last field */
3286 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003287 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003289 if (legacy) /* we do not read the last field, EAsize,
3290 fortunately since it varies by subdialect
3291 and on Set vs. Get, is two bytes or 4
3292 bytes depending but we don't care here */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003293 size = sizeof(FILE_INFO_STANDARD);
3294 else
3295 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 memcpy((char *) pFindData,
3297 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003298 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299 } else
3300 rc = -ENOMEM;
3301 }
3302 cifs_buf_release(pSMB);
3303 if (rc == -EAGAIN)
3304 goto QPathInfoRetry;
3305
3306 return rc;
3307}
3308
3309int
3310CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3311 const unsigned char *searchName,
3312 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003313 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314{
3315/* SMB_QUERY_FILE_UNIX_BASIC */
3316 TRANSACTION2_QPI_REQ *pSMB = NULL;
3317 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3318 int rc = 0;
3319 int bytes_returned = 0;
3320 int name_len;
3321 __u16 params, byte_count;
3322
3323 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3324UnixQPathInfoRetry:
3325 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3326 (void **) &pSMBr);
3327 if (rc)
3328 return rc;
3329
3330 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3331 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003332 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003333 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334 name_len++; /* trailing null */
3335 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003336 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337 name_len = strnlen(searchName, PATH_MAX);
3338 name_len++; /* trailing null */
3339 strncpy(pSMB->FileName, searchName, name_len);
3340 }
3341
Steve French50c2f752007-07-13 00:33:32 +00003342 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003343 pSMB->TotalDataCount = 0;
3344 pSMB->MaxParameterCount = cpu_to_le16(2);
3345 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003346 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 pSMB->MaxSetupCount = 0;
3348 pSMB->Reserved = 0;
3349 pSMB->Flags = 0;
3350 pSMB->Timeout = 0;
3351 pSMB->Reserved2 = 0;
3352 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003353 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003354 pSMB->DataCount = 0;
3355 pSMB->DataOffset = 0;
3356 pSMB->SetupCount = 1;
3357 pSMB->Reserved3 = 0;
3358 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3359 byte_count = params + 1 /* pad */ ;
3360 pSMB->TotalParameterCount = cpu_to_le16(params);
3361 pSMB->ParameterCount = pSMB->TotalParameterCount;
3362 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3363 pSMB->Reserved4 = 0;
3364 pSMB->hdr.smb_buf_length += byte_count;
3365 pSMB->ByteCount = cpu_to_le16(byte_count);
3366
3367 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3368 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3369 if (rc) {
3370 cFYI(1, ("Send error in QPathInfo = %d", rc));
3371 } else { /* decode response */
3372 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3373
3374 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003375 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3376 "Unix Extensions can be disabled on mount "
3377 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003378 rc = -EIO; /* bad smb */
3379 } else {
3380 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3381 memcpy((char *) pFindData,
3382 (char *) &pSMBr->hdr.Protocol +
3383 data_offset,
3384 sizeof (FILE_UNIX_BASIC_INFO));
3385 }
3386 }
3387 cifs_buf_release(pSMB);
3388 if (rc == -EAGAIN)
3389 goto UnixQPathInfoRetry;
3390
3391 return rc;
3392}
3393
3394#if 0 /* function unused at present */
3395int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3396 const char *searchName, FILE_ALL_INFO * findData,
3397 const struct nls_table *nls_codepage)
3398{
3399/* level 257 SMB_ */
3400 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3401 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3402 int rc = 0;
3403 int bytes_returned;
3404 int name_len;
3405 __u16 params, byte_count;
3406
3407 cFYI(1, ("In FindUnique"));
3408findUniqueRetry:
3409 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3410 (void **) &pSMBr);
3411 if (rc)
3412 return rc;
3413
3414 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3415 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003416 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3417 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 name_len++; /* trailing null */
3419 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003420 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421 name_len = strnlen(searchName, PATH_MAX);
3422 name_len++; /* trailing null */
3423 strncpy(pSMB->FileName, searchName, name_len);
3424 }
3425
3426 params = 12 + name_len /* includes null */ ;
3427 pSMB->TotalDataCount = 0; /* no EAs */
3428 pSMB->MaxParameterCount = cpu_to_le16(2);
3429 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3430 pSMB->MaxSetupCount = 0;
3431 pSMB->Reserved = 0;
3432 pSMB->Flags = 0;
3433 pSMB->Timeout = 0;
3434 pSMB->Reserved2 = 0;
3435 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003436 offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003437 pSMB->DataCount = 0;
3438 pSMB->DataOffset = 0;
3439 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3440 pSMB->Reserved3 = 0;
3441 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3442 byte_count = params + 1 /* pad */ ;
3443 pSMB->TotalParameterCount = cpu_to_le16(params);
3444 pSMB->ParameterCount = pSMB->TotalParameterCount;
3445 pSMB->SearchAttributes =
3446 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3447 ATTR_DIRECTORY);
3448 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3449 pSMB->SearchFlags = cpu_to_le16(1);
3450 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3451 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3452 pSMB->hdr.smb_buf_length += byte_count;
3453 pSMB->ByteCount = cpu_to_le16(byte_count);
3454
3455 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3456 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3457
3458 if (rc) {
3459 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3460 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003461 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 /* BB fill in */
3463 }
3464
3465 cifs_buf_release(pSMB);
3466 if (rc == -EAGAIN)
3467 goto findUniqueRetry;
3468
3469 return rc;
3470}
3471#endif /* end unused (temporarily) function */
3472
3473/* xid, tcon, searchName and codepage are input parms, rest are returned */
3474int
3475CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003476 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003478 __u16 *pnetfid,
3479 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003480{
3481/* level 257 SMB_ */
3482 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3483 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3484 T2_FFIRST_RSP_PARMS * parms;
3485 int rc = 0;
3486 int bytes_returned = 0;
3487 int name_len;
3488 __u16 params, byte_count;
3489
Steve French50c2f752007-07-13 00:33:32 +00003490 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491
3492findFirstRetry:
3493 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3494 (void **) &pSMBr);
3495 if (rc)
3496 return rc;
3497
3498 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3499 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003500 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003501 PATH_MAX, nls_codepage, remap);
3502 /* We can not add the asterik earlier in case
3503 it got remapped to 0xF03A as if it were part of the
3504 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003506 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003507 pSMB->FileName[name_len+1] = 0;
3508 pSMB->FileName[name_len+2] = '*';
3509 pSMB->FileName[name_len+3] = 0;
3510 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3512 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003513 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 } else { /* BB add check for overrun of SMB buf BB */
3515 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003517 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518 free buffer exit; BB */
3519 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003520 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003521 pSMB->FileName[name_len+1] = '*';
3522 pSMB->FileName[name_len+2] = 0;
3523 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 }
3525
3526 params = 12 + name_len /* includes null */ ;
3527 pSMB->TotalDataCount = 0; /* no EAs */
3528 pSMB->MaxParameterCount = cpu_to_le16(10);
3529 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3530 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3531 pSMB->MaxSetupCount = 0;
3532 pSMB->Reserved = 0;
3533 pSMB->Flags = 0;
3534 pSMB->Timeout = 0;
3535 pSMB->Reserved2 = 0;
3536 byte_count = params + 1 /* pad */ ;
3537 pSMB->TotalParameterCount = cpu_to_le16(params);
3538 pSMB->ParameterCount = pSMB->TotalParameterCount;
3539 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003540 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3541 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 pSMB->DataCount = 0;
3543 pSMB->DataOffset = 0;
3544 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3545 pSMB->Reserved3 = 0;
3546 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3547 pSMB->SearchAttributes =
3548 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3549 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003550 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3551 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552 CIFS_SEARCH_RETURN_RESUME);
3553 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3554
3555 /* BB what should we set StorageType to? Does it matter? BB */
3556 pSMB->SearchStorageType = 0;
3557 pSMB->hdr.smb_buf_length += byte_count;
3558 pSMB->ByteCount = cpu_to_le16(byte_count);
3559
3560 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3561 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003562 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563
Steve French88274812006-03-09 22:21:45 +00003564 if (rc) {/* BB add logic to retry regular search if Unix search
3565 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003566 /* BB Add code to handle unsupported level rc */
3567 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003568
Steve French88274812006-03-09 22:21:45 +00003569 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570
3571 /* BB eventually could optimize out free and realloc of buf */
3572 /* for this case */
3573 if (rc == -EAGAIN)
3574 goto findFirstRetry;
3575 } else { /* decode response */
3576 /* BB remember to free buffer if error BB */
3577 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003578 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003579 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3580 psrch_inf->unicode = TRUE;
3581 else
3582 psrch_inf->unicode = FALSE;
3583
3584 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003585 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003586 psrch_inf->srch_entries_start =
3587 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003588 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3590 le16_to_cpu(pSMBr->t2.ParameterOffset));
3591
Steve French790fe572007-07-07 19:25:05 +00003592 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003593 psrch_inf->endOfSearch = TRUE;
3594 else
3595 psrch_inf->endOfSearch = FALSE;
3596
Steve French50c2f752007-07-13 00:33:32 +00003597 psrch_inf->entries_in_buffer =
3598 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003599 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003600 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601 *pnetfid = parms->SearchHandle;
3602 } else {
3603 cifs_buf_release(pSMB);
3604 }
3605 }
3606
3607 return rc;
3608}
3609
3610int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003611 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003612{
3613 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3614 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3615 T2_FNEXT_RSP_PARMS * parms;
3616 char *response_data;
3617 int rc = 0;
3618 int bytes_returned, name_len;
3619 __u16 params, byte_count;
3620
3621 cFYI(1, ("In FindNext"));
3622
Steve French790fe572007-07-07 19:25:05 +00003623 if (psrch_inf->endOfSearch == TRUE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 return -ENOENT;
3625
3626 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3627 (void **) &pSMBr);
3628 if (rc)
3629 return rc;
3630
Steve French50c2f752007-07-13 00:33:32 +00003631 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003632 byte_count = 0;
3633 pSMB->TotalDataCount = 0; /* no EAs */
3634 pSMB->MaxParameterCount = cpu_to_le16(8);
3635 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003636 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3637 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 pSMB->MaxSetupCount = 0;
3639 pSMB->Reserved = 0;
3640 pSMB->Flags = 0;
3641 pSMB->Timeout = 0;
3642 pSMB->Reserved2 = 0;
3643 pSMB->ParameterOffset = cpu_to_le16(
3644 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3645 pSMB->DataCount = 0;
3646 pSMB->DataOffset = 0;
3647 pSMB->SetupCount = 1;
3648 pSMB->Reserved3 = 0;
3649 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3650 pSMB->SearchHandle = searchHandle; /* always kept as le */
3651 pSMB->SearchCount =
3652 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003653 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3654 pSMB->ResumeKey = psrch_inf->resume_key;
3655 pSMB->SearchFlags =
3656 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3657
3658 name_len = psrch_inf->resume_name_len;
3659 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003660 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3662 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003663 /* 14 byte parm len above enough for 2 byte null terminator */
3664 pSMB->ResumeFileName[name_len] = 0;
3665 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 } else {
3667 rc = -EINVAL;
3668 goto FNext2_err_exit;
3669 }
3670 byte_count = params + 1 /* pad */ ;
3671 pSMB->TotalParameterCount = cpu_to_le16(params);
3672 pSMB->ParameterCount = pSMB->TotalParameterCount;
3673 pSMB->hdr.smb_buf_length += byte_count;
3674 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003675
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3677 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003678 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 if (rc) {
3680 if (rc == -EBADF) {
3681 psrch_inf->endOfSearch = TRUE;
Steve French50c2f752007-07-13 00:33:32 +00003682 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003683 } else
3684 cFYI(1, ("FindNext returned = %d", rc));
3685 } else { /* decode response */
3686 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003687
Steve French790fe572007-07-07 19:25:05 +00003688 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003689 /* BB fixme add lock for file (srch_info) struct here */
3690 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3691 psrch_inf->unicode = TRUE;
3692 else
3693 psrch_inf->unicode = FALSE;
3694 response_data = (char *) &pSMBr->hdr.Protocol +
3695 le16_to_cpu(pSMBr->t2.ParameterOffset);
3696 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3697 response_data = (char *)&pSMBr->hdr.Protocol +
3698 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003699 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003700 cifs_small_buf_release(
3701 psrch_inf->ntwrk_buf_start);
3702 else
3703 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003704 psrch_inf->srch_entries_start = response_data;
3705 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003706 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003707 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003708 psrch_inf->endOfSearch = TRUE;
3709 else
3710 psrch_inf->endOfSearch = FALSE;
Steve French50c2f752007-07-13 00:33:32 +00003711 psrch_inf->entries_in_buffer =
3712 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 psrch_inf->index_of_last_entry +=
3714 psrch_inf->entries_in_buffer;
Steve French50c2f752007-07-13 00:33:32 +00003715/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3716 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717
3718 /* BB fixme add unlock here */
3719 }
3720
3721 }
3722
3723 /* BB On error, should we leave previous search buf (and count and
3724 last entry fields) intact or free the previous one? */
3725
3726 /* Note: On -EAGAIN error only caller can retry on handle based calls
3727 since file handle passed in no longer valid */
3728FNext2_err_exit:
3729 if (rc != 0)
3730 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 return rc;
3732}
3733
3734int
Steve French50c2f752007-07-13 00:33:32 +00003735CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3736 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737{
3738 int rc = 0;
3739 FINDCLOSE_REQ *pSMB = NULL;
3740 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3741 int bytes_returned;
3742
3743 cFYI(1, ("In CIFSSMBFindClose"));
3744 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3745
3746 /* no sense returning error if session restarted
3747 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003748 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003749 return 0;
3750 if (rc)
3751 return rc;
3752
3753 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3754 pSMB->FileID = searchHandle;
3755 pSMB->ByteCount = 0;
3756 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3757 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3758 if (rc) {
3759 cERROR(1, ("Send error in FindClose = %d", rc));
3760 }
Steve Frencha4544342005-08-24 13:59:35 -07003761 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003762 cifs_small_buf_release(pSMB);
3763
3764 /* Since session is dead, search handle closed on server already */
3765 if (rc == -EAGAIN)
3766 rc = 0;
3767
3768 return rc;
3769}
3770
Linus Torvalds1da177e2005-04-16 15:20:36 -07003771int
3772CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003773 const unsigned char *searchName,
3774 __u64 * inode_number,
3775 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003776{
3777 int rc = 0;
3778 TRANSACTION2_QPI_REQ *pSMB = NULL;
3779 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3780 int name_len, bytes_returned;
3781 __u16 params, byte_count;
3782
Steve French50c2f752007-07-13 00:33:32 +00003783 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003784 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003785 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003786
3787GetInodeNumberRetry:
3788 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003789 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003790 if (rc)
3791 return rc;
3792
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3794 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003795 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003796 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797 name_len++; /* trailing null */
3798 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003799 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003800 name_len = strnlen(searchName, PATH_MAX);
3801 name_len++; /* trailing null */
3802 strncpy(pSMB->FileName, searchName, name_len);
3803 }
3804
3805 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3806 pSMB->TotalDataCount = 0;
3807 pSMB->MaxParameterCount = cpu_to_le16(2);
3808 /* BB find exact max data count below from sess structure BB */
3809 pSMB->MaxDataCount = cpu_to_le16(4000);
3810 pSMB->MaxSetupCount = 0;
3811 pSMB->Reserved = 0;
3812 pSMB->Flags = 0;
3813 pSMB->Timeout = 0;
3814 pSMB->Reserved2 = 0;
3815 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003816 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003817 pSMB->DataCount = 0;
3818 pSMB->DataOffset = 0;
3819 pSMB->SetupCount = 1;
3820 pSMB->Reserved3 = 0;
3821 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3822 byte_count = params + 1 /* pad */ ;
3823 pSMB->TotalParameterCount = cpu_to_le16(params);
3824 pSMB->ParameterCount = pSMB->TotalParameterCount;
3825 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3826 pSMB->Reserved4 = 0;
3827 pSMB->hdr.smb_buf_length += byte_count;
3828 pSMB->ByteCount = cpu_to_le16(byte_count);
3829
3830 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3831 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3832 if (rc) {
3833 cFYI(1, ("error %d in QueryInternalInfo", rc));
3834 } else {
3835 /* decode response */
3836 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3837 if (rc || (pSMBr->ByteCount < 2))
3838 /* BB also check enough total bytes returned */
3839 /* If rc should we check for EOPNOSUPP and
3840 disable the srvino flag? or in caller? */
3841 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003842 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3844 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003845 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003847 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3849 rc = -EIO;
3850 goto GetInodeNumOut;
3851 }
3852 pfinfo = (struct file_internal_info *)
3853 (data_offset + (char *) &pSMBr->hdr.Protocol);
3854 *inode_number = pfinfo->UniqueId;
3855 }
3856 }
3857GetInodeNumOut:
3858 cifs_buf_release(pSMB);
3859 if (rc == -EAGAIN)
3860 goto GetInodeNumberRetry;
3861 return rc;
3862}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003863
3864int
3865CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3866 const unsigned char *searchName,
3867 unsigned char **targetUNCs,
3868 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003869 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870{
3871/* TRANS2_GET_DFS_REFERRAL */
3872 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3873 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003874 struct dfs_referral_level_3 *referrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003875 int rc = 0;
3876 int bytes_returned;
3877 int name_len;
3878 unsigned int i;
Steve French50c2f752007-07-13 00:33:32 +00003879 char *temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 __u16 params, byte_count;
3881 *number_of_UNC_in_array = 0;
3882 *targetUNCs = NULL;
3883
3884 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3885 if (ses == NULL)
3886 return -ENODEV;
3887getDFSRetry:
3888 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3889 (void **) &pSMBr);
3890 if (rc)
3891 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003892
3893 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07003894 but should never be null here anyway */
3895 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896 pSMB->hdr.Tid = ses->ipc_tid;
3897 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00003898 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003899 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00003900 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003902
3903 if (ses->capabilities & CAP_UNICODE) {
3904 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3905 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003906 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003907 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908 name_len++; /* trailing null */
3909 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003910 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911 name_len = strnlen(searchName, PATH_MAX);
3912 name_len++; /* trailing null */
3913 strncpy(pSMB->RequestFileName, searchName, name_len);
3914 }
3915
Steve French790fe572007-07-07 19:25:05 +00003916 if (ses->server) {
3917 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00003918 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3919 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3920 }
3921
Steve French50c2f752007-07-13 00:33:32 +00003922 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00003923
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 params = 2 /* level */ + name_len /*includes null */ ;
3925 pSMB->TotalDataCount = 0;
3926 pSMB->DataCount = 0;
3927 pSMB->DataOffset = 0;
3928 pSMB->MaxParameterCount = 0;
3929 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3930 pSMB->MaxSetupCount = 0;
3931 pSMB->Reserved = 0;
3932 pSMB->Flags = 0;
3933 pSMB->Timeout = 0;
3934 pSMB->Reserved2 = 0;
3935 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003936 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 pSMB->SetupCount = 1;
3938 pSMB->Reserved3 = 0;
3939 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3940 byte_count = params + 3 /* pad */ ;
3941 pSMB->ParameterCount = cpu_to_le16(params);
3942 pSMB->TotalParameterCount = pSMB->ParameterCount;
3943 pSMB->MaxReferralLevel = cpu_to_le16(3);
3944 pSMB->hdr.smb_buf_length += byte_count;
3945 pSMB->ByteCount = cpu_to_le16(byte_count);
3946
3947 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3948 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3949 if (rc) {
3950 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3951 } else { /* decode response */
3952/* BB Add logic to parse referrals here */
3953 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3954
Steve French50c2f752007-07-13 00:33:32 +00003955 /* BB Also check if enough total bytes returned? */
3956 if (rc || (pSMBr->ByteCount < 17))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 rc = -EIO; /* bad smb */
3958 else {
Steve French50c2f752007-07-13 00:33:32 +00003959 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3961
3962 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003963 ("Decoding GetDFSRefer response BCC: %d Offset %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003964 pSMBr->ByteCount, data_offset));
Steve French50c2f752007-07-13 00:33:32 +00003965 referrals =
3966 (struct dfs_referral_level_3 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003967 (8 /* sizeof start of data block */ +
3968 data_offset +
Steve French50c2f752007-07-13 00:33:32 +00003969 (char *) &pSMBr->hdr.Protocol);
Steve Frenchc18c8422007-07-18 23:21:09 +00003970 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
Steve French63135e02007-07-17 17:34:02 +00003971 "for referral one refer size: 0x%x srv "
3972 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
Steve French50c2f752007-07-13 00:33:32 +00003973 le16_to_cpu(pSMBr->NumberOfReferrals),
3974 le16_to_cpu(pSMBr->DFSFlags),
3975 le16_to_cpu(referrals->ReferralSize),
3976 le16_to_cpu(referrals->ServerType),
3977 le16_to_cpu(referrals->ReferralFlags),
3978 le16_to_cpu(referrals->TimeToLive)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 /* BB This field is actually two bytes in from start of
3980 data block so we could do safety check that DataBlock
3981 begins at address of pSMBr->NumberOfReferrals */
Steve French50c2f752007-07-13 00:33:32 +00003982 *number_of_UNC_in_array =
3983 le16_to_cpu(pSMBr->NumberOfReferrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003984
3985 /* BB Fix below so can return more than one referral */
Steve French790fe572007-07-07 19:25:05 +00003986 if (*number_of_UNC_in_array > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003987 *number_of_UNC_in_array = 1;
3988
3989 /* get the length of the strings describing refs */
3990 name_len = 0;
Steve French50c2f752007-07-13 00:33:32 +00003991 for (i = 0; i < *number_of_UNC_in_array; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992 /* make sure that DfsPathOffset not past end */
Steve French50c2f752007-07-13 00:33:32 +00003993 __u16 offset =
3994 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003995 if (offset > data_count) {
Steve French50c2f752007-07-13 00:33:32 +00003996 /* if invalid referral, stop here and do
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997 not try to copy any more */
3998 *number_of_UNC_in_array = i;
3999 break;
Steve French50c2f752007-07-13 00:33:32 +00004000 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004001 temp = ((char *)referrals) + offset;
4002
4003 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00004004 name_len += UniStrnlen((wchar_t *)temp,
4005 data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 } else {
Steve French50c2f752007-07-13 00:33:32 +00004007 name_len += strnlen(temp, data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 }
4009 referrals++;
Steve French50c2f752007-07-13 00:33:32 +00004010 /* BB add check that referral pointer does
4011 not fall off end PDU */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004012 }
4013 /* BB add check for name_len bigger than bcc */
Steve French50c2f752007-07-13 00:33:32 +00004014 *targetUNCs =
4015 kmalloc(name_len+1+(*number_of_UNC_in_array),
4016 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00004017 if (*targetUNCs == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018 rc = -ENOMEM;
4019 goto GetDFSRefExit;
4020 }
4021 /* copy the ref strings */
Steve French50c2f752007-07-13 00:33:32 +00004022 referrals = (struct dfs_referral_level_3 *)
4023 (8 /* sizeof data hdr */ + data_offset +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004024 (char *) &pSMBr->hdr.Protocol);
4025
Steve French50c2f752007-07-13 00:33:32 +00004026 for (i = 0; i < *number_of_UNC_in_array; i++) {
4027 temp = ((char *)referrals) +
4028 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4030 cifs_strfromUCS_le(*targetUNCs,
Steve French50c2f752007-07-13 00:33:32 +00004031 (__le16 *) temp,
4032 name_len,
4033 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034 } else {
Steve French50c2f752007-07-13 00:33:32 +00004035 strncpy(*targetUNCs, temp, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 }
4037 /* BB update target_uncs pointers */
4038 referrals++;
4039 }
4040 temp = *targetUNCs;
4041 temp[name_len] = 0;
4042 }
4043
4044 }
4045GetDFSRefExit:
4046 if (pSMB)
4047 cifs_buf_release(pSMB);
4048
4049 if (rc == -EAGAIN)
4050 goto getDFSRetry;
4051
4052 return rc;
4053}
4054
Steve French20962432005-09-21 22:05:57 -07004055/* Query File System Info such as free space to old servers such as Win 9x */
4056int
4057SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4058{
4059/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4060 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4061 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4062 FILE_SYSTEM_ALLOC_INFO *response_data;
4063 int rc = 0;
4064 int bytes_returned = 0;
4065 __u16 params, byte_count;
4066
4067 cFYI(1, ("OldQFSInfo"));
4068oldQFSInfoRetry:
4069 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4070 (void **) &pSMBr);
4071 if (rc)
4072 return rc;
Steve French20962432005-09-21 22:05:57 -07004073
4074 params = 2; /* level */
4075 pSMB->TotalDataCount = 0;
4076 pSMB->MaxParameterCount = cpu_to_le16(2);
4077 pSMB->MaxDataCount = cpu_to_le16(1000);
4078 pSMB->MaxSetupCount = 0;
4079 pSMB->Reserved = 0;
4080 pSMB->Flags = 0;
4081 pSMB->Timeout = 0;
4082 pSMB->Reserved2 = 0;
4083 byte_count = params + 1 /* pad */ ;
4084 pSMB->TotalParameterCount = cpu_to_le16(params);
4085 pSMB->ParameterCount = pSMB->TotalParameterCount;
4086 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4087 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4088 pSMB->DataCount = 0;
4089 pSMB->DataOffset = 0;
4090 pSMB->SetupCount = 1;
4091 pSMB->Reserved3 = 0;
4092 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4093 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4094 pSMB->hdr.smb_buf_length += byte_count;
4095 pSMB->ByteCount = cpu_to_le16(byte_count);
4096
4097 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4098 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4099 if (rc) {
4100 cFYI(1, ("Send error in QFSInfo = %d", rc));
4101 } else { /* decode response */
4102 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4103
4104 if (rc || (pSMBr->ByteCount < 18))
4105 rc = -EIO; /* bad smb */
4106 else {
4107 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004108 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004109 pSMBr->ByteCount, data_offset));
4110
Steve French50c2f752007-07-13 00:33:32 +00004111 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004112 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4113 FSData->f_bsize =
4114 le16_to_cpu(response_data->BytesPerSector) *
4115 le32_to_cpu(response_data->
4116 SectorsPerAllocationUnit);
4117 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004118 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004119 FSData->f_bfree = FSData->f_bavail =
4120 le32_to_cpu(response_data->FreeAllocationUnits);
4121 cFYI(1,
4122 ("Blocks: %lld Free: %lld Block size %ld",
4123 (unsigned long long)FSData->f_blocks,
4124 (unsigned long long)FSData->f_bfree,
4125 FSData->f_bsize));
4126 }
4127 }
4128 cifs_buf_release(pSMB);
4129
4130 if (rc == -EAGAIN)
4131 goto oldQFSInfoRetry;
4132
4133 return rc;
4134}
4135
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136int
Steve French737b7582005-04-28 22:41:06 -07004137CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138{
4139/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4140 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4141 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4142 FILE_SYSTEM_INFO *response_data;
4143 int rc = 0;
4144 int bytes_returned = 0;
4145 __u16 params, byte_count;
4146
4147 cFYI(1, ("In QFSInfo"));
4148QFSInfoRetry:
4149 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4150 (void **) &pSMBr);
4151 if (rc)
4152 return rc;
4153
4154 params = 2; /* level */
4155 pSMB->TotalDataCount = 0;
4156 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004157 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004158 pSMB->MaxSetupCount = 0;
4159 pSMB->Reserved = 0;
4160 pSMB->Flags = 0;
4161 pSMB->Timeout = 0;
4162 pSMB->Reserved2 = 0;
4163 byte_count = params + 1 /* pad */ ;
4164 pSMB->TotalParameterCount = cpu_to_le16(params);
4165 pSMB->ParameterCount = pSMB->TotalParameterCount;
4166 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004167 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 pSMB->DataCount = 0;
4169 pSMB->DataOffset = 0;
4170 pSMB->SetupCount = 1;
4171 pSMB->Reserved3 = 0;
4172 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4173 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4174 pSMB->hdr.smb_buf_length += byte_count;
4175 pSMB->ByteCount = cpu_to_le16(byte_count);
4176
4177 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4178 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4179 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004180 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004182 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183
Steve French20962432005-09-21 22:05:57 -07004184 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185 rc = -EIO; /* bad smb */
4186 else {
4187 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004188
4189 response_data =
4190 (FILE_SYSTEM_INFO
4191 *) (((char *) &pSMBr->hdr.Protocol) +
4192 data_offset);
4193 FSData->f_bsize =
4194 le32_to_cpu(response_data->BytesPerSector) *
4195 le32_to_cpu(response_data->
4196 SectorsPerAllocationUnit);
4197 FSData->f_blocks =
4198 le64_to_cpu(response_data->TotalAllocationUnits);
4199 FSData->f_bfree = FSData->f_bavail =
4200 le64_to_cpu(response_data->FreeAllocationUnits);
4201 cFYI(1,
4202 ("Blocks: %lld Free: %lld Block size %ld",
4203 (unsigned long long)FSData->f_blocks,
4204 (unsigned long long)FSData->f_bfree,
4205 FSData->f_bsize));
4206 }
4207 }
4208 cifs_buf_release(pSMB);
4209
4210 if (rc == -EAGAIN)
4211 goto QFSInfoRetry;
4212
4213 return rc;
4214}
4215
4216int
Steve French737b7582005-04-28 22:41:06 -07004217CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218{
4219/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4220 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4221 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4222 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4223 int rc = 0;
4224 int bytes_returned = 0;
4225 __u16 params, byte_count;
4226
4227 cFYI(1, ("In QFSAttributeInfo"));
4228QFSAttributeRetry:
4229 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4230 (void **) &pSMBr);
4231 if (rc)
4232 return rc;
4233
4234 params = 2; /* level */
4235 pSMB->TotalDataCount = 0;
4236 pSMB->MaxParameterCount = cpu_to_le16(2);
4237 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4238 pSMB->MaxSetupCount = 0;
4239 pSMB->Reserved = 0;
4240 pSMB->Flags = 0;
4241 pSMB->Timeout = 0;
4242 pSMB->Reserved2 = 0;
4243 byte_count = params + 1 /* pad */ ;
4244 pSMB->TotalParameterCount = cpu_to_le16(params);
4245 pSMB->ParameterCount = pSMB->TotalParameterCount;
4246 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004247 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004248 pSMB->DataCount = 0;
4249 pSMB->DataOffset = 0;
4250 pSMB->SetupCount = 1;
4251 pSMB->Reserved3 = 0;
4252 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4253 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4254 pSMB->hdr.smb_buf_length += byte_count;
4255 pSMB->ByteCount = cpu_to_le16(byte_count);
4256
4257 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4258 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4259 if (rc) {
4260 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4261 } else { /* decode response */
4262 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4263
Steve French50c2f752007-07-13 00:33:32 +00004264 if (rc || (pSMBr->ByteCount < 13)) {
4265 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266 rc = -EIO; /* bad smb */
4267 } else {
4268 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4269 response_data =
4270 (FILE_SYSTEM_ATTRIBUTE_INFO
4271 *) (((char *) &pSMBr->hdr.Protocol) +
4272 data_offset);
4273 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004274 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004275 }
4276 }
4277 cifs_buf_release(pSMB);
4278
4279 if (rc == -EAGAIN)
4280 goto QFSAttributeRetry;
4281
4282 return rc;
4283}
4284
4285int
Steve French737b7582005-04-28 22:41:06 -07004286CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287{
4288/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4289 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4290 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4291 FILE_SYSTEM_DEVICE_INFO *response_data;
4292 int rc = 0;
4293 int bytes_returned = 0;
4294 __u16 params, byte_count;
4295
4296 cFYI(1, ("In QFSDeviceInfo"));
4297QFSDeviceRetry:
4298 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4299 (void **) &pSMBr);
4300 if (rc)
4301 return rc;
4302
4303 params = 2; /* level */
4304 pSMB->TotalDataCount = 0;
4305 pSMB->MaxParameterCount = cpu_to_le16(2);
4306 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4307 pSMB->MaxSetupCount = 0;
4308 pSMB->Reserved = 0;
4309 pSMB->Flags = 0;
4310 pSMB->Timeout = 0;
4311 pSMB->Reserved2 = 0;
4312 byte_count = params + 1 /* pad */ ;
4313 pSMB->TotalParameterCount = cpu_to_le16(params);
4314 pSMB->ParameterCount = pSMB->TotalParameterCount;
4315 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004316 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317
4318 pSMB->DataCount = 0;
4319 pSMB->DataOffset = 0;
4320 pSMB->SetupCount = 1;
4321 pSMB->Reserved3 = 0;
4322 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4323 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4324 pSMB->hdr.smb_buf_length += byte_count;
4325 pSMB->ByteCount = cpu_to_le16(byte_count);
4326
4327 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4328 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4329 if (rc) {
4330 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4331 } else { /* decode response */
4332 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4333
4334 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4335 rc = -EIO; /* bad smb */
4336 else {
4337 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4338 response_data =
Steve French737b7582005-04-28 22:41:06 -07004339 (FILE_SYSTEM_DEVICE_INFO *)
4340 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004341 data_offset);
4342 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004343 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344 }
4345 }
4346 cifs_buf_release(pSMB);
4347
4348 if (rc == -EAGAIN)
4349 goto QFSDeviceRetry;
4350
4351 return rc;
4352}
4353
4354int
Steve French737b7582005-04-28 22:41:06 -07004355CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356{
4357/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4358 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4359 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4360 FILE_SYSTEM_UNIX_INFO *response_data;
4361 int rc = 0;
4362 int bytes_returned = 0;
4363 __u16 params, byte_count;
4364
4365 cFYI(1, ("In QFSUnixInfo"));
4366QFSUnixRetry:
4367 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4368 (void **) &pSMBr);
4369 if (rc)
4370 return rc;
4371
4372 params = 2; /* level */
4373 pSMB->TotalDataCount = 0;
4374 pSMB->DataCount = 0;
4375 pSMB->DataOffset = 0;
4376 pSMB->MaxParameterCount = cpu_to_le16(2);
4377 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4378 pSMB->MaxSetupCount = 0;
4379 pSMB->Reserved = 0;
4380 pSMB->Flags = 0;
4381 pSMB->Timeout = 0;
4382 pSMB->Reserved2 = 0;
4383 byte_count = params + 1 /* pad */ ;
4384 pSMB->ParameterCount = cpu_to_le16(params);
4385 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004386 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4387 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 pSMB->SetupCount = 1;
4389 pSMB->Reserved3 = 0;
4390 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4391 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4392 pSMB->hdr.smb_buf_length += byte_count;
4393 pSMB->ByteCount = cpu_to_le16(byte_count);
4394
4395 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4396 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4397 if (rc) {
4398 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4399 } else { /* decode response */
4400 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4401
4402 if (rc || (pSMBr->ByteCount < 13)) {
4403 rc = -EIO; /* bad smb */
4404 } else {
4405 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4406 response_data =
4407 (FILE_SYSTEM_UNIX_INFO
4408 *) (((char *) &pSMBr->hdr.Protocol) +
4409 data_offset);
4410 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004411 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 }
4413 }
4414 cifs_buf_release(pSMB);
4415
4416 if (rc == -EAGAIN)
4417 goto QFSUnixRetry;
4418
4419
4420 return rc;
4421}
4422
Jeremy Allisonac670552005-06-22 17:26:35 -07004423int
Steve French45abc6e2005-06-23 13:42:03 -05004424CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004425{
4426/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4427 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4428 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4429 int rc = 0;
4430 int bytes_returned = 0;
4431 __u16 params, param_offset, offset, byte_count;
4432
4433 cFYI(1, ("In SETFSUnixInfo"));
4434SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004435 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004436 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4437 (void **) &pSMBr);
4438 if (rc)
4439 return rc;
4440
4441 params = 4; /* 2 bytes zero followed by info level. */
4442 pSMB->MaxSetupCount = 0;
4443 pSMB->Reserved = 0;
4444 pSMB->Flags = 0;
4445 pSMB->Timeout = 0;
4446 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004447 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4448 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004449 offset = param_offset + params;
4450
4451 pSMB->MaxParameterCount = cpu_to_le16(4);
4452 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4453 pSMB->SetupCount = 1;
4454 pSMB->Reserved3 = 0;
4455 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4456 byte_count = 1 /* pad */ + params + 12;
4457
4458 pSMB->DataCount = cpu_to_le16(12);
4459 pSMB->ParameterCount = cpu_to_le16(params);
4460 pSMB->TotalDataCount = pSMB->DataCount;
4461 pSMB->TotalParameterCount = pSMB->ParameterCount;
4462 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4463 pSMB->DataOffset = cpu_to_le16(offset);
4464
4465 /* Params. */
4466 pSMB->FileNum = 0;
4467 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4468
4469 /* Data. */
4470 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4471 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4472 pSMB->ClientUnixCap = cpu_to_le64(cap);
4473
4474 pSMB->hdr.smb_buf_length += byte_count;
4475 pSMB->ByteCount = cpu_to_le16(byte_count);
4476
4477 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4478 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4479 if (rc) {
4480 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4481 } else { /* decode response */
4482 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4483 if (rc) {
4484 rc = -EIO; /* bad smb */
4485 }
4486 }
4487 cifs_buf_release(pSMB);
4488
4489 if (rc == -EAGAIN)
4490 goto SETFSUnixRetry;
4491
4492 return rc;
4493}
4494
4495
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496
4497int
4498CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004499 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500{
4501/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4502 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4503 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4504 FILE_SYSTEM_POSIX_INFO *response_data;
4505 int rc = 0;
4506 int bytes_returned = 0;
4507 __u16 params, byte_count;
4508
4509 cFYI(1, ("In QFSPosixInfo"));
4510QFSPosixRetry:
4511 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4512 (void **) &pSMBr);
4513 if (rc)
4514 return rc;
4515
4516 params = 2; /* level */
4517 pSMB->TotalDataCount = 0;
4518 pSMB->DataCount = 0;
4519 pSMB->DataOffset = 0;
4520 pSMB->MaxParameterCount = cpu_to_le16(2);
4521 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4522 pSMB->MaxSetupCount = 0;
4523 pSMB->Reserved = 0;
4524 pSMB->Flags = 0;
4525 pSMB->Timeout = 0;
4526 pSMB->Reserved2 = 0;
4527 byte_count = params + 1 /* pad */ ;
4528 pSMB->ParameterCount = cpu_to_le16(params);
4529 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004530 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4531 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532 pSMB->SetupCount = 1;
4533 pSMB->Reserved3 = 0;
4534 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4535 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4536 pSMB->hdr.smb_buf_length += byte_count;
4537 pSMB->ByteCount = cpu_to_le16(byte_count);
4538
4539 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4540 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4541 if (rc) {
4542 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4543 } else { /* decode response */
4544 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4545
4546 if (rc || (pSMBr->ByteCount < 13)) {
4547 rc = -EIO; /* bad smb */
4548 } else {
4549 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4550 response_data =
4551 (FILE_SYSTEM_POSIX_INFO
4552 *) (((char *) &pSMBr->hdr.Protocol) +
4553 data_offset);
4554 FSData->f_bsize =
4555 le32_to_cpu(response_data->BlockSize);
4556 FSData->f_blocks =
4557 le64_to_cpu(response_data->TotalBlocks);
4558 FSData->f_bfree =
4559 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004560 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 FSData->f_bavail = FSData->f_bfree;
4562 } else {
4563 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004564 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004565 }
Steve French790fe572007-07-07 19:25:05 +00004566 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004568 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004569 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004571 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 }
4573 }
4574 cifs_buf_release(pSMB);
4575
4576 if (rc == -EAGAIN)
4577 goto QFSPosixRetry;
4578
4579 return rc;
4580}
4581
4582
Steve French50c2f752007-07-13 00:33:32 +00004583/* We can not use write of zero bytes trick to
4584 set file size due to need for large file support. Also note that
4585 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 routine which is only needed to work around a sharing violation bug
4587 in Samba which this routine can run into */
4588
4589int
4590CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004591 __u64 size, int SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004592 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593{
4594 struct smb_com_transaction2_spi_req *pSMB = NULL;
4595 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4596 struct file_end_of_file_info *parm_data;
4597 int name_len;
4598 int rc = 0;
4599 int bytes_returned = 0;
4600 __u16 params, byte_count, data_count, param_offset, offset;
4601
4602 cFYI(1, ("In SetEOF"));
4603SetEOFRetry:
4604 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4605 (void **) &pSMBr);
4606 if (rc)
4607 return rc;
4608
4609 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4610 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004611 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004612 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613 name_len++; /* trailing null */
4614 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004615 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004616 name_len = strnlen(fileName, PATH_MAX);
4617 name_len++; /* trailing null */
4618 strncpy(pSMB->FileName, fileName, name_len);
4619 }
4620 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004621 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004622 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004623 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 pSMB->MaxSetupCount = 0;
4625 pSMB->Reserved = 0;
4626 pSMB->Flags = 0;
4627 pSMB->Timeout = 0;
4628 pSMB->Reserved2 = 0;
4629 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004630 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004631 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004632 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004633 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4634 pSMB->InformationLevel =
4635 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4636 else
4637 pSMB->InformationLevel =
4638 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4639 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004640 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4641 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004642 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643 else
4644 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004645 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646 }
4647
4648 parm_data =
4649 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4650 offset);
4651 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4652 pSMB->DataOffset = cpu_to_le16(offset);
4653 pSMB->SetupCount = 1;
4654 pSMB->Reserved3 = 0;
4655 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4656 byte_count = 3 /* pad */ + params + data_count;
4657 pSMB->DataCount = cpu_to_le16(data_count);
4658 pSMB->TotalDataCount = pSMB->DataCount;
4659 pSMB->ParameterCount = cpu_to_le16(params);
4660 pSMB->TotalParameterCount = pSMB->ParameterCount;
4661 pSMB->Reserved4 = 0;
4662 pSMB->hdr.smb_buf_length += byte_count;
4663 parm_data->FileSize = cpu_to_le64(size);
4664 pSMB->ByteCount = cpu_to_le16(byte_count);
4665 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4666 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4667 if (rc) {
4668 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4669 }
4670
4671 cifs_buf_release(pSMB);
4672
4673 if (rc == -EAGAIN)
4674 goto SetEOFRetry;
4675
4676 return rc;
4677}
4678
4679int
Steve French50c2f752007-07-13 00:33:32 +00004680CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4681 __u16 fid, __u32 pid_of_opener, int SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004682{
4683 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4684 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4685 char *data_offset;
4686 struct file_end_of_file_info *parm_data;
4687 int rc = 0;
4688 int bytes_returned = 0;
4689 __u16 params, param_offset, offset, byte_count, count;
4690
4691 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4692 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004693 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4694
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695 if (rc)
4696 return rc;
4697
Steve Frenchcd634992005-04-28 22:41:10 -07004698 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4699
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4701 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004702
Linus Torvalds1da177e2005-04-16 15:20:36 -07004703 params = 6;
4704 pSMB->MaxSetupCount = 0;
4705 pSMB->Reserved = 0;
4706 pSMB->Flags = 0;
4707 pSMB->Timeout = 0;
4708 pSMB->Reserved2 = 0;
4709 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4710 offset = param_offset + params;
4711
Steve French50c2f752007-07-13 00:33:32 +00004712 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713
4714 count = sizeof(struct file_end_of_file_info);
4715 pSMB->MaxParameterCount = cpu_to_le16(2);
4716 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4717 pSMB->SetupCount = 1;
4718 pSMB->Reserved3 = 0;
4719 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4720 byte_count = 3 /* pad */ + params + count;
4721 pSMB->DataCount = cpu_to_le16(count);
4722 pSMB->ParameterCount = cpu_to_le16(params);
4723 pSMB->TotalDataCount = pSMB->DataCount;
4724 pSMB->TotalParameterCount = pSMB->ParameterCount;
4725 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4726 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004727 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4728 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 pSMB->DataOffset = cpu_to_le16(offset);
4730 parm_data->FileSize = cpu_to_le64(size);
4731 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004732 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4734 pSMB->InformationLevel =
4735 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4736 else
4737 pSMB->InformationLevel =
4738 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004739 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004740 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4741 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004742 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743 else
4744 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004745 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746 }
4747 pSMB->Reserved4 = 0;
4748 pSMB->hdr.smb_buf_length += byte_count;
4749 pSMB->ByteCount = cpu_to_le16(byte_count);
4750 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4751 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4752 if (rc) {
4753 cFYI(1,
4754 ("Send error in SetFileInfo (SetFileSize) = %d",
4755 rc));
4756 }
4757
4758 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004759 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760
Steve French50c2f752007-07-13 00:33:32 +00004761 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 since file handle passed in no longer valid */
4763
4764 return rc;
4765}
4766
Steve French50c2f752007-07-13 00:33:32 +00004767/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768 an open handle, rather than by pathname - this is awkward due to
4769 potential access conflicts on the open, but it is unavoidable for these
4770 old servers since the only other choice is to go from 100 nanosecond DCE
4771 time and resort to the original setpathinfo level which takes the ancient
4772 DOS time format with 2 second granularity */
4773int
Steve French50c2f752007-07-13 00:33:32 +00004774CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4775 const FILE_BASIC_INFO *data, __u16 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004776{
4777 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4778 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4779 char *data_offset;
4780 int rc = 0;
4781 int bytes_returned = 0;
4782 __u16 params, param_offset, offset, byte_count, count;
4783
4784 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004785 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4786
Linus Torvalds1da177e2005-04-16 15:20:36 -07004787 if (rc)
4788 return rc;
4789
Steve Frenchcd634992005-04-28 22:41:10 -07004790 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4791
Linus Torvalds1da177e2005-04-16 15:20:36 -07004792 /* At this point there is no need to override the current pid
4793 with the pid of the opener, but that could change if we someday
4794 use an existing handle (rather than opening one on the fly) */
4795 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4796 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
Steve French50c2f752007-07-13 00:33:32 +00004797
Linus Torvalds1da177e2005-04-16 15:20:36 -07004798 params = 6;
4799 pSMB->MaxSetupCount = 0;
4800 pSMB->Reserved = 0;
4801 pSMB->Flags = 0;
4802 pSMB->Timeout = 0;
4803 pSMB->Reserved2 = 0;
4804 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4805 offset = param_offset + params;
4806
Steve French50c2f752007-07-13 00:33:32 +00004807 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004808
Steve French26f57362007-08-30 22:09:15 +00004809 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810 pSMB->MaxParameterCount = cpu_to_le16(2);
4811 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4812 pSMB->SetupCount = 1;
4813 pSMB->Reserved3 = 0;
4814 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4815 byte_count = 3 /* pad */ + params + count;
4816 pSMB->DataCount = cpu_to_le16(count);
4817 pSMB->ParameterCount = cpu_to_le16(params);
4818 pSMB->TotalDataCount = pSMB->DataCount;
4819 pSMB->TotalParameterCount = pSMB->ParameterCount;
4820 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4821 pSMB->DataOffset = cpu_to_le16(offset);
4822 pSMB->Fid = fid;
4823 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4824 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4825 else
4826 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4827 pSMB->Reserved4 = 0;
4828 pSMB->hdr.smb_buf_length += byte_count;
4829 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004830 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4832 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4833 if (rc) {
Steve French50c2f752007-07-13 00:33:32 +00004834 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835 }
4836
Steve Frenchcd634992005-04-28 22:41:10 -07004837 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004838
Steve French50c2f752007-07-13 00:33:32 +00004839 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 since file handle passed in no longer valid */
4841
4842 return rc;
4843}
4844
4845
4846int
4847CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004848 const FILE_BASIC_INFO *data,
Steve French737b7582005-04-28 22:41:06 -07004849 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850{
4851 TRANSACTION2_SPI_REQ *pSMB = NULL;
4852 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4853 int name_len;
4854 int rc = 0;
4855 int bytes_returned = 0;
4856 char *data_offset;
4857 __u16 params, param_offset, offset, byte_count, count;
4858
4859 cFYI(1, ("In SetTimes"));
4860
4861SetTimesRetry:
4862 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4863 (void **) &pSMBr);
4864 if (rc)
4865 return rc;
4866
4867 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4868 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004869 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004870 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871 name_len++; /* trailing null */
4872 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004873 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874 name_len = strnlen(fileName, PATH_MAX);
4875 name_len++; /* trailing null */
4876 strncpy(pSMB->FileName, fileName, name_len);
4877 }
4878
4879 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004880 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881 pSMB->MaxParameterCount = cpu_to_le16(2);
4882 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4883 pSMB->MaxSetupCount = 0;
4884 pSMB->Reserved = 0;
4885 pSMB->Flags = 0;
4886 pSMB->Timeout = 0;
4887 pSMB->Reserved2 = 0;
4888 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004889 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004890 offset = param_offset + params;
4891 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4892 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4893 pSMB->DataOffset = cpu_to_le16(offset);
4894 pSMB->SetupCount = 1;
4895 pSMB->Reserved3 = 0;
4896 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4897 byte_count = 3 /* pad */ + params + count;
4898
4899 pSMB->DataCount = cpu_to_le16(count);
4900 pSMB->ParameterCount = cpu_to_le16(params);
4901 pSMB->TotalDataCount = pSMB->DataCount;
4902 pSMB->TotalParameterCount = pSMB->ParameterCount;
4903 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4904 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4905 else
4906 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4907 pSMB->Reserved4 = 0;
4908 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00004909 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004910 pSMB->ByteCount = cpu_to_le16(byte_count);
4911 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4912 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4913 if (rc) {
4914 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4915 }
4916
4917 cifs_buf_release(pSMB);
4918
4919 if (rc == -EAGAIN)
4920 goto SetTimesRetry;
4921
4922 return rc;
4923}
4924
4925/* Can not be used to set time stamps yet (due to old DOS time format) */
4926/* Can be used to set attributes */
4927#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4928 handling it anyway and NT4 was what we thought it would be needed for
4929 Do not delete it until we prove whether needed for Win9x though */
4930int
4931CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4932 __u16 dos_attrs, const struct nls_table *nls_codepage)
4933{
4934 SETATTR_REQ *pSMB = NULL;
4935 SETATTR_RSP *pSMBr = NULL;
4936 int rc = 0;
4937 int bytes_returned;
4938 int name_len;
4939
4940 cFYI(1, ("In SetAttrLegacy"));
4941
4942SetAttrLgcyRetry:
4943 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4944 (void **) &pSMBr);
4945 if (rc)
4946 return rc;
4947
4948 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4949 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004950 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004951 PATH_MAX, nls_codepage);
4952 name_len++; /* trailing null */
4953 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004954 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955 name_len = strnlen(fileName, PATH_MAX);
4956 name_len++; /* trailing null */
4957 strncpy(pSMB->fileName, fileName, name_len);
4958 }
4959 pSMB->attr = cpu_to_le16(dos_attrs);
4960 pSMB->BufferFormat = 0x04;
4961 pSMB->hdr.smb_buf_length += name_len + 1;
4962 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4963 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4964 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4965 if (rc) {
4966 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4967 }
4968
4969 cifs_buf_release(pSMB);
4970
4971 if (rc == -EAGAIN)
4972 goto SetAttrLgcyRetry;
4973
4974 return rc;
4975}
4976#endif /* temporarily unneeded SetAttr legacy function */
4977
4978int
4979CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004980 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4981 dev_t device, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07004982 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004983{
4984 TRANSACTION2_SPI_REQ *pSMB = NULL;
4985 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4986 int name_len;
4987 int rc = 0;
4988 int bytes_returned = 0;
4989 FILE_UNIX_BASIC_INFO *data_offset;
4990 __u16 params, param_offset, offset, count, byte_count;
4991
4992 cFYI(1, ("In SetUID/GID/Mode"));
4993setPermsRetry:
4994 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4995 (void **) &pSMBr);
4996 if (rc)
4997 return rc;
4998
4999 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5000 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005001 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005002 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003 name_len++; /* trailing null */
5004 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005005 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005006 name_len = strnlen(fileName, PATH_MAX);
5007 name_len++; /* trailing null */
5008 strncpy(pSMB->FileName, fileName, name_len);
5009 }
5010
5011 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005012 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005013 pSMB->MaxParameterCount = cpu_to_le16(2);
5014 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
5015 pSMB->MaxSetupCount = 0;
5016 pSMB->Reserved = 0;
5017 pSMB->Flags = 0;
5018 pSMB->Timeout = 0;
5019 pSMB->Reserved2 = 0;
5020 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005021 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005022 offset = param_offset + params;
5023 data_offset =
5024 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5025 offset);
5026 memset(data_offset, 0, count);
5027 pSMB->DataOffset = cpu_to_le16(offset);
5028 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5029 pSMB->SetupCount = 1;
5030 pSMB->Reserved3 = 0;
5031 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5032 byte_count = 3 /* pad */ + params + count;
5033 pSMB->ParameterCount = cpu_to_le16(params);
5034 pSMB->DataCount = cpu_to_le16(count);
5035 pSMB->TotalParameterCount = pSMB->ParameterCount;
5036 pSMB->TotalDataCount = pSMB->DataCount;
5037 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5038 pSMB->Reserved4 = 0;
5039 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005040 /* Samba server ignores set of file size to zero due to bugs in some
5041 older clients, but we should be precise - we use SetFileSize to
5042 set file size and do not want to truncate file size to zero
5043 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005044 zero instead of -1 here */
Steve Frenchc7af1852007-03-01 04:11:22 +00005045 data_offset->EndOfFile = NO_CHANGE_64;
5046 data_offset->NumOfBytes = NO_CHANGE_64;
5047 data_offset->LastStatusChange = NO_CHANGE_64;
5048 data_offset->LastAccessTime = NO_CHANGE_64;
5049 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050 data_offset->Uid = cpu_to_le64(uid);
5051 data_offset->Gid = cpu_to_le64(gid);
5052 /* better to leave device as zero when it is */
5053 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5054 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5055 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005056
Steve French790fe572007-07-07 19:25:05 +00005057 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005058 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005059 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005061 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005063 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005065 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005067 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005069 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5071
5072
5073 pSMB->ByteCount = cpu_to_le16(byte_count);
5074 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5075 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5076 if (rc) {
5077 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5078 }
5079
5080 if (pSMB)
5081 cifs_buf_release(pSMB);
5082 if (rc == -EAGAIN)
5083 goto setPermsRetry;
5084 return rc;
5085}
5086
Steve French50c2f752007-07-13 00:33:32 +00005087int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005088 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005089 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005090 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005091{
5092 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005093 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5094 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005095 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005096 int bytes_returned;
5097
Steve French50c2f752007-07-13 00:33:32 +00005098 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005099 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005100 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101 if (rc)
5102 return rc;
5103
5104 pSMB->TotalParameterCount = 0 ;
5105 pSMB->TotalDataCount = 0;
5106 pSMB->MaxParameterCount = cpu_to_le32(2);
5107 /* BB find exact data count max from sess structure BB */
5108 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005109/* BB VERIFY verify which is correct for above BB */
5110 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5111 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5112
Linus Torvalds1da177e2005-04-16 15:20:36 -07005113 pSMB->MaxSetupCount = 4;
5114 pSMB->Reserved = 0;
5115 pSMB->ParameterOffset = 0;
5116 pSMB->DataCount = 0;
5117 pSMB->DataOffset = 0;
5118 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5119 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5120 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005121 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005122 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5123 pSMB->Reserved2 = 0;
5124 pSMB->CompletionFilter = cpu_to_le32(filter);
5125 pSMB->Fid = netfid; /* file handle always le */
5126 pSMB->ByteCount = 0;
5127
5128 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5129 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
5130 if (rc) {
5131 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005132 } else {
5133 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005134 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005135 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005136 sizeof(struct dir_notify_req),
5137 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005138 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005139 dnotify_req->Pid = pSMB->hdr.Pid;
5140 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5141 dnotify_req->Mid = pSMB->hdr.Mid;
5142 dnotify_req->Tid = pSMB->hdr.Tid;
5143 dnotify_req->Uid = pSMB->hdr.Uid;
5144 dnotify_req->netfid = netfid;
5145 dnotify_req->pfile = pfile;
5146 dnotify_req->filter = filter;
5147 dnotify_req->multishot = multishot;
5148 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005149 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005150 &GlobalDnotifyReqList);
5151 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005152 } else
Steve French47c786e2005-10-11 20:03:18 -07005153 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005154 }
5155 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005156 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005157}
5158#ifdef CONFIG_CIFS_XATTR
5159ssize_t
5160CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5161 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005162 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005163 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164{
5165 /* BB assumes one setup word */
5166 TRANSACTION2_QPI_REQ *pSMB = NULL;
5167 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5168 int rc = 0;
5169 int bytes_returned;
5170 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005171 struct fea *temp_fea;
5172 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005173 __u16 params, byte_count;
5174
5175 cFYI(1, ("In Query All EAs path %s", searchName));
5176QAllEAsRetry:
5177 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5178 (void **) &pSMBr);
5179 if (rc)
5180 return rc;
5181
5182 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5183 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005184 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005185 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005186 name_len++; /* trailing null */
5187 name_len *= 2;
5188 } else { /* BB improve the check for buffer overruns BB */
5189 name_len = strnlen(searchName, PATH_MAX);
5190 name_len++; /* trailing null */
5191 strncpy(pSMB->FileName, searchName, name_len);
5192 }
5193
Steve French50c2f752007-07-13 00:33:32 +00005194 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005195 pSMB->TotalDataCount = 0;
5196 pSMB->MaxParameterCount = cpu_to_le16(2);
5197 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5198 pSMB->MaxSetupCount = 0;
5199 pSMB->Reserved = 0;
5200 pSMB->Flags = 0;
5201 pSMB->Timeout = 0;
5202 pSMB->Reserved2 = 0;
5203 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005204 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205 pSMB->DataCount = 0;
5206 pSMB->DataOffset = 0;
5207 pSMB->SetupCount = 1;
5208 pSMB->Reserved3 = 0;
5209 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5210 byte_count = params + 1 /* pad */ ;
5211 pSMB->TotalParameterCount = cpu_to_le16(params);
5212 pSMB->ParameterCount = pSMB->TotalParameterCount;
5213 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5214 pSMB->Reserved4 = 0;
5215 pSMB->hdr.smb_buf_length += byte_count;
5216 pSMB->ByteCount = cpu_to_le16(byte_count);
5217
5218 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5219 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5220 if (rc) {
5221 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5222 } else { /* decode response */
5223 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5224
5225 /* BB also check enough total bytes returned */
5226 /* BB we need to improve the validity checking
5227 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005228 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 rc = -EIO; /* bad smb */
5230 /* else if (pFindData){
5231 memcpy((char *) pFindData,
5232 (char *) &pSMBr->hdr.Protocol +
5233 data_offset, kl);
5234 }*/ else {
5235 /* check that length of list is not more than bcc */
5236 /* check that each entry does not go beyond length
5237 of list */
5238 /* check that each element of each entry does not
5239 go beyond end of list */
5240 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005241 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005242 rc = 0;
5243 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005244 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005245 ea_response_data = (struct fealist *)
5246 (((char *) &pSMBr->hdr.Protocol) +
5247 data_offset);
5248 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005249 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005250 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005251 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005252 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 } else {
5254 /* account for ea list len */
5255 name_len -= 4;
5256 temp_fea = ea_response_data->list;
5257 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005258 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005259 __u16 value_len;
5260 name_len -= 4;
5261 temp_ptr += 4;
5262 rc += temp_fea->name_len;
5263 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005264 rc = rc + 5 + 1;
5265 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005266 memcpy(EAData, "user.", 5);
5267 EAData += 5;
5268 memcpy(EAData, temp_ptr,
5269 temp_fea->name_len);
5270 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 /* null terminate name */
5272 *EAData = 0;
5273 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005274 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005275 /* skip copy - calc size only */
5276 } else {
5277 /* stop before overrun buffer */
5278 rc = -ERANGE;
5279 break;
5280 }
5281 name_len -= temp_fea->name_len;
5282 temp_ptr += temp_fea->name_len;
5283 /* account for trailing null */
5284 name_len--;
5285 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005286 value_len =
5287 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005288 name_len -= value_len;
5289 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005290 /* BB check that temp_ptr is still
5291 within the SMB BB*/
5292
5293 /* no trailing null to account for
5294 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005295 /* go on to next EA */
5296 temp_fea = (struct fea *)temp_ptr;
5297 }
5298 }
5299 }
5300 }
5301 if (pSMB)
5302 cifs_buf_release(pSMB);
5303 if (rc == -EAGAIN)
5304 goto QAllEAsRetry;
5305
5306 return (ssize_t)rc;
5307}
5308
Steve French50c2f752007-07-13 00:33:32 +00005309ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5310 const unsigned char *searchName, const unsigned char *ea_name,
5311 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005312 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005313{
5314 TRANSACTION2_QPI_REQ *pSMB = NULL;
5315 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5316 int rc = 0;
5317 int bytes_returned;
5318 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005319 struct fea *temp_fea;
5320 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005321 __u16 params, byte_count;
5322
5323 cFYI(1, ("In Query EA path %s", searchName));
5324QEARetry:
5325 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5326 (void **) &pSMBr);
5327 if (rc)
5328 return rc;
5329
5330 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5331 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005332 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005333 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334 name_len++; /* trailing null */
5335 name_len *= 2;
5336 } else { /* BB improve the check for buffer overruns BB */
5337 name_len = strnlen(searchName, PATH_MAX);
5338 name_len++; /* trailing null */
5339 strncpy(pSMB->FileName, searchName, name_len);
5340 }
5341
Steve French50c2f752007-07-13 00:33:32 +00005342 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005343 pSMB->TotalDataCount = 0;
5344 pSMB->MaxParameterCount = cpu_to_le16(2);
5345 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5346 pSMB->MaxSetupCount = 0;
5347 pSMB->Reserved = 0;
5348 pSMB->Flags = 0;
5349 pSMB->Timeout = 0;
5350 pSMB->Reserved2 = 0;
5351 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005352 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005353 pSMB->DataCount = 0;
5354 pSMB->DataOffset = 0;
5355 pSMB->SetupCount = 1;
5356 pSMB->Reserved3 = 0;
5357 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5358 byte_count = params + 1 /* pad */ ;
5359 pSMB->TotalParameterCount = cpu_to_le16(params);
5360 pSMB->ParameterCount = pSMB->TotalParameterCount;
5361 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5362 pSMB->Reserved4 = 0;
5363 pSMB->hdr.smb_buf_length += byte_count;
5364 pSMB->ByteCount = cpu_to_le16(byte_count);
5365
5366 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5367 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5368 if (rc) {
5369 cFYI(1, ("Send error in Query EA = %d", rc));
5370 } else { /* decode response */
5371 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5372
5373 /* BB also check enough total bytes returned */
5374 /* BB we need to improve the validity checking
5375 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005376 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 rc = -EIO; /* bad smb */
5378 /* else if (pFindData){
5379 memcpy((char *) pFindData,
5380 (char *) &pSMBr->hdr.Protocol +
5381 data_offset, kl);
5382 }*/ else {
5383 /* check that length of list is not more than bcc */
5384 /* check that each entry does not go beyond length
5385 of list */
5386 /* check that each element of each entry does not
5387 go beyond end of list */
5388 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005389 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005390 rc = -ENODATA;
5391 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005392 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005393 ea_response_data = (struct fealist *)
5394 (((char *) &pSMBr->hdr.Protocol) +
5395 data_offset);
5396 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005397 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005398 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005399 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005400 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401 } else {
5402 /* account for ea list len */
5403 name_len -= 4;
5404 temp_fea = ea_response_data->list;
5405 temp_ptr = (char *)temp_fea;
5406 /* loop through checking if we have a matching
5407 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005408 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 __u16 value_len;
5410 name_len -= 4;
5411 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005412 value_len =
5413 le16_to_cpu(temp_fea->value_len);
5414 /* BB validate that value_len falls within SMB,
5415 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005416 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005417 temp_fea->name_len) == 0) {
5418 /* found a match */
5419 rc = value_len;
5420 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005421 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005422 memcpy(ea_value,
5423 temp_fea->name+temp_fea->name_len+1,
5424 rc);
Steve French50c2f752007-07-13 00:33:32 +00005425 /* ea values, unlike ea
5426 names, are not null
5427 terminated */
Steve French790fe572007-07-07 19:25:05 +00005428 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005429 /* skip copy - calc size only */
5430 } else {
Steve French50c2f752007-07-13 00:33:32 +00005431 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005432 rc = -ERANGE;
5433 }
5434 break;
5435 }
5436 name_len -= temp_fea->name_len;
5437 temp_ptr += temp_fea->name_len;
5438 /* account for trailing null */
5439 name_len--;
5440 temp_ptr++;
5441 name_len -= value_len;
5442 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005443 /* No trailing null to account for in
5444 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005445 temp_fea = (struct fea *)temp_ptr;
5446 }
Steve French50c2f752007-07-13 00:33:32 +00005447 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005448 }
5449 }
5450 if (pSMB)
5451 cifs_buf_release(pSMB);
5452 if (rc == -EAGAIN)
5453 goto QEARetry;
5454
5455 return (ssize_t)rc;
5456}
5457
5458int
5459CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005460 const char *ea_name, const void *ea_value,
5461 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5462 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463{
5464 struct smb_com_transaction2_spi_req *pSMB = NULL;
5465 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5466 struct fealist *parm_data;
5467 int name_len;
5468 int rc = 0;
5469 int bytes_returned = 0;
5470 __u16 params, param_offset, byte_count, offset, count;
5471
5472 cFYI(1, ("In SetEA"));
5473SetEARetry:
5474 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5475 (void **) &pSMBr);
5476 if (rc)
5477 return rc;
5478
5479 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5480 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005481 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005482 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483 name_len++; /* trailing null */
5484 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005485 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486 name_len = strnlen(fileName, PATH_MAX);
5487 name_len++; /* trailing null */
5488 strncpy(pSMB->FileName, fileName, name_len);
5489 }
5490
5491 params = 6 + name_len;
5492
5493 /* done calculating parms using name_len of file name,
5494 now use name_len to calculate length of ea name
5495 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005496 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497 name_len = 0;
5498 else
Steve French50c2f752007-07-13 00:33:32 +00005499 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005500
5501 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5502 pSMB->MaxParameterCount = cpu_to_le16(2);
5503 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5504 pSMB->MaxSetupCount = 0;
5505 pSMB->Reserved = 0;
5506 pSMB->Flags = 0;
5507 pSMB->Timeout = 0;
5508 pSMB->Reserved2 = 0;
5509 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005510 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511 offset = param_offset + params;
5512 pSMB->InformationLevel =
5513 cpu_to_le16(SMB_SET_FILE_EA);
5514
5515 parm_data =
5516 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5517 offset);
5518 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5519 pSMB->DataOffset = cpu_to_le16(offset);
5520 pSMB->SetupCount = 1;
5521 pSMB->Reserved3 = 0;
5522 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5523 byte_count = 3 /* pad */ + params + count;
5524 pSMB->DataCount = cpu_to_le16(count);
5525 parm_data->list_len = cpu_to_le32(count);
5526 parm_data->list[0].EA_flags = 0;
5527 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005528 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005530 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005531 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005532 parm_data->list[0].name[name_len] = 0;
5533 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5534 /* caller ensures that ea_value_len is less than 64K but
5535 we need to ensure that it fits within the smb */
5536
Steve French50c2f752007-07-13 00:33:32 +00005537 /*BB add length check to see if it would fit in
5538 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005539 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5540 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005541 memcpy(parm_data->list[0].name+name_len+1,
5542 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543
5544 pSMB->TotalDataCount = pSMB->DataCount;
5545 pSMB->ParameterCount = cpu_to_le16(params);
5546 pSMB->TotalParameterCount = pSMB->ParameterCount;
5547 pSMB->Reserved4 = 0;
5548 pSMB->hdr.smb_buf_length += byte_count;
5549 pSMB->ByteCount = cpu_to_le16(byte_count);
5550 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5551 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5552 if (rc) {
5553 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5554 }
5555
5556 cifs_buf_release(pSMB);
5557
5558 if (rc == -EAGAIN)
5559 goto SetEARetry;
5560
5561 return rc;
5562}
5563
5564#endif