blob: 9409524e4bf88e5634ebbc94c2a1b30e7df38aeb [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve French2dd29d32007-04-23 22:07:35 +00004 * Copyright (C) International Business Machines Corp., 2002,2007
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
33#include <linux/posix_acl_xattr.h>
34#include <asm/uaccess.h>
35#include "cifspdu.h"
36#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000037#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include "cifsproto.h"
39#include "cifs_unicode.h"
40#include "cifs_debug.h"
41
42#ifdef CONFIG_CIFS_POSIX
43static struct {
44 int index;
45 char *name;
46} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000047#ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000049 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000050#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000051 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000052 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 {BAD_PROT, "\2"}
54};
55#else
56static struct {
57 int index;
58 char *name;
59} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000060#ifdef CONFIG_CIFS_WEAK_PW_HASH
61 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000062 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000063#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000064 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 {BAD_PROT, "\2"}
66};
67#endif
68
Steve French39798772006-05-31 22:40:51 +000069/* define the number of elements in the cifs dialect array */
70#ifdef CONFIG_CIFS_POSIX
71#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000072#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000073#else
74#define CIFS_NUM_PROT 2
75#endif /* CIFS_WEAK_PW_HASH */
76#else /* not posix */
77#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000078#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000079#else
80#define CIFS_NUM_PROT 1
81#endif /* CONFIG_CIFS_WEAK_PW_HASH */
82#endif /* CIFS_POSIX */
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85/* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +000087static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070088{
89 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000090 struct list_head *tmp;
91 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
93/* list all files open on tree connection and mark them invalid */
94 write_lock(&GlobalSMBSeslock);
95 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000096 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve French26f57362007-08-30 22:09:15 +000097 if (open_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 open_file->invalidHandle = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 }
100 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700101 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
102 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103}
104
105/* If the return code is zero, this function must fill in request_buf pointer */
106static int
107small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
108 void **request_buf /* returned */)
109{
110 int rc = 0;
111
112 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
113 check for tcp and smb session status done differently
114 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000115 if (tcon) {
116 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800117 /* only tree disconnect, open, and write,
118 (and ulogoff which does not have tcon)
119 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000120 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French50c2f752007-07-13 00:33:32 +0000121 (smb_command != SMB_COM_OPEN_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800122 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000123 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800124 smb_command));
125 return -ENODEV;
126 }
127 }
Steve French790fe572007-07-07 19:25:05 +0000128 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000129 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 struct nls_table *nls_codepage;
Steve French50c2f752007-07-13 00:33:32 +0000131 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700132 reconnect, should be greater than cifs socket
133 timeout which is 7 seconds */
Steve Frenchc18c8422007-07-18 23:21:09 +0000134 while (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000135 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve Frenchc18c8422007-07-18 23:21:09 +0000137 (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000138 CifsGood), 10 * HZ);
139 if (tcon->ses->server->tcpStatus ==
140 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 /* on "soft" mounts we wait once */
Steve French790fe572007-07-07 19:25:05 +0000142 if ((tcon->retry == FALSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000144 cFYI(1, ("gave up waiting on "
145 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700147 } /* else "hard" mount - keep retrying
148 until process is killed or server
149 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 } else /* TCP session is reestablished now */
151 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 }
Steve French50c2f752007-07-13 00:33:32 +0000153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 nls_codepage = load_nls_default();
155 /* need to prevent multiple threads trying to
156 simultaneously reconnect the same SMB session */
157 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000158 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000159 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700160 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000161 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 mark_open_files_invalid(tcon);
Steve French50c2f752007-07-13 00:33:32 +0000163 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
Steve French8af18972007-02-14 04:42:51 +0000164 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 up(&tcon->ses->sesSem);
Steve French8af18972007-02-14 04:42:51 +0000166 /* tell server which Unix caps we support */
167 if (tcon->ses->capabilities & CAP_UNIX)
168 reset_cifs_unix_caps(0 /* no xid */,
Steve French50c2f752007-07-13 00:33:32 +0000169 tcon,
Steve French8af18972007-02-14 04:42:51 +0000170 NULL /* we do not know sb */,
Steve French50c2f752007-07-13 00:33:32 +0000171 NULL /* no vol info */);
Steve French3e844692005-10-03 13:37:24 -0700172 /* BB FIXME add code to check if wsize needs
173 update due to negotiated smb buffer size
174 shrinking */
Steve French790fe572007-07-07 19:25:05 +0000175 if (rc == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 atomic_inc(&tconInfoReconnectCount);
177
178 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000179 /* Removed call to reopen open files here.
180 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700181 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Steve French50c2f752007-07-13 00:33:32 +0000183 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700184 know whether we can continue or not without
185 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000186 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 case SMB_COM_READ_ANDX:
188 case SMB_COM_WRITE_ANDX:
189 case SMB_COM_CLOSE:
190 case SMB_COM_FIND_CLOSE2:
191 case SMB_COM_LOCKING_ANDX: {
192 unload_nls(nls_codepage);
193 return -EAGAIN;
194 }
195 }
196 } else {
197 up(&tcon->ses->sesSem);
198 }
199 unload_nls(nls_codepage);
200
201 } else {
202 return -EIO;
203 }
204 }
Steve French790fe572007-07-07 19:25:05 +0000205 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 return rc;
207
208 *request_buf = cifs_small_buf_get();
209 if (*request_buf == NULL) {
210 /* BB should we add a retry in here if not a writepage? */
211 return -ENOMEM;
212 }
213
Steve French63135e02007-07-17 17:34:02 +0000214 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000215 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
Steve French790fe572007-07-07 19:25:05 +0000217 if (tcon != NULL)
218 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700219
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000221}
222
Steve French12b3b8f2006-02-09 21:12:47 +0000223int
Steve French50c2f752007-07-13 00:33:32 +0000224small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000225 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000226{
227 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000228 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000229
Steve French5815449d2006-02-14 01:36:20 +0000230 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000231 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000232 return rc;
233
Steve French04fdabe2006-02-10 05:52:50 +0000234 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000235 buffer->Mid = GetNextMid(ses->server);
236 if (ses->capabilities & CAP_UNICODE)
237 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000238 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000239 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
240
241 /* uid, tid can stay at zero as set in header assemble */
242
Steve French50c2f752007-07-13 00:33:32 +0000243 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000244 this function is used after 1st of session setup requests */
245
246 return rc;
247}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
249/* If the return code is zero, this function must fill in request_buf pointer */
250static int
251smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
252 void **request_buf /* returned */ ,
253 void **response_buf /* returned */ )
254{
255 int rc = 0;
256
257 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
258 check for tcp and smb session status done differently
259 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000260 if (tcon) {
261 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800262 /* only tree disconnect, open, and write,
263 (and ulogoff which does not have tcon)
264 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000265 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800266 (smb_command != SMB_COM_OPEN_ANDX) &&
267 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000268 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800269 smb_command));
270 return -ENODEV;
271 }
272 }
273
Steve French790fe572007-07-07 19:25:05 +0000274 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000275 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700277 /* Give Demultiplex thread up to 10 seconds to
278 reconnect, should be greater than cifs socket
279 timeout which is 7 seconds */
Steve French63135e02007-07-17 17:34:02 +0000280 while (tcon->ses->server->tcpStatus ==
281 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000283 (tcon->ses->server->tcpStatus ==
284 CifsGood), 10 * HZ);
Steve French790fe572007-07-07 19:25:05 +0000285 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700286 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 /* on "soft" mounts we wait once */
Steve French790fe572007-07-07 19:25:05 +0000288 if ((tcon->retry == FALSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000290 cFYI(1, ("gave up waiting on "
291 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700293 } /* else "hard" mount - keep retrying
294 until process is killed or server
295 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 } else /* TCP session is reestablished now */
297 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 nls_codepage = load_nls_default();
300 /* need to prevent multiple threads trying to
301 simultaneously reconnect the same SMB session */
302 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000303 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000304 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700305 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000306 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700308 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
309 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 up(&tcon->ses->sesSem);
Steve French8af18972007-02-14 04:42:51 +0000311 /* tell server which Unix caps we support */
312 if (tcon->ses->capabilities & CAP_UNIX)
313 reset_cifs_unix_caps(0 /* no xid */,
Steve French50c2f752007-07-13 00:33:32 +0000314 tcon,
Steve French8af18972007-02-14 04:42:51 +0000315 NULL /* do not know sb */,
316 NULL /* no vol info */);
Steve French3e844692005-10-03 13:37:24 -0700317 /* BB FIXME add code to check if wsize needs
318 update due to negotiated smb buffer size
319 shrinking */
Steve French790fe572007-07-07 19:25:05 +0000320 if (rc == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 atomic_inc(&tconInfoReconnectCount);
322
323 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000324 /* Removed call to reopen open files here.
325 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700326 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
Steve French50c2f752007-07-13 00:33:32 +0000328 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700329 know whether we can continue or not without
330 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000331 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 case SMB_COM_READ_ANDX:
333 case SMB_COM_WRITE_ANDX:
334 case SMB_COM_CLOSE:
335 case SMB_COM_FIND_CLOSE2:
336 case SMB_COM_LOCKING_ANDX: {
337 unload_nls(nls_codepage);
338 return -EAGAIN;
339 }
340 }
341 } else {
342 up(&tcon->ses->sesSem);
343 }
344 unload_nls(nls_codepage);
345
346 } else {
347 return -EIO;
348 }
349 }
Steve French790fe572007-07-07 19:25:05 +0000350 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 return rc;
352
353 *request_buf = cifs_buf_get();
354 if (*request_buf == NULL) {
355 /* BB should we add a retry in here if not a writepage? */
356 return -ENOMEM;
357 }
358 /* Although the original thought was we needed the response buf for */
359 /* potential retries of smb operations it turns out we can determine */
360 /* from the mid flags when the request buffer can be resent without */
361 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000362 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000363 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
365 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
366 wct /*wct */ );
367
Steve French790fe572007-07-07 19:25:05 +0000368 if (tcon != NULL)
369 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700370
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 return rc;
372}
373
Steve French50c2f752007-07-13 00:33:32 +0000374static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375{
376 int rc = -EINVAL;
377 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000378 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380 /* check for plausible wct, bcc and t2 data and parm sizes */
381 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000382 if (pSMB->hdr.WordCount >= 10) {
383 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
385 /* check that bcc is at least as big as parms + data */
386 /* check that bcc is less than negotiated smb buffer */
387 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000388 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000389 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000390 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000392 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700393 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000395 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000396 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
398 return 0;
399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 }
401 }
402 }
Steve French50c2f752007-07-13 00:33:32 +0000403 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 sizeof(struct smb_t2_rsp) + 16);
405 return rc;
406}
407int
408CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
409{
410 NEGOTIATE_REQ *pSMB;
411 NEGOTIATE_RSP *pSMBr;
412 int rc = 0;
413 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000414 int i;
Steve French50c2f752007-07-13 00:33:32 +0000415 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000417 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100418 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Steve French790fe572007-07-07 19:25:05 +0000420 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 server = ses->server;
422 else {
423 rc = -EIO;
424 return rc;
425 }
426 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
427 (void **) &pSMB, (void **) &pSMBr);
428 if (rc)
429 return rc;
Steve French750d1152006-06-27 06:28:30 +0000430
431 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000432 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000433 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000434 else /* if override flags set only sign/seal OR them with global auth */
435 secFlags = extended_security | ses->overrideSecFlg;
436
Steve French762e5ab2007-06-28 18:41:42 +0000437 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000438
Steve French1982c342005-08-17 12:38:22 -0700439 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000440 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000441
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000442 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000443 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000444 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
445 cFYI(1, ("Kerberos only mechanism, enable extended security"));
446 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
447 }
Steve French50c2f752007-07-13 00:33:32 +0000448
Steve French39798772006-05-31 22:40:51 +0000449 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000450 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000451 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
452 count += strlen(protocols[i].name) + 1;
453 /* null at end of source and target buffers anyway */
454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 pSMB->hdr.smb_buf_length += count;
456 pSMB->ByteCount = cpu_to_le16(count);
457
458 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
459 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000460 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000461 goto neg_err_exit;
462
Al Viro733f99a2006-10-14 16:48:26 +0100463 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000464 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000465 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000466 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000467 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000468 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000469 could not negotiate a common dialect */
470 rc = -EOPNOTSUPP;
471 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000472#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000473 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100474 && ((dialect == LANMAN_PROT)
475 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000476 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000477 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000478
Steve French790fe572007-07-07 19:25:05 +0000479 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000480 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000481 server->secType = LANMAN;
482 else {
483 cERROR(1, ("mount failed weak security disabled"
484 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000485 rc = -EOPNOTSUPP;
486 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000487 }
Steve French254e55e2006-06-04 05:53:15 +0000488 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
489 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
490 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000491 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000492 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
493 /* even though we do not use raw we might as well set this
494 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000495 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve French254e55e2006-06-04 05:53:15 +0000496 server->maxRw = 0xFF00;
497 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
498 } else {
499 server->maxRw = 0;/* we do not need to use raw anyway */
500 server->capabilities = CAP_MPX_MODE;
501 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000502 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000503 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000504 /* OS/2 often does not set timezone therefore
505 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000506 * Could deviate slightly from the right zone.
507 * Smallest defined timezone difference is 15 minutes
508 * (i.e. Nepal). Rounding up/down is done to match
509 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000510 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000511 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000512 struct timespec ts, utc;
513 utc = CURRENT_TIME;
514 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
515 le16_to_cpu(rsp->SrvTime.Time));
Steve French50c2f752007-07-13 00:33:32 +0000516 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
517 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000518 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000519 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000520 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000521 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000522 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000523 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000524 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000525 if (val < 0)
Steve Frenchb815f1e52006-10-02 05:53:29 +0000526 result = - result;
527 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000528 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000529 server->timeAdj = (int)tmp;
530 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000531 }
Steve French790fe572007-07-07 19:25:05 +0000532 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000533
Steve French39798772006-05-31 22:40:51 +0000534
Steve French254e55e2006-06-04 05:53:15 +0000535 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000536 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000537
Steve French50c2f752007-07-13 00:33:32 +0000538 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000539 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000540 memcpy(server->cryptKey, rsp->EncryptionKey,
541 CIFS_CRYPTO_KEY_SIZE);
542 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
543 rc = -EIO; /* need cryptkey unless plain text */
544 goto neg_err_exit;
545 }
Steve French39798772006-05-31 22:40:51 +0000546
Steve French790fe572007-07-07 19:25:05 +0000547 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000548 /* we will not end up setting signing flags - as no signing
549 was in LANMAN and server did not return the flags on */
550 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000551#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000552 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000553 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000554 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000555 rc = -EOPNOTSUPP;
556#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000557 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000558 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000559 /* unknown wct */
560 rc = -EOPNOTSUPP;
561 goto neg_err_exit;
562 }
563 /* else wct == 17 NTLM */
564 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000565 if ((server->secMode & SECMODE_USER) == 0)
566 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000567
Steve French790fe572007-07-07 19:25:05 +0000568 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000569#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000570 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000571#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000572 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000573 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000574
Steve French790fe572007-07-07 19:25:05 +0000575 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000576 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000577 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000578 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000579 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000580 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000581 else if (secFlags & CIFSSEC_MAY_KRB5)
582 server->secType = Kerberos;
583 else if (secFlags & CIFSSEC_MAY_LANMAN)
584 server->secType = LANMAN;
585/* #ifdef CONFIG_CIFS_EXPERIMENTAL
586 else if (secFlags & CIFSSEC_MAY_PLNTXT)
587 server->secType = ??
588#endif */
589 else {
590 rc = -EOPNOTSUPP;
591 cERROR(1, ("Invalid security type"));
592 goto neg_err_exit;
593 }
594 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000595
Steve French254e55e2006-06-04 05:53:15 +0000596 /* one byte, so no need to convert this or EncryptionKeyLen from
597 little endian */
598 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
599 /* probably no need to store and check maxvcs */
600 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000602 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
603 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
604 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
605 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000606 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
607 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000608 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
609 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
610 CIFS_CRYPTO_KEY_SIZE);
611 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
612 && (pSMBr->EncryptionKeyLength == 0)) {
613 /* decode security blob */
614 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
615 rc = -EIO; /* no crypt key only if plain text pwd */
616 goto neg_err_exit;
617 }
618
619 /* BB might be helpful to save off the domain of server here */
620
Steve French50c2f752007-07-13 00:33:32 +0000621 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000622 (server->capabilities & CAP_EXTENDED_SECURITY)) {
623 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000624 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000626 goto neg_err_exit;
627 }
628
629 if (server->socketUseCount.counter > 1) {
630 if (memcmp(server->server_GUID,
631 pSMBr->u.extended_response.
632 GUID, 16) != 0) {
633 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000634 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000635 pSMBr->u.extended_response.GUID,
636 16);
637 }
638 } else
639 memcpy(server->server_GUID,
640 pSMBr->u.extended_response.GUID, 16);
641
642 if (count == 16) {
643 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000644 } else {
645 rc = decode_negTokenInit(pSMBr->u.extended_response.
646 SecurityBlob,
647 count - 16,
648 &server->secType);
Steve French790fe572007-07-07 19:25:05 +0000649 if (rc == 1) {
Jeff Laytone5459372007-11-03 05:11:06 +0000650 rc = 0;
Steve French254e55e2006-06-04 05:53:15 +0000651 } else {
652 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 }
Steve French254e55e2006-06-04 05:53:15 +0000655 } else
656 server->capabilities &= ~CAP_EXTENDED_SECURITY;
657
Steve French6344a422006-06-12 04:18:35 +0000658#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000659signing_check:
Steve French6344a422006-06-12 04:18:35 +0000660#endif
Steve French762e5ab2007-06-28 18:41:42 +0000661 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
662 /* MUST_SIGN already includes the MAY_SIGN FLAG
663 so if this is zero it means that signing is disabled */
664 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000665 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000666 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000667 "packet signing to be enabled in "
668 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000669 rc = -EOPNOTSUPP;
670 }
Steve French50c2f752007-07-13 00:33:32 +0000671 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000672 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000673 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
674 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000675 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000676 if ((server->secMode &
677 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
678 cERROR(1,
679 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000680 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000681 } else
682 server->secMode |= SECMODE_SIGN_REQUIRED;
683 } else {
684 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000685 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000686 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000687 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 }
Steve French50c2f752007-07-13 00:33:32 +0000689
690neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700691 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000692
Steve French790fe572007-07-07 19:25:05 +0000693 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 return rc;
695}
696
697int
698CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
699{
700 struct smb_hdr *smb_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
703 cFYI(1, ("In tree disconnect"));
704 /*
705 * If last user of the connection and
706 * connection alive - disconnect it
707 * If this is the last connection on the server session disconnect it
Steve French50c2f752007-07-13 00:33:32 +0000708 * (and inside session disconnect we should check if tcp socket needs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 * to be freed and kernel thread woken up).
710 */
711 if (tcon)
712 down(&tcon->tconSem);
713 else
714 return -EIO;
715
716 atomic_dec(&tcon->useCount);
717 if (atomic_read(&tcon->useCount) > 0) {
718 up(&tcon->tconSem);
719 return -EBUSY;
720 }
721
Steve French50c2f752007-07-13 00:33:32 +0000722 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 closed on server already e.g. due to tcp session crashing */
Steve French790fe572007-07-07 19:25:05 +0000724 if (tcon->tidStatus == CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 up(&tcon->tconSem);
Steve French50c2f752007-07-13 00:33:32 +0000726 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 }
728
Steve French790fe572007-07-07 19:25:05 +0000729 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 up(&tcon->tconSem);
731 return -EIO;
732 }
Steve French50c2f752007-07-13 00:33:32 +0000733 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700734 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 if (rc) {
736 up(&tcon->tconSem);
737 return rc;
Steve Frenchcd634992005-04-28 22:41:10 -0700738 }
Steve French133672e2007-11-13 22:41:37 +0000739
740 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700742 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 up(&tcon->tconSem);
745
Steve French50c2f752007-07-13 00:33:32 +0000746 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 closed on server already e.g. due to tcp session crashing */
748 if (rc == -EAGAIN)
749 rc = 0;
750
751 return rc;
752}
753
754int
755CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
756{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 LOGOFF_ANDX_REQ *pSMB;
758 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
760 cFYI(1, ("In SMBLogoff for session disconnect"));
761 if (ses)
762 down(&ses->sesSem);
763 else
764 return -EIO;
765
766 atomic_dec(&ses->inUse);
767 if (atomic_read(&ses->inUse) > 0) {
768 up(&ses->sesSem);
769 return -EBUSY;
770 }
771 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
772 if (rc) {
773 up(&ses->sesSem);
774 return rc;
775 }
776
Steve French790fe572007-07-07 19:25:05 +0000777 if (ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700778 pSMB->hdr.Mid = GetNextMid(ses->server);
779
Steve French790fe572007-07-07 19:25:05 +0000780 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
782 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
783 }
784
785 pSMB->hdr.Uid = ses->Suid;
786
787 pSMB->AndXCommand = 0xFF;
Steve French133672e2007-11-13 22:41:37 +0000788 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 if (ses->server) {
790 atomic_dec(&ses->server->socketUseCount);
791 if (atomic_read(&ses->server->socketUseCount) == 0) {
792 spin_lock(&GlobalMid_Lock);
793 ses->server->tcpStatus = CifsExiting;
794 spin_unlock(&GlobalMid_Lock);
795 rc = -ESHUTDOWN;
796 }
797 }
Steve Frencha59c6582005-08-17 12:12:19 -0700798 up(&ses->sesSem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799
800 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000801 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 error */
803 if (rc == -EAGAIN)
804 rc = 0;
805 return rc;
806}
807
808int
Steve French2d785a52007-07-15 01:48:57 +0000809CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
810 __u16 type, const struct nls_table *nls_codepage, int remap)
811{
812 TRANSACTION2_SPI_REQ *pSMB = NULL;
813 TRANSACTION2_SPI_RSP *pSMBr = NULL;
814 struct unlink_psx_rq *pRqD;
815 int name_len;
816 int rc = 0;
817 int bytes_returned = 0;
818 __u16 params, param_offset, offset, byte_count;
819
820 cFYI(1, ("In POSIX delete"));
821PsxDelete:
822 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
823 (void **) &pSMBr);
824 if (rc)
825 return rc;
826
827 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
828 name_len =
829 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
830 PATH_MAX, nls_codepage, remap);
831 name_len++; /* trailing null */
832 name_len *= 2;
833 } else { /* BB add path length overrun check */
834 name_len = strnlen(fileName, PATH_MAX);
835 name_len++; /* trailing null */
836 strncpy(pSMB->FileName, fileName, name_len);
837 }
838
839 params = 6 + name_len;
840 pSMB->MaxParameterCount = cpu_to_le16(2);
841 pSMB->MaxDataCount = 0; /* BB double check this with jra */
842 pSMB->MaxSetupCount = 0;
843 pSMB->Reserved = 0;
844 pSMB->Flags = 0;
845 pSMB->Timeout = 0;
846 pSMB->Reserved2 = 0;
847 param_offset = offsetof(struct smb_com_transaction2_spi_req,
848 InformationLevel) - 4;
849 offset = param_offset + params;
850
851 /* Setup pointer to Request Data (inode type) */
852 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
853 pRqD->type = cpu_to_le16(type);
854 pSMB->ParameterOffset = cpu_to_le16(param_offset);
855 pSMB->DataOffset = cpu_to_le16(offset);
856 pSMB->SetupCount = 1;
857 pSMB->Reserved3 = 0;
858 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
859 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
860
861 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
862 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
863 pSMB->ParameterCount = cpu_to_le16(params);
864 pSMB->TotalParameterCount = pSMB->ParameterCount;
865 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
866 pSMB->Reserved4 = 0;
867 pSMB->hdr.smb_buf_length += byte_count;
868 pSMB->ByteCount = cpu_to_le16(byte_count);
869 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
870 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
871 if (rc) {
872 cFYI(1, ("Posix delete returned %d", rc));
873 }
874 cifs_buf_release(pSMB);
875
876 cifs_stats_inc(&tcon->num_deletes);
877
878 if (rc == -EAGAIN)
879 goto PsxDelete;
880
881 return rc;
882}
883
884int
Steve French737b7582005-04-28 22:41:06 -0700885CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
886 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887{
888 DELETE_FILE_REQ *pSMB = NULL;
889 DELETE_FILE_RSP *pSMBr = NULL;
890 int rc = 0;
891 int bytes_returned;
892 int name_len;
893
894DelFileRetry:
895 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
896 (void **) &pSMBr);
897 if (rc)
898 return rc;
899
900 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
901 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000902 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700903 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 name_len++; /* trailing null */
905 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700906 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 name_len = strnlen(fileName, PATH_MAX);
908 name_len++; /* trailing null */
909 strncpy(pSMB->fileName, fileName, name_len);
910 }
911 pSMB->SearchAttributes =
912 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
913 pSMB->BufferFormat = 0x04;
914 pSMB->hdr.smb_buf_length += name_len + 1;
915 pSMB->ByteCount = cpu_to_le16(name_len + 1);
916 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
917 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700918 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 if (rc) {
920 cFYI(1, ("Error in RMFile = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000921 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
923 cifs_buf_release(pSMB);
924 if (rc == -EAGAIN)
925 goto DelFileRetry;
926
927 return rc;
928}
929
930int
Steve French50c2f752007-07-13 00:33:32 +0000931CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700932 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933{
934 DELETE_DIRECTORY_REQ *pSMB = NULL;
935 DELETE_DIRECTORY_RSP *pSMBr = NULL;
936 int rc = 0;
937 int bytes_returned;
938 int name_len;
939
940 cFYI(1, ("In CIFSSMBRmDir"));
941RmDirRetry:
942 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
943 (void **) &pSMBr);
944 if (rc)
945 return rc;
946
947 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700948 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
949 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 name_len++; /* trailing null */
951 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700952 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 name_len = strnlen(dirName, PATH_MAX);
954 name_len++; /* trailing null */
955 strncpy(pSMB->DirName, dirName, name_len);
956 }
957
958 pSMB->BufferFormat = 0x04;
959 pSMB->hdr.smb_buf_length += name_len + 1;
960 pSMB->ByteCount = cpu_to_le16(name_len + 1);
961 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
962 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700963 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 if (rc) {
965 cFYI(1, ("Error in RMDir = %d", rc));
966 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
968 cifs_buf_release(pSMB);
969 if (rc == -EAGAIN)
970 goto RmDirRetry;
971 return rc;
972}
973
974int
975CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700976 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977{
978 int rc = 0;
979 CREATE_DIRECTORY_REQ *pSMB = NULL;
980 CREATE_DIRECTORY_RSP *pSMBr = NULL;
981 int bytes_returned;
982 int name_len;
983
984 cFYI(1, ("In CIFSSMBMkDir"));
985MkDirRetry:
986 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
987 (void **) &pSMBr);
988 if (rc)
989 return rc;
990
991 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +0000992 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -0700993 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 name_len++; /* trailing null */
995 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700996 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 name_len = strnlen(name, PATH_MAX);
998 name_len++; /* trailing null */
999 strncpy(pSMB->DirName, name, name_len);
1000 }
1001
1002 pSMB->BufferFormat = 0x04;
1003 pSMB->hdr.smb_buf_length += name_len + 1;
1004 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1005 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1006 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001007 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 if (rc) {
1009 cFYI(1, ("Error in Mkdir = %d", rc));
1010 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001011
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 cifs_buf_release(pSMB);
1013 if (rc == -EAGAIN)
1014 goto MkDirRetry;
1015 return rc;
1016}
1017
Steve French2dd29d32007-04-23 22:07:35 +00001018int
1019CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1020 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001021 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001022 const struct nls_table *nls_codepage, int remap)
1023{
1024 TRANSACTION2_SPI_REQ *pSMB = NULL;
1025 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1026 int name_len;
1027 int rc = 0;
1028 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001029 __u16 params, param_offset, offset, byte_count, count;
1030 OPEN_PSX_REQ * pdata;
1031 OPEN_PSX_RSP * psx_rsp;
1032
1033 cFYI(1, ("In POSIX Create"));
1034PsxCreat:
1035 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1036 (void **) &pSMBr);
1037 if (rc)
1038 return rc;
1039
1040 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1041 name_len =
1042 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1043 PATH_MAX, nls_codepage, remap);
1044 name_len++; /* trailing null */
1045 name_len *= 2;
1046 } else { /* BB improve the check for buffer overruns BB */
1047 name_len = strnlen(name, PATH_MAX);
1048 name_len++; /* trailing null */
1049 strncpy(pSMB->FileName, name, name_len);
1050 }
1051
1052 params = 6 + name_len;
1053 count = sizeof(OPEN_PSX_REQ);
1054 pSMB->MaxParameterCount = cpu_to_le16(2);
1055 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1056 pSMB->MaxSetupCount = 0;
1057 pSMB->Reserved = 0;
1058 pSMB->Flags = 0;
1059 pSMB->Timeout = 0;
1060 pSMB->Reserved2 = 0;
1061 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001062 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001063 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001064 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001065 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001066 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001067 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001068 pdata->OpenFlags = cpu_to_le32(*pOplock);
1069 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1070 pSMB->DataOffset = cpu_to_le16(offset);
1071 pSMB->SetupCount = 1;
1072 pSMB->Reserved3 = 0;
1073 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1074 byte_count = 3 /* pad */ + params + count;
1075
1076 pSMB->DataCount = cpu_to_le16(count);
1077 pSMB->ParameterCount = cpu_to_le16(params);
1078 pSMB->TotalDataCount = pSMB->DataCount;
1079 pSMB->TotalParameterCount = pSMB->ParameterCount;
1080 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1081 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001082 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001083 pSMB->ByteCount = cpu_to_le16(byte_count);
1084 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1085 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1086 if (rc) {
1087 cFYI(1, ("Posix create returned %d", rc));
1088 goto psx_create_err;
1089 }
1090
Steve French790fe572007-07-07 19:25:05 +00001091 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001092 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1093
1094 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1095 rc = -EIO; /* bad smb */
1096 goto psx_create_err;
1097 }
1098
1099 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001100 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001101 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001102
Steve French2dd29d32007-04-23 22:07:35 +00001103 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001104 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001105 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1106 /* Let caller know file was created so we can set the mode. */
1107 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001108 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001109 *pOplock |= CIFS_CREATE_ACTION;
1110 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001111 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1112 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001113#ifdef CONFIG_CIFS_DEBUG2
Steve French790fe572007-07-07 19:25:05 +00001114 cFYI(1, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001115#endif
1116 } else {
Steve French790fe572007-07-07 19:25:05 +00001117 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001118 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001119 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001120 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001121 goto psx_create_err;
1122 }
Steve French50c2f752007-07-13 00:33:32 +00001123 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001124 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001125 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001126 }
Steve French2dd29d32007-04-23 22:07:35 +00001127
1128psx_create_err:
1129 cifs_buf_release(pSMB);
1130
1131 cifs_stats_inc(&tcon->num_mkdirs);
1132
1133 if (rc == -EAGAIN)
1134 goto PsxCreat;
1135
Steve French50c2f752007-07-13 00:33:32 +00001136 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001137}
1138
Steve Frencha9d02ad2005-08-24 23:06:05 -07001139static __u16 convert_disposition(int disposition)
1140{
1141 __u16 ofun = 0;
1142
1143 switch (disposition) {
1144 case FILE_SUPERSEDE:
1145 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1146 break;
1147 case FILE_OPEN:
1148 ofun = SMBOPEN_OAPPEND;
1149 break;
1150 case FILE_CREATE:
1151 ofun = SMBOPEN_OCREATE;
1152 break;
1153 case FILE_OPEN_IF:
1154 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1155 break;
1156 case FILE_OVERWRITE:
1157 ofun = SMBOPEN_OTRUNC;
1158 break;
1159 case FILE_OVERWRITE_IF:
1160 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1161 break;
1162 default:
Steve French790fe572007-07-07 19:25:05 +00001163 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001164 ofun = SMBOPEN_OAPPEND; /* regular open */
1165 }
1166 return ofun;
1167}
1168
1169int
1170SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1171 const char *fileName, const int openDisposition,
1172 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001173 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001174 const struct nls_table *nls_codepage, int remap)
1175{
1176 int rc = -EACCES;
1177 OPENX_REQ *pSMB = NULL;
1178 OPENX_RSP *pSMBr = NULL;
1179 int bytes_returned;
1180 int name_len;
1181 __u16 count;
1182
1183OldOpenRetry:
1184 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1185 (void **) &pSMBr);
1186 if (rc)
1187 return rc;
1188
1189 pSMB->AndXCommand = 0xFF; /* none */
1190
1191 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1192 count = 1; /* account for one byte pad to word boundary */
1193 name_len =
1194 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1195 fileName, PATH_MAX, nls_codepage, remap);
1196 name_len++; /* trailing null */
1197 name_len *= 2;
1198 } else { /* BB improve check for buffer overruns BB */
1199 count = 0; /* no pad */
1200 name_len = strnlen(fileName, PATH_MAX);
1201 name_len++; /* trailing null */
1202 strncpy(pSMB->fileName, fileName, name_len);
1203 }
1204 if (*pOplock & REQ_OPLOCK)
1205 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001206 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001207 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001208
Steve Frencha9d02ad2005-08-24 23:06:05 -07001209 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1210 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1211 /* 0 = read
1212 1 = write
1213 2 = rw
1214 3 = execute
Steve French50c2f752007-07-13 00:33:32 +00001215 */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001216 pSMB->Mode = cpu_to_le16(2);
1217 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1218 /* set file as system file if special file such
1219 as fifo and server expecting SFU style and
1220 no Unix extensions */
1221
Steve French790fe572007-07-07 19:25:05 +00001222 if (create_options & CREATE_OPTION_SPECIAL)
1223 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1224 else
Steve French3e87d802005-09-18 20:49:21 -07001225 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001226
1227 /* if ((omode & S_IWUGO) == 0)
1228 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1229 /* Above line causes problems due to vfs splitting create into two
1230 pieces - need to set mode after file created not while it is
1231 being created */
1232
1233 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001234/* pSMB->CreateOptions = cpu_to_le32(create_options &
1235 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001236 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001237
1238 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001239 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001240 count += name_len;
1241 pSMB->hdr.smb_buf_length += count;
1242
1243 pSMB->ByteCount = cpu_to_le16(count);
1244 /* long_op set to 1 to allow for oplock break timeouts */
1245 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001246 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001247 cifs_stats_inc(&tcon->num_opens);
1248 if (rc) {
1249 cFYI(1, ("Error in Open = %d", rc));
1250 } else {
1251 /* BB verify if wct == 15 */
1252
1253/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1254
1255 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1256 /* Let caller know file was created so we can set the mode. */
1257 /* Do we care about the CreateAction in any other cases? */
1258 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001259/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 *pOplock |= CIFS_CREATE_ACTION; */
1261 /* BB FIXME END */
1262
Steve French790fe572007-07-07 19:25:05 +00001263 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001264 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1265 pfile_info->LastAccessTime = 0; /* BB fixme */
1266 pfile_info->LastWriteTime = 0; /* BB fixme */
1267 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001268 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001269 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001270 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001271 pfile_info->AllocationSize =
1272 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1273 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001274 pfile_info->NumberOfLinks = cpu_to_le32(1);
1275 }
1276 }
1277
1278 cifs_buf_release(pSMB);
1279 if (rc == -EAGAIN)
1280 goto OldOpenRetry;
1281 return rc;
1282}
1283
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284int
1285CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1286 const char *fileName, const int openDisposition,
1287 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001288 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001289 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290{
1291 int rc = -EACCES;
1292 OPEN_REQ *pSMB = NULL;
1293 OPEN_RSP *pSMBr = NULL;
1294 int bytes_returned;
1295 int name_len;
1296 __u16 count;
1297
1298openRetry:
1299 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1300 (void **) &pSMBr);
1301 if (rc)
1302 return rc;
1303
1304 pSMB->AndXCommand = 0xFF; /* none */
1305
1306 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1307 count = 1; /* account for one byte pad to word boundary */
1308 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001309 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001310 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 name_len++; /* trailing null */
1312 name_len *= 2;
1313 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001314 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 count = 0; /* no pad */
1316 name_len = strnlen(fileName, PATH_MAX);
1317 name_len++; /* trailing null */
1318 pSMB->NameLength = cpu_to_le16(name_len);
1319 strncpy(pSMB->fileName, fileName, name_len);
1320 }
1321 if (*pOplock & REQ_OPLOCK)
1322 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001323 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1326 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001327 /* set file as system file if special file such
1328 as fifo and server expecting SFU style and
1329 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001330 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001331 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1332 else
1333 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 /* XP does not handle ATTR_POSIX_SEMANTICS */
1335 /* but it helps speed up case sensitive checks for other
1336 servers such as Samba */
1337 if (tcon->ses->capabilities & CAP_UNIX)
1338 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1339
1340 /* if ((omode & S_IWUGO) == 0)
1341 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1342 /* Above line causes problems due to vfs splitting create into two
1343 pieces - need to set mode after file created not while it is
1344 being created */
1345 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1346 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001347 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001348 /* BB Expirement with various impersonation levels and verify */
1349 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 pSMB->SecurityFlags =
1351 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1352
1353 count += name_len;
1354 pSMB->hdr.smb_buf_length += count;
1355
1356 pSMB->ByteCount = cpu_to_le16(count);
1357 /* long_op set to 1 to allow for oplock break timeouts */
1358 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00001359 (struct smb_hdr *)pSMBr, &bytes_returned, CIFS_LONG_OP);
Steve Frencha4544342005-08-24 13:59:35 -07001360 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 if (rc) {
1362 cFYI(1, ("Error in Open = %d", rc));
1363 } else {
Steve French09d1db52005-04-28 22:41:08 -07001364 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1366 /* Let caller know file was created so we can set the mode. */
1367 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001368 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001369 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001370 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001371 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 36 /* CreationTime to Attributes */);
1373 /* the file_info buf is endian converted by caller */
1374 pfile_info->AllocationSize = pSMBr->AllocationSize;
1375 pfile_info->EndOfFile = pSMBr->EndOfFile;
1376 pfile_info->NumberOfLinks = cpu_to_le32(1);
1377 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001379
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 cifs_buf_release(pSMB);
1381 if (rc == -EAGAIN)
1382 goto openRetry;
1383 return rc;
1384}
1385
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386int
Steve French50c2f752007-07-13 00:33:32 +00001387CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1388 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1389 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390{
1391 int rc = -EACCES;
1392 READ_REQ *pSMB = NULL;
1393 READ_RSP *pSMBr = NULL;
1394 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001395 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001396 int resp_buf_type = 0;
1397 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398
Steve French790fe572007-07-07 19:25:05 +00001399 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1400 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001401 wct = 12;
1402 else
1403 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
1405 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001406 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001407 if (rc)
1408 return rc;
1409
1410 /* tcon and ses pointer are checked in smb_init */
1411 if (tcon->ses->server == NULL)
1412 return -ECONNABORTED;
1413
Steve Frenchec637e32005-12-12 20:53:18 -08001414 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 pSMB->Fid = netfid;
1416 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001417 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001418 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001419 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001420 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001421
Linus Torvalds1da177e2005-04-16 15:20:36 -07001422 pSMB->Remaining = 0;
1423 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1424 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001425 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001426 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1427 else {
1428 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001429 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001430 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001431 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001432 }
Steve Frenchec637e32005-12-12 20:53:18 -08001433
1434 iov[0].iov_base = (char *)pSMB;
1435 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001436 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
Steve French133672e2007-11-13 22:41:37 +00001437 &resp_buf_type, CIFS_STD_OP | CIFS_LOG_ERROR);
Steve Frencha4544342005-08-24 13:59:35 -07001438 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001439 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 if (rc) {
1441 cERROR(1, ("Send error in read = %d", rc));
1442 } else {
1443 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1444 data_length = data_length << 16;
1445 data_length += le16_to_cpu(pSMBr->DataLength);
1446 *nbytes = data_length;
1447
1448 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001449 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001451 cFYI(1, ("bad length %d for count %d",
1452 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 rc = -EIO;
1454 *nbytes = 0;
1455 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001456 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001457 le16_to_cpu(pSMBr->DataOffset);
1458/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001459 cERROR(1,("Faulting on read rc = %d",rc));
1460 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001461 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001462 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001463 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464 }
1465 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466
Steve French4b8f9302006-02-26 16:41:18 +00001467/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001468 if (*buf) {
1469 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001470 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001471 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001472 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001473 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001474 /* return buffer to caller to free */
1475 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001476 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001477 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001478 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001479 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001480 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001481
1482 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 since file handle passed in no longer valid */
1484 return rc;
1485}
1486
Steve Frenchec637e32005-12-12 20:53:18 -08001487
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488int
1489CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1490 const int netfid, const unsigned int count,
1491 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001492 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493{
1494 int rc = -EACCES;
1495 WRITE_REQ *pSMB = NULL;
1496 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001497 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 __u32 bytes_sent;
1499 __u16 byte_count;
1500
1501 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001502 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001503 return -ECONNABORTED;
1504
Steve French790fe572007-07-07 19:25:05 +00001505 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001506 wct = 14;
1507 else
1508 wct = 12;
1509
1510 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 (void **) &pSMBr);
1512 if (rc)
1513 return rc;
1514 /* tcon and ses pointer are checked in smb_init */
1515 if (tcon->ses->server == NULL)
1516 return -ECONNABORTED;
1517
1518 pSMB->AndXCommand = 0xFF; /* none */
1519 pSMB->Fid = netfid;
1520 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001521 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001522 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001523 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001524 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001525
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 pSMB->Reserved = 0xFFFFFFFF;
1527 pSMB->WriteMode = 0;
1528 pSMB->Remaining = 0;
1529
Steve French50c2f752007-07-13 00:33:32 +00001530 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 can send more if LARGE_WRITE_X capability returned by the server and if
1532 our buffer is big enough or if we convert to iovecs on socket writes
1533 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001534 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1536 } else {
1537 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1538 & ~0xFF;
1539 }
1540
1541 if (bytes_sent > count)
1542 bytes_sent = count;
1543 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001544 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001545 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001546 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001547 else if (ubuf) {
1548 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 cifs_buf_release(pSMB);
1550 return -EFAULT;
1551 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001552 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 /* No buffer */
1554 cifs_buf_release(pSMB);
1555 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001556 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001557 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001558 byte_count = bytes_sent + 1; /* pad */
1559 else /* wct == 12 */ {
1560 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1563 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001564 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001565
Steve French790fe572007-07-07 19:25:05 +00001566 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001567 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001568 else { /* old style write has byte count 4 bytes earlier
1569 so 4 bytes pad */
1570 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001571 (struct smb_com_writex_req *)pSMB;
1572 pSMBW->ByteCount = cpu_to_le16(byte_count);
1573 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574
1575 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1576 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001577 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 if (rc) {
1579 cFYI(1, ("Send error in write = %d", rc));
1580 *nbytes = 0;
1581 } else {
1582 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1583 *nbytes = (*nbytes) << 16;
1584 *nbytes += le16_to_cpu(pSMBr->Count);
1585 }
1586
1587 cifs_buf_release(pSMB);
1588
Steve French50c2f752007-07-13 00:33:32 +00001589 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 since file handle passed in no longer valid */
1591
1592 return rc;
1593}
1594
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001595int
1596CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001598 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1599 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600{
1601 int rc = -EACCES;
1602 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001603 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001604 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001605 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
Steve French790fe572007-07-07 19:25:05 +00001607 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001608
Steve French790fe572007-07-07 19:25:05 +00001609 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001610 wct = 14;
1611 else
1612 wct = 12;
1613 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614 if (rc)
1615 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 /* tcon and ses pointer are checked in smb_init */
1617 if (tcon->ses->server == NULL)
1618 return -ECONNABORTED;
1619
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001620 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001621 pSMB->Fid = netfid;
1622 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001623 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001624 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001625 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001626 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 pSMB->Reserved = 0xFFFFFFFF;
1628 pSMB->WriteMode = 0;
1629 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001630
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001632 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
Steve French3e844692005-10-03 13:37:24 -07001634 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1635 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001636 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001637 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001638 pSMB->hdr.smb_buf_length += count+1;
1639 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001640 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1641 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001642 pSMB->ByteCount = cpu_to_le16(count + 1);
1643 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001644 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001645 (struct smb_com_writex_req *)pSMB;
1646 pSMBW->ByteCount = cpu_to_le16(count + 5);
1647 }
Steve French3e844692005-10-03 13:37:24 -07001648 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001649 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001650 iov[0].iov_len = smb_hdr_len + 4;
1651 else /* wct == 12 pad bigger by four bytes */
1652 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001653
Steve French3e844692005-10-03 13:37:24 -07001654
Steve Frenchec637e32005-12-12 20:53:18 -08001655 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve French133672e2007-11-13 22:41:37 +00001656 long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001657 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001659 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001661 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001662 /* presumably this can not happen, but best to be safe */
1663 rc = -EIO;
1664 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001665 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001666 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001667 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1668 *nbytes = (*nbytes) << 16;
1669 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001670 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
Steve French4b8f9302006-02-26 16:41:18 +00001672/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001673 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001674 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001675 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001676 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677
Steve French50c2f752007-07-13 00:33:32 +00001678 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 since file handle passed in no longer valid */
1680
1681 return rc;
1682}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001683
1684
Linus Torvalds1da177e2005-04-16 15:20:36 -07001685int
1686CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1687 const __u16 smb_file_id, const __u64 len,
1688 const __u64 offset, const __u32 numUnlock,
1689 const __u32 numLock, const __u8 lockType, const int waitFlag)
1690{
1691 int rc = 0;
1692 LOCK_REQ *pSMB = NULL;
1693 LOCK_RSP *pSMBr = NULL;
1694 int bytes_returned;
1695 int timeout = 0;
1696 __u16 count;
1697
Steve French133672e2007-11-13 22:41:37 +00001698 cFYI(1, ("CIFSSMBLock timeout %d numLock %d", waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001699 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1700
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 if (rc)
1702 return rc;
1703
Steve French46810cb2005-04-28 22:41:09 -07001704 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1705
Steve French790fe572007-07-07 19:25:05 +00001706 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Steve French133672e2007-11-13 22:41:37 +00001707 timeout = CIFS_ASYNC_OP; /* no response expected */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 pSMB->Timeout = 0;
1709 } else if (waitFlag == TRUE) {
Steve French133672e2007-11-13 22:41:37 +00001710 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1712 } else {
1713 pSMB->Timeout = 0;
1714 }
1715
1716 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1717 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1718 pSMB->LockType = lockType;
1719 pSMB->AndXCommand = 0xFF; /* none */
1720 pSMB->Fid = smb_file_id; /* netfid stays le */
1721
Steve French790fe572007-07-07 19:25:05 +00001722 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1724 /* BB where to store pid high? */
1725 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1726 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1727 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1728 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1729 count = sizeof(LOCKING_ANDX_RANGE);
1730 } else {
1731 /* oplock break */
1732 count = 0;
1733 }
1734 pSMB->hdr.smb_buf_length += count;
1735 pSMB->ByteCount = cpu_to_le16(count);
1736
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001737 if (waitFlag) {
1738 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1739 (struct smb_hdr *) pSMBr, &bytes_returned);
Steve French133672e2007-11-13 22:41:37 +00001740 cifs_small_buf_release(pSMB);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001741 } else {
Steve French133672e2007-11-13 22:41:37 +00001742 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB,
1743 timeout);
1744 /* SMB buffer freed by function above */
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001745 }
Steve Frencha4544342005-08-24 13:59:35 -07001746 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 if (rc) {
1748 cFYI(1, ("Send error in Lock = %d", rc));
1749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750
Steve French50c2f752007-07-13 00:33:32 +00001751 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 since file handle passed in no longer valid */
1753 return rc;
1754}
1755
1756int
Steve French08547b02006-02-28 22:39:25 +00001757CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1758 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001759 struct file_lock *pLockData, const __u16 lock_type,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001760 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001761{
1762 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1763 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001764 struct cifs_posix_lock *parm_data;
1765 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001766 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001767 int bytes_returned = 0;
Steve French133672e2007-11-13 22:41:37 +00001768 int resp_buf_type = 0;
Steve French08547b02006-02-28 22:39:25 +00001769 __u16 params, param_offset, offset, byte_count, count;
Steve French133672e2007-11-13 22:41:37 +00001770 struct kvec iov[1];
Steve French08547b02006-02-28 22:39:25 +00001771
1772 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001773
Steve French790fe572007-07-07 19:25:05 +00001774 if (pLockData == NULL)
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001775 return EINVAL;
1776
Steve French08547b02006-02-28 22:39:25 +00001777 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1778
1779 if (rc)
1780 return rc;
1781
1782 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1783
Steve French50c2f752007-07-13 00:33:32 +00001784 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001785 pSMB->MaxSetupCount = 0;
1786 pSMB->Reserved = 0;
1787 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001788 pSMB->Reserved2 = 0;
1789 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1790 offset = param_offset + params;
1791
Steve French08547b02006-02-28 22:39:25 +00001792 count = sizeof(struct cifs_posix_lock);
1793 pSMB->MaxParameterCount = cpu_to_le16(2);
1794 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1795 pSMB->SetupCount = 1;
1796 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001797 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001798 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1799 else
1800 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1801 byte_count = 3 /* pad */ + params + count;
1802 pSMB->DataCount = cpu_to_le16(count);
1803 pSMB->ParameterCount = cpu_to_le16(params);
1804 pSMB->TotalDataCount = pSMB->DataCount;
1805 pSMB->TotalParameterCount = pSMB->ParameterCount;
1806 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001807 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001808 (((char *) &pSMB->hdr.Protocol) + offset);
1809
1810 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001811 if (waitFlag) {
Steve French133672e2007-11-13 22:41:37 +00001812 timeout = CIFS_BLOCKING_OP; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001813 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001814 pSMB->Timeout = cpu_to_le32(-1);
1815 } else
1816 pSMB->Timeout = 0;
1817
Steve French08547b02006-02-28 22:39:25 +00001818 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001819 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001820 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001821
1822 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001823 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001824 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1825 pSMB->Reserved4 = 0;
1826 pSMB->hdr.smb_buf_length += byte_count;
1827 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001828 if (waitFlag) {
1829 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1830 (struct smb_hdr *) pSMBr, &bytes_returned);
1831 } else {
Steve French133672e2007-11-13 22:41:37 +00001832 iov[0].iov_base = (char *)pSMB;
1833 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
1834 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1835 &resp_buf_type, timeout);
1836 pSMB = NULL; /* request buf already freed by SendReceive2. Do
1837 not try to free it twice below on exit */
1838 pSMBr = (struct smb_com_transaction2_sfi_rsp *)iov[0].iov_base;
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001839 }
1840
Steve French08547b02006-02-28 22:39:25 +00001841 if (rc) {
1842 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001843 } else if (get_flag) {
1844 /* lock structure can be returned on get */
1845 __u16 data_offset;
1846 __u16 data_count;
1847 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001848
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001849 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1850 rc = -EIO; /* bad smb */
1851 goto plk_err_exit;
1852 }
Steve French790fe572007-07-07 19:25:05 +00001853 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001854 rc = -EINVAL;
1855 goto plk_err_exit;
1856 }
1857 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1858 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001859 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001860 rc = -EIO;
1861 goto plk_err_exit;
1862 }
1863 parm_data = (struct cifs_posix_lock *)
1864 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001865 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001866 pLockData->fl_type = F_UNLCK;
1867 }
Steve French50c2f752007-07-13 00:33:32 +00001868
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001869plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001870 if (pSMB)
1871 cifs_small_buf_release(pSMB);
1872
Steve French133672e2007-11-13 22:41:37 +00001873 if (resp_buf_type == CIFS_SMALL_BUFFER)
1874 cifs_small_buf_release(iov[0].iov_base);
1875 else if (resp_buf_type == CIFS_LARGE_BUFFER)
1876 cifs_buf_release(iov[0].iov_base);
1877
Steve French08547b02006-02-28 22:39:25 +00001878 /* 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 cFYI(1, ("In CIFSSMBClose"));
1891
1892/* do not retry on dead session on close */
1893 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001894 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895 return 0;
1896 if (rc)
1897 return rc;
1898
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001900 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00001902 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001903 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001905 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 /* EINTR is expected when user ctl-c to kill app */
1907 cERROR(1, ("Send error in Close = %d", rc));
1908 }
1909 }
1910
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001912 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 rc = 0;
1914
1915 return rc;
1916}
1917
1918int
1919CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1920 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001921 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922{
1923 int rc = 0;
1924 RENAME_REQ *pSMB = NULL;
1925 RENAME_RSP *pSMBr = NULL;
1926 int bytes_returned;
1927 int name_len, name_len2;
1928 __u16 count;
1929
1930 cFYI(1, ("In CIFSSMBRename"));
1931renameRetry:
1932 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1933 (void **) &pSMBr);
1934 if (rc)
1935 return rc;
1936
1937 pSMB->BufferFormat = 0x04;
1938 pSMB->SearchAttributes =
1939 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1940 ATTR_DIRECTORY);
1941
1942 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1943 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001944 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001945 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 name_len++; /* trailing null */
1947 name_len *= 2;
1948 pSMB->OldFileName[name_len] = 0x04; /* pad */
1949 /* protocol requires ASCII signature byte on Unicode string */
1950 pSMB->OldFileName[name_len + 1] = 0x00;
1951 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001952 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001953 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1955 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001956 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 name_len = strnlen(fromName, PATH_MAX);
1958 name_len++; /* trailing null */
1959 strncpy(pSMB->OldFileName, fromName, name_len);
1960 name_len2 = strnlen(toName, PATH_MAX);
1961 name_len2++; /* trailing null */
1962 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1963 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1964 name_len2++; /* trailing null */
1965 name_len2++; /* signature byte */
1966 }
1967
1968 count = 1 /* 1st signature byte */ + name_len + name_len2;
1969 pSMB->hdr.smb_buf_length += count;
1970 pSMB->ByteCount = cpu_to_le16(count);
1971
1972 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1973 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001974 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 if (rc) {
1976 cFYI(1, ("Send error in rename = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +00001977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 cifs_buf_release(pSMB);
1980
1981 if (rc == -EAGAIN)
1982 goto renameRetry;
1983
1984 return rc;
1985}
1986
Steve French50c2f752007-07-13 00:33:32 +00001987int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1988 int netfid, char *target_name,
1989 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990{
1991 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1992 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00001993 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 char *data_offset;
1995 char dummy_string[30];
1996 int rc = 0;
1997 int bytes_returned = 0;
1998 int len_of_str;
1999 __u16 params, param_offset, offset, count, byte_count;
2000
2001 cFYI(1, ("Rename to File by handle"));
2002 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2003 (void **) &pSMBr);
2004 if (rc)
2005 return rc;
2006
2007 params = 6;
2008 pSMB->MaxSetupCount = 0;
2009 pSMB->Reserved = 0;
2010 pSMB->Flags = 0;
2011 pSMB->Timeout = 0;
2012 pSMB->Reserved2 = 0;
2013 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2014 offset = param_offset + params;
2015
2016 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2017 rename_info = (struct set_file_rename *) data_offset;
2018 pSMB->MaxParameterCount = cpu_to_le16(2);
2019 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
2020 pSMB->SetupCount = 1;
2021 pSMB->Reserved3 = 0;
2022 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2023 byte_count = 3 /* pad */ + params;
2024 pSMB->ParameterCount = cpu_to_le16(params);
2025 pSMB->TotalParameterCount = pSMB->ParameterCount;
2026 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2027 pSMB->DataOffset = cpu_to_le16(offset);
2028 /* construct random name ".cifs_tmp<inodenum><mid>" */
2029 rename_info->overwrite = cpu_to_le32(1);
2030 rename_info->root_fid = 0;
2031 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002032 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002033 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2034 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002035 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002037 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002038 target_name, PATH_MAX, nls_codepage,
2039 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040 }
2041 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2042 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2043 byte_count += count;
2044 pSMB->DataCount = cpu_to_le16(count);
2045 pSMB->TotalDataCount = pSMB->DataCount;
2046 pSMB->Fid = netfid;
2047 pSMB->InformationLevel =
2048 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2049 pSMB->Reserved4 = 0;
2050 pSMB->hdr.smb_buf_length += byte_count;
2051 pSMB->ByteCount = cpu_to_le16(byte_count);
2052 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002053 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002054 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002056 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 }
Steve Frencha5a2b482005-08-20 21:42:53 -07002058
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 cifs_buf_release(pSMB);
2060
2061 /* Note: On -EAGAIN error only caller can retry on handle based calls
2062 since file handle passed in no longer valid */
2063
2064 return rc;
2065}
2066
2067int
Steve French50c2f752007-07-13 00:33:32 +00002068CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2069 const __u16 target_tid, const char *toName, const int flags,
2070 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071{
2072 int rc = 0;
2073 COPY_REQ *pSMB = NULL;
2074 COPY_RSP *pSMBr = NULL;
2075 int bytes_returned;
2076 int name_len, name_len2;
2077 __u16 count;
2078
2079 cFYI(1, ("In CIFSSMBCopy"));
2080copyRetry:
2081 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2082 (void **) &pSMBr);
2083 if (rc)
2084 return rc;
2085
2086 pSMB->BufferFormat = 0x04;
2087 pSMB->Tid2 = target_tid;
2088
2089 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2090
2091 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002092 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002093 fromName, PATH_MAX, nls_codepage,
2094 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 name_len++; /* trailing null */
2096 name_len *= 2;
2097 pSMB->OldFileName[name_len] = 0x04; /* pad */
2098 /* protocol requires ASCII signature byte on Unicode string */
2099 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002100 name_len2 =
2101 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002102 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2104 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002105 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106 name_len = strnlen(fromName, PATH_MAX);
2107 name_len++; /* trailing null */
2108 strncpy(pSMB->OldFileName, fromName, name_len);
2109 name_len2 = strnlen(toName, PATH_MAX);
2110 name_len2++; /* trailing null */
2111 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2112 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2113 name_len2++; /* trailing null */
2114 name_len2++; /* signature byte */
2115 }
2116
2117 count = 1 /* 1st signature byte */ + name_len + name_len2;
2118 pSMB->hdr.smb_buf_length += count;
2119 pSMB->ByteCount = cpu_to_le16(count);
2120
2121 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2122 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2123 if (rc) {
2124 cFYI(1, ("Send error in copy = %d with %d files copied",
2125 rc, le16_to_cpu(pSMBr->CopyCount)));
2126 }
2127 if (pSMB)
2128 cifs_buf_release(pSMB);
2129
2130 if (rc == -EAGAIN)
2131 goto copyRetry;
2132
2133 return rc;
2134}
2135
2136int
2137CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2138 const char *fromName, const char *toName,
2139 const struct nls_table *nls_codepage)
2140{
2141 TRANSACTION2_SPI_REQ *pSMB = NULL;
2142 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2143 char *data_offset;
2144 int name_len;
2145 int name_len_target;
2146 int rc = 0;
2147 int bytes_returned = 0;
2148 __u16 params, param_offset, offset, byte_count;
2149
2150 cFYI(1, ("In Symlink Unix style"));
2151createSymLinkRetry:
2152 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2153 (void **) &pSMBr);
2154 if (rc)
2155 return rc;
2156
2157 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2158 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002159 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 /* find define for this maxpathcomponent */
2161 , nls_codepage);
2162 name_len++; /* trailing null */
2163 name_len *= 2;
2164
Steve French50c2f752007-07-13 00:33:32 +00002165 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 name_len = strnlen(fromName, PATH_MAX);
2167 name_len++; /* trailing null */
2168 strncpy(pSMB->FileName, fromName, name_len);
2169 }
2170 params = 6 + name_len;
2171 pSMB->MaxSetupCount = 0;
2172 pSMB->Reserved = 0;
2173 pSMB->Flags = 0;
2174 pSMB->Timeout = 0;
2175 pSMB->Reserved2 = 0;
2176 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002177 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178 offset = param_offset + params;
2179
2180 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2181 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2182 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002183 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 /* find define for this maxpathcomponent */
2185 , nls_codepage);
2186 name_len_target++; /* trailing null */
2187 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002188 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 name_len_target = strnlen(toName, PATH_MAX);
2190 name_len_target++; /* trailing null */
2191 strncpy(data_offset, toName, name_len_target);
2192 }
2193
2194 pSMB->MaxParameterCount = cpu_to_le16(2);
2195 /* BB find exact max on data count below from sess */
2196 pSMB->MaxDataCount = cpu_to_le16(1000);
2197 pSMB->SetupCount = 1;
2198 pSMB->Reserved3 = 0;
2199 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2200 byte_count = 3 /* pad */ + params + name_len_target;
2201 pSMB->DataCount = cpu_to_le16(name_len_target);
2202 pSMB->ParameterCount = cpu_to_le16(params);
2203 pSMB->TotalDataCount = pSMB->DataCount;
2204 pSMB->TotalParameterCount = pSMB->ParameterCount;
2205 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2206 pSMB->DataOffset = cpu_to_le16(offset);
2207 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2208 pSMB->Reserved4 = 0;
2209 pSMB->hdr.smb_buf_length += byte_count;
2210 pSMB->ByteCount = cpu_to_le16(byte_count);
2211 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2212 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002213 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 if (rc) {
Steve French2d785a52007-07-15 01:48:57 +00002215 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216 }
2217
2218 if (pSMB)
2219 cifs_buf_release(pSMB);
2220
2221 if (rc == -EAGAIN)
2222 goto createSymLinkRetry;
2223
2224 return rc;
2225}
2226
2227int
2228CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2229 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002230 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231{
2232 TRANSACTION2_SPI_REQ *pSMB = NULL;
2233 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2234 char *data_offset;
2235 int name_len;
2236 int name_len_target;
2237 int rc = 0;
2238 int bytes_returned = 0;
2239 __u16 params, param_offset, offset, byte_count;
2240
2241 cFYI(1, ("In Create Hard link Unix style"));
2242createHardLinkRetry:
2243 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2244 (void **) &pSMBr);
2245 if (rc)
2246 return rc;
2247
2248 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002249 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002250 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251 name_len++; /* trailing null */
2252 name_len *= 2;
2253
Steve French50c2f752007-07-13 00:33:32 +00002254 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 name_len = strnlen(toName, PATH_MAX);
2256 name_len++; /* trailing null */
2257 strncpy(pSMB->FileName, toName, name_len);
2258 }
2259 params = 6 + name_len;
2260 pSMB->MaxSetupCount = 0;
2261 pSMB->Reserved = 0;
2262 pSMB->Flags = 0;
2263 pSMB->Timeout = 0;
2264 pSMB->Reserved2 = 0;
2265 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002266 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 offset = param_offset + params;
2268
2269 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2270 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2271 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002272 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002273 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 name_len_target++; /* trailing null */
2275 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002276 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 name_len_target = strnlen(fromName, PATH_MAX);
2278 name_len_target++; /* trailing null */
2279 strncpy(data_offset, fromName, name_len_target);
2280 }
2281
2282 pSMB->MaxParameterCount = cpu_to_le16(2);
2283 /* BB find exact max on data count below from sess*/
2284 pSMB->MaxDataCount = cpu_to_le16(1000);
2285 pSMB->SetupCount = 1;
2286 pSMB->Reserved3 = 0;
2287 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2288 byte_count = 3 /* pad */ + params + name_len_target;
2289 pSMB->ParameterCount = cpu_to_le16(params);
2290 pSMB->TotalParameterCount = pSMB->ParameterCount;
2291 pSMB->DataCount = cpu_to_le16(name_len_target);
2292 pSMB->TotalDataCount = pSMB->DataCount;
2293 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2294 pSMB->DataOffset = cpu_to_le16(offset);
2295 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2296 pSMB->Reserved4 = 0;
2297 pSMB->hdr.smb_buf_length += byte_count;
2298 pSMB->ByteCount = cpu_to_le16(byte_count);
2299 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2300 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002301 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 if (rc) {
2303 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2304 }
2305
2306 cifs_buf_release(pSMB);
2307 if (rc == -EAGAIN)
2308 goto createHardLinkRetry;
2309
2310 return rc;
2311}
2312
2313int
2314CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2315 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002316 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317{
2318 int rc = 0;
2319 NT_RENAME_REQ *pSMB = NULL;
2320 RENAME_RSP *pSMBr = NULL;
2321 int bytes_returned;
2322 int name_len, name_len2;
2323 __u16 count;
2324
2325 cFYI(1, ("In CIFSCreateHardLink"));
2326winCreateHardLinkRetry:
2327
2328 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2329 (void **) &pSMBr);
2330 if (rc)
2331 return rc;
2332
2333 pSMB->SearchAttributes =
2334 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2335 ATTR_DIRECTORY);
2336 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2337 pSMB->ClusterCount = 0;
2338
2339 pSMB->BufferFormat = 0x04;
2340
2341 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2342 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002343 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002344 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 name_len++; /* trailing null */
2346 name_len *= 2;
2347 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002348 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002350 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002351 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2353 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002354 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 name_len = strnlen(fromName, PATH_MAX);
2356 name_len++; /* trailing null */
2357 strncpy(pSMB->OldFileName, fromName, name_len);
2358 name_len2 = strnlen(toName, PATH_MAX);
2359 name_len2++; /* trailing null */
2360 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2361 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2362 name_len2++; /* trailing null */
2363 name_len2++; /* signature byte */
2364 }
2365
2366 count = 1 /* string type byte */ + name_len + name_len2;
2367 pSMB->hdr.smb_buf_length += count;
2368 pSMB->ByteCount = cpu_to_le16(count);
2369
2370 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2371 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002372 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373 if (rc) {
2374 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2375 }
2376 cifs_buf_release(pSMB);
2377 if (rc == -EAGAIN)
2378 goto winCreateHardLinkRetry;
2379
2380 return rc;
2381}
2382
2383int
2384CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2385 const unsigned char *searchName,
2386 char *symlinkinfo, const int buflen,
2387 const struct nls_table *nls_codepage)
2388{
2389/* SMB_QUERY_FILE_UNIX_LINK */
2390 TRANSACTION2_QPI_REQ *pSMB = NULL;
2391 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2392 int rc = 0;
2393 int bytes_returned;
2394 int name_len;
2395 __u16 params, byte_count;
2396
2397 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2398
2399querySymLinkRetry:
2400 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2401 (void **) &pSMBr);
2402 if (rc)
2403 return rc;
2404
2405 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2406 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002407 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2408 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 name_len++; /* trailing null */
2410 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002411 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 name_len = strnlen(searchName, PATH_MAX);
2413 name_len++; /* trailing null */
2414 strncpy(pSMB->FileName, searchName, name_len);
2415 }
2416
2417 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2418 pSMB->TotalDataCount = 0;
2419 pSMB->MaxParameterCount = cpu_to_le16(2);
2420 /* BB find exact max data count below from sess structure BB */
2421 pSMB->MaxDataCount = cpu_to_le16(4000);
2422 pSMB->MaxSetupCount = 0;
2423 pSMB->Reserved = 0;
2424 pSMB->Flags = 0;
2425 pSMB->Timeout = 0;
2426 pSMB->Reserved2 = 0;
2427 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002428 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 pSMB->DataCount = 0;
2430 pSMB->DataOffset = 0;
2431 pSMB->SetupCount = 1;
2432 pSMB->Reserved3 = 0;
2433 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2434 byte_count = params + 1 /* pad */ ;
2435 pSMB->TotalParameterCount = cpu_to_le16(params);
2436 pSMB->ParameterCount = pSMB->TotalParameterCount;
2437 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2438 pSMB->Reserved4 = 0;
2439 pSMB->hdr.smb_buf_length += byte_count;
2440 pSMB->ByteCount = cpu_to_le16(byte_count);
2441
2442 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2443 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2444 if (rc) {
2445 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2446 } else {
2447 /* decode response */
2448
2449 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2450 if (rc || (pSMBr->ByteCount < 2))
2451 /* BB also check enough total bytes returned */
2452 rc = -EIO; /* bad smb */
2453 else {
2454 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2455 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2456
2457 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2458 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002459 &pSMBr->hdr.Protocol + data_offset),
2460 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002461 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002463 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2464 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002465 name_len, nls_codepage);
2466 } else {
2467 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002468 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 data_offset,
2470 min_t(const int, buflen, count));
2471 }
2472 symlinkinfo[buflen] = 0;
2473 /* just in case so calling code does not go off the end of buffer */
2474 }
2475 }
2476 cifs_buf_release(pSMB);
2477 if (rc == -EAGAIN)
2478 goto querySymLinkRetry;
2479 return rc;
2480}
2481
Parag Warudkarc9489772007-10-23 18:09:48 +00002482#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002483/* Initialize NT TRANSACT SMB into small smb request buffer.
2484 This assumes that all NT TRANSACTS that we init here have
2485 total parm and data under about 400 bytes (to fit in small cifs
2486 buffer size), which is the case so far, it easily fits. NB:
2487 Setup words themselves and ByteCount
2488 MaxSetupCount (size of returned setup area) and
2489 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002490static int
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002491smb_init_nttransact(const __u16 sub_command, const int setup_count,
Steve French0a4b92c2006-01-12 15:44:21 -08002492 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002493 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002494{
2495 int rc;
2496 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002497 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002498
2499 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2500 (void **)&pSMB);
2501 if (rc)
2502 return rc;
2503 *ret_buf = (void *)pSMB;
2504 pSMB->Reserved = 0;
2505 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2506 pSMB->TotalDataCount = 0;
2507 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2508 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2509 pSMB->ParameterCount = pSMB->TotalParameterCount;
2510 pSMB->DataCount = pSMB->TotalDataCount;
2511 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2512 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2513 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2514 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2515 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2516 pSMB->SubCommand = cpu_to_le16(sub_command);
2517 return 0;
2518}
2519
2520static int
Steve French50c2f752007-07-13 00:33:32 +00002521validate_ntransact(char *buf, char **ppparm, char **ppdata,
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00002522 __u32 *pparmlen, __u32 *pdatalen)
Steve French0a4b92c2006-01-12 15:44:21 -08002523{
Steve French50c2f752007-07-13 00:33:32 +00002524 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002525 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002526 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002527
Steve French630f3f0c2007-10-25 21:17:17 +00002528 *pdatalen = 0;
2529 *pparmlen = 0;
2530
Steve French790fe572007-07-07 19:25:05 +00002531 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002532 return -EINVAL;
2533
2534 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2535
2536 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002537 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002538 (char *)&pSMBr->ByteCount;
2539
Steve French0a4b92c2006-01-12 15:44:21 -08002540 data_offset = le32_to_cpu(pSMBr->DataOffset);
2541 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002542 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002543 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2544
2545 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2546 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2547
2548 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002549 if (*ppparm > end_of_smb) {
2550 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002551 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002552 } else if (parm_count + *ppparm > end_of_smb) {
2553 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002554 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002555 } else if (*ppdata > end_of_smb) {
2556 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002557 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002558 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002559 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002560 *ppdata, data_count, (data_count + *ppdata),
2561 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002562 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002563 } else if (parm_count + data_count > pSMBr->ByteCount) {
2564 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002565 return -EINVAL;
2566 }
Steve French630f3f0c2007-10-25 21:17:17 +00002567 *pdatalen = data_count;
2568 *pparmlen = parm_count;
Steve French0a4b92c2006-01-12 15:44:21 -08002569 return 0;
2570}
Parag Warudkarc9489772007-10-23 18:09:48 +00002571#endif /* CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08002572
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 French630f3f0c2007-10-25 21:17:17 +00003070 struct cifs_ntsd **acl_inf, __u32 *pbuflen)
Steve French0a4b92c2006-01-12 15:44:21 -08003071{
3072 int rc = 0;
3073 int buf_type = 0;
3074 QUERY_SEC_DESC_REQ * pSMB;
3075 struct kvec iov[1];
3076
3077 cFYI(1, ("GetCifsACL"));
3078
Steve French630f3f0c2007-10-25 21:17:17 +00003079 *pbuflen = 0;
3080 *acl_inf = NULL;
3081
Steve Frenchb9c7a2b2007-10-26 23:40:20 +00003082 rc = smb_init_nttransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
Steve French0a4b92c2006-01-12 15:44:21 -08003083 8 /* parm len */, tcon, (void **) &pSMB);
3084 if (rc)
3085 return rc;
3086
3087 pSMB->MaxParameterCount = cpu_to_le32(4);
3088 /* BB TEST with big acls that might need to be e.g. larger than 16K */
3089 pSMB->MaxSetupCount = 0;
3090 pSMB->Fid = fid; /* file handle always le */
3091 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
3092 CIFS_ACL_DACL);
3093 pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
3094 pSMB->hdr.smb_buf_length += 11;
3095 iov[0].iov_base = (char *)pSMB;
3096 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
3097
Steve Frencha761ac52007-10-18 21:45:27 +00003098 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type,
Steve French133672e2007-11-13 22:41:37 +00003099 CIFS_STD_OP);
Steve French0a4b92c2006-01-12 15:44:21 -08003100 cifs_stats_inc(&tcon->num_acl_get);
3101 if (rc) {
3102 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
3103 } else { /* decode response */
Steve French0a4b92c2006-01-12 15:44:21 -08003104 __le32 * parm;
Steve French630f3f0c2007-10-25 21:17:17 +00003105 __u32 parm_len;
3106 __u32 acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003107 struct smb_com_ntransact_rsp *pSMBr;
Steve French630f3f0c2007-10-25 21:17:17 +00003108 char *pdata;
Steve French0a4b92c2006-01-12 15:44:21 -08003109
3110/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003111 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French630f3f0c2007-10-25 21:17:17 +00003112 &pdata, &parm_len, pbuflen);
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 French630f3f0c2007-10-25 21:17:17 +00003117 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, *acl_inf));
Steve French0a4b92c2006-01-12 15:44:21 -08003118
3119 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3120 rc = -EIO; /* bad smb */
Steve French630f3f0c2007-10-25 21:17:17 +00003121 *pbuflen = 0;
Steve French0a4b92c2006-01-12 15:44:21 -08003122 goto qsec_out;
3123 }
3124
3125/* BB check that data area is minimum length and as big as acl_len */
3126
Steve Frenchaf6f4612007-10-16 18:40:37 +00003127 acl_len = le32_to_cpu(*parm);
Steve French630f3f0c2007-10-25 21:17:17 +00003128 if (acl_len != *pbuflen) {
3129 cERROR(1, ("acl length %d does not match %d",
3130 acl_len, *pbuflen));
3131 if (*pbuflen > acl_len)
3132 *pbuflen = acl_len;
3133 }
Steve French0a4b92c2006-01-12 15:44:21 -08003134
Steve French630f3f0c2007-10-25 21:17:17 +00003135 /* check if buffer is big enough for the acl
3136 header followed by the smallest SID */
3137 if ((*pbuflen < sizeof(struct cifs_ntsd) + 8) ||
3138 (*pbuflen >= 64 * 1024)) {
3139 cERROR(1, ("bad acl length %d", *pbuflen));
3140 rc = -EINVAL;
3141 *pbuflen = 0;
3142 } else {
3143 *acl_inf = kmalloc(*pbuflen, GFP_KERNEL);
3144 if (*acl_inf == NULL) {
3145 *pbuflen = 0;
3146 rc = -ENOMEM;
3147 }
3148 memcpy(*acl_inf, pdata, *pbuflen);
3149 }
Steve French0a4b92c2006-01-12 15:44:21 -08003150 }
3151qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003152 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003153 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003154 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003155 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003156/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003157 return rc;
3158}
Steve French97837582007-12-31 07:47:21 +00003159
3160int
3161CIFSSMBSetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
3162 struct cifs_ntsd *pntsd, __u32 acllen)
3163{
3164 __u16 byte_count, param_count, data_count, param_offset, data_offset;
3165 int rc = 0;
3166 int bytes_returned = 0;
3167 SET_SEC_DESC_REQ *pSMB = NULL;
3168 NTRANSACT_RSP *pSMBr = NULL;
3169
3170setCifsAclRetry:
3171 rc = smb_init(SMB_COM_NT_TRANSACT, 19, tcon, (void **) &pSMB,
3172 (void **) &pSMBr);
3173 if (rc)
3174 return (rc);
3175
3176 pSMB->MaxSetupCount = 0;
3177 pSMB->Reserved = 0;
3178
3179 param_count = 8;
3180 param_offset = offsetof(struct smb_com_transaction_ssec_req, Fid) - 4;
3181 data_count = acllen;
3182 data_offset = param_offset + param_count;
3183 byte_count = 3 /* pad */ + param_count;
3184
3185 pSMB->DataCount = cpu_to_le32(data_count);
3186 pSMB->TotalDataCount = pSMB->DataCount;
3187 pSMB->MaxParameterCount = cpu_to_le32(4);
3188 pSMB->MaxDataCount = cpu_to_le32(16384);
3189 pSMB->ParameterCount = cpu_to_le32(param_count);
3190 pSMB->ParameterOffset = cpu_to_le32(param_offset);
3191 pSMB->TotalParameterCount = pSMB->ParameterCount;
3192 pSMB->DataOffset = cpu_to_le32(data_offset);
3193 pSMB->SetupCount = 0;
3194 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_SET_SECURITY_DESC);
3195 pSMB->ByteCount = cpu_to_le16(byte_count+data_count);
3196
3197 pSMB->Fid = fid; /* file handle always le */
3198 pSMB->Reserved2 = 0;
3199 pSMB->AclFlags = cpu_to_le32(CIFS_ACL_DACL);
3200
3201 if (pntsd && acllen) {
3202 memcpy((char *) &pSMBr->hdr.Protocol + data_offset,
3203 (char *) pntsd,
3204 acllen);
3205 pSMB->hdr.smb_buf_length += (byte_count + data_count);
3206
3207 } else
3208 pSMB->hdr.smb_buf_length += byte_count;
3209
3210 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3211 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3212
3213 cFYI(1, ("SetCIFSACL bytes_returned: %d, rc: %d", bytes_returned, rc));
3214 if (rc)
3215 cFYI(1, ("Set CIFS ACL returned %d", rc));
3216 cifs_buf_release(pSMB);
3217
3218 if (rc == -EAGAIN)
3219 goto setCifsAclRetry;
3220
3221 return (rc);
3222}
3223
Steve French297647c2007-10-12 04:11:59 +00003224#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003225
Steve French6b8edfe2005-08-23 20:26:03 -07003226/* Legacy Query Path Information call for lookup to old servers such
3227 as Win9x/WinME */
3228int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003229 const unsigned char *searchName,
3230 FILE_ALL_INFO *pFinfo,
3231 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003232{
3233 QUERY_INFORMATION_REQ * pSMB;
3234 QUERY_INFORMATION_RSP * pSMBr;
3235 int rc = 0;
3236 int bytes_returned;
3237 int name_len;
3238
Steve French50c2f752007-07-13 00:33:32 +00003239 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003240QInfRetry:
3241 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003242 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003243 if (rc)
3244 return rc;
3245
3246 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3247 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003248 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3249 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003250 name_len++; /* trailing null */
3251 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003252 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003253 name_len = strnlen(searchName, PATH_MAX);
3254 name_len++; /* trailing null */
3255 strncpy(pSMB->FileName, searchName, name_len);
3256 }
3257 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003258 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003259 pSMB->hdr.smb_buf_length += (__u16) name_len;
3260 pSMB->ByteCount = cpu_to_le16(name_len);
3261
3262 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003263 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003264 if (rc) {
3265 cFYI(1, ("Send error in QueryInfo = %d", rc));
3266 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003267 struct timespec ts;
3268 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3269 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003270 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003271 ts.tv_nsec = 0;
3272 ts.tv_sec = time;
3273 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003274 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003275 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3276 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003277 pFinfo->AllocationSize =
3278 cpu_to_le64(le32_to_cpu(pSMBr->size));
3279 pFinfo->EndOfFile = pFinfo->AllocationSize;
3280 pFinfo->Attributes =
3281 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003282 } else
3283 rc = -EIO; /* bad buffer passed in */
3284
3285 cifs_buf_release(pSMB);
3286
3287 if (rc == -EAGAIN)
3288 goto QInfRetry;
3289
3290 return rc;
3291}
3292
3293
3294
3295
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296int
3297CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3298 const unsigned char *searchName,
3299 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003300 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003301 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302{
3303/* level 263 SMB_QUERY_FILE_ALL_INFO */
3304 TRANSACTION2_QPI_REQ *pSMB = NULL;
3305 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3306 int rc = 0;
3307 int bytes_returned;
3308 int name_len;
3309 __u16 params, byte_count;
3310
3311/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3312QPathInfoRetry:
3313 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3314 (void **) &pSMBr);
3315 if (rc)
3316 return rc;
3317
3318 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3319 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003320 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003321 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003322 name_len++; /* trailing null */
3323 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003324 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325 name_len = strnlen(searchName, PATH_MAX);
3326 name_len++; /* trailing null */
3327 strncpy(pSMB->FileName, searchName, name_len);
3328 }
3329
Steve French50c2f752007-07-13 00:33:32 +00003330 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 pSMB->TotalDataCount = 0;
3332 pSMB->MaxParameterCount = cpu_to_le16(2);
3333 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3334 pSMB->MaxSetupCount = 0;
3335 pSMB->Reserved = 0;
3336 pSMB->Flags = 0;
3337 pSMB->Timeout = 0;
3338 pSMB->Reserved2 = 0;
3339 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003340 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 pSMB->DataCount = 0;
3342 pSMB->DataOffset = 0;
3343 pSMB->SetupCount = 1;
3344 pSMB->Reserved3 = 0;
3345 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3346 byte_count = params + 1 /* pad */ ;
3347 pSMB->TotalParameterCount = cpu_to_le16(params);
3348 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003349 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003350 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3351 else
3352 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353 pSMB->Reserved4 = 0;
3354 pSMB->hdr.smb_buf_length += byte_count;
3355 pSMB->ByteCount = cpu_to_le16(byte_count);
3356
3357 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3358 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3359 if (rc) {
3360 cFYI(1, ("Send error in QPathInfo = %d", rc));
3361 } else { /* decode response */
3362 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3363
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003364 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3365 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003366 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003368 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003369 rc = -EIO; /* 24 or 26 expected but we do not read
3370 last field */
3371 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003372 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003373 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003374 if (legacy) /* we do not read the last field, EAsize,
3375 fortunately since it varies by subdialect
3376 and on Set vs. Get, is two bytes or 4
3377 bytes depending but we don't care here */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003378 size = sizeof(FILE_INFO_STANDARD);
3379 else
3380 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 memcpy((char *) pFindData,
3382 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003383 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003384 } else
3385 rc = -ENOMEM;
3386 }
3387 cifs_buf_release(pSMB);
3388 if (rc == -EAGAIN)
3389 goto QPathInfoRetry;
3390
3391 return rc;
3392}
3393
3394int
3395CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3396 const unsigned char *searchName,
3397 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003398 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003399{
3400/* SMB_QUERY_FILE_UNIX_BASIC */
3401 TRANSACTION2_QPI_REQ *pSMB = NULL;
3402 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3403 int rc = 0;
3404 int bytes_returned = 0;
3405 int name_len;
3406 __u16 params, byte_count;
3407
3408 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3409UnixQPathInfoRetry:
3410 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3411 (void **) &pSMBr);
3412 if (rc)
3413 return rc;
3414
3415 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3416 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003417 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003418 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003419 name_len++; /* trailing null */
3420 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003421 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003422 name_len = strnlen(searchName, PATH_MAX);
3423 name_len++; /* trailing null */
3424 strncpy(pSMB->FileName, searchName, name_len);
3425 }
3426
Steve French50c2f752007-07-13 00:33:32 +00003427 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003428 pSMB->TotalDataCount = 0;
3429 pSMB->MaxParameterCount = cpu_to_le16(2);
3430 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003431 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003432 pSMB->MaxSetupCount = 0;
3433 pSMB->Reserved = 0;
3434 pSMB->Flags = 0;
3435 pSMB->Timeout = 0;
3436 pSMB->Reserved2 = 0;
3437 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003438 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 pSMB->DataCount = 0;
3440 pSMB->DataOffset = 0;
3441 pSMB->SetupCount = 1;
3442 pSMB->Reserved3 = 0;
3443 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3444 byte_count = params + 1 /* pad */ ;
3445 pSMB->TotalParameterCount = cpu_to_le16(params);
3446 pSMB->ParameterCount = pSMB->TotalParameterCount;
3447 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3448 pSMB->Reserved4 = 0;
3449 pSMB->hdr.smb_buf_length += byte_count;
3450 pSMB->ByteCount = cpu_to_le16(byte_count);
3451
3452 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3453 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3454 if (rc) {
3455 cFYI(1, ("Send error in QPathInfo = %d", rc));
3456 } else { /* decode response */
3457 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3458
3459 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003460 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3461 "Unix Extensions can be disabled on mount "
3462 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463 rc = -EIO; /* bad smb */
3464 } else {
3465 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3466 memcpy((char *) pFindData,
3467 (char *) &pSMBr->hdr.Protocol +
3468 data_offset,
Steve French630f3f0c2007-10-25 21:17:17 +00003469 sizeof(FILE_UNIX_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 }
3471 }
3472 cifs_buf_release(pSMB);
3473 if (rc == -EAGAIN)
3474 goto UnixQPathInfoRetry;
3475
3476 return rc;
3477}
3478
3479#if 0 /* function unused at present */
3480int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3481 const char *searchName, FILE_ALL_INFO * findData,
3482 const struct nls_table *nls_codepage)
3483{
3484/* level 257 SMB_ */
3485 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3486 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3487 int rc = 0;
3488 int bytes_returned;
3489 int name_len;
3490 __u16 params, byte_count;
3491
3492 cFYI(1, ("In FindUnique"));
3493findUniqueRetry:
3494 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3495 (void **) &pSMBr);
3496 if (rc)
3497 return rc;
3498
3499 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3500 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003501 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3502 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003503 name_len++; /* trailing null */
3504 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003505 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 name_len = strnlen(searchName, PATH_MAX);
3507 name_len++; /* trailing null */
3508 strncpy(pSMB->FileName, searchName, name_len);
3509 }
3510
3511 params = 12 + name_len /* includes null */ ;
3512 pSMB->TotalDataCount = 0; /* no EAs */
3513 pSMB->MaxParameterCount = cpu_to_le16(2);
3514 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3515 pSMB->MaxSetupCount = 0;
3516 pSMB->Reserved = 0;
3517 pSMB->Flags = 0;
3518 pSMB->Timeout = 0;
3519 pSMB->Reserved2 = 0;
3520 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00003521 offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522 pSMB->DataCount = 0;
3523 pSMB->DataOffset = 0;
3524 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3525 pSMB->Reserved3 = 0;
3526 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3527 byte_count = params + 1 /* pad */ ;
3528 pSMB->TotalParameterCount = cpu_to_le16(params);
3529 pSMB->ParameterCount = pSMB->TotalParameterCount;
3530 pSMB->SearchAttributes =
3531 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3532 ATTR_DIRECTORY);
3533 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3534 pSMB->SearchFlags = cpu_to_le16(1);
3535 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3536 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3537 pSMB->hdr.smb_buf_length += byte_count;
3538 pSMB->ByteCount = cpu_to_le16(byte_count);
3539
3540 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3541 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3542
3543 if (rc) {
3544 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3545 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003546 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003547 /* BB fill in */
3548 }
3549
3550 cifs_buf_release(pSMB);
3551 if (rc == -EAGAIN)
3552 goto findUniqueRetry;
3553
3554 return rc;
3555}
3556#endif /* end unused (temporarily) function */
3557
3558/* xid, tcon, searchName and codepage are input parms, rest are returned */
3559int
3560CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003561 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003562 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003563 __u16 *pnetfid,
3564 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565{
3566/* level 257 SMB_ */
3567 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3568 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3569 T2_FFIRST_RSP_PARMS * parms;
3570 int rc = 0;
3571 int bytes_returned = 0;
3572 int name_len;
3573 __u16 params, byte_count;
3574
Steve French50c2f752007-07-13 00:33:32 +00003575 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003576
3577findFirstRetry:
3578 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3579 (void **) &pSMBr);
3580 if (rc)
3581 return rc;
3582
3583 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3584 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003585 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003586 PATH_MAX, nls_codepage, remap);
3587 /* We can not add the asterik earlier in case
3588 it got remapped to 0xF03A as if it were part of the
3589 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003591 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003592 pSMB->FileName[name_len+1] = 0;
3593 pSMB->FileName[name_len+2] = '*';
3594 pSMB->FileName[name_len+3] = 0;
3595 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003596 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3597 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003598 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003599 } else { /* BB add check for overrun of SMB buf BB */
3600 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003601/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003602 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 free buffer exit; BB */
3604 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003605 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003606 pSMB->FileName[name_len+1] = '*';
3607 pSMB->FileName[name_len+2] = 0;
3608 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003609 }
3610
3611 params = 12 + name_len /* includes null */ ;
3612 pSMB->TotalDataCount = 0; /* no EAs */
3613 pSMB->MaxParameterCount = cpu_to_le16(10);
3614 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3615 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3616 pSMB->MaxSetupCount = 0;
3617 pSMB->Reserved = 0;
3618 pSMB->Flags = 0;
3619 pSMB->Timeout = 0;
3620 pSMB->Reserved2 = 0;
3621 byte_count = params + 1 /* pad */ ;
3622 pSMB->TotalParameterCount = cpu_to_le16(params);
3623 pSMB->ParameterCount = pSMB->TotalParameterCount;
3624 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003625 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3626 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627 pSMB->DataCount = 0;
3628 pSMB->DataOffset = 0;
3629 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3630 pSMB->Reserved3 = 0;
3631 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3632 pSMB->SearchAttributes =
3633 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3634 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003635 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3636 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003637 CIFS_SEARCH_RETURN_RESUME);
3638 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3639
3640 /* BB what should we set StorageType to? Does it matter? BB */
3641 pSMB->SearchStorageType = 0;
3642 pSMB->hdr.smb_buf_length += byte_count;
3643 pSMB->ByteCount = cpu_to_le16(byte_count);
3644
3645 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3646 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003647 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003648
Steve French88274812006-03-09 22:21:45 +00003649 if (rc) {/* BB add logic to retry regular search if Unix search
3650 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651 /* BB Add code to handle unsupported level rc */
3652 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003653
Steve French88274812006-03-09 22:21:45 +00003654 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655
3656 /* BB eventually could optimize out free and realloc of buf */
3657 /* for this case */
3658 if (rc == -EAGAIN)
3659 goto findFirstRetry;
3660 } else { /* decode response */
3661 /* BB remember to free buffer if error BB */
3662 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003663 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3665 psrch_inf->unicode = TRUE;
3666 else
3667 psrch_inf->unicode = FALSE;
3668
3669 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003670 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003671 psrch_inf->srch_entries_start =
3672 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003673 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3675 le16_to_cpu(pSMBr->t2.ParameterOffset));
3676
Steve French790fe572007-07-07 19:25:05 +00003677 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 psrch_inf->endOfSearch = TRUE;
3679 else
3680 psrch_inf->endOfSearch = FALSE;
3681
Steve French50c2f752007-07-13 00:33:32 +00003682 psrch_inf->entries_in_buffer =
3683 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003684 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 *pnetfid = parms->SearchHandle;
3687 } else {
3688 cifs_buf_release(pSMB);
3689 }
3690 }
3691
3692 return rc;
3693}
3694
3695int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003696 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003697{
3698 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3699 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3700 T2_FNEXT_RSP_PARMS * parms;
3701 char *response_data;
3702 int rc = 0;
3703 int bytes_returned, name_len;
3704 __u16 params, byte_count;
3705
3706 cFYI(1, ("In FindNext"));
3707
Steve French790fe572007-07-07 19:25:05 +00003708 if (psrch_inf->endOfSearch == TRUE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709 return -ENOENT;
3710
3711 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3712 (void **) &pSMBr);
3713 if (rc)
3714 return rc;
3715
Steve French50c2f752007-07-13 00:33:32 +00003716 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 byte_count = 0;
3718 pSMB->TotalDataCount = 0; /* no EAs */
3719 pSMB->MaxParameterCount = cpu_to_le16(8);
3720 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003721 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3722 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003723 pSMB->MaxSetupCount = 0;
3724 pSMB->Reserved = 0;
3725 pSMB->Flags = 0;
3726 pSMB->Timeout = 0;
3727 pSMB->Reserved2 = 0;
3728 pSMB->ParameterOffset = cpu_to_le16(
3729 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3730 pSMB->DataCount = 0;
3731 pSMB->DataOffset = 0;
3732 pSMB->SetupCount = 1;
3733 pSMB->Reserved3 = 0;
3734 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3735 pSMB->SearchHandle = searchHandle; /* always kept as le */
3736 pSMB->SearchCount =
Steve French630f3f0c2007-10-25 21:17:17 +00003737 cpu_to_le16(CIFSMaxBufSize / sizeof(FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3739 pSMB->ResumeKey = psrch_inf->resume_key;
3740 pSMB->SearchFlags =
3741 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3742
3743 name_len = psrch_inf->resume_name_len;
3744 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003745 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003746 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3747 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003748 /* 14 byte parm len above enough for 2 byte null terminator */
3749 pSMB->ResumeFileName[name_len] = 0;
3750 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 } else {
3752 rc = -EINVAL;
3753 goto FNext2_err_exit;
3754 }
3755 byte_count = params + 1 /* pad */ ;
3756 pSMB->TotalParameterCount = cpu_to_le16(params);
3757 pSMB->ParameterCount = pSMB->TotalParameterCount;
3758 pSMB->hdr.smb_buf_length += byte_count;
3759 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003760
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3762 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003763 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764 if (rc) {
3765 if (rc == -EBADF) {
3766 psrch_inf->endOfSearch = TRUE;
Steve French50c2f752007-07-13 00:33:32 +00003767 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 } else
3769 cFYI(1, ("FindNext returned = %d", rc));
3770 } else { /* decode response */
3771 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003772
Steve French790fe572007-07-07 19:25:05 +00003773 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003774 /* BB fixme add lock for file (srch_info) struct here */
3775 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3776 psrch_inf->unicode = TRUE;
3777 else
3778 psrch_inf->unicode = FALSE;
3779 response_data = (char *) &pSMBr->hdr.Protocol +
3780 le16_to_cpu(pSMBr->t2.ParameterOffset);
3781 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3782 response_data = (char *)&pSMBr->hdr.Protocol +
3783 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003784 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003785 cifs_small_buf_release(
3786 psrch_inf->ntwrk_buf_start);
3787 else
3788 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789 psrch_inf->srch_entries_start = response_data;
3790 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003791 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003792 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003793 psrch_inf->endOfSearch = TRUE;
3794 else
3795 psrch_inf->endOfSearch = FALSE;
Steve French50c2f752007-07-13 00:33:32 +00003796 psrch_inf->entries_in_buffer =
3797 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003798 psrch_inf->index_of_last_entry +=
3799 psrch_inf->entries_in_buffer;
Steve French50c2f752007-07-13 00:33:32 +00003800/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3801 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802
3803 /* BB fixme add unlock here */
3804 }
3805
3806 }
3807
3808 /* BB On error, should we leave previous search buf (and count and
3809 last entry fields) intact or free the previous one? */
3810
3811 /* Note: On -EAGAIN error only caller can retry on handle based calls
3812 since file handle passed in no longer valid */
3813FNext2_err_exit:
3814 if (rc != 0)
3815 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003816 return rc;
3817}
3818
3819int
Steve French50c2f752007-07-13 00:33:32 +00003820CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3821 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003822{
3823 int rc = 0;
3824 FINDCLOSE_REQ *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003825
3826 cFYI(1, ("In CIFSSMBFindClose"));
3827 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3828
3829 /* no sense returning error if session restarted
3830 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003831 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003832 return 0;
3833 if (rc)
3834 return rc;
3835
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 pSMB->FileID = searchHandle;
3837 pSMB->ByteCount = 0;
Steve French133672e2007-11-13 22:41:37 +00003838 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003839 if (rc) {
3840 cERROR(1, ("Send error in FindClose = %d", rc));
3841 }
Steve Frencha4544342005-08-24 13:59:35 -07003842 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003843
3844 /* Since session is dead, search handle closed on server already */
3845 if (rc == -EAGAIN)
3846 rc = 0;
3847
3848 return rc;
3849}
3850
Linus Torvalds1da177e2005-04-16 15:20:36 -07003851int
3852CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003853 const unsigned char *searchName,
3854 __u64 * inode_number,
3855 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856{
3857 int rc = 0;
3858 TRANSACTION2_QPI_REQ *pSMB = NULL;
3859 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3860 int name_len, bytes_returned;
3861 __u16 params, byte_count;
3862
Steve French50c2f752007-07-13 00:33:32 +00003863 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003864 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003865 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866
3867GetInodeNumberRetry:
3868 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003869 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 if (rc)
3871 return rc;
3872
Linus Torvalds1da177e2005-04-16 15:20:36 -07003873 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3874 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003875 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003876 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 name_len++; /* trailing null */
3878 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003879 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 name_len = strnlen(searchName, PATH_MAX);
3881 name_len++; /* trailing null */
3882 strncpy(pSMB->FileName, searchName, name_len);
3883 }
3884
3885 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3886 pSMB->TotalDataCount = 0;
3887 pSMB->MaxParameterCount = cpu_to_le16(2);
3888 /* BB find exact max data count below from sess structure BB */
3889 pSMB->MaxDataCount = cpu_to_le16(4000);
3890 pSMB->MaxSetupCount = 0;
3891 pSMB->Reserved = 0;
3892 pSMB->Flags = 0;
3893 pSMB->Timeout = 0;
3894 pSMB->Reserved2 = 0;
3895 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003896 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003897 pSMB->DataCount = 0;
3898 pSMB->DataOffset = 0;
3899 pSMB->SetupCount = 1;
3900 pSMB->Reserved3 = 0;
3901 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3902 byte_count = params + 1 /* pad */ ;
3903 pSMB->TotalParameterCount = cpu_to_le16(params);
3904 pSMB->ParameterCount = pSMB->TotalParameterCount;
3905 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3906 pSMB->Reserved4 = 0;
3907 pSMB->hdr.smb_buf_length += byte_count;
3908 pSMB->ByteCount = cpu_to_le16(byte_count);
3909
3910 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3911 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3912 if (rc) {
3913 cFYI(1, ("error %d in QueryInternalInfo", rc));
3914 } else {
3915 /* decode response */
3916 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3917 if (rc || (pSMBr->ByteCount < 2))
3918 /* BB also check enough total bytes returned */
3919 /* If rc should we check for EOPNOSUPP and
3920 disable the srvino flag? or in caller? */
3921 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003922 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003923 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3924 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003925 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003927 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003928 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3929 rc = -EIO;
3930 goto GetInodeNumOut;
3931 }
3932 pfinfo = (struct file_internal_info *)
3933 (data_offset + (char *) &pSMBr->hdr.Protocol);
3934 *inode_number = pfinfo->UniqueId;
3935 }
3936 }
3937GetInodeNumOut:
3938 cifs_buf_release(pSMB);
3939 if (rc == -EAGAIN)
3940 goto GetInodeNumberRetry;
3941 return rc;
3942}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003943
3944int
3945CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3946 const unsigned char *searchName,
3947 unsigned char **targetUNCs,
3948 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003949 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950{
3951/* TRANS2_GET_DFS_REFERRAL */
3952 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3953 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003954 struct dfs_referral_level_3 *referrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003955 int rc = 0;
3956 int bytes_returned;
3957 int name_len;
3958 unsigned int i;
Steve French50c2f752007-07-13 00:33:32 +00003959 char *temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 __u16 params, byte_count;
3961 *number_of_UNC_in_array = 0;
3962 *targetUNCs = NULL;
3963
3964 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3965 if (ses == NULL)
3966 return -ENODEV;
3967getDFSRetry:
3968 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3969 (void **) &pSMBr);
3970 if (rc)
3971 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003972
3973 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07003974 but should never be null here anyway */
3975 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976 pSMB->hdr.Tid = ses->ipc_tid;
3977 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00003978 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00003980 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003982
3983 if (ses->capabilities & CAP_UNICODE) {
3984 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3985 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003986 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003987 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 name_len++; /* trailing null */
3989 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003990 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003991 name_len = strnlen(searchName, PATH_MAX);
3992 name_len++; /* trailing null */
3993 strncpy(pSMB->RequestFileName, searchName, name_len);
3994 }
3995
Steve French790fe572007-07-07 19:25:05 +00003996 if (ses->server) {
3997 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00003998 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3999 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
4000 }
4001
Steve French50c2f752007-07-13 00:33:32 +00004002 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00004003
Linus Torvalds1da177e2005-04-16 15:20:36 -07004004 params = 2 /* level */ + name_len /*includes null */ ;
4005 pSMB->TotalDataCount = 0;
4006 pSMB->DataCount = 0;
4007 pSMB->DataOffset = 0;
4008 pSMB->MaxParameterCount = 0;
4009 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4010 pSMB->MaxSetupCount = 0;
4011 pSMB->Reserved = 0;
4012 pSMB->Flags = 0;
4013 pSMB->Timeout = 0;
4014 pSMB->Reserved2 = 0;
4015 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004016 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004017 pSMB->SetupCount = 1;
4018 pSMB->Reserved3 = 0;
4019 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
4020 byte_count = params + 3 /* pad */ ;
4021 pSMB->ParameterCount = cpu_to_le16(params);
4022 pSMB->TotalParameterCount = pSMB->ParameterCount;
4023 pSMB->MaxReferralLevel = cpu_to_le16(3);
4024 pSMB->hdr.smb_buf_length += byte_count;
4025 pSMB->ByteCount = cpu_to_le16(byte_count);
4026
4027 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
4028 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4029 if (rc) {
4030 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
4031 } else { /* decode response */
4032/* BB Add logic to parse referrals here */
4033 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4034
Steve French50c2f752007-07-13 00:33:32 +00004035 /* BB Also check if enough total bytes returned? */
4036 if (rc || (pSMBr->ByteCount < 17))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037 rc = -EIO; /* bad smb */
4038 else {
Steve French50c2f752007-07-13 00:33:32 +00004039 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
4041
4042 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00004043 ("Decoding GetDFSRefer response BCC: %d Offset %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044 pSMBr->ByteCount, data_offset));
Steve French50c2f752007-07-13 00:33:32 +00004045 referrals =
4046 (struct dfs_referral_level_3 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004047 (8 /* sizeof start of data block */ +
4048 data_offset +
Steve French50c2f752007-07-13 00:33:32 +00004049 (char *) &pSMBr->hdr.Protocol);
Steve Frenchc18c8422007-07-18 23:21:09 +00004050 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
Steve French63135e02007-07-17 17:34:02 +00004051 "for referral one refer size: 0x%x srv "
4052 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
Steve French50c2f752007-07-13 00:33:32 +00004053 le16_to_cpu(pSMBr->NumberOfReferrals),
4054 le16_to_cpu(pSMBr->DFSFlags),
4055 le16_to_cpu(referrals->ReferralSize),
4056 le16_to_cpu(referrals->ServerType),
4057 le16_to_cpu(referrals->ReferralFlags),
4058 le16_to_cpu(referrals->TimeToLive)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 /* BB This field is actually two bytes in from start of
4060 data block so we could do safety check that DataBlock
4061 begins at address of pSMBr->NumberOfReferrals */
Steve French50c2f752007-07-13 00:33:32 +00004062 *number_of_UNC_in_array =
4063 le16_to_cpu(pSMBr->NumberOfReferrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004064
4065 /* BB Fix below so can return more than one referral */
Steve French790fe572007-07-07 19:25:05 +00004066 if (*number_of_UNC_in_array > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004067 *number_of_UNC_in_array = 1;
4068
4069 /* get the length of the strings describing refs */
4070 name_len = 0;
Steve French50c2f752007-07-13 00:33:32 +00004071 for (i = 0; i < *number_of_UNC_in_array; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 /* make sure that DfsPathOffset not past end */
Steve French50c2f752007-07-13 00:33:32 +00004073 __u16 offset =
4074 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004075 if (offset > data_count) {
Steve French50c2f752007-07-13 00:33:32 +00004076 /* if invalid referral, stop here and do
Linus Torvalds1da177e2005-04-16 15:20:36 -07004077 not try to copy any more */
4078 *number_of_UNC_in_array = i;
4079 break;
Steve French50c2f752007-07-13 00:33:32 +00004080 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 temp = ((char *)referrals) + offset;
4082
4083 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00004084 name_len += UniStrnlen((wchar_t *)temp,
4085 data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004086 } else {
Steve French50c2f752007-07-13 00:33:32 +00004087 name_len += strnlen(temp, data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088 }
4089 referrals++;
Steve French50c2f752007-07-13 00:33:32 +00004090 /* BB add check that referral pointer does
4091 not fall off end PDU */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092 }
4093 /* BB add check for name_len bigger than bcc */
Steve French50c2f752007-07-13 00:33:32 +00004094 *targetUNCs =
4095 kmalloc(name_len+1+(*number_of_UNC_in_array),
4096 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00004097 if (*targetUNCs == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098 rc = -ENOMEM;
4099 goto GetDFSRefExit;
4100 }
4101 /* copy the ref strings */
Steve French50c2f752007-07-13 00:33:32 +00004102 referrals = (struct dfs_referral_level_3 *)
4103 (8 /* sizeof data hdr */ + data_offset +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 (char *) &pSMBr->hdr.Protocol);
4105
Steve French50c2f752007-07-13 00:33:32 +00004106 for (i = 0; i < *number_of_UNC_in_array; i++) {
4107 temp = ((char *)referrals) +
4108 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4110 cifs_strfromUCS_le(*targetUNCs,
Steve French50c2f752007-07-13 00:33:32 +00004111 (__le16 *) temp,
4112 name_len,
4113 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114 } else {
Steve French50c2f752007-07-13 00:33:32 +00004115 strncpy(*targetUNCs, temp, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116 }
4117 /* BB update target_uncs pointers */
4118 referrals++;
4119 }
4120 temp = *targetUNCs;
4121 temp[name_len] = 0;
4122 }
4123
4124 }
4125GetDFSRefExit:
4126 if (pSMB)
4127 cifs_buf_release(pSMB);
4128
4129 if (rc == -EAGAIN)
4130 goto getDFSRetry;
4131
4132 return rc;
4133}
4134
Steve French20962432005-09-21 22:05:57 -07004135/* Query File System Info such as free space to old servers such as Win 9x */
4136int
4137SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4138{
4139/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4140 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4141 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4142 FILE_SYSTEM_ALLOC_INFO *response_data;
4143 int rc = 0;
4144 int bytes_returned = 0;
4145 __u16 params, byte_count;
4146
4147 cFYI(1, ("OldQFSInfo"));
4148oldQFSInfoRetry:
4149 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4150 (void **) &pSMBr);
4151 if (rc)
4152 return rc;
Steve French20962432005-09-21 22:05:57 -07004153
4154 params = 2; /* level */
4155 pSMB->TotalDataCount = 0;
4156 pSMB->MaxParameterCount = cpu_to_le16(2);
4157 pSMB->MaxDataCount = cpu_to_le16(1000);
4158 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(
4167 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4168 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_INFO_ALLOCATION);
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) {
4180 cFYI(1, ("Send error in QFSInfo = %d", rc));
4181 } else { /* decode response */
4182 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4183
4184 if (rc || (pSMBr->ByteCount < 18))
4185 rc = -EIO; /* bad smb */
4186 else {
4187 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004188 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004189 pSMBr->ByteCount, data_offset));
4190
Steve French50c2f752007-07-13 00:33:32 +00004191 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004192 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4193 FSData->f_bsize =
4194 le16_to_cpu(response_data->BytesPerSector) *
4195 le32_to_cpu(response_data->
4196 SectorsPerAllocationUnit);
4197 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004198 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004199 FSData->f_bfree = FSData->f_bavail =
4200 le32_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 oldQFSInfoRetry;
4212
4213 return rc;
4214}
4215
Linus Torvalds1da177e2005-04-16 15:20:36 -07004216int
Steve French737b7582005-04-28 22:41:06 -07004217CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218{
4219/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4220 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4221 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4222 FILE_SYSTEM_INFO *response_data;
4223 int rc = 0;
4224 int bytes_returned = 0;
4225 __u16 params, byte_count;
4226
4227 cFYI(1, ("In QFSInfo"));
4228QFSInfoRetry:
4229 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4230 (void **) &pSMBr);
4231 if (rc)
4232 return rc;
4233
4234 params = 2; /* level */
4235 pSMB->TotalDataCount = 0;
4236 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004237 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 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_SIZE_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) {
Steve French20962432005-09-21 22:05:57 -07004260 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004262 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004263
Steve French20962432005-09-21 22:05:57 -07004264 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265 rc = -EIO; /* bad smb */
4266 else {
4267 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268
4269 response_data =
4270 (FILE_SYSTEM_INFO
4271 *) (((char *) &pSMBr->hdr.Protocol) +
4272 data_offset);
4273 FSData->f_bsize =
4274 le32_to_cpu(response_data->BytesPerSector) *
4275 le32_to_cpu(response_data->
4276 SectorsPerAllocationUnit);
4277 FSData->f_blocks =
4278 le64_to_cpu(response_data->TotalAllocationUnits);
4279 FSData->f_bfree = FSData->f_bavail =
4280 le64_to_cpu(response_data->FreeAllocationUnits);
4281 cFYI(1,
4282 ("Blocks: %lld Free: %lld Block size %ld",
4283 (unsigned long long)FSData->f_blocks,
4284 (unsigned long long)FSData->f_bfree,
4285 FSData->f_bsize));
4286 }
4287 }
4288 cifs_buf_release(pSMB);
4289
4290 if (rc == -EAGAIN)
4291 goto QFSInfoRetry;
4292
4293 return rc;
4294}
4295
4296int
Steve French737b7582005-04-28 22:41:06 -07004297CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298{
4299/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4300 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4301 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4302 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4303 int rc = 0;
4304 int bytes_returned = 0;
4305 __u16 params, byte_count;
4306
4307 cFYI(1, ("In QFSAttributeInfo"));
4308QFSAttributeRetry:
4309 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4310 (void **) &pSMBr);
4311 if (rc)
4312 return rc;
4313
4314 params = 2; /* level */
4315 pSMB->TotalDataCount = 0;
4316 pSMB->MaxParameterCount = cpu_to_le16(2);
4317 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4318 pSMB->MaxSetupCount = 0;
4319 pSMB->Reserved = 0;
4320 pSMB->Flags = 0;
4321 pSMB->Timeout = 0;
4322 pSMB->Reserved2 = 0;
4323 byte_count = params + 1 /* pad */ ;
4324 pSMB->TotalParameterCount = cpu_to_le16(params);
4325 pSMB->ParameterCount = pSMB->TotalParameterCount;
4326 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004327 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 pSMB->DataCount = 0;
4329 pSMB->DataOffset = 0;
4330 pSMB->SetupCount = 1;
4331 pSMB->Reserved3 = 0;
4332 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4333 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4334 pSMB->hdr.smb_buf_length += byte_count;
4335 pSMB->ByteCount = cpu_to_le16(byte_count);
4336
4337 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4338 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4339 if (rc) {
4340 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4341 } else { /* decode response */
4342 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4343
Steve French50c2f752007-07-13 00:33:32 +00004344 if (rc || (pSMBr->ByteCount < 13)) {
4345 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 rc = -EIO; /* bad smb */
4347 } else {
4348 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4349 response_data =
4350 (FILE_SYSTEM_ATTRIBUTE_INFO
4351 *) (((char *) &pSMBr->hdr.Protocol) +
4352 data_offset);
4353 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004354 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004355 }
4356 }
4357 cifs_buf_release(pSMB);
4358
4359 if (rc == -EAGAIN)
4360 goto QFSAttributeRetry;
4361
4362 return rc;
4363}
4364
4365int
Steve French737b7582005-04-28 22:41:06 -07004366CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367{
4368/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4369 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4370 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4371 FILE_SYSTEM_DEVICE_INFO *response_data;
4372 int rc = 0;
4373 int bytes_returned = 0;
4374 __u16 params, byte_count;
4375
4376 cFYI(1, ("In QFSDeviceInfo"));
4377QFSDeviceRetry:
4378 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4379 (void **) &pSMBr);
4380 if (rc)
4381 return rc;
4382
4383 params = 2; /* level */
4384 pSMB->TotalDataCount = 0;
4385 pSMB->MaxParameterCount = cpu_to_le16(2);
4386 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4387 pSMB->MaxSetupCount = 0;
4388 pSMB->Reserved = 0;
4389 pSMB->Flags = 0;
4390 pSMB->Timeout = 0;
4391 pSMB->Reserved2 = 0;
4392 byte_count = params + 1 /* pad */ ;
4393 pSMB->TotalParameterCount = cpu_to_le16(params);
4394 pSMB->ParameterCount = pSMB->TotalParameterCount;
4395 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004396 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004397
4398 pSMB->DataCount = 0;
4399 pSMB->DataOffset = 0;
4400 pSMB->SetupCount = 1;
4401 pSMB->Reserved3 = 0;
4402 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4403 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4404 pSMB->hdr.smb_buf_length += byte_count;
4405 pSMB->ByteCount = cpu_to_le16(byte_count);
4406
4407 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4408 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4409 if (rc) {
4410 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4411 } else { /* decode response */
4412 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4413
Steve French630f3f0c2007-10-25 21:17:17 +00004414 if (rc || (pSMBr->ByteCount < sizeof(FILE_SYSTEM_DEVICE_INFO)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 rc = -EIO; /* bad smb */
4416 else {
4417 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4418 response_data =
Steve French737b7582005-04-28 22:41:06 -07004419 (FILE_SYSTEM_DEVICE_INFO *)
4420 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004421 data_offset);
4422 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004423 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 }
4425 }
4426 cifs_buf_release(pSMB);
4427
4428 if (rc == -EAGAIN)
4429 goto QFSDeviceRetry;
4430
4431 return rc;
4432}
4433
4434int
Steve French737b7582005-04-28 22:41:06 -07004435CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436{
4437/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4438 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4439 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4440 FILE_SYSTEM_UNIX_INFO *response_data;
4441 int rc = 0;
4442 int bytes_returned = 0;
4443 __u16 params, byte_count;
4444
4445 cFYI(1, ("In QFSUnixInfo"));
4446QFSUnixRetry:
4447 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4448 (void **) &pSMBr);
4449 if (rc)
4450 return rc;
4451
4452 params = 2; /* level */
4453 pSMB->TotalDataCount = 0;
4454 pSMB->DataCount = 0;
4455 pSMB->DataOffset = 0;
4456 pSMB->MaxParameterCount = cpu_to_le16(2);
4457 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4458 pSMB->MaxSetupCount = 0;
4459 pSMB->Reserved = 0;
4460 pSMB->Flags = 0;
4461 pSMB->Timeout = 0;
4462 pSMB->Reserved2 = 0;
4463 byte_count = params + 1 /* pad */ ;
4464 pSMB->ParameterCount = cpu_to_le16(params);
4465 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004466 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4467 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004468 pSMB->SetupCount = 1;
4469 pSMB->Reserved3 = 0;
4470 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4471 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4472 pSMB->hdr.smb_buf_length += byte_count;
4473 pSMB->ByteCount = cpu_to_le16(byte_count);
4474
4475 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4476 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4477 if (rc) {
4478 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4479 } else { /* decode response */
4480 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4481
4482 if (rc || (pSMBr->ByteCount < 13)) {
4483 rc = -EIO; /* bad smb */
4484 } else {
4485 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4486 response_data =
4487 (FILE_SYSTEM_UNIX_INFO
4488 *) (((char *) &pSMBr->hdr.Protocol) +
4489 data_offset);
4490 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004491 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004492 }
4493 }
4494 cifs_buf_release(pSMB);
4495
4496 if (rc == -EAGAIN)
4497 goto QFSUnixRetry;
4498
4499
4500 return rc;
4501}
4502
Jeremy Allisonac670552005-06-22 17:26:35 -07004503int
Steve French45abc6e2005-06-23 13:42:03 -05004504CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004505{
4506/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4507 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4508 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4509 int rc = 0;
4510 int bytes_returned = 0;
4511 __u16 params, param_offset, offset, byte_count;
4512
4513 cFYI(1, ("In SETFSUnixInfo"));
4514SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004515 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004516 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4517 (void **) &pSMBr);
4518 if (rc)
4519 return rc;
4520
4521 params = 4; /* 2 bytes zero followed by info level. */
4522 pSMB->MaxSetupCount = 0;
4523 pSMB->Reserved = 0;
4524 pSMB->Flags = 0;
4525 pSMB->Timeout = 0;
4526 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004527 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4528 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004529 offset = param_offset + params;
4530
4531 pSMB->MaxParameterCount = cpu_to_le16(4);
4532 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4533 pSMB->SetupCount = 1;
4534 pSMB->Reserved3 = 0;
4535 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4536 byte_count = 1 /* pad */ + params + 12;
4537
4538 pSMB->DataCount = cpu_to_le16(12);
4539 pSMB->ParameterCount = cpu_to_le16(params);
4540 pSMB->TotalDataCount = pSMB->DataCount;
4541 pSMB->TotalParameterCount = pSMB->ParameterCount;
4542 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4543 pSMB->DataOffset = cpu_to_le16(offset);
4544
4545 /* Params. */
4546 pSMB->FileNum = 0;
4547 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4548
4549 /* Data. */
4550 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4551 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4552 pSMB->ClientUnixCap = cpu_to_le64(cap);
4553
4554 pSMB->hdr.smb_buf_length += byte_count;
4555 pSMB->ByteCount = cpu_to_le16(byte_count);
4556
4557 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4558 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4559 if (rc) {
4560 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4561 } else { /* decode response */
4562 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4563 if (rc) {
4564 rc = -EIO; /* bad smb */
4565 }
4566 }
4567 cifs_buf_release(pSMB);
4568
4569 if (rc == -EAGAIN)
4570 goto SETFSUnixRetry;
4571
4572 return rc;
4573}
4574
4575
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576
4577int
4578CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004579 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004580{
4581/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4582 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4583 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4584 FILE_SYSTEM_POSIX_INFO *response_data;
4585 int rc = 0;
4586 int bytes_returned = 0;
4587 __u16 params, byte_count;
4588
4589 cFYI(1, ("In QFSPosixInfo"));
4590QFSPosixRetry:
4591 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4592 (void **) &pSMBr);
4593 if (rc)
4594 return rc;
4595
4596 params = 2; /* level */
4597 pSMB->TotalDataCount = 0;
4598 pSMB->DataCount = 0;
4599 pSMB->DataOffset = 0;
4600 pSMB->MaxParameterCount = cpu_to_le16(2);
4601 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4602 pSMB->MaxSetupCount = 0;
4603 pSMB->Reserved = 0;
4604 pSMB->Flags = 0;
4605 pSMB->Timeout = 0;
4606 pSMB->Reserved2 = 0;
4607 byte_count = params + 1 /* pad */ ;
4608 pSMB->ParameterCount = cpu_to_le16(params);
4609 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004610 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4611 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 pSMB->SetupCount = 1;
4613 pSMB->Reserved3 = 0;
4614 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4615 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4616 pSMB->hdr.smb_buf_length += byte_count;
4617 pSMB->ByteCount = cpu_to_le16(byte_count);
4618
4619 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4620 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4621 if (rc) {
4622 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4623 } else { /* decode response */
4624 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4625
4626 if (rc || (pSMBr->ByteCount < 13)) {
4627 rc = -EIO; /* bad smb */
4628 } else {
4629 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4630 response_data =
4631 (FILE_SYSTEM_POSIX_INFO
4632 *) (((char *) &pSMBr->hdr.Protocol) +
4633 data_offset);
4634 FSData->f_bsize =
4635 le32_to_cpu(response_data->BlockSize);
4636 FSData->f_blocks =
4637 le64_to_cpu(response_data->TotalBlocks);
4638 FSData->f_bfree =
4639 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004640 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004641 FSData->f_bavail = FSData->f_bfree;
4642 } else {
4643 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004644 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645 }
Steve French790fe572007-07-07 19:25:05 +00004646 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004648 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004649 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004651 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652 }
4653 }
4654 cifs_buf_release(pSMB);
4655
4656 if (rc == -EAGAIN)
4657 goto QFSPosixRetry;
4658
4659 return rc;
4660}
4661
4662
Steve French50c2f752007-07-13 00:33:32 +00004663/* We can not use write of zero bytes trick to
4664 set file size due to need for large file support. Also note that
4665 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 routine which is only needed to work around a sharing violation bug
4667 in Samba which this routine can run into */
4668
4669int
4670CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004671 __u64 size, int SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004672 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673{
4674 struct smb_com_transaction2_spi_req *pSMB = NULL;
4675 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4676 struct file_end_of_file_info *parm_data;
4677 int name_len;
4678 int rc = 0;
4679 int bytes_returned = 0;
4680 __u16 params, byte_count, data_count, param_offset, offset;
4681
4682 cFYI(1, ("In SetEOF"));
4683SetEOFRetry:
4684 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4685 (void **) &pSMBr);
4686 if (rc)
4687 return rc;
4688
4689 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4690 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004691 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004692 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693 name_len++; /* trailing null */
4694 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004695 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696 name_len = strnlen(fileName, PATH_MAX);
4697 name_len++; /* trailing null */
4698 strncpy(pSMB->FileName, fileName, name_len);
4699 }
4700 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004701 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004703 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704 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_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004710 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004712 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004713 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4714 pSMB->InformationLevel =
4715 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4716 else
4717 pSMB->InformationLevel =
4718 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4719 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004720 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4721 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004722 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723 else
4724 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004725 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726 }
4727
4728 parm_data =
4729 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4730 offset);
4731 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4732 pSMB->DataOffset = cpu_to_le16(offset);
4733 pSMB->SetupCount = 1;
4734 pSMB->Reserved3 = 0;
4735 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4736 byte_count = 3 /* pad */ + params + data_count;
4737 pSMB->DataCount = cpu_to_le16(data_count);
4738 pSMB->TotalDataCount = pSMB->DataCount;
4739 pSMB->ParameterCount = cpu_to_le16(params);
4740 pSMB->TotalParameterCount = pSMB->ParameterCount;
4741 pSMB->Reserved4 = 0;
4742 pSMB->hdr.smb_buf_length += byte_count;
4743 parm_data->FileSize = cpu_to_le64(size);
4744 pSMB->ByteCount = cpu_to_le16(byte_count);
4745 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4746 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4747 if (rc) {
4748 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4749 }
4750
4751 cifs_buf_release(pSMB);
4752
4753 if (rc == -EAGAIN)
4754 goto SetEOFRetry;
4755
4756 return rc;
4757}
4758
4759int
Steve French50c2f752007-07-13 00:33:32 +00004760CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4761 __u16 fid, __u32 pid_of_opener, int SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762{
4763 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764 char *data_offset;
4765 struct file_end_of_file_info *parm_data;
4766 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 __u16 params, param_offset, offset, byte_count, count;
4768
4769 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4770 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004771 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4772
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 if (rc)
4774 return rc;
4775
4776 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4777 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004778
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 params = 6;
4780 pSMB->MaxSetupCount = 0;
4781 pSMB->Reserved = 0;
4782 pSMB->Flags = 0;
4783 pSMB->Timeout = 0;
4784 pSMB->Reserved2 = 0;
4785 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4786 offset = param_offset + params;
4787
Steve French50c2f752007-07-13 00:33:32 +00004788 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789
4790 count = sizeof(struct file_end_of_file_info);
4791 pSMB->MaxParameterCount = cpu_to_le16(2);
4792 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4793 pSMB->SetupCount = 1;
4794 pSMB->Reserved3 = 0;
4795 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4796 byte_count = 3 /* pad */ + params + count;
4797 pSMB->DataCount = cpu_to_le16(count);
4798 pSMB->ParameterCount = cpu_to_le16(params);
4799 pSMB->TotalDataCount = pSMB->DataCount;
4800 pSMB->TotalParameterCount = pSMB->ParameterCount;
4801 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4802 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004803 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4804 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004805 pSMB->DataOffset = cpu_to_le16(offset);
4806 parm_data->FileSize = cpu_to_le64(size);
4807 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004808 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004809 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4810 pSMB->InformationLevel =
4811 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4812 else
4813 pSMB->InformationLevel =
4814 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004815 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4817 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004818 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 else
4820 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004821 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004822 }
4823 pSMB->Reserved4 = 0;
4824 pSMB->hdr.smb_buf_length += byte_count;
4825 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French133672e2007-11-13 22:41:37 +00004826 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 if (rc) {
4828 cFYI(1,
4829 ("Send error in SetFileInfo (SetFileSize) = %d",
4830 rc));
4831 }
4832
Steve French50c2f752007-07-13 00:33:32 +00004833 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834 since file handle passed in no longer valid */
4835
4836 return rc;
4837}
4838
Steve French50c2f752007-07-13 00:33:32 +00004839/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840 an open handle, rather than by pathname - this is awkward due to
4841 potential access conflicts on the open, but it is unavoidable for these
4842 old servers since the only other choice is to go from 100 nanosecond DCE
4843 time and resort to the original setpathinfo level which takes the ancient
4844 DOS time format with 2 second granularity */
4845int
Steve French50c2f752007-07-13 00:33:32 +00004846CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4847 const FILE_BASIC_INFO *data, __u16 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848{
4849 struct smb_com_transaction2_sfi_req *pSMB = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004850 char *data_offset;
4851 int rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 __u16 params, param_offset, offset, byte_count, count;
4853
4854 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004855 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4856
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857 if (rc)
4858 return rc;
4859
4860 /* At this point there is no need to override the current pid
4861 with the pid of the opener, but that could change if we someday
4862 use an existing handle (rather than opening one on the fly) */
4863 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4864 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
Steve French50c2f752007-07-13 00:33:32 +00004865
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 params = 6;
4867 pSMB->MaxSetupCount = 0;
4868 pSMB->Reserved = 0;
4869 pSMB->Flags = 0;
4870 pSMB->Timeout = 0;
4871 pSMB->Reserved2 = 0;
4872 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4873 offset = param_offset + params;
4874
Steve French50c2f752007-07-13 00:33:32 +00004875 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876
Steve French26f57362007-08-30 22:09:15 +00004877 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004878 pSMB->MaxParameterCount = cpu_to_le16(2);
4879 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4880 pSMB->SetupCount = 1;
4881 pSMB->Reserved3 = 0;
4882 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4883 byte_count = 3 /* pad */ + params + count;
4884 pSMB->DataCount = cpu_to_le16(count);
4885 pSMB->ParameterCount = cpu_to_le16(params);
4886 pSMB->TotalDataCount = pSMB->DataCount;
4887 pSMB->TotalParameterCount = pSMB->ParameterCount;
4888 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4889 pSMB->DataOffset = cpu_to_le16(offset);
4890 pSMB->Fid = fid;
4891 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4892 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4893 else
4894 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4895 pSMB->Reserved4 = 0;
4896 pSMB->hdr.smb_buf_length += byte_count;
4897 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004898 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Steve French133672e2007-11-13 22:41:37 +00004899 rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *) pSMB, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900 if (rc) {
Steve French50c2f752007-07-13 00:33:32 +00004901 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004902 }
4903
Steve French50c2f752007-07-13 00:33:32 +00004904 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004905 since file handle passed in no longer valid */
4906
4907 return rc;
4908}
4909
4910
4911int
4912CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004913 const FILE_BASIC_INFO *data,
Steve French737b7582005-04-28 22:41:06 -07004914 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004915{
4916 TRANSACTION2_SPI_REQ *pSMB = NULL;
4917 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4918 int name_len;
4919 int rc = 0;
4920 int bytes_returned = 0;
4921 char *data_offset;
4922 __u16 params, param_offset, offset, byte_count, count;
4923
4924 cFYI(1, ("In SetTimes"));
4925
4926SetTimesRetry:
4927 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4928 (void **) &pSMBr);
4929 if (rc)
4930 return rc;
4931
4932 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4933 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004934 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004935 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004936 name_len++; /* trailing null */
4937 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004938 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004939 name_len = strnlen(fileName, PATH_MAX);
4940 name_len++; /* trailing null */
4941 strncpy(pSMB->FileName, fileName, name_len);
4942 }
4943
4944 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004945 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946 pSMB->MaxParameterCount = cpu_to_le16(2);
4947 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4948 pSMB->MaxSetupCount = 0;
4949 pSMB->Reserved = 0;
4950 pSMB->Flags = 0;
4951 pSMB->Timeout = 0;
4952 pSMB->Reserved2 = 0;
4953 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004954 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955 offset = param_offset + params;
4956 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4957 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4958 pSMB->DataOffset = cpu_to_le16(offset);
4959 pSMB->SetupCount = 1;
4960 pSMB->Reserved3 = 0;
4961 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4962 byte_count = 3 /* pad */ + params + count;
4963
4964 pSMB->DataCount = cpu_to_le16(count);
4965 pSMB->ParameterCount = cpu_to_le16(params);
4966 pSMB->TotalDataCount = pSMB->DataCount;
4967 pSMB->TotalParameterCount = pSMB->ParameterCount;
4968 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4969 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4970 else
4971 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4972 pSMB->Reserved4 = 0;
4973 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00004974 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004975 pSMB->ByteCount = cpu_to_le16(byte_count);
4976 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4977 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4978 if (rc) {
4979 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4980 }
4981
4982 cifs_buf_release(pSMB);
4983
4984 if (rc == -EAGAIN)
4985 goto SetTimesRetry;
4986
4987 return rc;
4988}
4989
4990/* Can not be used to set time stamps yet (due to old DOS time format) */
4991/* Can be used to set attributes */
4992#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4993 handling it anyway and NT4 was what we thought it would be needed for
4994 Do not delete it until we prove whether needed for Win9x though */
4995int
4996CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4997 __u16 dos_attrs, const struct nls_table *nls_codepage)
4998{
4999 SETATTR_REQ *pSMB = NULL;
5000 SETATTR_RSP *pSMBr = NULL;
5001 int rc = 0;
5002 int bytes_returned;
5003 int name_len;
5004
5005 cFYI(1, ("In SetAttrLegacy"));
5006
5007SetAttrLgcyRetry:
5008 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
5009 (void **) &pSMBr);
5010 if (rc)
5011 return rc;
5012
5013 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5014 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005015 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016 PATH_MAX, nls_codepage);
5017 name_len++; /* trailing null */
5018 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005019 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005020 name_len = strnlen(fileName, PATH_MAX);
5021 name_len++; /* trailing null */
5022 strncpy(pSMB->fileName, fileName, name_len);
5023 }
5024 pSMB->attr = cpu_to_le16(dos_attrs);
5025 pSMB->BufferFormat = 0x04;
5026 pSMB->hdr.smb_buf_length += name_len + 1;
5027 pSMB->ByteCount = cpu_to_le16(name_len + 1);
5028 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5029 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5030 if (rc) {
5031 cFYI(1, ("Error in LegacySetAttr = %d", rc));
5032 }
5033
5034 cifs_buf_release(pSMB);
5035
5036 if (rc == -EAGAIN)
5037 goto SetAttrLgcyRetry;
5038
5039 return rc;
5040}
5041#endif /* temporarily unneeded SetAttr legacy function */
5042
5043int
5044CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00005045 char *fileName, __u64 mode, __u64 uid, __u64 gid,
5046 dev_t device, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07005047 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005048{
5049 TRANSACTION2_SPI_REQ *pSMB = NULL;
5050 TRANSACTION2_SPI_RSP *pSMBr = NULL;
5051 int name_len;
5052 int rc = 0;
5053 int bytes_returned = 0;
5054 FILE_UNIX_BASIC_INFO *data_offset;
5055 __u16 params, param_offset, offset, count, byte_count;
5056
5057 cFYI(1, ("In SetUID/GID/Mode"));
5058setPermsRetry:
5059 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5060 (void **) &pSMBr);
5061 if (rc)
5062 return rc;
5063
5064 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5065 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005066 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005067 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068 name_len++; /* trailing null */
5069 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005070 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005071 name_len = strnlen(fileName, PATH_MAX);
5072 name_len++; /* trailing null */
5073 strncpy(pSMB->FileName, fileName, name_len);
5074 }
5075
5076 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005077 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005078 pSMB->MaxParameterCount = cpu_to_le16(2);
5079 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
5080 pSMB->MaxSetupCount = 0;
5081 pSMB->Reserved = 0;
5082 pSMB->Flags = 0;
5083 pSMB->Timeout = 0;
5084 pSMB->Reserved2 = 0;
5085 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005086 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087 offset = param_offset + params;
5088 data_offset =
5089 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5090 offset);
5091 memset(data_offset, 0, count);
5092 pSMB->DataOffset = cpu_to_le16(offset);
5093 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5094 pSMB->SetupCount = 1;
5095 pSMB->Reserved3 = 0;
5096 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5097 byte_count = 3 /* pad */ + params + count;
5098 pSMB->ParameterCount = cpu_to_le16(params);
5099 pSMB->DataCount = cpu_to_le16(count);
5100 pSMB->TotalParameterCount = pSMB->ParameterCount;
5101 pSMB->TotalDataCount = pSMB->DataCount;
5102 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5103 pSMB->Reserved4 = 0;
5104 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005105 /* Samba server ignores set of file size to zero due to bugs in some
5106 older clients, but we should be precise - we use SetFileSize to
5107 set file size and do not want to truncate file size to zero
5108 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005109 zero instead of -1 here */
Steve Frenchc7af1852007-03-01 04:11:22 +00005110 data_offset->EndOfFile = NO_CHANGE_64;
5111 data_offset->NumOfBytes = NO_CHANGE_64;
5112 data_offset->LastStatusChange = NO_CHANGE_64;
5113 data_offset->LastAccessTime = NO_CHANGE_64;
5114 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005115 data_offset->Uid = cpu_to_le64(uid);
5116 data_offset->Gid = cpu_to_le64(gid);
5117 /* better to leave device as zero when it is */
5118 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5119 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5120 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005121
Steve French790fe572007-07-07 19:25:05 +00005122 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005123 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005124 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005125 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005126 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005127 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005128 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005129 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005130 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005131 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005132 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005134 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005135 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5136
5137
5138 pSMB->ByteCount = cpu_to_le16(byte_count);
5139 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5140 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5141 if (rc) {
5142 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5143 }
5144
5145 if (pSMB)
5146 cifs_buf_release(pSMB);
5147 if (rc == -EAGAIN)
5148 goto setPermsRetry;
5149 return rc;
5150}
5151
Steve French50c2f752007-07-13 00:33:32 +00005152int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005153 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005154 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005155 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156{
5157 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005158 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5159 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005160 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005161 int bytes_returned;
5162
Steve French50c2f752007-07-13 00:33:32 +00005163 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005164 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005165 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166 if (rc)
5167 return rc;
5168
5169 pSMB->TotalParameterCount = 0 ;
5170 pSMB->TotalDataCount = 0;
5171 pSMB->MaxParameterCount = cpu_to_le32(2);
5172 /* BB find exact data count max from sess structure BB */
5173 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005174/* BB VERIFY verify which is correct for above BB */
5175 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5176 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5177
Linus Torvalds1da177e2005-04-16 15:20:36 -07005178 pSMB->MaxSetupCount = 4;
5179 pSMB->Reserved = 0;
5180 pSMB->ParameterOffset = 0;
5181 pSMB->DataCount = 0;
5182 pSMB->DataOffset = 0;
5183 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5184 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5185 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005186 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005187 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5188 pSMB->Reserved2 = 0;
5189 pSMB->CompletionFilter = cpu_to_le32(filter);
5190 pSMB->Fid = netfid; /* file handle always le */
5191 pSMB->ByteCount = 0;
5192
5193 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French133672e2007-11-13 22:41:37 +00005194 (struct smb_hdr *)pSMBr, &bytes_returned,
5195 CIFS_ASYNC_OP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005196 if (rc) {
5197 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005198 } else {
5199 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005200 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005201 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005202 sizeof(struct dir_notify_req),
5203 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005204 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005205 dnotify_req->Pid = pSMB->hdr.Pid;
5206 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5207 dnotify_req->Mid = pSMB->hdr.Mid;
5208 dnotify_req->Tid = pSMB->hdr.Tid;
5209 dnotify_req->Uid = pSMB->hdr.Uid;
5210 dnotify_req->netfid = netfid;
5211 dnotify_req->pfile = pfile;
5212 dnotify_req->filter = filter;
5213 dnotify_req->multishot = multishot;
5214 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005215 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005216 &GlobalDnotifyReqList);
5217 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005218 } else
Steve French47c786e2005-10-11 20:03:18 -07005219 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005220 }
5221 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005222 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223}
5224#ifdef CONFIG_CIFS_XATTR
5225ssize_t
5226CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5227 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005228 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005229 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005230{
5231 /* BB assumes one setup word */
5232 TRANSACTION2_QPI_REQ *pSMB = NULL;
5233 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5234 int rc = 0;
5235 int bytes_returned;
5236 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005237 struct fea *temp_fea;
5238 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005239 __u16 params, byte_count;
5240
5241 cFYI(1, ("In Query All EAs path %s", searchName));
5242QAllEAsRetry:
5243 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5244 (void **) &pSMBr);
5245 if (rc)
5246 return rc;
5247
5248 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5249 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005250 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005251 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005252 name_len++; /* trailing null */
5253 name_len *= 2;
5254 } else { /* BB improve the check for buffer overruns BB */
5255 name_len = strnlen(searchName, PATH_MAX);
5256 name_len++; /* trailing null */
5257 strncpy(pSMB->FileName, searchName, name_len);
5258 }
5259
Steve French50c2f752007-07-13 00:33:32 +00005260 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261 pSMB->TotalDataCount = 0;
5262 pSMB->MaxParameterCount = cpu_to_le16(2);
5263 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5264 pSMB->MaxSetupCount = 0;
5265 pSMB->Reserved = 0;
5266 pSMB->Flags = 0;
5267 pSMB->Timeout = 0;
5268 pSMB->Reserved2 = 0;
5269 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005270 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005271 pSMB->DataCount = 0;
5272 pSMB->DataOffset = 0;
5273 pSMB->SetupCount = 1;
5274 pSMB->Reserved3 = 0;
5275 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5276 byte_count = params + 1 /* pad */ ;
5277 pSMB->TotalParameterCount = cpu_to_le16(params);
5278 pSMB->ParameterCount = pSMB->TotalParameterCount;
5279 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5280 pSMB->Reserved4 = 0;
5281 pSMB->hdr.smb_buf_length += byte_count;
5282 pSMB->ByteCount = cpu_to_le16(byte_count);
5283
5284 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5285 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5286 if (rc) {
5287 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5288 } else { /* decode response */
5289 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5290
5291 /* BB also check enough total bytes returned */
5292 /* BB we need to improve the validity checking
5293 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005294 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005295 rc = -EIO; /* bad smb */
5296 /* else if (pFindData){
5297 memcpy((char *) pFindData,
5298 (char *) &pSMBr->hdr.Protocol +
5299 data_offset, kl);
5300 }*/ else {
5301 /* check that length of list is not more than bcc */
5302 /* check that each entry does not go beyond length
5303 of list */
5304 /* check that each element of each entry does not
5305 go beyond end of list */
5306 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005307 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005308 rc = 0;
5309 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005310 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 ea_response_data = (struct fealist *)
5312 (((char *) &pSMBr->hdr.Protocol) +
5313 data_offset);
5314 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005315 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005316 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005317 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005318 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005319 } else {
5320 /* account for ea list len */
5321 name_len -= 4;
5322 temp_fea = ea_response_data->list;
5323 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005324 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005325 __u16 value_len;
5326 name_len -= 4;
5327 temp_ptr += 4;
5328 rc += temp_fea->name_len;
5329 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005330 rc = rc + 5 + 1;
5331 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005332 memcpy(EAData, "user.", 5);
5333 EAData += 5;
5334 memcpy(EAData, temp_ptr,
5335 temp_fea->name_len);
5336 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005337 /* null terminate name */
5338 *EAData = 0;
5339 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005340 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005341 /* skip copy - calc size only */
5342 } else {
5343 /* stop before overrun buffer */
5344 rc = -ERANGE;
5345 break;
5346 }
5347 name_len -= temp_fea->name_len;
5348 temp_ptr += temp_fea->name_len;
5349 /* account for trailing null */
5350 name_len--;
5351 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005352 value_len =
5353 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005354 name_len -= value_len;
5355 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005356 /* BB check that temp_ptr is still
5357 within the SMB BB*/
5358
5359 /* no trailing null to account for
5360 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361 /* go on to next EA */
5362 temp_fea = (struct fea *)temp_ptr;
5363 }
5364 }
5365 }
5366 }
5367 if (pSMB)
5368 cifs_buf_release(pSMB);
5369 if (rc == -EAGAIN)
5370 goto QAllEAsRetry;
5371
5372 return (ssize_t)rc;
5373}
5374
Steve French50c2f752007-07-13 00:33:32 +00005375ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5376 const unsigned char *searchName, const unsigned char *ea_name,
5377 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005378 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379{
5380 TRANSACTION2_QPI_REQ *pSMB = NULL;
5381 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5382 int rc = 0;
5383 int bytes_returned;
5384 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005385 struct fea *temp_fea;
5386 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005387 __u16 params, byte_count;
5388
5389 cFYI(1, ("In Query EA path %s", searchName));
5390QEARetry:
5391 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5392 (void **) &pSMBr);
5393 if (rc)
5394 return rc;
5395
5396 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5397 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005398 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005399 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005400 name_len++; /* trailing null */
5401 name_len *= 2;
5402 } else { /* BB improve the check for buffer overruns BB */
5403 name_len = strnlen(searchName, PATH_MAX);
5404 name_len++; /* trailing null */
5405 strncpy(pSMB->FileName, searchName, name_len);
5406 }
5407
Steve French50c2f752007-07-13 00:33:32 +00005408 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409 pSMB->TotalDataCount = 0;
5410 pSMB->MaxParameterCount = cpu_to_le16(2);
5411 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5412 pSMB->MaxSetupCount = 0;
5413 pSMB->Reserved = 0;
5414 pSMB->Flags = 0;
5415 pSMB->Timeout = 0;
5416 pSMB->Reserved2 = 0;
5417 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005418 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419 pSMB->DataCount = 0;
5420 pSMB->DataOffset = 0;
5421 pSMB->SetupCount = 1;
5422 pSMB->Reserved3 = 0;
5423 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5424 byte_count = params + 1 /* pad */ ;
5425 pSMB->TotalParameterCount = cpu_to_le16(params);
5426 pSMB->ParameterCount = pSMB->TotalParameterCount;
5427 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5428 pSMB->Reserved4 = 0;
5429 pSMB->hdr.smb_buf_length += byte_count;
5430 pSMB->ByteCount = cpu_to_le16(byte_count);
5431
5432 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5433 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5434 if (rc) {
5435 cFYI(1, ("Send error in Query EA = %d", rc));
5436 } else { /* decode response */
5437 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5438
5439 /* BB also check enough total bytes returned */
5440 /* BB we need to improve the validity checking
5441 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005442 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 rc = -EIO; /* bad smb */
5444 /* else if (pFindData){
5445 memcpy((char *) pFindData,
5446 (char *) &pSMBr->hdr.Protocol +
5447 data_offset, kl);
5448 }*/ else {
5449 /* check that length of list is not more than bcc */
5450 /* check that each entry does not go beyond length
5451 of list */
5452 /* check that each element of each entry does not
5453 go beyond end of list */
5454 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005455 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456 rc = -ENODATA;
5457 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005458 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459 ea_response_data = (struct fealist *)
5460 (((char *) &pSMBr->hdr.Protocol) +
5461 data_offset);
5462 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005463 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005464 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005466 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 } else {
5468 /* account for ea list len */
5469 name_len -= 4;
5470 temp_fea = ea_response_data->list;
5471 temp_ptr = (char *)temp_fea;
5472 /* loop through checking if we have a matching
5473 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005474 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475 __u16 value_len;
5476 name_len -= 4;
5477 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005478 value_len =
5479 le16_to_cpu(temp_fea->value_len);
5480 /* BB validate that value_len falls within SMB,
5481 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005482 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005483 temp_fea->name_len) == 0) {
5484 /* found a match */
5485 rc = value_len;
5486 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005487 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488 memcpy(ea_value,
5489 temp_fea->name+temp_fea->name_len+1,
5490 rc);
Steve French50c2f752007-07-13 00:33:32 +00005491 /* ea values, unlike ea
5492 names, are not null
5493 terminated */
Steve French790fe572007-07-07 19:25:05 +00005494 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005495 /* skip copy - calc size only */
5496 } else {
Steve French50c2f752007-07-13 00:33:32 +00005497 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005498 rc = -ERANGE;
5499 }
5500 break;
5501 }
5502 name_len -= temp_fea->name_len;
5503 temp_ptr += temp_fea->name_len;
5504 /* account for trailing null */
5505 name_len--;
5506 temp_ptr++;
5507 name_len -= value_len;
5508 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005509 /* No trailing null to account for in
5510 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005511 temp_fea = (struct fea *)temp_ptr;
5512 }
Steve French50c2f752007-07-13 00:33:32 +00005513 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005514 }
5515 }
5516 if (pSMB)
5517 cifs_buf_release(pSMB);
5518 if (rc == -EAGAIN)
5519 goto QEARetry;
5520
5521 return (ssize_t)rc;
5522}
5523
5524int
5525CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005526 const char *ea_name, const void *ea_value,
5527 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5528 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005529{
5530 struct smb_com_transaction2_spi_req *pSMB = NULL;
5531 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5532 struct fealist *parm_data;
5533 int name_len;
5534 int rc = 0;
5535 int bytes_returned = 0;
5536 __u16 params, param_offset, byte_count, offset, count;
5537
5538 cFYI(1, ("In SetEA"));
5539SetEARetry:
5540 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5541 (void **) &pSMBr);
5542 if (rc)
5543 return rc;
5544
5545 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5546 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005547 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005548 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005549 name_len++; /* trailing null */
5550 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005551 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552 name_len = strnlen(fileName, PATH_MAX);
5553 name_len++; /* trailing null */
5554 strncpy(pSMB->FileName, fileName, name_len);
5555 }
5556
5557 params = 6 + name_len;
5558
5559 /* done calculating parms using name_len of file name,
5560 now use name_len to calculate length of ea name
5561 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005562 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005563 name_len = 0;
5564 else
Steve French50c2f752007-07-13 00:33:32 +00005565 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005566
Steve Frenchdae5dbdb2007-12-30 23:49:57 +00005567 count = sizeof(*parm_data) + ea_value_len + name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005568 pSMB->MaxParameterCount = cpu_to_le16(2);
5569 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5570 pSMB->MaxSetupCount = 0;
5571 pSMB->Reserved = 0;
5572 pSMB->Flags = 0;
5573 pSMB->Timeout = 0;
5574 pSMB->Reserved2 = 0;
5575 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005576 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005577 offset = param_offset + params;
5578 pSMB->InformationLevel =
5579 cpu_to_le16(SMB_SET_FILE_EA);
5580
5581 parm_data =
5582 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5583 offset);
5584 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5585 pSMB->DataOffset = cpu_to_le16(offset);
5586 pSMB->SetupCount = 1;
5587 pSMB->Reserved3 = 0;
5588 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5589 byte_count = 3 /* pad */ + params + count;
5590 pSMB->DataCount = cpu_to_le16(count);
5591 parm_data->list_len = cpu_to_le32(count);
5592 parm_data->list[0].EA_flags = 0;
5593 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005594 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005595 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005596 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005597 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005598 parm_data->list[0].name[name_len] = 0;
5599 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5600 /* caller ensures that ea_value_len is less than 64K but
5601 we need to ensure that it fits within the smb */
5602
Steve French50c2f752007-07-13 00:33:32 +00005603 /*BB add length check to see if it would fit in
5604 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005605 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5606 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005607 memcpy(parm_data->list[0].name+name_len+1,
5608 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005609
5610 pSMB->TotalDataCount = pSMB->DataCount;
5611 pSMB->ParameterCount = cpu_to_le16(params);
5612 pSMB->TotalParameterCount = pSMB->ParameterCount;
5613 pSMB->Reserved4 = 0;
5614 pSMB->hdr.smb_buf_length += byte_count;
5615 pSMB->ByteCount = cpu_to_le16(byte_count);
5616 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5617 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5618 if (rc) {
5619 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5620 }
5621
5622 cifs_buf_release(pSMB);
5623
5624 if (rc == -EAGAIN)
5625 goto SetEARetry;
5626
5627 return rc;
5628}
5629
5630#endif