blob: 61d24f6ee64ec7b8ac31771f6e01bd77aa5f6caa [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/cifs/cifssmb.c
3 *
Steve French2dd29d32007-04-23 22:07:35 +00004 * Copyright (C) International Business Machines Corp., 2002,2007
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 * Contains the routines for constructing the SMB PDUs themselves
8 *
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c */
25 /* These are mostly routines that operate on a pathname, or on a tree id */
26 /* (mounted volume), but there are eight handle based routines which must be */
Steve French2dd29d32007-04-23 22:07:35 +000027 /* treated slightly differently for reconnection purposes since we never */
28 /* want to reuse a stale file handle and only the caller knows the file info */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#include <linux/fs.h>
31#include <linux/kernel.h>
32#include <linux/vfs.h>
33#include <linux/posix_acl_xattr.h>
34#include <asm/uaccess.h>
35#include "cifspdu.h"
36#include "cifsglob.h"
Shirish Pargaonkard0d66c42007-10-03 18:22:19 +000037#include "cifsacl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include "cifsproto.h"
39#include "cifs_unicode.h"
40#include "cifs_debug.h"
41
42#ifdef CONFIG_CIFS_POSIX
43static struct {
44 int index;
45 char *name;
46} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000047#ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"},
Steve French9ac00b72006-09-30 04:13:17 +000049 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000050#endif /* weak password hashing for legacy clients */
Steve French50c2f752007-07-13 00:33:32 +000051 {CIFS_PROT, "\2NT LM 0.12"},
Steve French39798772006-05-31 22:40:51 +000052 {POSIX_PROT, "\2POSIX 2"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 {BAD_PROT, "\2"}
54};
55#else
56static struct {
57 int index;
58 char *name;
59} protocols[] = {
Steve French39798772006-05-31 22:40:51 +000060#ifdef CONFIG_CIFS_WEAK_PW_HASH
61 {LANMAN_PROT, "\2LM1.2X002"},
Steve French18f75ca2006-10-01 03:13:01 +000062 {LANMAN2_PROT, "\2LANMAN2.1"},
Steve French39798772006-05-31 22:40:51 +000063#endif /* weak password hashing for legacy clients */
Steve French790fe572007-07-07 19:25:05 +000064 {CIFS_PROT, "\2NT LM 0.12"},
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 {BAD_PROT, "\2"}
66};
67#endif
68
Steve French39798772006-05-31 22:40:51 +000069/* define the number of elements in the cifs dialect array */
70#ifdef CONFIG_CIFS_POSIX
71#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000072#define CIFS_NUM_PROT 4
Steve French39798772006-05-31 22:40:51 +000073#else
74#define CIFS_NUM_PROT 2
75#endif /* CIFS_WEAK_PW_HASH */
76#else /* not posix */
77#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French9ac00b72006-09-30 04:13:17 +000078#define CIFS_NUM_PROT 3
Steve French39798772006-05-31 22:40:51 +000079#else
80#define CIFS_NUM_PROT 1
81#endif /* CONFIG_CIFS_WEAK_PW_HASH */
82#endif /* CIFS_POSIX */
83
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85/* Mark as invalid, all open files on tree connections since they
86 were closed when session to server was lost */
Steve French790fe572007-07-07 19:25:05 +000087static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070088{
89 struct cifsFileInfo *open_file = NULL;
Steve French790fe572007-07-07 19:25:05 +000090 struct list_head *tmp;
91 struct list_head *tmp1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
93/* list all files open on tree connection and mark them invalid */
94 write_lock(&GlobalSMBSeslock);
95 list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
Steve French790fe572007-07-07 19:25:05 +000096 open_file = list_entry(tmp, struct cifsFileInfo, tlist);
Steve French26f57362007-08-30 22:09:15 +000097 if (open_file)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 open_file->invalidHandle = TRUE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 }
100 write_unlock(&GlobalSMBSeslock);
Steve French09d1db52005-04-28 22:41:08 -0700101 /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
102 to this tcon */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103}
104
105/* If the return code is zero, this function must fill in request_buf pointer */
106static int
107small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
108 void **request_buf /* returned */)
109{
110 int rc = 0;
111
112 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
113 check for tcp and smb session status done differently
114 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000115 if (tcon) {
116 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800117 /* only tree disconnect, open, and write,
118 (and ulogoff which does not have tcon)
119 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000120 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French50c2f752007-07-13 00:33:32 +0000121 (smb_command != SMB_COM_OPEN_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800122 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000123 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800124 smb_command));
125 return -ENODEV;
126 }
127 }
Steve French790fe572007-07-07 19:25:05 +0000128 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000129 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 struct nls_table *nls_codepage;
Steve French50c2f752007-07-13 00:33:32 +0000131 /* Give Demultiplex thread up to 10 seconds to
Steve French09d1db52005-04-28 22:41:08 -0700132 reconnect, should be greater than cifs socket
133 timeout which is 7 seconds */
Steve Frenchc18c8422007-07-18 23:21:09 +0000134 while (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000135 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve Frenchc18c8422007-07-18 23:21:09 +0000137 (tcon->ses->server->tcpStatus ==
Steve French63135e02007-07-17 17:34:02 +0000138 CifsGood), 10 * HZ);
139 if (tcon->ses->server->tcpStatus ==
140 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 /* on "soft" mounts we wait once */
Steve French790fe572007-07-07 19:25:05 +0000142 if ((tcon->retry == FALSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000144 cFYI(1, ("gave up waiting on "
145 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700147 } /* else "hard" mount - keep retrying
148 until process is killed or server
149 comes back on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 } else /* TCP session is reestablished now */
151 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 }
Steve French50c2f752007-07-13 00:33:32 +0000153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 nls_codepage = load_nls_default();
155 /* need to prevent multiple threads trying to
156 simultaneously reconnect the same SMB session */
157 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000158 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000159 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700160 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000161 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 mark_open_files_invalid(tcon);
Steve French50c2f752007-07-13 00:33:32 +0000163 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
Steve French8af18972007-02-14 04:42:51 +0000164 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 up(&tcon->ses->sesSem);
Steve French8af18972007-02-14 04:42:51 +0000166 /* tell server which Unix caps we support */
167 if (tcon->ses->capabilities & CAP_UNIX)
168 reset_cifs_unix_caps(0 /* no xid */,
Steve French50c2f752007-07-13 00:33:32 +0000169 tcon,
Steve French8af18972007-02-14 04:42:51 +0000170 NULL /* we do not know sb */,
Steve French50c2f752007-07-13 00:33:32 +0000171 NULL /* no vol info */);
Steve French3e844692005-10-03 13:37:24 -0700172 /* BB FIXME add code to check if wsize needs
173 update due to negotiated smb buffer size
174 shrinking */
Steve French790fe572007-07-07 19:25:05 +0000175 if (rc == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 atomic_inc(&tconInfoReconnectCount);
177
178 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000179 /* Removed call to reopen open files here.
180 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700181 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Steve French50c2f752007-07-13 00:33:32 +0000183 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700184 know whether we can continue or not without
185 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000186 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 case SMB_COM_READ_ANDX:
188 case SMB_COM_WRITE_ANDX:
189 case SMB_COM_CLOSE:
190 case SMB_COM_FIND_CLOSE2:
191 case SMB_COM_LOCKING_ANDX: {
192 unload_nls(nls_codepage);
193 return -EAGAIN;
194 }
195 }
196 } else {
197 up(&tcon->ses->sesSem);
198 }
199 unload_nls(nls_codepage);
200
201 } else {
202 return -EIO;
203 }
204 }
Steve French790fe572007-07-07 19:25:05 +0000205 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 return rc;
207
208 *request_buf = cifs_small_buf_get();
209 if (*request_buf == NULL) {
210 /* BB should we add a retry in here if not a writepage? */
211 return -ENOMEM;
212 }
213
Steve French63135e02007-07-17 17:34:02 +0000214 header_assemble((struct smb_hdr *) *request_buf, smb_command,
Steve Frenchc18c8422007-07-18 23:21:09 +0000215 tcon, wct);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
Steve French790fe572007-07-07 19:25:05 +0000217 if (tcon != NULL)
218 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700219
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 return rc;
Steve French5815449d2006-02-14 01:36:20 +0000221}
222
Steve French12b3b8f2006-02-09 21:12:47 +0000223int
Steve French50c2f752007-07-13 00:33:32 +0000224small_smb_init_no_tc(const int smb_command, const int wct,
Steve French5815449d2006-02-14 01:36:20 +0000225 struct cifsSesInfo *ses, void **request_buf)
Steve French12b3b8f2006-02-09 21:12:47 +0000226{
227 int rc;
Steve French50c2f752007-07-13 00:33:32 +0000228 struct smb_hdr *buffer;
Steve French12b3b8f2006-02-09 21:12:47 +0000229
Steve French5815449d2006-02-14 01:36:20 +0000230 rc = small_smb_init(smb_command, wct, NULL, request_buf);
Steve French790fe572007-07-07 19:25:05 +0000231 if (rc)
Steve French12b3b8f2006-02-09 21:12:47 +0000232 return rc;
233
Steve French04fdabe2006-02-10 05:52:50 +0000234 buffer = (struct smb_hdr *)*request_buf;
Steve French12b3b8f2006-02-09 21:12:47 +0000235 buffer->Mid = GetNextMid(ses->server);
236 if (ses->capabilities & CAP_UNICODE)
237 buffer->Flags2 |= SMBFLG2_UNICODE;
Steve French04fdabe2006-02-10 05:52:50 +0000238 if (ses->capabilities & CAP_STATUS32)
Steve French12b3b8f2006-02-09 21:12:47 +0000239 buffer->Flags2 |= SMBFLG2_ERR_STATUS;
240
241 /* uid, tid can stay at zero as set in header assemble */
242
Steve French50c2f752007-07-13 00:33:32 +0000243 /* BB add support for turning on the signing when
Steve French12b3b8f2006-02-09 21:12:47 +0000244 this function is used after 1st of session setup requests */
245
246 return rc;
247}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
249/* If the return code is zero, this function must fill in request_buf pointer */
250static int
251smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
252 void **request_buf /* returned */ ,
253 void **response_buf /* returned */ )
254{
255 int rc = 0;
256
257 /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
258 check for tcp and smb session status done differently
259 for those three - in the calling routine */
Steve French790fe572007-07-07 19:25:05 +0000260 if (tcon) {
261 if (tcon->tidStatus == CifsExiting) {
Steve French6ab16d22005-11-29 20:55:11 -0800262 /* only tree disconnect, open, and write,
263 (and ulogoff which does not have tcon)
264 are allowed as we start force umount */
Steve French790fe572007-07-07 19:25:05 +0000265 if ((smb_command != SMB_COM_WRITE_ANDX) &&
Steve French6ab16d22005-11-29 20:55:11 -0800266 (smb_command != SMB_COM_OPEN_ANDX) &&
267 (smb_command != SMB_COM_TREE_DISCONNECT)) {
Steve French790fe572007-07-07 19:25:05 +0000268 cFYI(1, ("can not send cmd %d while umounting",
Steve French6ab16d22005-11-29 20:55:11 -0800269 smb_command));
270 return -ENODEV;
271 }
272 }
273
Steve French790fe572007-07-07 19:25:05 +0000274 if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
Steve French50c2f752007-07-13 00:33:32 +0000275 (tcon->ses->server)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 struct nls_table *nls_codepage;
Steve French09d1db52005-04-28 22:41:08 -0700277 /* Give Demultiplex thread up to 10 seconds to
278 reconnect, should be greater than cifs socket
279 timeout which is 7 seconds */
Steve French63135e02007-07-17 17:34:02 +0000280 while (tcon->ses->server->tcpStatus ==
281 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 wait_event_interruptible_timeout(tcon->ses->server->response_q,
Steve French63135e02007-07-17 17:34:02 +0000283 (tcon->ses->server->tcpStatus ==
284 CifsGood), 10 * HZ);
Steve French790fe572007-07-07 19:25:05 +0000285 if (tcon->ses->server->tcpStatus ==
Steve French09d1db52005-04-28 22:41:08 -0700286 CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 /* on "soft" mounts we wait once */
Steve French790fe572007-07-07 19:25:05 +0000288 if ((tcon->retry == FALSE) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 (tcon->ses->status == CifsExiting)) {
Steve French50c2f752007-07-13 00:33:32 +0000290 cFYI(1, ("gave up waiting on "
291 "reconnect in smb_init"));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 return -EHOSTDOWN;
Steve French09d1db52005-04-28 22:41:08 -0700293 } /* else "hard" mount - keep retrying
294 until process is killed or server
295 comes on-line */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 } else /* TCP session is reestablished now */
297 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 nls_codepage = load_nls_default();
300 /* need to prevent multiple threads trying to
301 simultaneously reconnect the same SMB session */
302 down(&tcon->ses->sesSem);
Steve French790fe572007-07-07 19:25:05 +0000303 if (tcon->ses->status == CifsNeedReconnect)
Steve French50c2f752007-07-13 00:33:32 +0000304 rc = cifs_setup_session(0, tcon->ses,
Steve French09d1db52005-04-28 22:41:08 -0700305 nls_codepage);
Steve French790fe572007-07-07 19:25:05 +0000306 if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 mark_open_files_invalid(tcon);
Steve French09d1db52005-04-28 22:41:08 -0700308 rc = CIFSTCon(0, tcon->ses, tcon->treeName,
309 tcon, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 up(&tcon->ses->sesSem);
Steve French8af18972007-02-14 04:42:51 +0000311 /* tell server which Unix caps we support */
312 if (tcon->ses->capabilities & CAP_UNIX)
313 reset_cifs_unix_caps(0 /* no xid */,
Steve French50c2f752007-07-13 00:33:32 +0000314 tcon,
Steve French8af18972007-02-14 04:42:51 +0000315 NULL /* do not know sb */,
316 NULL /* no vol info */);
Steve French3e844692005-10-03 13:37:24 -0700317 /* BB FIXME add code to check if wsize needs
318 update due to negotiated smb buffer size
319 shrinking */
Steve French790fe572007-07-07 19:25:05 +0000320 if (rc == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 atomic_inc(&tconInfoReconnectCount);
322
323 cFYI(1, ("reconnect tcon rc = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000324 /* Removed call to reopen open files here.
325 It is safer (and faster) to reopen files
Steve French09d1db52005-04-28 22:41:08 -0700326 one at a time as needed in read and write */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327
Steve French50c2f752007-07-13 00:33:32 +0000328 /* Check if handle based operation so we
Steve French09d1db52005-04-28 22:41:08 -0700329 know whether we can continue or not without
330 returning to caller to reset file handle */
Steve French50c2f752007-07-13 00:33:32 +0000331 switch (smb_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 case SMB_COM_READ_ANDX:
333 case SMB_COM_WRITE_ANDX:
334 case SMB_COM_CLOSE:
335 case SMB_COM_FIND_CLOSE2:
336 case SMB_COM_LOCKING_ANDX: {
337 unload_nls(nls_codepage);
338 return -EAGAIN;
339 }
340 }
341 } else {
342 up(&tcon->ses->sesSem);
343 }
344 unload_nls(nls_codepage);
345
346 } else {
347 return -EIO;
348 }
349 }
Steve French790fe572007-07-07 19:25:05 +0000350 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 return rc;
352
353 *request_buf = cifs_buf_get();
354 if (*request_buf == NULL) {
355 /* BB should we add a retry in here if not a writepage? */
356 return -ENOMEM;
357 }
358 /* Although the original thought was we needed the response buf for */
359 /* potential retries of smb operations it turns out we can determine */
360 /* from the mid flags when the request buffer can be resent without */
361 /* having to use a second distinct buffer for the response */
Steve French790fe572007-07-07 19:25:05 +0000362 if (response_buf)
Steve French50c2f752007-07-13 00:33:32 +0000363 *response_buf = *request_buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
365 header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
366 wct /*wct */ );
367
Steve French790fe572007-07-07 19:25:05 +0000368 if (tcon != NULL)
369 cifs_stats_inc(&tcon->num_smbs_sent);
Steve Frencha4544342005-08-24 13:59:35 -0700370
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 return rc;
372}
373
Steve French50c2f752007-07-13 00:33:32 +0000374static int validate_t2(struct smb_t2_rsp *pSMB)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375{
376 int rc = -EINVAL;
377 int total_size;
Steve French50c2f752007-07-13 00:33:32 +0000378 char *pBCC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380 /* check for plausible wct, bcc and t2 data and parm sizes */
381 /* check for parm and data offset going beyond end of smb */
Steve French790fe572007-07-07 19:25:05 +0000382 if (pSMB->hdr.WordCount >= 10) {
383 if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
385 /* check that bcc is at least as big as parms + data */
386 /* check that bcc is less than negotiated smb buffer */
387 total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
Steve French790fe572007-07-07 19:25:05 +0000388 if (total_size < 512) {
Steve Frenchc18c8422007-07-18 23:21:09 +0000389 total_size +=
Steve French63135e02007-07-17 17:34:02 +0000390 le16_to_cpu(pSMB->t2_rsp.DataCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 /* BCC le converted in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +0000392 pBCC = (pSMB->hdr.WordCount * 2) +
Steve French09d1db52005-04-28 22:41:08 -0700393 sizeof(struct smb_hdr) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 (char *)pSMB;
Steve French790fe572007-07-07 19:25:05 +0000395 if ((total_size <= (*(u16 *)pBCC)) &&
Steve French50c2f752007-07-13 00:33:32 +0000396 (total_size <
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
398 return 0;
399 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 }
401 }
402 }
Steve French50c2f752007-07-13 00:33:32 +0000403 cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 sizeof(struct smb_t2_rsp) + 16);
405 return rc;
406}
407int
408CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
409{
410 NEGOTIATE_REQ *pSMB;
411 NEGOTIATE_RSP *pSMBr;
412 int rc = 0;
413 int bytes_returned;
Steve French39798772006-05-31 22:40:51 +0000414 int i;
Steve French50c2f752007-07-13 00:33:32 +0000415 struct TCP_Server_Info *server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 u16 count;
Steve French750d1152006-06-27 06:28:30 +0000417 unsigned int secFlags;
Al Viro733f99a2006-10-14 16:48:26 +0100418 u16 dialect;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419
Steve French790fe572007-07-07 19:25:05 +0000420 if (ses->server)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421 server = ses->server;
422 else {
423 rc = -EIO;
424 return rc;
425 }
426 rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
427 (void **) &pSMB, (void **) &pSMBr);
428 if (rc)
429 return rc;
Steve French750d1152006-06-27 06:28:30 +0000430
431 /* if any of auth flags (ie not sign or seal) are overriden use them */
Steve French790fe572007-07-07 19:25:05 +0000432 if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
Steve French762e5ab2007-06-28 18:41:42 +0000433 secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
Steve French750d1152006-06-27 06:28:30 +0000434 else /* if override flags set only sign/seal OR them with global auth */
435 secFlags = extended_security | ses->overrideSecFlg;
436
Steve French762e5ab2007-06-28 18:41:42 +0000437 cFYI(1, ("secFlags 0x%x", secFlags));
Steve Frenchf40c5622006-06-28 00:13:38 +0000438
Steve French1982c342005-08-17 12:38:22 -0700439 pSMB->hdr.Mid = GetNextMid(server);
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000440 pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
Steve Frencha0136892007-10-04 20:05:09 +0000441
Yehuda Sadeh Weinraub100c1dd2007-06-05 21:31:16 +0000442 if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
Steve French254e55e2006-06-04 05:53:15 +0000443 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
Steve Frencha0136892007-10-04 20:05:09 +0000444 else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
445 cFYI(1, ("Kerberos only mechanism, enable extended security"));
446 pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
447 }
Steve French50c2f752007-07-13 00:33:32 +0000448
Steve French39798772006-05-31 22:40:51 +0000449 count = 0;
Steve French50c2f752007-07-13 00:33:32 +0000450 for (i = 0; i < CIFS_NUM_PROT; i++) {
Steve French39798772006-05-31 22:40:51 +0000451 strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
452 count += strlen(protocols[i].name) + 1;
453 /* null at end of source and target buffers anyway */
454 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 pSMB->hdr.smb_buf_length += count;
456 pSMB->ByteCount = cpu_to_le16(count);
457
458 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
459 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French50c2f752007-07-13 00:33:32 +0000460 if (rc != 0)
Steve French254e55e2006-06-04 05:53:15 +0000461 goto neg_err_exit;
462
Al Viro733f99a2006-10-14 16:48:26 +0100463 dialect = le16_to_cpu(pSMBr->DialectIndex);
Steve French790fe572007-07-07 19:25:05 +0000464 cFYI(1, ("Dialect: %d", dialect));
Steve French254e55e2006-06-04 05:53:15 +0000465 /* Check wct = 1 error case */
Steve French790fe572007-07-07 19:25:05 +0000466 if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
Steve French254e55e2006-06-04 05:53:15 +0000467 /* core returns wct = 1, but we do not ask for core - otherwise
Steve French50c2f752007-07-13 00:33:32 +0000468 small wct just comes when dialect index is -1 indicating we
Steve French254e55e2006-06-04 05:53:15 +0000469 could not negotiate a common dialect */
470 rc = -EOPNOTSUPP;
471 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000472#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French790fe572007-07-07 19:25:05 +0000473 } else if ((pSMBr->hdr.WordCount == 13)
Al Viro733f99a2006-10-14 16:48:26 +0100474 && ((dialect == LANMAN_PROT)
475 || (dialect == LANMAN2_PROT))) {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000476 __s16 tmp;
Steve French50c2f752007-07-13 00:33:32 +0000477 struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
Steve French254e55e2006-06-04 05:53:15 +0000478
Steve French790fe572007-07-07 19:25:05 +0000479 if ((secFlags & CIFSSEC_MAY_LANMAN) ||
Steve French750d1152006-06-27 06:28:30 +0000480 (secFlags & CIFSSEC_MAY_PLNTXT))
Steve French254e55e2006-06-04 05:53:15 +0000481 server->secType = LANMAN;
482 else {
483 cERROR(1, ("mount failed weak security disabled"
484 " in /proc/fs/cifs/SecurityFlags"));
Steve French39798772006-05-31 22:40:51 +0000485 rc = -EOPNOTSUPP;
486 goto neg_err_exit;
Steve French50c2f752007-07-13 00:33:32 +0000487 }
Steve French254e55e2006-06-04 05:53:15 +0000488 server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
489 server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
490 server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
Steve French39798772006-05-31 22:40:51 +0000491 (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000492 GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
493 /* even though we do not use raw we might as well set this
494 accurately, in case we ever find a need for it */
Steve French790fe572007-07-07 19:25:05 +0000495 if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
Steve French254e55e2006-06-04 05:53:15 +0000496 server->maxRw = 0xFF00;
497 server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
498 } else {
499 server->maxRw = 0;/* we do not need to use raw anyway */
500 server->capabilities = CAP_MPX_MODE;
501 }
Steve Frenchb815f1e52006-10-02 05:53:29 +0000502 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
Steve French1a70d652006-10-02 05:59:18 +0000503 if (tmp == -1) {
Steve French25ee4a92006-09-30 00:54:23 +0000504 /* OS/2 often does not set timezone therefore
505 * we must use server time to calc time zone.
Steve Frenchb815f1e52006-10-02 05:53:29 +0000506 * Could deviate slightly from the right zone.
507 * Smallest defined timezone difference is 15 minutes
508 * (i.e. Nepal). Rounding up/down is done to match
509 * this requirement.
Steve French25ee4a92006-09-30 00:54:23 +0000510 */
Steve Frenchb815f1e52006-10-02 05:53:29 +0000511 int val, seconds, remain, result;
Steve French25ee4a92006-09-30 00:54:23 +0000512 struct timespec ts, utc;
513 utc = CURRENT_TIME;
514 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
515 le16_to_cpu(rsp->SrvTime.Time));
Steve French50c2f752007-07-13 00:33:32 +0000516 cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
517 (int)ts.tv_sec, (int)utc.tv_sec,
Steve French25ee4a92006-09-30 00:54:23 +0000518 (int)(utc.tv_sec - ts.tv_sec)));
Steve Frenchb815f1e52006-10-02 05:53:29 +0000519 val = (int)(utc.tv_sec - ts.tv_sec);
Andre Haupt8594c152007-08-30 20:18:41 +0000520 seconds = abs(val);
Steve French947a5062006-10-02 05:55:25 +0000521 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
Steve Frenchb815f1e52006-10-02 05:53:29 +0000522 remain = seconds % MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000523 if (remain >= (MIN_TZ_ADJ / 2))
Steve Frenchb815f1e52006-10-02 05:53:29 +0000524 result += MIN_TZ_ADJ;
Steve French790fe572007-07-07 19:25:05 +0000525 if (val < 0)
Steve Frenchb815f1e52006-10-02 05:53:29 +0000526 result = - result;
527 server->timeAdj = result;
Steve French25ee4a92006-09-30 00:54:23 +0000528 } else {
Steve Frenchb815f1e52006-10-02 05:53:29 +0000529 server->timeAdj = (int)tmp;
530 server->timeAdj *= 60; /* also in seconds */
Steve French25ee4a92006-09-30 00:54:23 +0000531 }
Steve French790fe572007-07-07 19:25:05 +0000532 cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
Steve French25ee4a92006-09-30 00:54:23 +0000533
Steve French39798772006-05-31 22:40:51 +0000534
Steve French254e55e2006-06-04 05:53:15 +0000535 /* BB get server time for time conversions and add
Steve French50c2f752007-07-13 00:33:32 +0000536 code to use it and timezone since this is not UTC */
Steve French39798772006-05-31 22:40:51 +0000537
Steve French50c2f752007-07-13 00:33:32 +0000538 if (rsp->EncryptionKeyLength ==
Steve French25ee4a92006-09-30 00:54:23 +0000539 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
Steve French254e55e2006-06-04 05:53:15 +0000540 memcpy(server->cryptKey, rsp->EncryptionKey,
541 CIFS_CRYPTO_KEY_SIZE);
542 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
543 rc = -EIO; /* need cryptkey unless plain text */
544 goto neg_err_exit;
545 }
Steve French39798772006-05-31 22:40:51 +0000546
Steve French790fe572007-07-07 19:25:05 +0000547 cFYI(1, ("LANMAN negotiated"));
Steve French254e55e2006-06-04 05:53:15 +0000548 /* we will not end up setting signing flags - as no signing
549 was in LANMAN and server did not return the flags on */
550 goto signing_check;
Steve French7c7b25b2006-06-01 19:20:10 +0000551#else /* weak security disabled */
Steve French790fe572007-07-07 19:25:05 +0000552 } else if (pSMBr->hdr.WordCount == 13) {
Steve French50c2f752007-07-13 00:33:32 +0000553 cERROR(1, ("mount failed, cifs module not built "
Steve French254e55e2006-06-04 05:53:15 +0000554 "with CIFS_WEAK_PW_HASH support"));
Steve French7c7b25b2006-06-01 19:20:10 +0000555 rc = -EOPNOTSUPP;
556#endif /* WEAK_PW_HASH */
Steve French254e55e2006-06-04 05:53:15 +0000557 goto neg_err_exit;
Steve French790fe572007-07-07 19:25:05 +0000558 } else if (pSMBr->hdr.WordCount != 17) {
Steve French254e55e2006-06-04 05:53:15 +0000559 /* unknown wct */
560 rc = -EOPNOTSUPP;
561 goto neg_err_exit;
562 }
563 /* else wct == 17 NTLM */
564 server->secMode = pSMBr->SecurityMode;
Steve French790fe572007-07-07 19:25:05 +0000565 if ((server->secMode & SECMODE_USER) == 0)
566 cFYI(1, ("share mode security"));
Steve French39798772006-05-31 22:40:51 +0000567
Steve French790fe572007-07-07 19:25:05 +0000568 if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000569#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French750d1152006-06-27 06:28:30 +0000570 if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
Steve Frenchbdc4bf6e2006-06-02 22:57:13 +0000571#endif /* CIFS_WEAK_PW_HASH */
Steve French50c2f752007-07-13 00:33:32 +0000572 cERROR(1, ("Server requests plain text password"
Steve French254e55e2006-06-04 05:53:15 +0000573 " but client support disabled"));
Steve French9312f672006-06-04 22:21:07 +0000574
Steve French790fe572007-07-07 19:25:05 +0000575 if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
Steve French254e55e2006-06-04 05:53:15 +0000576 server->secType = NTLMv2;
Steve French790fe572007-07-07 19:25:05 +0000577 else if (secFlags & CIFSSEC_MAY_NTLM)
Steve French254e55e2006-06-04 05:53:15 +0000578 server->secType = NTLM;
Steve French790fe572007-07-07 19:25:05 +0000579 else if (secFlags & CIFSSEC_MAY_NTLMV2)
Steve Frenchf40c5622006-06-28 00:13:38 +0000580 server->secType = NTLMv2;
Steve Frencha0136892007-10-04 20:05:09 +0000581 else if (secFlags & CIFSSEC_MAY_KRB5)
582 server->secType = Kerberos;
583 else if (secFlags & CIFSSEC_MAY_LANMAN)
584 server->secType = LANMAN;
585/* #ifdef CONFIG_CIFS_EXPERIMENTAL
586 else if (secFlags & CIFSSEC_MAY_PLNTXT)
587 server->secType = ??
588#endif */
589 else {
590 rc = -EOPNOTSUPP;
591 cERROR(1, ("Invalid security type"));
592 goto neg_err_exit;
593 }
594 /* else ... any others ...? */
Steve French7c7b25b2006-06-01 19:20:10 +0000595
Steve French254e55e2006-06-04 05:53:15 +0000596 /* one byte, so no need to convert this or EncryptionKeyLen from
597 little endian */
598 server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
599 /* probably no need to store and check maxvcs */
600 server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
Steve French254e55e2006-06-04 05:53:15 +0000602 server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
603 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
604 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
605 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
Steve Frenchb815f1e52006-10-02 05:53:29 +0000606 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
607 server->timeAdj *= 60;
Steve French254e55e2006-06-04 05:53:15 +0000608 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
609 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
610 CIFS_CRYPTO_KEY_SIZE);
611 } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
612 && (pSMBr->EncryptionKeyLength == 0)) {
613 /* decode security blob */
614 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
615 rc = -EIO; /* no crypt key only if plain text pwd */
616 goto neg_err_exit;
617 }
618
619 /* BB might be helpful to save off the domain of server here */
620
Steve French50c2f752007-07-13 00:33:32 +0000621 if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
Steve French254e55e2006-06-04 05:53:15 +0000622 (server->capabilities & CAP_EXTENDED_SECURITY)) {
623 count = pSMBr->ByteCount;
Jeff Laytone187e442007-10-16 17:10:44 +0000624 if (count < 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625 rc = -EIO;
Jeff Laytone187e442007-10-16 17:10:44 +0000626 goto neg_err_exit;
627 }
628
629 if (server->socketUseCount.counter > 1) {
630 if (memcmp(server->server_GUID,
631 pSMBr->u.extended_response.
632 GUID, 16) != 0) {
633 cFYI(1, ("server UID changed"));
Steve French254e55e2006-06-04 05:53:15 +0000634 memcpy(server->server_GUID,
Jeff Laytone187e442007-10-16 17:10:44 +0000635 pSMBr->u.extended_response.GUID,
636 16);
637 }
638 } else
639 memcpy(server->server_GUID,
640 pSMBr->u.extended_response.GUID, 16);
641
642 if (count == 16) {
643 server->secType = RawNTLMSSP;
Steve French254e55e2006-06-04 05:53:15 +0000644 } else {
645 rc = decode_negTokenInit(pSMBr->u.extended_response.
646 SecurityBlob,
647 count - 16,
648 &server->secType);
Steve French790fe572007-07-07 19:25:05 +0000649 if (rc == 1) {
Steve French254e55e2006-06-04 05:53:15 +0000650 /* BB Need to fill struct for sessetup here */
651 rc = -EOPNOTSUPP;
652 } else {
653 rc = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 }
Steve French254e55e2006-06-04 05:53:15 +0000656 } else
657 server->capabilities &= ~CAP_EXTENDED_SECURITY;
658
Steve French6344a422006-06-12 04:18:35 +0000659#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French254e55e2006-06-04 05:53:15 +0000660signing_check:
Steve French6344a422006-06-12 04:18:35 +0000661#endif
Steve French762e5ab2007-06-28 18:41:42 +0000662 if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
663 /* MUST_SIGN already includes the MAY_SIGN FLAG
664 so if this is zero it means that signing is disabled */
665 cFYI(1, ("Signing disabled"));
Steve Frenchabb63d62007-10-18 02:58:40 +0000666 if (server->secMode & SECMODE_SIGN_REQUIRED) {
Steve French762e5ab2007-06-28 18:41:42 +0000667 cERROR(1, ("Server requires "
Jeff Layton7111d212007-10-16 16:50:25 +0000668 "packet signing to be enabled in "
669 "/proc/fs/cifs/SecurityFlags."));
Steve Frenchabb63d62007-10-18 02:58:40 +0000670 rc = -EOPNOTSUPP;
671 }
Steve French50c2f752007-07-13 00:33:32 +0000672 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000673 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Steve French762e5ab2007-06-28 18:41:42 +0000674 } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
675 /* signing required */
Jeff38c10a12007-07-06 21:10:07 +0000676 cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
Steve French762e5ab2007-06-28 18:41:42 +0000677 if ((server->secMode &
678 (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
679 cERROR(1,
680 ("signing required but server lacks support"));
Jeff38c10a12007-07-06 21:10:07 +0000681 rc = -EOPNOTSUPP;
Steve French762e5ab2007-06-28 18:41:42 +0000682 } else
683 server->secMode |= SECMODE_SIGN_REQUIRED;
684 } else {
685 /* signing optional ie CIFSSEC_MAY_SIGN */
Steve French790fe572007-07-07 19:25:05 +0000686 if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
Steve French50c2f752007-07-13 00:33:32 +0000687 server->secMode &=
Steve French254e55e2006-06-04 05:53:15 +0000688 ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 }
Steve French50c2f752007-07-13 00:33:32 +0000690
691neg_err_exit:
Steve French4a6d87f2005-08-13 08:15:54 -0700692 cifs_buf_release(pSMB);
Steve French254e55e2006-06-04 05:53:15 +0000693
Steve French790fe572007-07-07 19:25:05 +0000694 cFYI(1, ("negprot rc %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 return rc;
696}
697
698int
699CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
700{
701 struct smb_hdr *smb_buffer;
702 struct smb_hdr *smb_buffer_response; /* BB removeme BB */
703 int rc = 0;
704 int length;
705
706 cFYI(1, ("In tree disconnect"));
707 /*
708 * If last user of the connection and
709 * connection alive - disconnect it
710 * If this is the last connection on the server session disconnect it
Steve French50c2f752007-07-13 00:33:32 +0000711 * (and inside session disconnect we should check if tcp socket needs
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 * to be freed and kernel thread woken up).
713 */
714 if (tcon)
715 down(&tcon->tconSem);
716 else
717 return -EIO;
718
719 atomic_dec(&tcon->useCount);
720 if (atomic_read(&tcon->useCount) > 0) {
721 up(&tcon->tconSem);
722 return -EBUSY;
723 }
724
Steve French50c2f752007-07-13 00:33:32 +0000725 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 closed on server already e.g. due to tcp session crashing */
Steve French790fe572007-07-07 19:25:05 +0000727 if (tcon->tidStatus == CifsNeedReconnect) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 up(&tcon->tconSem);
Steve French50c2f752007-07-13 00:33:32 +0000729 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 }
731
Steve French790fe572007-07-07 19:25:05 +0000732 if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 up(&tcon->tconSem);
734 return -EIO;
735 }
Steve French50c2f752007-07-13 00:33:32 +0000736 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
Steve French09d1db52005-04-28 22:41:08 -0700737 (void **)&smb_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 if (rc) {
739 up(&tcon->tconSem);
740 return rc;
741 } else {
742 smb_buffer_response = smb_buffer; /* BB removeme BB */
Steve Frenchcd634992005-04-28 22:41:10 -0700743 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
745 &length, 0);
746 if (rc)
Steve French966ca922005-04-28 22:41:08 -0700747 cFYI(1, ("Tree disconnect failed %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748
749 if (smb_buffer)
750 cifs_small_buf_release(smb_buffer);
751 up(&tcon->tconSem);
752
Steve French50c2f752007-07-13 00:33:32 +0000753 /* No need to return error on this operation if tid invalidated and
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 closed on server already e.g. due to tcp session crashing */
755 if (rc == -EAGAIN)
756 rc = 0;
757
758 return rc;
759}
760
761int
762CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
763{
764 struct smb_hdr *smb_buffer_response;
765 LOGOFF_ANDX_REQ *pSMB;
766 int rc = 0;
767 int length;
768
769 cFYI(1, ("In SMBLogoff for session disconnect"));
770 if (ses)
771 down(&ses->sesSem);
772 else
773 return -EIO;
774
775 atomic_dec(&ses->inUse);
776 if (atomic_read(&ses->inUse) > 0) {
777 up(&ses->sesSem);
778 return -EBUSY;
779 }
780 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
781 if (rc) {
782 up(&ses->sesSem);
783 return rc;
784 }
785
786 smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
Steve French50c2f752007-07-13 00:33:32 +0000787
Steve French790fe572007-07-07 19:25:05 +0000788 if (ses->server) {
Steve French1982c342005-08-17 12:38:22 -0700789 pSMB->hdr.Mid = GetNextMid(ses->server);
790
Steve French790fe572007-07-07 19:25:05 +0000791 if (ses->server->secMode &
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
793 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
794 }
795
796 pSMB->hdr.Uid = ses->Suid;
797
798 pSMB->AndXCommand = 0xFF;
799 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
800 smb_buffer_response, &length, 0);
801 if (ses->server) {
802 atomic_dec(&ses->server->socketUseCount);
803 if (atomic_read(&ses->server->socketUseCount) == 0) {
804 spin_lock(&GlobalMid_Lock);
805 ses->server->tcpStatus = CifsExiting;
806 spin_unlock(&GlobalMid_Lock);
807 rc = -ESHUTDOWN;
808 }
809 }
Steve Frencha59c6582005-08-17 12:12:19 -0700810 up(&ses->sesSem);
Steve French4a6d87f2005-08-13 08:15:54 -0700811 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813 /* if session dead then we do not need to do ulogoff,
Steve French50c2f752007-07-13 00:33:32 +0000814 since server closed smb session, no sense reporting
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 error */
816 if (rc == -EAGAIN)
817 rc = 0;
818 return rc;
819}
820
821int
Steve French2d785a52007-07-15 01:48:57 +0000822CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
823 __u16 type, const struct nls_table *nls_codepage, int remap)
824{
825 TRANSACTION2_SPI_REQ *pSMB = NULL;
826 TRANSACTION2_SPI_RSP *pSMBr = NULL;
827 struct unlink_psx_rq *pRqD;
828 int name_len;
829 int rc = 0;
830 int bytes_returned = 0;
831 __u16 params, param_offset, offset, byte_count;
832
833 cFYI(1, ("In POSIX delete"));
834PsxDelete:
835 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
836 (void **) &pSMBr);
837 if (rc)
838 return rc;
839
840 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
841 name_len =
842 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
843 PATH_MAX, nls_codepage, remap);
844 name_len++; /* trailing null */
845 name_len *= 2;
846 } else { /* BB add path length overrun check */
847 name_len = strnlen(fileName, PATH_MAX);
848 name_len++; /* trailing null */
849 strncpy(pSMB->FileName, fileName, name_len);
850 }
851
852 params = 6 + name_len;
853 pSMB->MaxParameterCount = cpu_to_le16(2);
854 pSMB->MaxDataCount = 0; /* BB double check this with jra */
855 pSMB->MaxSetupCount = 0;
856 pSMB->Reserved = 0;
857 pSMB->Flags = 0;
858 pSMB->Timeout = 0;
859 pSMB->Reserved2 = 0;
860 param_offset = offsetof(struct smb_com_transaction2_spi_req,
861 InformationLevel) - 4;
862 offset = param_offset + params;
863
864 /* Setup pointer to Request Data (inode type) */
865 pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
866 pRqD->type = cpu_to_le16(type);
867 pSMB->ParameterOffset = cpu_to_le16(param_offset);
868 pSMB->DataOffset = cpu_to_le16(offset);
869 pSMB->SetupCount = 1;
870 pSMB->Reserved3 = 0;
871 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
872 byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
873
874 pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
875 pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
876 pSMB->ParameterCount = cpu_to_le16(params);
877 pSMB->TotalParameterCount = pSMB->ParameterCount;
878 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
879 pSMB->Reserved4 = 0;
880 pSMB->hdr.smb_buf_length += byte_count;
881 pSMB->ByteCount = cpu_to_le16(byte_count);
882 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
883 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
884 if (rc) {
885 cFYI(1, ("Posix delete returned %d", rc));
886 }
887 cifs_buf_release(pSMB);
888
889 cifs_stats_inc(&tcon->num_deletes);
890
891 if (rc == -EAGAIN)
892 goto PsxDelete;
893
894 return rc;
895}
896
897int
Steve French737b7582005-04-28 22:41:06 -0700898CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
899 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900{
901 DELETE_FILE_REQ *pSMB = NULL;
902 DELETE_FILE_RSP *pSMBr = NULL;
903 int rc = 0;
904 int bytes_returned;
905 int name_len;
906
907DelFileRetry:
908 rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
909 (void **) &pSMBr);
910 if (rc)
911 return rc;
912
913 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
914 name_len =
Steve French50c2f752007-07-13 00:33:32 +0000915 cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
Steve French737b7582005-04-28 22:41:06 -0700916 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 name_len++; /* trailing null */
918 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700919 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 name_len = strnlen(fileName, PATH_MAX);
921 name_len++; /* trailing null */
922 strncpy(pSMB->fileName, fileName, name_len);
923 }
924 pSMB->SearchAttributes =
925 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
926 pSMB->BufferFormat = 0x04;
927 pSMB->hdr.smb_buf_length += name_len + 1;
928 pSMB->ByteCount = cpu_to_le16(name_len + 1);
929 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
930 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700931 cifs_stats_inc(&tcon->num_deletes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 if (rc) {
933 cFYI(1, ("Error in RMFile = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +0000934 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935
936 cifs_buf_release(pSMB);
937 if (rc == -EAGAIN)
938 goto DelFileRetry;
939
940 return rc;
941}
942
943int
Steve French50c2f752007-07-13 00:33:32 +0000944CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
Steve French737b7582005-04-28 22:41:06 -0700945 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946{
947 DELETE_DIRECTORY_REQ *pSMB = NULL;
948 DELETE_DIRECTORY_RSP *pSMBr = NULL;
949 int rc = 0;
950 int bytes_returned;
951 int name_len;
952
953 cFYI(1, ("In CIFSSMBRmDir"));
954RmDirRetry:
955 rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
956 (void **) &pSMBr);
957 if (rc)
958 return rc;
959
960 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French737b7582005-04-28 22:41:06 -0700961 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, dirName,
962 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 name_len++; /* trailing null */
964 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -0700965 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 name_len = strnlen(dirName, PATH_MAX);
967 name_len++; /* trailing null */
968 strncpy(pSMB->DirName, dirName, name_len);
969 }
970
971 pSMB->BufferFormat = 0x04;
972 pSMB->hdr.smb_buf_length += name_len + 1;
973 pSMB->ByteCount = cpu_to_le16(name_len + 1);
974 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
975 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -0700976 cifs_stats_inc(&tcon->num_rmdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 if (rc) {
978 cFYI(1, ("Error in RMDir = %d", rc));
979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
981 cifs_buf_release(pSMB);
982 if (rc == -EAGAIN)
983 goto RmDirRetry;
984 return rc;
985}
986
987int
988CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -0700989 const char *name, const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990{
991 int rc = 0;
992 CREATE_DIRECTORY_REQ *pSMB = NULL;
993 CREATE_DIRECTORY_RSP *pSMBr = NULL;
994 int bytes_returned;
995 int name_len;
996
997 cFYI(1, ("In CIFSSMBMkDir"));
998MkDirRetry:
999 rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
1000 (void **) &pSMBr);
1001 if (rc)
1002 return rc;
1003
1004 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00001005 name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
Steve French737b7582005-04-28 22:41:06 -07001006 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 name_len++; /* trailing null */
1008 name_len *= 2;
Steve French09d1db52005-04-28 22:41:08 -07001009 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 name_len = strnlen(name, PATH_MAX);
1011 name_len++; /* trailing null */
1012 strncpy(pSMB->DirName, name, name_len);
1013 }
1014
1015 pSMB->BufferFormat = 0x04;
1016 pSMB->hdr.smb_buf_length += name_len + 1;
1017 pSMB->ByteCount = cpu_to_le16(name_len + 1);
1018 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1019 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001020 cifs_stats_inc(&tcon->num_mkdirs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 if (rc) {
1022 cFYI(1, ("Error in Mkdir = %d", rc));
1023 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001024
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 cifs_buf_release(pSMB);
1026 if (rc == -EAGAIN)
1027 goto MkDirRetry;
1028 return rc;
1029}
1030
Steve French2dd29d32007-04-23 22:07:35 +00001031int
1032CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
1033 __u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
Steve French50c2f752007-07-13 00:33:32 +00001034 __u32 *pOplock, const char *name,
Steve French2dd29d32007-04-23 22:07:35 +00001035 const struct nls_table *nls_codepage, int remap)
1036{
1037 TRANSACTION2_SPI_REQ *pSMB = NULL;
1038 TRANSACTION2_SPI_RSP *pSMBr = NULL;
1039 int name_len;
1040 int rc = 0;
1041 int bytes_returned = 0;
Steve French2dd29d32007-04-23 22:07:35 +00001042 __u16 params, param_offset, offset, byte_count, count;
1043 OPEN_PSX_REQ * pdata;
1044 OPEN_PSX_RSP * psx_rsp;
1045
1046 cFYI(1, ("In POSIX Create"));
1047PsxCreat:
1048 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1049 (void **) &pSMBr);
1050 if (rc)
1051 return rc;
1052
1053 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1054 name_len =
1055 cifsConvertToUCS((__le16 *) pSMB->FileName, name,
1056 PATH_MAX, nls_codepage, remap);
1057 name_len++; /* trailing null */
1058 name_len *= 2;
1059 } else { /* BB improve the check for buffer overruns BB */
1060 name_len = strnlen(name, PATH_MAX);
1061 name_len++; /* trailing null */
1062 strncpy(pSMB->FileName, name, name_len);
1063 }
1064
1065 params = 6 + name_len;
1066 count = sizeof(OPEN_PSX_REQ);
1067 pSMB->MaxParameterCount = cpu_to_le16(2);
1068 pSMB->MaxDataCount = cpu_to_le16(1000); /* large enough */
1069 pSMB->MaxSetupCount = 0;
1070 pSMB->Reserved = 0;
1071 pSMB->Flags = 0;
1072 pSMB->Timeout = 0;
1073 pSMB->Reserved2 = 0;
1074 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00001075 InformationLevel) - 4;
Steve French2dd29d32007-04-23 22:07:35 +00001076 offset = param_offset + params;
Steve French2dd29d32007-04-23 22:07:35 +00001077 pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001078 pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
Steve French2dd29d32007-04-23 22:07:35 +00001079 pdata->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00001080 pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
Steve French2dd29d32007-04-23 22:07:35 +00001081 pdata->OpenFlags = cpu_to_le32(*pOplock);
1082 pSMB->ParameterOffset = cpu_to_le16(param_offset);
1083 pSMB->DataOffset = cpu_to_le16(offset);
1084 pSMB->SetupCount = 1;
1085 pSMB->Reserved3 = 0;
1086 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1087 byte_count = 3 /* pad */ + params + count;
1088
1089 pSMB->DataCount = cpu_to_le16(count);
1090 pSMB->ParameterCount = cpu_to_le16(params);
1091 pSMB->TotalDataCount = pSMB->DataCount;
1092 pSMB->TotalParameterCount = pSMB->ParameterCount;
1093 pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
1094 pSMB->Reserved4 = 0;
Steve French50c2f752007-07-13 00:33:32 +00001095 pSMB->hdr.smb_buf_length += byte_count;
Steve French2dd29d32007-04-23 22:07:35 +00001096 pSMB->ByteCount = cpu_to_le16(byte_count);
1097 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1098 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1099 if (rc) {
1100 cFYI(1, ("Posix create returned %d", rc));
1101 goto psx_create_err;
1102 }
1103
Steve French790fe572007-07-07 19:25:05 +00001104 cFYI(1, ("copying inode info"));
Steve French2dd29d32007-04-23 22:07:35 +00001105 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1106
1107 if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
1108 rc = -EIO; /* bad smb */
1109 goto psx_create_err;
1110 }
1111
1112 /* copy return information to pRetData */
Steve French50c2f752007-07-13 00:33:32 +00001113 psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
Steve French2dd29d32007-04-23 22:07:35 +00001114 + le16_to_cpu(pSMBr->t2.DataOffset));
Steve French50c2f752007-07-13 00:33:32 +00001115
Steve French2dd29d32007-04-23 22:07:35 +00001116 *pOplock = le16_to_cpu(psx_rsp->OplockFlags);
Steve French790fe572007-07-07 19:25:05 +00001117 if (netfid)
Steve French2dd29d32007-04-23 22:07:35 +00001118 *netfid = psx_rsp->Fid; /* cifs fid stays in le */
1119 /* Let caller know file was created so we can set the mode. */
1120 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001121 if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
Steve French2dd29d32007-04-23 22:07:35 +00001122 *pOplock |= CIFS_CREATE_ACTION;
1123 /* check to make sure response data is there */
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001124 if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) {
1125 pRetData->Type = cpu_to_le32(-1); /* unknown */
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001126#ifdef CONFIG_CIFS_DEBUG2
Steve French790fe572007-07-07 19:25:05 +00001127 cFYI(1, ("unknown type"));
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001128#endif
1129 } else {
Steve French790fe572007-07-07 19:25:05 +00001130 if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
Steve French2dd29d32007-04-23 22:07:35 +00001131 + sizeof(FILE_UNIX_BASIC_INFO)) {
Steve French50c2f752007-07-13 00:33:32 +00001132 cERROR(1, ("Open response data too small"));
Cyril Gorcunov8f2376a2007-10-14 17:58:43 +00001133 pRetData->Type = cpu_to_le32(-1);
Steve French2dd29d32007-04-23 22:07:35 +00001134 goto psx_create_err;
1135 }
Steve French50c2f752007-07-13 00:33:32 +00001136 memcpy((char *) pRetData,
Steve Frenchcbac3cb2007-04-25 11:46:06 +00001137 (char *)psx_rsp + sizeof(OPEN_PSX_RSP),
Steve French26f57362007-08-30 22:09:15 +00001138 sizeof(FILE_UNIX_BASIC_INFO));
Steve French2dd29d32007-04-23 22:07:35 +00001139 }
Steve French2dd29d32007-04-23 22:07:35 +00001140
1141psx_create_err:
1142 cifs_buf_release(pSMB);
1143
1144 cifs_stats_inc(&tcon->num_mkdirs);
1145
1146 if (rc == -EAGAIN)
1147 goto PsxCreat;
1148
Steve French50c2f752007-07-13 00:33:32 +00001149 return rc;
Steve French2dd29d32007-04-23 22:07:35 +00001150}
1151
Steve Frencha9d02ad2005-08-24 23:06:05 -07001152static __u16 convert_disposition(int disposition)
1153{
1154 __u16 ofun = 0;
1155
1156 switch (disposition) {
1157 case FILE_SUPERSEDE:
1158 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1159 break;
1160 case FILE_OPEN:
1161 ofun = SMBOPEN_OAPPEND;
1162 break;
1163 case FILE_CREATE:
1164 ofun = SMBOPEN_OCREATE;
1165 break;
1166 case FILE_OPEN_IF:
1167 ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND;
1168 break;
1169 case FILE_OVERWRITE:
1170 ofun = SMBOPEN_OTRUNC;
1171 break;
1172 case FILE_OVERWRITE_IF:
1173 ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
1174 break;
1175 default:
Steve French790fe572007-07-07 19:25:05 +00001176 cFYI(1, ("unknown disposition %d", disposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001177 ofun = SMBOPEN_OAPPEND; /* regular open */
1178 }
1179 return ofun;
1180}
1181
1182int
1183SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
1184 const char *fileName, const int openDisposition,
1185 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001186 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve Frencha9d02ad2005-08-24 23:06:05 -07001187 const struct nls_table *nls_codepage, int remap)
1188{
1189 int rc = -EACCES;
1190 OPENX_REQ *pSMB = NULL;
1191 OPENX_RSP *pSMBr = NULL;
1192 int bytes_returned;
1193 int name_len;
1194 __u16 count;
1195
1196OldOpenRetry:
1197 rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB,
1198 (void **) &pSMBr);
1199 if (rc)
1200 return rc;
1201
1202 pSMB->AndXCommand = 0xFF; /* none */
1203
1204 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1205 count = 1; /* account for one byte pad to word boundary */
1206 name_len =
1207 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
1208 fileName, PATH_MAX, nls_codepage, remap);
1209 name_len++; /* trailing null */
1210 name_len *= 2;
1211 } else { /* BB improve check for buffer overruns BB */
1212 count = 0; /* no pad */
1213 name_len = strnlen(fileName, PATH_MAX);
1214 name_len++; /* trailing null */
1215 strncpy(pSMB->fileName, fileName, name_len);
1216 }
1217 if (*pOplock & REQ_OPLOCK)
1218 pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001219 else if (*pOplock & REQ_BATCHOPLOCK)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001220 pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001221
Steve Frencha9d02ad2005-08-24 23:06:05 -07001222 pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO);
1223 /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */
1224 /* 0 = read
1225 1 = write
1226 2 = rw
1227 3 = execute
Steve French50c2f752007-07-13 00:33:32 +00001228 */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001229 pSMB->Mode = cpu_to_le16(2);
1230 pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
1231 /* set file as system file if special file such
1232 as fifo and server expecting SFU style and
1233 no Unix extensions */
1234
Steve French790fe572007-07-07 19:25:05 +00001235 if (create_options & CREATE_OPTION_SPECIAL)
1236 pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
1237 else
Steve French3e87d802005-09-18 20:49:21 -07001238 pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001239
1240 /* if ((omode & S_IWUGO) == 0)
1241 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1242 /* Above line causes problems due to vfs splitting create into two
1243 pieces - need to set mode after file created not while it is
1244 being created */
1245
1246 /* BB FIXME BB */
Steve French50c2f752007-07-13 00:33:32 +00001247/* pSMB->CreateOptions = cpu_to_le32(create_options &
1248 CREATE_OPTIONS_MASK); */
Steve Frencha9d02ad2005-08-24 23:06:05 -07001249 /* BB FIXME END BB */
Steve French3e87d802005-09-18 20:49:21 -07001250
1251 pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
Steve French70ca7342005-09-22 16:32:06 -07001252 pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001253 count += name_len;
1254 pSMB->hdr.smb_buf_length += count;
1255
1256 pSMB->ByteCount = cpu_to_le16(count);
1257 /* long_op set to 1 to allow for oplock break timeouts */
1258 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00001259 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha9d02ad2005-08-24 23:06:05 -07001260 cifs_stats_inc(&tcon->num_opens);
1261 if (rc) {
1262 cFYI(1, ("Error in Open = %d", rc));
1263 } else {
1264 /* BB verify if wct == 15 */
1265
1266/* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */
1267
1268 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1269 /* Let caller know file was created so we can set the mode. */
1270 /* Do we care about the CreateAction in any other cases? */
1271 /* BB FIXME BB */
Steve French790fe572007-07-07 19:25:05 +00001272/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve Frencha9d02ad2005-08-24 23:06:05 -07001273 *pOplock |= CIFS_CREATE_ACTION; */
1274 /* BB FIXME END */
1275
Steve French790fe572007-07-07 19:25:05 +00001276 if (pfile_info) {
Steve Frencha9d02ad2005-08-24 23:06:05 -07001277 pfile_info->CreationTime = 0; /* BB convert CreateTime*/
1278 pfile_info->LastAccessTime = 0; /* BB fixme */
1279 pfile_info->LastWriteTime = 0; /* BB fixme */
1280 pfile_info->ChangeTime = 0; /* BB fixme */
Steve French70ca7342005-09-22 16:32:06 -07001281 pfile_info->Attributes =
Steve French50c2f752007-07-13 00:33:32 +00001282 cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
Steve Frencha9d02ad2005-08-24 23:06:05 -07001283 /* the file_info buf is endian converted by caller */
Steve French70ca7342005-09-22 16:32:06 -07001284 pfile_info->AllocationSize =
1285 cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
1286 pfile_info->EndOfFile = pfile_info->AllocationSize;
Steve Frencha9d02ad2005-08-24 23:06:05 -07001287 pfile_info->NumberOfLinks = cpu_to_le32(1);
1288 }
1289 }
1290
1291 cifs_buf_release(pSMB);
1292 if (rc == -EAGAIN)
1293 goto OldOpenRetry;
1294 return rc;
1295}
1296
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297int
1298CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
1299 const char *fileName, const int openDisposition,
1300 const int access_flags, const int create_options, __u16 * netfid,
Steve French50c2f752007-07-13 00:33:32 +00001301 int *pOplock, FILE_ALL_INFO * pfile_info,
Steve French737b7582005-04-28 22:41:06 -07001302 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303{
1304 int rc = -EACCES;
1305 OPEN_REQ *pSMB = NULL;
1306 OPEN_RSP *pSMBr = NULL;
1307 int bytes_returned;
1308 int name_len;
1309 __u16 count;
1310
1311openRetry:
1312 rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
1313 (void **) &pSMBr);
1314 if (rc)
1315 return rc;
1316
1317 pSMB->AndXCommand = 0xFF; /* none */
1318
1319 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1320 count = 1; /* account for one byte pad to word boundary */
1321 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05001322 cifsConvertToUCS((__le16 *) (pSMB->fileName + 1),
Steve French737b7582005-04-28 22:41:06 -07001323 fileName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 name_len++; /* trailing null */
1325 name_len *= 2;
1326 pSMB->NameLength = cpu_to_le16(name_len);
Steve French09d1db52005-04-28 22:41:08 -07001327 } else { /* BB improve check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328 count = 0; /* no pad */
1329 name_len = strnlen(fileName, PATH_MAX);
1330 name_len++; /* trailing null */
1331 pSMB->NameLength = cpu_to_le16(name_len);
1332 strncpy(pSMB->fileName, fileName, name_len);
1333 }
1334 if (*pOplock & REQ_OPLOCK)
1335 pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
Steve French26f57362007-08-30 22:09:15 +00001336 else if (*pOplock & REQ_BATCHOPLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 pSMB->DesiredAccess = cpu_to_le32(access_flags);
1339 pSMB->AllocationSize = 0;
Steve Frencheda3c0292005-07-21 15:20:28 -07001340 /* set file as system file if special file such
1341 as fifo and server expecting SFU style and
1342 no Unix extensions */
Steve French790fe572007-07-07 19:25:05 +00001343 if (create_options & CREATE_OPTION_SPECIAL)
Steve Frencheda3c0292005-07-21 15:20:28 -07001344 pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
1345 else
1346 pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 /* XP does not handle ATTR_POSIX_SEMANTICS */
1348 /* but it helps speed up case sensitive checks for other
1349 servers such as Samba */
1350 if (tcon->ses->capabilities & CAP_UNIX)
1351 pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
1352
1353 /* if ((omode & S_IWUGO) == 0)
1354 pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
1355 /* Above line causes problems due to vfs splitting create into two
1356 pieces - need to set mode after file created not while it is
1357 being created */
1358 pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
1359 pSMB->CreateDisposition = cpu_to_le32(openDisposition);
Steve Frencheda3c0292005-07-21 15:20:28 -07001360 pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK);
Steve French09d1db52005-04-28 22:41:08 -07001361 /* BB Expirement with various impersonation levels and verify */
1362 pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 pSMB->SecurityFlags =
1364 SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
1365
1366 count += name_len;
1367 pSMB->hdr.smb_buf_length += count;
1368
1369 pSMB->ByteCount = cpu_to_le16(count);
1370 /* long_op set to 1 to allow for oplock break timeouts */
1371 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1372 (struct smb_hdr *) pSMBr, &bytes_returned, 1);
Steve Frencha4544342005-08-24 13:59:35 -07001373 cifs_stats_inc(&tcon->num_opens);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 if (rc) {
1375 cFYI(1, ("Error in Open = %d", rc));
1376 } else {
Steve French09d1db52005-04-28 22:41:08 -07001377 *pOplock = pSMBr->OplockLevel; /* 1 byte no need to le_to_cpu */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 *netfid = pSMBr->Fid; /* cifs fid stays in le */
1379 /* Let caller know file was created so we can set the mode. */
1380 /* Do we care about the CreateAction in any other cases? */
Steve French790fe572007-07-07 19:25:05 +00001381 if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
Steve French50c2f752007-07-13 00:33:32 +00001382 *pOplock |= CIFS_CREATE_ACTION;
Steve French790fe572007-07-07 19:25:05 +00001383 if (pfile_info) {
Steve French50c2f752007-07-13 00:33:32 +00001384 memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 36 /* CreationTime to Attributes */);
1386 /* the file_info buf is endian converted by caller */
1387 pfile_info->AllocationSize = pSMBr->AllocationSize;
1388 pfile_info->EndOfFile = pSMBr->EndOfFile;
1389 pfile_info->NumberOfLinks = cpu_to_le32(1);
1390 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 }
Steve Frencha5a2b482005-08-20 21:42:53 -07001392
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393 cifs_buf_release(pSMB);
1394 if (rc == -EAGAIN)
1395 goto openRetry;
1396 return rc;
1397}
1398
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399int
Steve French50c2f752007-07-13 00:33:32 +00001400CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
1401 const unsigned int count, const __u64 lseek, unsigned int *nbytes,
1402 char **buf, int *pbuf_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403{
1404 int rc = -EACCES;
1405 READ_REQ *pSMB = NULL;
1406 READ_RSP *pSMBr = NULL;
1407 char *pReadData = NULL;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001408 int wct;
Steve Frenchec637e32005-12-12 20:53:18 -08001409 int resp_buf_type = 0;
1410 struct kvec iov[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
Steve French790fe572007-07-07 19:25:05 +00001412 cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
1413 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001414 wct = 12;
1415 else
1416 wct = 10; /* old style read */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417
1418 *nbytes = 0;
Steve Frenchec637e32005-12-12 20:53:18 -08001419 rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 if (rc)
1421 return rc;
1422
1423 /* tcon and ses pointer are checked in smb_init */
1424 if (tcon->ses->server == NULL)
1425 return -ECONNABORTED;
1426
Steve Frenchec637e32005-12-12 20:53:18 -08001427 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 pSMB->Fid = netfid;
1429 pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001430 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001431 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
Steve French790fe572007-07-07 19:25:05 +00001432 else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
Steve Frenchec637e32005-12-12 20:53:18 -08001433 return -EIO;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001434
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 pSMB->Remaining = 0;
1436 pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
1437 pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
Steve French790fe572007-07-07 19:25:05 +00001438 if (wct == 12)
Steve Frenchbfa0d752005-08-31 21:50:37 -07001439 pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
1440 else {
1441 /* old style read */
Steve French50c2f752007-07-13 00:33:32 +00001442 struct smb_com_readx_req *pSMBW =
Steve Frenchbfa0d752005-08-31 21:50:37 -07001443 (struct smb_com_readx_req *)pSMB;
Steve Frenchec637e32005-12-12 20:53:18 -08001444 pSMBW->ByteCount = 0;
Steve Frenchbfa0d752005-08-31 21:50:37 -07001445 }
Steve Frenchec637e32005-12-12 20:53:18 -08001446
1447 iov[0].iov_base = (char *)pSMB;
1448 iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
Steve Frencha761ac52007-10-18 21:45:27 +00001449 rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */,
1450 &resp_buf_type, 0 /* not long op */, 1 /* log err */ );
Steve Frencha4544342005-08-24 13:59:35 -07001451 cifs_stats_inc(&tcon->num_reads);
Steve Frenchec637e32005-12-12 20:53:18 -08001452 pSMBr = (READ_RSP *)iov[0].iov_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 if (rc) {
1454 cERROR(1, ("Send error in read = %d", rc));
1455 } else {
1456 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
1457 data_length = data_length << 16;
1458 data_length += le16_to_cpu(pSMBr->DataLength);
1459 *nbytes = data_length;
1460
1461 /*check that DataLength would not go beyond end of SMB */
Steve Frenchec637e32005-12-12 20:53:18 -08001462 if ((data_length > CIFSMaxBufSize)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 || (data_length > count)) {
Steve French50c2f752007-07-13 00:33:32 +00001464 cFYI(1, ("bad length %d for count %d",
1465 data_length, count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 rc = -EIO;
1467 *nbytes = 0;
1468 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001469 pReadData = (char *) (&pSMBr->hdr.Protocol) +
Steve French26f57362007-08-30 22:09:15 +00001470 le16_to_cpu(pSMBr->DataOffset);
1471/* if (rc = copy_to_user(buf, pReadData, data_length)) {
Steve French50c2f752007-07-13 00:33:32 +00001472 cERROR(1,("Faulting on read rc = %d",rc));
1473 rc = -EFAULT;
Steve French26f57362007-08-30 22:09:15 +00001474 }*/ /* can not use copy_to_user when using page cache*/
Steve French790fe572007-07-07 19:25:05 +00001475 if (*buf)
Steve French50c2f752007-07-13 00:33:32 +00001476 memcpy(*buf, pReadData, data_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 }
1478 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479
Steve French4b8f9302006-02-26 16:41:18 +00001480/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001481 if (*buf) {
1482 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001483 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001484 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001485 cifs_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001486 } else if (resp_buf_type != CIFS_NO_BUFFER) {
Steve French50c2f752007-07-13 00:33:32 +00001487 /* return buffer to caller to free */
1488 *buf = iov[0].iov_base;
Steve French790fe572007-07-07 19:25:05 +00001489 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001490 *pbuf_type = CIFS_SMALL_BUFFER;
Steve French790fe572007-07-07 19:25:05 +00001491 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001492 *pbuf_type = CIFS_LARGE_BUFFER;
Steve French6cec2ae2006-02-22 17:31:52 -06001493 } /* else no valid buffer on return - leave as null */
Steve Frenchec637e32005-12-12 20:53:18 -08001494
1495 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001496 since file handle passed in no longer valid */
1497 return rc;
1498}
1499
Steve Frenchec637e32005-12-12 20:53:18 -08001500
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501int
1502CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1503 const int netfid, const unsigned int count,
1504 const __u64 offset, unsigned int *nbytes, const char *buf,
Steve French50c2f752007-07-13 00:33:32 +00001505 const char __user *ubuf, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506{
1507 int rc = -EACCES;
1508 WRITE_REQ *pSMB = NULL;
1509 WRITE_RSP *pSMBr = NULL;
Steve French1c955182005-08-30 20:58:07 -07001510 int bytes_returned, wct;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 __u32 bytes_sent;
1512 __u16 byte_count;
1513
1514 /* cFYI(1,("write at %lld %d bytes",offset,count));*/
Steve French790fe572007-07-07 19:25:05 +00001515 if (tcon->ses == NULL)
Steve French1c955182005-08-30 20:58:07 -07001516 return -ECONNABORTED;
1517
Steve French790fe572007-07-07 19:25:05 +00001518 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French1c955182005-08-30 20:58:07 -07001519 wct = 14;
1520 else
1521 wct = 12;
1522
1523 rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 (void **) &pSMBr);
1525 if (rc)
1526 return rc;
1527 /* tcon and ses pointer are checked in smb_init */
1528 if (tcon->ses->server == NULL)
1529 return -ECONNABORTED;
1530
1531 pSMB->AndXCommand = 0xFF; /* none */
1532 pSMB->Fid = netfid;
1533 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001534 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001535 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001536 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French1c955182005-08-30 20:58:07 -07001537 return -EIO;
Steve French50c2f752007-07-13 00:33:32 +00001538
Linus Torvalds1da177e2005-04-16 15:20:36 -07001539 pSMB->Reserved = 0xFFFFFFFF;
1540 pSMB->WriteMode = 0;
1541 pSMB->Remaining = 0;
1542
Steve French50c2f752007-07-13 00:33:32 +00001543 /* Can increase buffer size if buffer is big enough in some cases ie we
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 can send more if LARGE_WRITE_X capability returned by the server and if
1545 our buffer is big enough or if we convert to iovecs on socket writes
1546 and eliminate the copy to the CIFS buffer */
Steve French790fe572007-07-07 19:25:05 +00001547 if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1549 } else {
1550 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1551 & ~0xFF;
1552 }
1553
1554 if (bytes_sent > count)
1555 bytes_sent = count;
1556 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001557 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Steve French790fe572007-07-07 19:25:05 +00001558 if (buf)
Steve French50c2f752007-07-13 00:33:32 +00001559 memcpy(pSMB->Data, buf, bytes_sent);
Steve French790fe572007-07-07 19:25:05 +00001560 else if (ubuf) {
1561 if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 cifs_buf_release(pSMB);
1563 return -EFAULT;
1564 }
Steve Frenche30dcf32005-09-20 20:49:16 -07001565 } else if (count != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 /* No buffer */
1567 cifs_buf_release(pSMB);
1568 return -EINVAL;
Steve Frenche30dcf32005-09-20 20:49:16 -07001569 } /* else setting file size with write of zero bytes */
Steve French790fe572007-07-07 19:25:05 +00001570 if (wct == 14)
Steve Frenche30dcf32005-09-20 20:49:16 -07001571 byte_count = bytes_sent + 1; /* pad */
1572 else /* wct == 12 */ {
1573 byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1576 pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
Steve Frenche30dcf32005-09-20 20:49:16 -07001577 pSMB->hdr.smb_buf_length += byte_count;
Steve French1c955182005-08-30 20:58:07 -07001578
Steve French790fe572007-07-07 19:25:05 +00001579 if (wct == 14)
Steve French1c955182005-08-30 20:58:07 -07001580 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00001581 else { /* old style write has byte count 4 bytes earlier
1582 so 4 bytes pad */
1583 struct smb_com_writex_req *pSMBW =
Steve French1c955182005-08-30 20:58:07 -07001584 (struct smb_com_writex_req *)pSMB;
1585 pSMBW->ByteCount = cpu_to_le16(byte_count);
1586 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587
1588 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1589 (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
Steve Frencha4544342005-08-24 13:59:35 -07001590 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 if (rc) {
1592 cFYI(1, ("Send error in write = %d", rc));
1593 *nbytes = 0;
1594 } else {
1595 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1596 *nbytes = (*nbytes) << 16;
1597 *nbytes += le16_to_cpu(pSMBr->Count);
1598 }
1599
1600 cifs_buf_release(pSMB);
1601
Steve French50c2f752007-07-13 00:33:32 +00001602 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 since file handle passed in no longer valid */
1604
1605 return rc;
1606}
1607
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001608int
1609CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 const int netfid, const unsigned int count,
Steve French3e844692005-10-03 13:37:24 -07001611 const __u64 offset, unsigned int *nbytes, struct kvec *iov,
1612 int n_vec, const int long_op)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613{
1614 int rc = -EACCES;
1615 WRITE_REQ *pSMB = NULL;
Steve Frenchec637e32005-12-12 20:53:18 -08001616 int wct;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001617 int smb_hdr_len;
Steve Frenchec637e32005-12-12 20:53:18 -08001618 int resp_buf_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619
Steve French790fe572007-07-07 19:25:05 +00001620 cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
Steve Frenchff7feac2005-11-15 16:45:16 -08001621
Steve French790fe572007-07-07 19:25:05 +00001622 if (tcon->ses->capabilities & CAP_LARGE_FILES)
Steve French8cc64c62005-10-03 13:49:43 -07001623 wct = 14;
1624 else
1625 wct = 12;
1626 rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 if (rc)
1628 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629 /* tcon and ses pointer are checked in smb_init */
1630 if (tcon->ses->server == NULL)
1631 return -ECONNABORTED;
1632
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001633 pSMB->AndXCommand = 0xFF; /* none */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 pSMB->Fid = netfid;
1635 pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
Steve French790fe572007-07-07 19:25:05 +00001636 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001637 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
Steve French790fe572007-07-07 19:25:05 +00001638 else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
Steve French8cc64c62005-10-03 13:49:43 -07001639 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 pSMB->Reserved = 0xFFFFFFFF;
1641 pSMB->WriteMode = 0;
1642 pSMB->Remaining = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001643
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 pSMB->DataOffset =
Steve French50c2f752007-07-13 00:33:32 +00001645 cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646
Steve French3e844692005-10-03 13:37:24 -07001647 pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
1648 pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001649 smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
Steve French790fe572007-07-07 19:25:05 +00001650 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001651 pSMB->hdr.smb_buf_length += count+1;
1652 else /* wct == 12 */
Steve French790fe572007-07-07 19:25:05 +00001653 pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
1654 if (wct == 14)
Steve French8cc64c62005-10-03 13:49:43 -07001655 pSMB->ByteCount = cpu_to_le16(count + 1);
1656 else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
Steve French50c2f752007-07-13 00:33:32 +00001657 struct smb_com_writex_req *pSMBW =
Steve French8cc64c62005-10-03 13:49:43 -07001658 (struct smb_com_writex_req *)pSMB;
1659 pSMBW->ByteCount = cpu_to_le16(count + 5);
1660 }
Steve French3e844692005-10-03 13:37:24 -07001661 iov[0].iov_base = pSMB;
Steve French790fe572007-07-07 19:25:05 +00001662 if (wct == 14)
Steve Frenchec637e32005-12-12 20:53:18 -08001663 iov[0].iov_len = smb_hdr_len + 4;
1664 else /* wct == 12 pad bigger by four bytes */
1665 iov[0].iov_len = smb_hdr_len + 8;
Steve French50c2f752007-07-13 00:33:32 +00001666
Steve French3e844692005-10-03 13:37:24 -07001667
Steve Frenchec637e32005-12-12 20:53:18 -08001668 rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
Steve Frencha761ac52007-10-18 21:45:27 +00001669 long_op, 0 /* do not log STATUS code */ );
Steve Frencha4544342005-08-24 13:59:35 -07001670 cifs_stats_inc(&tcon->num_writes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 if (rc) {
Steve French8cc64c62005-10-03 13:49:43 -07001672 cFYI(1, ("Send error Write2 = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 *nbytes = 0;
Steve French790fe572007-07-07 19:25:05 +00001674 } else if (resp_buf_type == 0) {
Steve Frenchec637e32005-12-12 20:53:18 -08001675 /* presumably this can not happen, but best to be safe */
1676 rc = -EIO;
1677 *nbytes = 0;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001678 } else {
Steve Frenchec637e32005-12-12 20:53:18 -08001679 WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base;
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001680 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1681 *nbytes = (*nbytes) << 16;
1682 *nbytes += le16_to_cpu(pSMBr->Count);
Steve French50c2f752007-07-13 00:33:32 +00001683 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
Steve French4b8f9302006-02-26 16:41:18 +00001685/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French790fe572007-07-07 19:25:05 +00001686 if (resp_buf_type == CIFS_SMALL_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001687 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00001688 else if (resp_buf_type == CIFS_LARGE_BUFFER)
Steve Frenchec637e32005-12-12 20:53:18 -08001689 cifs_buf_release(iov[0].iov_base);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690
Steve French50c2f752007-07-13 00:33:32 +00001691 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 since file handle passed in no longer valid */
1693
1694 return rc;
1695}
Steve Frenchd6e04ae2005-06-13 13:24:43 -05001696
1697
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698int
1699CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1700 const __u16 smb_file_id, const __u64 len,
1701 const __u64 offset, const __u32 numUnlock,
1702 const __u32 numLock, const __u8 lockType, const int waitFlag)
1703{
1704 int rc = 0;
1705 LOCK_REQ *pSMB = NULL;
1706 LOCK_RSP *pSMBr = NULL;
1707 int bytes_returned;
1708 int timeout = 0;
1709 __u16 count;
1710
Steve French50c2f752007-07-13 00:33:32 +00001711 cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock));
Steve French46810cb2005-04-28 22:41:09 -07001712 rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1713
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 if (rc)
1715 return rc;
1716
Steve French46810cb2005-04-28 22:41:09 -07001717 pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1718
Steve French790fe572007-07-07 19:25:05 +00001719 if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 timeout = -1; /* no response expected */
1721 pSMB->Timeout = 0;
1722 } else if (waitFlag == TRUE) {
1723 timeout = 3; /* blocking operation, no timeout */
1724 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1725 } else {
1726 pSMB->Timeout = 0;
1727 }
1728
1729 pSMB->NumberOfLocks = cpu_to_le16(numLock);
1730 pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1731 pSMB->LockType = lockType;
1732 pSMB->AndXCommand = 0xFF; /* none */
1733 pSMB->Fid = smb_file_id; /* netfid stays le */
1734
Steve French790fe572007-07-07 19:25:05 +00001735 if ((numLock != 0) || (numUnlock != 0)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1737 /* BB where to store pid high? */
1738 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1739 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1740 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1741 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1742 count = sizeof(LOCKING_ANDX_RANGE);
1743 } else {
1744 /* oplock break */
1745 count = 0;
1746 }
1747 pSMB->hdr.smb_buf_length += count;
1748 pSMB->ByteCount = cpu_to_le16(count);
1749
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001750 if (waitFlag) {
1751 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1752 (struct smb_hdr *) pSMBr, &bytes_returned);
1753 } else {
1754 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001756 }
Steve Frencha4544342005-08-24 13:59:35 -07001757 cifs_stats_inc(&tcon->num_locks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 if (rc) {
1759 cFYI(1, ("Send error in Lock = %d", rc));
1760 }
Steve French46810cb2005-04-28 22:41:09 -07001761 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762
Steve French50c2f752007-07-13 00:33:32 +00001763 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 since file handle passed in no longer valid */
1765 return rc;
1766}
1767
1768int
Steve French08547b02006-02-28 22:39:25 +00001769CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
1770 const __u16 smb_file_id, const int get_flag, const __u64 len,
Steve French50c2f752007-07-13 00:33:32 +00001771 struct file_lock *pLockData, const __u16 lock_type,
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001772 const int waitFlag)
Steve French08547b02006-02-28 22:39:25 +00001773{
1774 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1775 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French08547b02006-02-28 22:39:25 +00001776 struct cifs_posix_lock *parm_data;
1777 int rc = 0;
Steve French3a5ff612006-07-14 22:37:11 +00001778 int timeout = 0;
Steve French08547b02006-02-28 22:39:25 +00001779 int bytes_returned = 0;
1780 __u16 params, param_offset, offset, byte_count, count;
1781
1782 cFYI(1, ("Posix Lock"));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001783
Steve French790fe572007-07-07 19:25:05 +00001784 if (pLockData == NULL)
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001785 return EINVAL;
1786
Steve French08547b02006-02-28 22:39:25 +00001787 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
1788
1789 if (rc)
1790 return rc;
1791
1792 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
1793
Steve French50c2f752007-07-13 00:33:32 +00001794 params = 6;
Steve French08547b02006-02-28 22:39:25 +00001795 pSMB->MaxSetupCount = 0;
1796 pSMB->Reserved = 0;
1797 pSMB->Flags = 0;
Steve French08547b02006-02-28 22:39:25 +00001798 pSMB->Reserved2 = 0;
1799 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1800 offset = param_offset + params;
1801
Steve French08547b02006-02-28 22:39:25 +00001802 count = sizeof(struct cifs_posix_lock);
1803 pSMB->MaxParameterCount = cpu_to_le16(2);
1804 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1805 pSMB->SetupCount = 1;
1806 pSMB->Reserved3 = 0;
Steve French790fe572007-07-07 19:25:05 +00001807 if (get_flag)
Steve French08547b02006-02-28 22:39:25 +00001808 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
1809 else
1810 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1811 byte_count = 3 /* pad */ + params + count;
1812 pSMB->DataCount = cpu_to_le16(count);
1813 pSMB->ParameterCount = cpu_to_le16(params);
1814 pSMB->TotalDataCount = pSMB->DataCount;
1815 pSMB->TotalParameterCount = pSMB->ParameterCount;
1816 pSMB->ParameterOffset = cpu_to_le16(param_offset);
Steve French50c2f752007-07-13 00:33:32 +00001817 parm_data = (struct cifs_posix_lock *)
Steve French08547b02006-02-28 22:39:25 +00001818 (((char *) &pSMB->hdr.Protocol) + offset);
1819
1820 parm_data->lock_type = cpu_to_le16(lock_type);
Steve French790fe572007-07-07 19:25:05 +00001821 if (waitFlag) {
Steve French3a5ff612006-07-14 22:37:11 +00001822 timeout = 3; /* blocking operation, no timeout */
Steve Frenchcec6815a2006-05-30 18:07:17 +00001823 parm_data->lock_flags = cpu_to_le16(1);
Steve French3a5ff612006-07-14 22:37:11 +00001824 pSMB->Timeout = cpu_to_le32(-1);
1825 } else
1826 pSMB->Timeout = 0;
1827
Steve French08547b02006-02-28 22:39:25 +00001828 parm_data->pid = cpu_to_le32(current->tgid);
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001829 parm_data->start = cpu_to_le64(pLockData->fl_start);
Steve Frenchcec6815a2006-05-30 18:07:17 +00001830 parm_data->length = cpu_to_le64(len); /* normalize negative numbers */
Steve French08547b02006-02-28 22:39:25 +00001831
1832 pSMB->DataOffset = cpu_to_le16(offset);
Steve Frenchf26282c2006-03-01 09:17:37 +00001833 pSMB->Fid = smb_file_id;
Steve French08547b02006-02-28 22:39:25 +00001834 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_LOCK);
1835 pSMB->Reserved4 = 0;
1836 pSMB->hdr.smb_buf_length += byte_count;
1837 pSMB->ByteCount = cpu_to_le16(byte_count);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001838 if (waitFlag) {
1839 rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB,
1840 (struct smb_hdr *) pSMBr, &bytes_returned);
1841 } else {
1842 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French3a5ff612006-07-14 22:37:11 +00001843 (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
Jeremy Allison7ee1af72006-08-02 21:56:33 +00001844 }
1845
Steve French08547b02006-02-28 22:39:25 +00001846 if (rc) {
1847 cFYI(1, ("Send error in Posix Lock = %d", rc));
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001848 } else if (get_flag) {
1849 /* lock structure can be returned on get */
1850 __u16 data_offset;
1851 __u16 data_count;
1852 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French08547b02006-02-28 22:39:25 +00001853
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001854 if (rc || (pSMBr->ByteCount < sizeof(struct cifs_posix_lock))) {
1855 rc = -EIO; /* bad smb */
1856 goto plk_err_exit;
1857 }
Steve French790fe572007-07-07 19:25:05 +00001858 if (pLockData == NULL) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001859 rc = -EINVAL;
1860 goto plk_err_exit;
1861 }
1862 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1863 data_count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French790fe572007-07-07 19:25:05 +00001864 if (data_count < sizeof(struct cifs_posix_lock)) {
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001865 rc = -EIO;
1866 goto plk_err_exit;
1867 }
1868 parm_data = (struct cifs_posix_lock *)
1869 ((char *)&pSMBr->hdr.Protocol + data_offset);
Steve French790fe572007-07-07 19:25:05 +00001870 if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001871 pLockData->fl_type = F_UNLCK;
1872 }
Steve French50c2f752007-07-13 00:33:32 +00001873
Steve Frenchfc94cdb2006-05-30 18:03:32 +00001874plk_err_exit:
Steve French08547b02006-02-28 22:39:25 +00001875 if (pSMB)
1876 cifs_small_buf_release(pSMB);
1877
1878 /* Note: On -EAGAIN error only caller can retry on handle based calls
1879 since file handle passed in no longer valid */
1880
1881 return rc;
1882}
1883
1884
1885int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1887{
1888 int rc = 0;
1889 CLOSE_REQ *pSMB = NULL;
1890 CLOSE_RSP *pSMBr = NULL;
1891 int bytes_returned;
1892 cFYI(1, ("In CIFSSMBClose"));
1893
1894/* do not retry on dead session on close */
1895 rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
Steve French790fe572007-07-07 19:25:05 +00001896 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 return 0;
1898 if (rc)
1899 return rc;
1900
1901 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1902
1903 pSMB->FileID = (__u16) smb_file_id;
Steve Frenchb815f1e52006-10-02 05:53:29 +00001904 pSMB->LastWriteTime = 0xFFFFFFFF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 pSMB->ByteCount = 0;
1906 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1907 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001908 cifs_stats_inc(&tcon->num_closes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00001910 if (rc != -EINTR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 /* EINTR is expected when user ctl-c to kill app */
1912 cERROR(1, ("Send error in Close = %d", rc));
1913 }
1914 }
1915
1916 cifs_small_buf_release(pSMB);
1917
1918 /* Since session is dead, file will be closed on server already */
Steve French790fe572007-07-07 19:25:05 +00001919 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920 rc = 0;
1921
1922 return rc;
1923}
1924
1925int
1926CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1927 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07001928 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929{
1930 int rc = 0;
1931 RENAME_REQ *pSMB = NULL;
1932 RENAME_RSP *pSMBr = NULL;
1933 int bytes_returned;
1934 int name_len, name_len2;
1935 __u16 count;
1936
1937 cFYI(1, ("In CIFSSMBRename"));
1938renameRetry:
1939 rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1940 (void **) &pSMBr);
1941 if (rc)
1942 return rc;
1943
1944 pSMB->BufferFormat = 0x04;
1945 pSMB->SearchAttributes =
1946 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1947 ATTR_DIRECTORY);
1948
1949 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1950 name_len =
Steve French50c2f752007-07-13 00:33:32 +00001951 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07001952 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 name_len++; /* trailing null */
1954 name_len *= 2;
1955 pSMB->OldFileName[name_len] = 0x04; /* pad */
1956 /* protocol requires ASCII signature byte on Unicode string */
1957 pSMB->OldFileName[name_len + 1] = 0x00;
1958 name_len2 =
Steve Frenchb1a45692005-05-17 16:07:23 -05001959 cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07001960 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
1962 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00001963 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 name_len = strnlen(fromName, PATH_MAX);
1965 name_len++; /* trailing null */
1966 strncpy(pSMB->OldFileName, fromName, name_len);
1967 name_len2 = strnlen(toName, PATH_MAX);
1968 name_len2++; /* trailing null */
1969 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
1970 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1971 name_len2++; /* trailing null */
1972 name_len2++; /* signature byte */
1973 }
1974
1975 count = 1 /* 1st signature byte */ + name_len + name_len2;
1976 pSMB->hdr.smb_buf_length += count;
1977 pSMB->ByteCount = cpu_to_le16(count);
1978
1979 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1980 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07001981 cifs_stats_inc(&tcon->num_renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 if (rc) {
1983 cFYI(1, ("Send error in rename = %d", rc));
Steve French50c2f752007-07-13 00:33:32 +00001984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 cifs_buf_release(pSMB);
1987
1988 if (rc == -EAGAIN)
1989 goto renameRetry;
1990
1991 return rc;
1992}
1993
Steve French50c2f752007-07-13 00:33:32 +00001994int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
1995 int netfid, char *target_name,
1996 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997{
1998 struct smb_com_transaction2_sfi_req *pSMB = NULL;
1999 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00002000 struct set_file_rename *rename_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 char *data_offset;
2002 char dummy_string[30];
2003 int rc = 0;
2004 int bytes_returned = 0;
2005 int len_of_str;
2006 __u16 params, param_offset, offset, count, byte_count;
2007
2008 cFYI(1, ("Rename to File by handle"));
2009 rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
2010 (void **) &pSMBr);
2011 if (rc)
2012 return rc;
2013
2014 params = 6;
2015 pSMB->MaxSetupCount = 0;
2016 pSMB->Reserved = 0;
2017 pSMB->Flags = 0;
2018 pSMB->Timeout = 0;
2019 pSMB->Reserved2 = 0;
2020 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
2021 offset = param_offset + params;
2022
2023 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2024 rename_info = (struct set_file_rename *) data_offset;
2025 pSMB->MaxParameterCount = cpu_to_le16(2);
2026 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
2027 pSMB->SetupCount = 1;
2028 pSMB->Reserved3 = 0;
2029 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
2030 byte_count = 3 /* pad */ + params;
2031 pSMB->ParameterCount = cpu_to_le16(params);
2032 pSMB->TotalParameterCount = pSMB->ParameterCount;
2033 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2034 pSMB->DataOffset = cpu_to_le16(offset);
2035 /* construct random name ".cifs_tmp<inodenum><mid>" */
2036 rename_info->overwrite = cpu_to_le32(1);
2037 rename_info->root_fid = 0;
2038 /* unicode only call */
Steve French790fe572007-07-07 19:25:05 +00002039 if (target_name == NULL) {
Steve French50c2f752007-07-13 00:33:32 +00002040 sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
2041 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French737b7582005-04-28 22:41:06 -07002042 dummy_string, 24, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 } else {
Steve Frenchb1a45692005-05-17 16:07:23 -05002044 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
Steve French50c2f752007-07-13 00:33:32 +00002045 target_name, PATH_MAX, nls_codepage,
2046 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 }
2048 rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
2049 count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
2050 byte_count += count;
2051 pSMB->DataCount = cpu_to_le16(count);
2052 pSMB->TotalDataCount = pSMB->DataCount;
2053 pSMB->Fid = netfid;
2054 pSMB->InformationLevel =
2055 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
2056 pSMB->Reserved4 = 0;
2057 pSMB->hdr.smb_buf_length += byte_count;
2058 pSMB->ByteCount = cpu_to_le16(byte_count);
2059 rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002060 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002061 cifs_stats_inc(&pTcon->num_t2renames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 if (rc) {
Steve French790fe572007-07-07 19:25:05 +00002063 cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 }
Steve Frencha5a2b482005-08-20 21:42:53 -07002065
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 cifs_buf_release(pSMB);
2067
2068 /* Note: On -EAGAIN error only caller can retry on handle based calls
2069 since file handle passed in no longer valid */
2070
2071 return rc;
2072}
2073
2074int
Steve French50c2f752007-07-13 00:33:32 +00002075CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
2076 const __u16 target_tid, const char *toName, const int flags,
2077 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002078{
2079 int rc = 0;
2080 COPY_REQ *pSMB = NULL;
2081 COPY_RSP *pSMBr = NULL;
2082 int bytes_returned;
2083 int name_len, name_len2;
2084 __u16 count;
2085
2086 cFYI(1, ("In CIFSSMBCopy"));
2087copyRetry:
2088 rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
2089 (void **) &pSMBr);
2090 if (rc)
2091 return rc;
2092
2093 pSMB->BufferFormat = 0x04;
2094 pSMB->Tid2 = target_tid;
2095
2096 pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
2097
2098 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00002099 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
Steve French737b7582005-04-28 22:41:06 -07002100 fromName, PATH_MAX, nls_codepage,
2101 remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 name_len++; /* trailing null */
2103 name_len *= 2;
2104 pSMB->OldFileName[name_len] = 0x04; /* pad */
2105 /* protocol requires ASCII signature byte on Unicode string */
2106 pSMB->OldFileName[name_len + 1] = 0x00;
Steve French50c2f752007-07-13 00:33:32 +00002107 name_len2 =
2108 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002109 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2111 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002112 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113 name_len = strnlen(fromName, PATH_MAX);
2114 name_len++; /* trailing null */
2115 strncpy(pSMB->OldFileName, fromName, name_len);
2116 name_len2 = strnlen(toName, PATH_MAX);
2117 name_len2++; /* trailing null */
2118 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2119 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2120 name_len2++; /* trailing null */
2121 name_len2++; /* signature byte */
2122 }
2123
2124 count = 1 /* 1st signature byte */ + name_len + name_len2;
2125 pSMB->hdr.smb_buf_length += count;
2126 pSMB->ByteCount = cpu_to_le16(count);
2127
2128 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2129 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2130 if (rc) {
2131 cFYI(1, ("Send error in copy = %d with %d files copied",
2132 rc, le16_to_cpu(pSMBr->CopyCount)));
2133 }
2134 if (pSMB)
2135 cifs_buf_release(pSMB);
2136
2137 if (rc == -EAGAIN)
2138 goto copyRetry;
2139
2140 return rc;
2141}
2142
2143int
2144CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
2145 const char *fromName, const char *toName,
2146 const struct nls_table *nls_codepage)
2147{
2148 TRANSACTION2_SPI_REQ *pSMB = NULL;
2149 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2150 char *data_offset;
2151 int name_len;
2152 int name_len_target;
2153 int rc = 0;
2154 int bytes_returned = 0;
2155 __u16 params, param_offset, offset, byte_count;
2156
2157 cFYI(1, ("In Symlink Unix style"));
2158createSymLinkRetry:
2159 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2160 (void **) &pSMBr);
2161 if (rc)
2162 return rc;
2163
2164 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2165 name_len =
Steve Frenche89dc922005-11-11 15:18:19 -08002166 cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 /* find define for this maxpathcomponent */
2168 , nls_codepage);
2169 name_len++; /* trailing null */
2170 name_len *= 2;
2171
Steve French50c2f752007-07-13 00:33:32 +00002172 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 name_len = strnlen(fromName, PATH_MAX);
2174 name_len++; /* trailing null */
2175 strncpy(pSMB->FileName, fromName, name_len);
2176 }
2177 params = 6 + name_len;
2178 pSMB->MaxSetupCount = 0;
2179 pSMB->Reserved = 0;
2180 pSMB->Flags = 0;
2181 pSMB->Timeout = 0;
2182 pSMB->Reserved2 = 0;
2183 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002184 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 offset = param_offset + params;
2186
2187 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2188 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2189 name_len_target =
Steve Frenche89dc922005-11-11 15:18:19 -08002190 cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 /* find define for this maxpathcomponent */
2192 , nls_codepage);
2193 name_len_target++; /* trailing null */
2194 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002195 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002196 name_len_target = strnlen(toName, PATH_MAX);
2197 name_len_target++; /* trailing null */
2198 strncpy(data_offset, toName, name_len_target);
2199 }
2200
2201 pSMB->MaxParameterCount = cpu_to_le16(2);
2202 /* BB find exact max on data count below from sess */
2203 pSMB->MaxDataCount = cpu_to_le16(1000);
2204 pSMB->SetupCount = 1;
2205 pSMB->Reserved3 = 0;
2206 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2207 byte_count = 3 /* pad */ + params + name_len_target;
2208 pSMB->DataCount = cpu_to_le16(name_len_target);
2209 pSMB->ParameterCount = cpu_to_le16(params);
2210 pSMB->TotalDataCount = pSMB->DataCount;
2211 pSMB->TotalParameterCount = pSMB->ParameterCount;
2212 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2213 pSMB->DataOffset = cpu_to_le16(offset);
2214 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
2215 pSMB->Reserved4 = 0;
2216 pSMB->hdr.smb_buf_length += byte_count;
2217 pSMB->ByteCount = cpu_to_le16(byte_count);
2218 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2219 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002220 cifs_stats_inc(&tcon->num_symlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 if (rc) {
Steve French2d785a52007-07-15 01:48:57 +00002222 cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002223 }
2224
2225 if (pSMB)
2226 cifs_buf_release(pSMB);
2227
2228 if (rc == -EAGAIN)
2229 goto createSymLinkRetry;
2230
2231 return rc;
2232}
2233
2234int
2235CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2236 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002237 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238{
2239 TRANSACTION2_SPI_REQ *pSMB = NULL;
2240 TRANSACTION2_SPI_RSP *pSMBr = NULL;
2241 char *data_offset;
2242 int name_len;
2243 int name_len_target;
2244 int rc = 0;
2245 int bytes_returned = 0;
2246 __u16 params, param_offset, offset, byte_count;
2247
2248 cFYI(1, ("In Create Hard link Unix style"));
2249createHardLinkRetry:
2250 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2251 (void **) &pSMBr);
2252 if (rc)
2253 return rc;
2254
2255 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve Frenchb1a45692005-05-17 16:07:23 -05002256 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
Steve French737b7582005-04-28 22:41:06 -07002257 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002258 name_len++; /* trailing null */
2259 name_len *= 2;
2260
Steve French50c2f752007-07-13 00:33:32 +00002261 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 name_len = strnlen(toName, PATH_MAX);
2263 name_len++; /* trailing null */
2264 strncpy(pSMB->FileName, toName, name_len);
2265 }
2266 params = 6 + name_len;
2267 pSMB->MaxSetupCount = 0;
2268 pSMB->Reserved = 0;
2269 pSMB->Flags = 0;
2270 pSMB->Timeout = 0;
2271 pSMB->Reserved2 = 0;
2272 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002273 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 offset = param_offset + params;
2275
2276 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
2277 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2278 name_len_target =
Steve Frenchb1a45692005-05-17 16:07:23 -05002279 cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
Steve French737b7582005-04-28 22:41:06 -07002280 nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 name_len_target++; /* trailing null */
2282 name_len_target *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002283 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002284 name_len_target = strnlen(fromName, PATH_MAX);
2285 name_len_target++; /* trailing null */
2286 strncpy(data_offset, fromName, name_len_target);
2287 }
2288
2289 pSMB->MaxParameterCount = cpu_to_le16(2);
2290 /* BB find exact max on data count below from sess*/
2291 pSMB->MaxDataCount = cpu_to_le16(1000);
2292 pSMB->SetupCount = 1;
2293 pSMB->Reserved3 = 0;
2294 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2295 byte_count = 3 /* pad */ + params + name_len_target;
2296 pSMB->ParameterCount = cpu_to_le16(params);
2297 pSMB->TotalParameterCount = pSMB->ParameterCount;
2298 pSMB->DataCount = cpu_to_le16(name_len_target);
2299 pSMB->TotalDataCount = pSMB->DataCount;
2300 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2301 pSMB->DataOffset = cpu_to_le16(offset);
2302 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
2303 pSMB->Reserved4 = 0;
2304 pSMB->hdr.smb_buf_length += byte_count;
2305 pSMB->ByteCount = cpu_to_le16(byte_count);
2306 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2307 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002308 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309 if (rc) {
2310 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
2311 }
2312
2313 cifs_buf_release(pSMB);
2314 if (rc == -EAGAIN)
2315 goto createHardLinkRetry;
2316
2317 return rc;
2318}
2319
2320int
2321CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
2322 const char *fromName, const char *toName,
Steve French737b7582005-04-28 22:41:06 -07002323 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002324{
2325 int rc = 0;
2326 NT_RENAME_REQ *pSMB = NULL;
2327 RENAME_RSP *pSMBr = NULL;
2328 int bytes_returned;
2329 int name_len, name_len2;
2330 __u16 count;
2331
2332 cFYI(1, ("In CIFSCreateHardLink"));
2333winCreateHardLinkRetry:
2334
2335 rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
2336 (void **) &pSMBr);
2337 if (rc)
2338 return rc;
2339
2340 pSMB->SearchAttributes =
2341 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2342 ATTR_DIRECTORY);
2343 pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
2344 pSMB->ClusterCount = 0;
2345
2346 pSMB->BufferFormat = 0x04;
2347
2348 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2349 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05002350 cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
Steve French737b7582005-04-28 22:41:06 -07002351 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 name_len++; /* trailing null */
2353 name_len *= 2;
2354 pSMB->OldFileName[name_len] = 0; /* pad */
Steve French50c2f752007-07-13 00:33:32 +00002355 pSMB->OldFileName[name_len + 1] = 0x04;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 name_len2 =
Steve French50c2f752007-07-13 00:33:32 +00002357 cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
Steve French737b7582005-04-28 22:41:06 -07002358 toName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
2360 name_len2 *= 2; /* convert to bytes */
Steve French50c2f752007-07-13 00:33:32 +00002361 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 name_len = strnlen(fromName, PATH_MAX);
2363 name_len++; /* trailing null */
2364 strncpy(pSMB->OldFileName, fromName, name_len);
2365 name_len2 = strnlen(toName, PATH_MAX);
2366 name_len2++; /* trailing null */
2367 pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
2368 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
2369 name_len2++; /* trailing null */
2370 name_len2++; /* signature byte */
2371 }
2372
2373 count = 1 /* string type byte */ + name_len + name_len2;
2374 pSMB->hdr.smb_buf_length += count;
2375 pSMB->ByteCount = cpu_to_le16(count);
2376
2377 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2378 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07002379 cifs_stats_inc(&tcon->num_hardlinks);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 if (rc) {
2381 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
2382 }
2383 cifs_buf_release(pSMB);
2384 if (rc == -EAGAIN)
2385 goto winCreateHardLinkRetry;
2386
2387 return rc;
2388}
2389
2390int
2391CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
2392 const unsigned char *searchName,
2393 char *symlinkinfo, const int buflen,
2394 const struct nls_table *nls_codepage)
2395{
2396/* SMB_QUERY_FILE_UNIX_LINK */
2397 TRANSACTION2_QPI_REQ *pSMB = NULL;
2398 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2399 int rc = 0;
2400 int bytes_returned;
2401 int name_len;
2402 __u16 params, byte_count;
2403
2404 cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
2405
2406querySymLinkRetry:
2407 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2408 (void **) &pSMBr);
2409 if (rc)
2410 return rc;
2411
2412 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2413 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002414 cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
2415 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416 name_len++; /* trailing null */
2417 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002418 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002419 name_len = strnlen(searchName, PATH_MAX);
2420 name_len++; /* trailing null */
2421 strncpy(pSMB->FileName, searchName, name_len);
2422 }
2423
2424 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2425 pSMB->TotalDataCount = 0;
2426 pSMB->MaxParameterCount = cpu_to_le16(2);
2427 /* BB find exact max data count below from sess structure BB */
2428 pSMB->MaxDataCount = cpu_to_le16(4000);
2429 pSMB->MaxSetupCount = 0;
2430 pSMB->Reserved = 0;
2431 pSMB->Flags = 0;
2432 pSMB->Timeout = 0;
2433 pSMB->Reserved2 = 0;
2434 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00002435 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 pSMB->DataCount = 0;
2437 pSMB->DataOffset = 0;
2438 pSMB->SetupCount = 1;
2439 pSMB->Reserved3 = 0;
2440 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2441 byte_count = params + 1 /* pad */ ;
2442 pSMB->TotalParameterCount = cpu_to_le16(params);
2443 pSMB->ParameterCount = pSMB->TotalParameterCount;
2444 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
2445 pSMB->Reserved4 = 0;
2446 pSMB->hdr.smb_buf_length += byte_count;
2447 pSMB->ByteCount = cpu_to_le16(byte_count);
2448
2449 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2450 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2451 if (rc) {
2452 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
2453 } else {
2454 /* decode response */
2455
2456 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2457 if (rc || (pSMBr->ByteCount < 2))
2458 /* BB also check enough total bytes returned */
2459 rc = -EIO; /* bad smb */
2460 else {
2461 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2462 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2463
2464 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2465 name_len = UniStrnlen((wchar_t *) ((char *)
Steve French50c2f752007-07-13 00:33:32 +00002466 &pSMBr->hdr.Protocol + data_offset),
2467 min_t(const int, buflen, count) / 2);
Steve French737b7582005-04-28 22:41:06 -07002468 /* BB FIXME investigate remapping reserved chars here */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002470 (__le16 *) ((char *)&pSMBr->hdr.Protocol
2471 + data_offset),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002472 name_len, nls_codepage);
2473 } else {
2474 strncpy(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002475 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 data_offset,
2477 min_t(const int, buflen, count));
2478 }
2479 symlinkinfo[buflen] = 0;
2480 /* just in case so calling code does not go off the end of buffer */
2481 }
2482 }
2483 cifs_buf_release(pSMB);
2484 if (rc == -EAGAIN)
2485 goto querySymLinkRetry;
2486 return rc;
2487}
2488
Parag Warudkarc9489772007-10-23 18:09:48 +00002489#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08002490/* Initialize NT TRANSACT SMB into small smb request buffer.
2491 This assumes that all NT TRANSACTS that we init here have
2492 total parm and data under about 400 bytes (to fit in small cifs
2493 buffer size), which is the case so far, it easily fits. NB:
2494 Setup words themselves and ByteCount
2495 MaxSetupCount (size of returned setup area) and
2496 MaxParameterCount (returned parms size) must be set by caller */
Steve French50c2f752007-07-13 00:33:32 +00002497static int
Steve French0a4b92c2006-01-12 15:44:21 -08002498smb_init_ntransact(const __u16 sub_command, const int setup_count,
2499 const int parm_len, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002500 void **ret_buf)
Steve French0a4b92c2006-01-12 15:44:21 -08002501{
2502 int rc;
2503 __u32 temp_offset;
Steve French50c2f752007-07-13 00:33:32 +00002504 struct smb_com_ntransact_req *pSMB;
Steve French0a4b92c2006-01-12 15:44:21 -08002505
2506 rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
2507 (void **)&pSMB);
2508 if (rc)
2509 return rc;
2510 *ret_buf = (void *)pSMB;
2511 pSMB->Reserved = 0;
2512 pSMB->TotalParameterCount = cpu_to_le32(parm_len);
2513 pSMB->TotalDataCount = 0;
2514 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2515 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2516 pSMB->ParameterCount = pSMB->TotalParameterCount;
2517 pSMB->DataCount = pSMB->TotalDataCount;
2518 temp_offset = offsetof(struct smb_com_ntransact_req, Parms) +
2519 (setup_count * 2) - 4 /* for rfc1001 length itself */;
2520 pSMB->ParameterOffset = cpu_to_le32(temp_offset);
2521 pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len);
2522 pSMB->SetupCount = setup_count; /* no need to le convert byte fields */
2523 pSMB->SubCommand = cpu_to_le16(sub_command);
2524 return 0;
2525}
2526
2527static int
Steve French50c2f752007-07-13 00:33:32 +00002528validate_ntransact(char *buf, char **ppparm, char **ppdata,
2529 int *pdatalen, int *pparmlen)
Steve French0a4b92c2006-01-12 15:44:21 -08002530{
Steve French50c2f752007-07-13 00:33:32 +00002531 char *end_of_smb;
Steve French0a4b92c2006-01-12 15:44:21 -08002532 __u32 data_count, data_offset, parm_count, parm_offset;
Steve French50c2f752007-07-13 00:33:32 +00002533 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08002534
Steve French790fe572007-07-07 19:25:05 +00002535 if (buf == NULL)
Steve French0a4b92c2006-01-12 15:44:21 -08002536 return -EINVAL;
2537
2538 pSMBr = (struct smb_com_ntransact_rsp *)buf;
2539
2540 /* ByteCount was converted from little endian in SendReceive */
Steve French50c2f752007-07-13 00:33:32 +00002541 end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
Steve French0a4b92c2006-01-12 15:44:21 -08002542 (char *)&pSMBr->ByteCount;
2543
Steve French0a4b92c2006-01-12 15:44:21 -08002544 data_offset = le32_to_cpu(pSMBr->DataOffset);
2545 data_count = le32_to_cpu(pSMBr->DataCount);
Steve French50c2f752007-07-13 00:33:32 +00002546 parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
Steve French0a4b92c2006-01-12 15:44:21 -08002547 parm_count = le32_to_cpu(pSMBr->ParameterCount);
2548
2549 *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
2550 *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
2551
2552 /* should we also check that parm and data areas do not overlap? */
Steve French790fe572007-07-07 19:25:05 +00002553 if (*ppparm > end_of_smb) {
2554 cFYI(1, ("parms start after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002555 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002556 } else if (parm_count + *ppparm > end_of_smb) {
2557 cFYI(1, ("parm end after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002558 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002559 } else if (*ppdata > end_of_smb) {
2560 cFYI(1, ("data starts after end of smb"));
Steve French0a4b92c2006-01-12 15:44:21 -08002561 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002562 } else if (data_count + *ppdata > end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002563 cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p",
Steve French50c2f752007-07-13 00:33:32 +00002564 *ppdata, data_count, (data_count + *ppdata),
2565 end_of_smb, pSMBr));
Steve French0a4b92c2006-01-12 15:44:21 -08002566 return -EINVAL;
Steve French790fe572007-07-07 19:25:05 +00002567 } else if (parm_count + data_count > pSMBr->ByteCount) {
2568 cFYI(1, ("parm count and data count larger than SMB"));
Steve French0a4b92c2006-01-12 15:44:21 -08002569 return -EINVAL;
2570 }
2571 return 0;
2572}
Parag Warudkarc9489772007-10-23 18:09:48 +00002573#endif /* CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08002574
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575int
2576CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
2577 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00002578 char *symlinkinfo, const int buflen, __u16 fid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 const struct nls_table *nls_codepage)
2580{
2581 int rc = 0;
2582 int bytes_returned;
2583 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00002584 struct smb_com_transaction_ioctl_req *pSMB;
2585 struct smb_com_transaction_ioctl_rsp *pSMBr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586
2587 cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
2588 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
2589 (void **) &pSMBr);
2590 if (rc)
2591 return rc;
2592
2593 pSMB->TotalParameterCount = 0 ;
2594 pSMB->TotalDataCount = 0;
2595 pSMB->MaxParameterCount = cpu_to_le32(2);
2596 /* BB find exact data count max from sess structure BB */
Steve French0a4b92c2006-01-12 15:44:21 -08002597 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
2598 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 pSMB->MaxSetupCount = 4;
2600 pSMB->Reserved = 0;
2601 pSMB->ParameterOffset = 0;
2602 pSMB->DataCount = 0;
2603 pSMB->DataOffset = 0;
2604 pSMB->SetupCount = 4;
2605 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
2606 pSMB->ParameterCount = pSMB->TotalParameterCount;
2607 pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
2608 pSMB->IsFsctl = 1; /* FSCTL */
2609 pSMB->IsRootFlag = 0;
2610 pSMB->Fid = fid; /* file handle always le */
2611 pSMB->ByteCount = 0;
2612
2613 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2614 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2615 if (rc) {
2616 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
2617 } else { /* decode response */
2618 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
2619 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
2620 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
2621 /* BB also check enough total bytes returned */
2622 rc = -EIO; /* bad smb */
2623 else {
Steve French790fe572007-07-07 19:25:05 +00002624 if (data_count && (data_count < 2048)) {
Steve French50c2f752007-07-13 00:33:32 +00002625 char *end_of_smb = 2 /* sizeof byte count */ +
Steve French0a4b92c2006-01-12 15:44:21 -08002626 pSMBr->ByteCount +
2627 (char *)&pSMBr->ByteCount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628
Steve French50c2f752007-07-13 00:33:32 +00002629 struct reparse_data *reparse_buf =
2630 (struct reparse_data *)
2631 ((char *)&pSMBr->hdr.Protocol
2632 + data_offset);
Steve French790fe572007-07-07 19:25:05 +00002633 if ((char *)reparse_buf >= end_of_smb) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 rc = -EIO;
2635 goto qreparse_out;
2636 }
Steve French790fe572007-07-07 19:25:05 +00002637 if ((reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 reparse_buf->TargetNameOffset +
2639 reparse_buf->TargetNameLen) >
2640 end_of_smb) {
Steve French26f57362007-08-30 22:09:15 +00002641 cFYI(1, ("reparse buf beyond SMB"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 rc = -EIO;
2643 goto qreparse_out;
2644 }
Steve French50c2f752007-07-13 00:33:32 +00002645
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2647 name_len = UniStrnlen((wchar_t *)
Steve French50c2f752007-07-13 00:33:32 +00002648 (reparse_buf->LinkNamesBuf +
2649 reparse_buf->TargetNameOffset),
2650 min(buflen/2,
2651 reparse_buf->TargetNameLen / 2));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 cifs_strfromUCS_le(symlinkinfo,
Steve French50c2f752007-07-13 00:33:32 +00002653 (__le16 *) (reparse_buf->LinkNamesBuf +
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 reparse_buf->TargetNameOffset),
2655 name_len, nls_codepage);
2656 } else { /* ASCII names */
Steve French50c2f752007-07-13 00:33:32 +00002657 strncpy(symlinkinfo,
2658 reparse_buf->LinkNamesBuf +
2659 reparse_buf->TargetNameOffset,
2660 min_t(const int, buflen,
2661 reparse_buf->TargetNameLen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 }
2663 } else {
2664 rc = -EIO;
Steve French63135e02007-07-17 17:34:02 +00002665 cFYI(1, ("Invalid return data count on "
2666 "get reparse info ioctl"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667 }
2668 symlinkinfo[buflen] = 0; /* just in case so the caller
2669 does not go off the end of the buffer */
Steve French50c2f752007-07-13 00:33:32 +00002670 cFYI(1, ("readlink result - %s", symlinkinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 }
2672 }
2673qreparse_out:
Steve French4a6d87f2005-08-13 08:15:54 -07002674 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675
2676 /* Note: On -EAGAIN error only caller can retry on handle based calls
2677 since file handle passed in no longer valid */
2678
2679 return rc;
2680}
2681
2682#ifdef CONFIG_CIFS_POSIX
2683
2684/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
Steve French50c2f752007-07-13 00:33:32 +00002685static void cifs_convert_ace(posix_acl_xattr_entry *ace,
2686 struct cifs_posix_ace *cifs_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687{
2688 /* u8 cifs fields do not need le conversion */
Steve Frenchff7feac2005-11-15 16:45:16 -08002689 ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2690 ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag);
2691 ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2693
2694 return;
2695}
2696
2697/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
Steve French50c2f752007-07-13 00:33:32 +00002698static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
2699 const int acl_type, const int size_of_data_area)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700{
2701 int size = 0;
2702 int i;
2703 __u16 count;
Steve French50c2f752007-07-13 00:33:32 +00002704 struct cifs_posix_ace *pACE;
2705 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
2706 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707
2708 if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2709 return -EOPNOTSUPP;
2710
Steve French790fe572007-07-07 19:25:05 +00002711 if (acl_type & ACL_TYPE_ACCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 count = le16_to_cpu(cifs_acl->access_entry_count);
2713 pACE = &cifs_acl->ace_array[0];
2714 size = sizeof(struct cifs_posix_acl);
2715 size += sizeof(struct cifs_posix_ace) * count;
2716 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002717 if (size_of_data_area < size) {
Steve French50c2f752007-07-13 00:33:32 +00002718 cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
2719 size_of_data_area, size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 return -EINVAL;
2721 }
Steve French790fe572007-07-07 19:25:05 +00002722 } else if (acl_type & ACL_TYPE_DEFAULT) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 count = le16_to_cpu(cifs_acl->access_entry_count);
2724 size = sizeof(struct cifs_posix_acl);
2725 size += sizeof(struct cifs_posix_ace) * count;
2726/* skip past access ACEs to get to default ACEs */
2727 pACE = &cifs_acl->ace_array[count];
2728 count = le16_to_cpu(cifs_acl->default_entry_count);
2729 size += sizeof(struct cifs_posix_ace) * count;
2730 /* check if we would go beyond end of SMB */
Steve French790fe572007-07-07 19:25:05 +00002731 if (size_of_data_area < size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002732 return -EINVAL;
2733 } else {
2734 /* illegal type */
2735 return -EINVAL;
2736 }
2737
2738 size = posix_acl_xattr_size(count);
Steve French790fe572007-07-07 19:25:05 +00002739 if ((buflen == 0) || (local_acl == NULL)) {
Steve French50c2f752007-07-13 00:33:32 +00002740 /* used to query ACL EA size */
Steve French790fe572007-07-07 19:25:05 +00002741 } else if (size > buflen) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 return -ERANGE;
2743 } else /* buffer big enough */ {
Steve Frenchff7feac2005-11-15 16:45:16 -08002744 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
Steve French50c2f752007-07-13 00:33:32 +00002745 for (i = 0; i < count ; i++) {
2746 cifs_convert_ace(&local_acl->a_entries[i], pACE);
2747 pACE++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 }
2749 }
2750 return size;
2751}
2752
Steve French50c2f752007-07-13 00:33:32 +00002753static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
2754 const posix_acl_xattr_entry *local_ace)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755{
2756 __u16 rc = 0; /* 0 = ACL converted ok */
2757
Steve Frenchff7feac2005-11-15 16:45:16 -08002758 cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2759 cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 /* BB is there a better way to handle the large uid? */
Steve French790fe572007-07-07 19:25:05 +00002761 if (local_ace->e_id == cpu_to_le32(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 /* Probably no need to le convert -1 on any arch but can not hurt */
2763 cifs_ace->cifs_uid = cpu_to_le64(-1);
Steve French50c2f752007-07-13 00:33:32 +00002764 } else
Steve Frenchff7feac2005-11-15 16:45:16 -08002765 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
Steve French50c2f752007-07-13 00:33:32 +00002766 /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 return rc;
2768}
2769
2770/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
Steve French50c2f752007-07-13 00:33:32 +00002771static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
2772 const int buflen, const int acl_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773{
2774 __u16 rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00002775 struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
2776 posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 int count;
2778 int i;
2779
Steve French790fe572007-07-07 19:25:05 +00002780 if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 return 0;
2782
2783 count = posix_acl_xattr_count((size_t)buflen);
Steve Frenchc18c8422007-07-18 23:21:09 +00002784 cFYI(1, ("setting acl with %d entries from buf of length %d and "
Steve French63135e02007-07-17 17:34:02 +00002785 "version of %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002786 count, buflen, le32_to_cpu(local_acl->a_version)));
Steve French790fe572007-07-07 19:25:05 +00002787 if (le32_to_cpu(local_acl->a_version) != 2) {
Steve French50c2f752007-07-13 00:33:32 +00002788 cFYI(1, ("unknown POSIX ACL version %d",
Steve Frenchff7feac2005-11-15 16:45:16 -08002789 le32_to_cpu(local_acl->a_version)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790 return 0;
2791 }
2792 cifs_acl->version = cpu_to_le16(1);
Steve French790fe572007-07-07 19:25:05 +00002793 if (acl_type == ACL_TYPE_ACCESS)
Steve Frenchff7feac2005-11-15 16:45:16 -08002794 cifs_acl->access_entry_count = cpu_to_le16(count);
Steve French790fe572007-07-07 19:25:05 +00002795 else if (acl_type == ACL_TYPE_DEFAULT)
Steve Frenchff7feac2005-11-15 16:45:16 -08002796 cifs_acl->default_entry_count = cpu_to_le16(count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 else {
Steve French50c2f752007-07-13 00:33:32 +00002798 cFYI(1, ("unknown ACL type %d", acl_type));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 return 0;
2800 }
Steve French50c2f752007-07-13 00:33:32 +00002801 for (i = 0; i < count; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2803 &local_acl->a_entries[i]);
Steve French790fe572007-07-07 19:25:05 +00002804 if (rc != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002805 /* ACE not converted */
2806 break;
2807 }
2808 }
Steve French790fe572007-07-07 19:25:05 +00002809 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2811 rc += sizeof(struct cifs_posix_acl);
2812 /* BB add check to make sure ACL does not overflow SMB */
2813 }
2814 return rc;
2815}
2816
2817int
2818CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002819 const unsigned char *searchName,
2820 char *acl_inf, const int buflen, const int acl_type,
2821 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822{
2823/* SMB_QUERY_POSIX_ACL */
2824 TRANSACTION2_QPI_REQ *pSMB = NULL;
2825 TRANSACTION2_QPI_RSP *pSMBr = NULL;
2826 int rc = 0;
2827 int bytes_returned;
2828 int name_len;
2829 __u16 params, byte_count;
Steve French50c2f752007-07-13 00:33:32 +00002830
Linus Torvalds1da177e2005-04-16 15:20:36 -07002831 cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2832
2833queryAclRetry:
2834 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2835 (void **) &pSMBr);
2836 if (rc)
2837 return rc;
Steve French50c2f752007-07-13 00:33:32 +00002838
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2840 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002841 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07002842 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843 name_len++; /* trailing null */
2844 name_len *= 2;
2845 pSMB->FileName[name_len] = 0;
2846 pSMB->FileName[name_len+1] = 0;
Steve French50c2f752007-07-13 00:33:32 +00002847 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 name_len = strnlen(searchName, PATH_MAX);
2849 name_len++; /* trailing null */
2850 strncpy(pSMB->FileName, searchName, name_len);
2851 }
2852
2853 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
2854 pSMB->TotalDataCount = 0;
2855 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French50c2f752007-07-13 00:33:32 +00002856 /* BB find exact max data count below from sess structure BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 pSMB->MaxDataCount = cpu_to_le16(4000);
2858 pSMB->MaxSetupCount = 0;
2859 pSMB->Reserved = 0;
2860 pSMB->Flags = 0;
2861 pSMB->Timeout = 0;
2862 pSMB->Reserved2 = 0;
2863 pSMB->ParameterOffset = cpu_to_le16(
Steve French50c2f752007-07-13 00:33:32 +00002864 offsetof(struct smb_com_transaction2_qpi_req,
2865 InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 pSMB->DataCount = 0;
2867 pSMB->DataOffset = 0;
2868 pSMB->SetupCount = 1;
2869 pSMB->Reserved3 = 0;
2870 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2871 byte_count = params + 1 /* pad */ ;
2872 pSMB->TotalParameterCount = cpu_to_le16(params);
2873 pSMB->ParameterCount = pSMB->TotalParameterCount;
2874 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2875 pSMB->Reserved4 = 0;
2876 pSMB->hdr.smb_buf_length += byte_count;
2877 pSMB->ByteCount = cpu_to_le16(byte_count);
2878
2879 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2880 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French0a4b92c2006-01-12 15:44:21 -08002881 cifs_stats_inc(&tcon->num_acl_get);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 if (rc) {
2883 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2884 } else {
2885 /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00002886
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2888 if (rc || (pSMBr->ByteCount < 2))
2889 /* BB also check enough total bytes returned */
2890 rc = -EIO; /* bad smb */
2891 else {
2892 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2893 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2894 rc = cifs_copy_posix_acl(acl_inf,
2895 (char *)&pSMBr->hdr.Protocol+data_offset,
Steve French50c2f752007-07-13 00:33:32 +00002896 buflen, acl_type, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897 }
2898 }
2899 cifs_buf_release(pSMB);
2900 if (rc == -EAGAIN)
2901 goto queryAclRetry;
2902 return rc;
2903}
2904
2905int
2906CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002907 const unsigned char *fileName,
2908 const char *local_acl, const int buflen,
2909 const int acl_type,
2910 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911{
2912 struct smb_com_transaction2_spi_req *pSMB = NULL;
2913 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2914 char *parm_data;
2915 int name_len;
2916 int rc = 0;
2917 int bytes_returned = 0;
2918 __u16 params, byte_count, data_count, param_offset, offset;
2919
2920 cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2921setAclRetry:
2922 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002923 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 if (rc)
2925 return rc;
2926 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2927 name_len =
Steve French50c2f752007-07-13 00:33:32 +00002928 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07002929 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 name_len++; /* trailing null */
2931 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00002932 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 name_len = strnlen(fileName, PATH_MAX);
2934 name_len++; /* trailing null */
2935 strncpy(pSMB->FileName, fileName, name_len);
2936 }
2937 params = 6 + name_len;
2938 pSMB->MaxParameterCount = cpu_to_le16(2);
2939 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2940 pSMB->MaxSetupCount = 0;
2941 pSMB->Reserved = 0;
2942 pSMB->Flags = 0;
2943 pSMB->Timeout = 0;
2944 pSMB->Reserved2 = 0;
2945 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00002946 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 offset = param_offset + params;
2948 parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2949 pSMB->ParameterOffset = cpu_to_le16(param_offset);
2950
2951 /* convert to on the wire format for POSIX ACL */
Steve French50c2f752007-07-13 00:33:32 +00002952 data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953
Steve French790fe572007-07-07 19:25:05 +00002954 if (data_count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 rc = -EOPNOTSUPP;
2956 goto setACLerrorExit;
2957 }
2958 pSMB->DataOffset = cpu_to_le16(offset);
2959 pSMB->SetupCount = 1;
2960 pSMB->Reserved3 = 0;
2961 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2962 pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2963 byte_count = 3 /* pad */ + params + data_count;
2964 pSMB->DataCount = cpu_to_le16(data_count);
2965 pSMB->TotalDataCount = pSMB->DataCount;
2966 pSMB->ParameterCount = cpu_to_le16(params);
2967 pSMB->TotalParameterCount = pSMB->ParameterCount;
2968 pSMB->Reserved4 = 0;
2969 pSMB->hdr.smb_buf_length += byte_count;
2970 pSMB->ByteCount = cpu_to_le16(byte_count);
2971 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00002972 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002973 if (rc) {
2974 cFYI(1, ("Set POSIX ACL returned %d", rc));
2975 }
2976
2977setACLerrorExit:
2978 cifs_buf_release(pSMB);
2979 if (rc == -EAGAIN)
2980 goto setAclRetry;
2981 return rc;
2982}
2983
Steve Frenchf654bac2005-04-28 22:41:04 -07002984/* BB fix tabs in this function FIXME BB */
2985int
2986CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00002987 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
Steve Frenchf654bac2005-04-28 22:41:04 -07002988{
Steve French50c2f752007-07-13 00:33:32 +00002989 int rc = 0;
2990 struct smb_t2_qfi_req *pSMB = NULL;
2991 struct smb_t2_qfi_rsp *pSMBr = NULL;
2992 int bytes_returned;
2993 __u16 params, byte_count;
Steve Frenchf654bac2005-04-28 22:41:04 -07002994
Steve French790fe572007-07-07 19:25:05 +00002995 cFYI(1, ("In GetExtAttr"));
2996 if (tcon == NULL)
2997 return -ENODEV;
Steve Frenchf654bac2005-04-28 22:41:04 -07002998
2999GetExtAttrRetry:
Steve French790fe572007-07-07 19:25:05 +00003000 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3001 (void **) &pSMBr);
3002 if (rc)
3003 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003004
Steve French790fe572007-07-07 19:25:05 +00003005 params = 2 /* level */ +2 /* fid */;
3006 pSMB->t2.TotalDataCount = 0;
3007 pSMB->t2.MaxParameterCount = cpu_to_le16(4);
3008 /* BB find exact max data count below from sess structure BB */
3009 pSMB->t2.MaxDataCount = cpu_to_le16(4000);
3010 pSMB->t2.MaxSetupCount = 0;
3011 pSMB->t2.Reserved = 0;
3012 pSMB->t2.Flags = 0;
3013 pSMB->t2.Timeout = 0;
3014 pSMB->t2.Reserved2 = 0;
3015 pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
3016 Fid) - 4);
3017 pSMB->t2.DataCount = 0;
3018 pSMB->t2.DataOffset = 0;
3019 pSMB->t2.SetupCount = 1;
3020 pSMB->t2.Reserved3 = 0;
3021 pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
3022 byte_count = params + 1 /* pad */ ;
3023 pSMB->t2.TotalParameterCount = cpu_to_le16(params);
3024 pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
3025 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
3026 pSMB->Pad = 0;
Steve Frenchf654bac2005-04-28 22:41:04 -07003027 pSMB->Fid = netfid;
Steve French790fe572007-07-07 19:25:05 +00003028 pSMB->hdr.smb_buf_length += byte_count;
3029 pSMB->t2.ByteCount = cpu_to_le16(byte_count);
Steve Frenchf654bac2005-04-28 22:41:04 -07003030
Steve French790fe572007-07-07 19:25:05 +00003031 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3032 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3033 if (rc) {
3034 cFYI(1, ("error %d in GetExtAttr", rc));
3035 } else {
3036 /* decode response */
3037 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3038 if (rc || (pSMBr->ByteCount < 2))
3039 /* BB also check enough total bytes returned */
3040 /* If rc should we check for EOPNOSUPP and
3041 disable the srvino flag? or in caller? */
3042 rc = -EIO; /* bad smb */
3043 else {
3044 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3045 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3046 struct file_chattr_info *pfinfo;
3047 /* BB Do we need a cast or hash here ? */
3048 if (count != 16) {
3049 cFYI(1, ("Illegal size ret in GetExtAttr"));
3050 rc = -EIO;
3051 goto GetExtAttrOut;
3052 }
3053 pfinfo = (struct file_chattr_info *)
3054 (data_offset + (char *) &pSMBr->hdr.Protocol);
3055 *pExtAttrBits = le64_to_cpu(pfinfo->mode);
Steve Frenchf654bac2005-04-28 22:41:04 -07003056 *pMask = le64_to_cpu(pfinfo->mask);
Steve French790fe572007-07-07 19:25:05 +00003057 }
3058 }
Steve Frenchf654bac2005-04-28 22:41:04 -07003059GetExtAttrOut:
Steve French790fe572007-07-07 19:25:05 +00003060 cifs_buf_release(pSMB);
3061 if (rc == -EAGAIN)
3062 goto GetExtAttrRetry;
3063 return rc;
Steve Frenchf654bac2005-04-28 22:41:04 -07003064}
3065
Steve Frenchf654bac2005-04-28 22:41:04 -07003066#endif /* CONFIG_POSIX */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067
Steve French297647c2007-10-12 04:11:59 +00003068#ifdef CONFIG_CIFS_EXPERIMENTAL
Steve French0a4b92c2006-01-12 15:44:21 -08003069/* Get Security Descriptor (by handle) from remote server for a file or dir */
3070int
3071CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
Steve French50c2f752007-07-13 00:33:32 +00003072 /* BB fix up return info */ char *acl_inf, const int buflen,
Steve French442aa312007-09-24 20:25:46 +00003073 const int acl_type)
Steve French0a4b92c2006-01-12 15:44:21 -08003074{
3075 int rc = 0;
3076 int buf_type = 0;
3077 QUERY_SEC_DESC_REQ * pSMB;
3078 struct kvec iov[1];
3079
3080 cFYI(1, ("GetCifsACL"));
3081
Steve French50c2f752007-07-13 00:33:32 +00003082 rc = smb_init_ntransact(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,
3099 0 /* not long op */, 0 /* do not log STATUS codes */ );
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 French442aa312007-09-24 20:25:46 +00003104 struct cifs_ntsd *psec_desc;
Steve French0a4b92c2006-01-12 15:44:21 -08003105 __le32 * parm;
3106 int parm_len;
3107 int data_len;
3108 int acl_len;
Steve French50c2f752007-07-13 00:33:32 +00003109 struct smb_com_ntransact_rsp *pSMBr;
Steve French0a4b92c2006-01-12 15:44:21 -08003110
3111/* validate_nttransact */
Steve French50c2f752007-07-13 00:33:32 +00003112 rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
Steve French0a4b92c2006-01-12 15:44:21 -08003113 (char **)&psec_desc,
3114 &parm_len, &data_len);
Steve French790fe572007-07-07 19:25:05 +00003115 if (rc)
Steve French0a4b92c2006-01-12 15:44:21 -08003116 goto qsec_out;
3117 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
3118
Steve Frencha0136892007-10-04 20:05:09 +00003119 cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, psec_desc));
Steve French0a4b92c2006-01-12 15:44:21 -08003120
3121 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
3122 rc = -EIO; /* bad smb */
3123 goto qsec_out;
3124 }
3125
3126/* BB check that data area is minimum length and as big as acl_len */
3127
Steve Frenchaf6f4612007-10-16 18:40:37 +00003128 acl_len = le32_to_cpu(*parm);
Steve French790fe572007-07-07 19:25:05 +00003129 /* BB check if (acl_len > bufsize) */
Steve French0a4b92c2006-01-12 15:44:21 -08003130
3131 parse_sec_desc(psec_desc, acl_len);
3132 }
3133qsec_out:
Steve French790fe572007-07-07 19:25:05 +00003134 if (buf_type == CIFS_SMALL_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003135 cifs_small_buf_release(iov[0].iov_base);
Steve French790fe572007-07-07 19:25:05 +00003136 else if (buf_type == CIFS_LARGE_BUFFER)
Steve French0a4b92c2006-01-12 15:44:21 -08003137 cifs_buf_release(iov[0].iov_base);
Steve French4b8f9302006-02-26 16:41:18 +00003138/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
Steve French0a4b92c2006-01-12 15:44:21 -08003139 return rc;
3140}
Steve French297647c2007-10-12 04:11:59 +00003141#endif /* CONFIG_CIFS_EXPERIMENTAL */
Steve French0a4b92c2006-01-12 15:44:21 -08003142
Steve French6b8edfe2005-08-23 20:26:03 -07003143/* Legacy Query Path Information call for lookup to old servers such
3144 as Win9x/WinME */
3145int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003146 const unsigned char *searchName,
3147 FILE_ALL_INFO *pFinfo,
3148 const struct nls_table *nls_codepage, int remap)
Steve French6b8edfe2005-08-23 20:26:03 -07003149{
3150 QUERY_INFORMATION_REQ * pSMB;
3151 QUERY_INFORMATION_RSP * pSMBr;
3152 int rc = 0;
3153 int bytes_returned;
3154 int name_len;
3155
Steve French50c2f752007-07-13 00:33:32 +00003156 cFYI(1, ("In SMBQPath path %s", searchName));
Steve French6b8edfe2005-08-23 20:26:03 -07003157QInfRetry:
3158 rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003159 (void **) &pSMBr);
Steve French6b8edfe2005-08-23 20:26:03 -07003160 if (rc)
3161 return rc;
3162
3163 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3164 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003165 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3166 PATH_MAX, nls_codepage, remap);
Steve French6b8edfe2005-08-23 20:26:03 -07003167 name_len++; /* trailing null */
3168 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003169 } else {
Steve French6b8edfe2005-08-23 20:26:03 -07003170 name_len = strnlen(searchName, PATH_MAX);
3171 name_len++; /* trailing null */
3172 strncpy(pSMB->FileName, searchName, name_len);
3173 }
3174 pSMB->BufferFormat = 0x04;
Steve French50c2f752007-07-13 00:33:32 +00003175 name_len++; /* account for buffer type byte */
Steve French6b8edfe2005-08-23 20:26:03 -07003176 pSMB->hdr.smb_buf_length += (__u16) name_len;
3177 pSMB->ByteCount = cpu_to_le16(name_len);
3178
3179 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003180 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve French6b8edfe2005-08-23 20:26:03 -07003181 if (rc) {
3182 cFYI(1, ("Send error in QueryInfo = %d", rc));
3183 } else if (pFinfo) { /* decode response */
Steve French1bd5bbc2006-09-28 03:35:57 +00003184 struct timespec ts;
3185 __u32 time = le32_to_cpu(pSMBr->last_write_time);
3186 /* BB FIXME - add time zone adjustment BB */
Steve French6b8edfe2005-08-23 20:26:03 -07003187 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
Steve French1bd5bbc2006-09-28 03:35:57 +00003188 ts.tv_nsec = 0;
3189 ts.tv_sec = time;
3190 /* decode time fields */
Al Viro733f99a2006-10-14 16:48:26 +01003191 pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
Steve French1bd5bbc2006-09-28 03:35:57 +00003192 pFinfo->LastWriteTime = pFinfo->ChangeTime;
3193 pFinfo->LastAccessTime = 0;
Steve French70ca7342005-09-22 16:32:06 -07003194 pFinfo->AllocationSize =
3195 cpu_to_le64(le32_to_cpu(pSMBr->size));
3196 pFinfo->EndOfFile = pFinfo->AllocationSize;
3197 pFinfo->Attributes =
3198 cpu_to_le32(le16_to_cpu(pSMBr->attr));
Steve French6b8edfe2005-08-23 20:26:03 -07003199 } else
3200 rc = -EIO; /* bad buffer passed in */
3201
3202 cifs_buf_release(pSMB);
3203
3204 if (rc == -EAGAIN)
3205 goto QInfRetry;
3206
3207 return rc;
3208}
3209
3210
3211
3212
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213int
3214CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
3215 const unsigned char *searchName,
3216 FILE_ALL_INFO * pFindData,
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003217 int legacy /* old style infolevel */,
Steve French737b7582005-04-28 22:41:06 -07003218 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219{
3220/* level 263 SMB_QUERY_FILE_ALL_INFO */
3221 TRANSACTION2_QPI_REQ *pSMB = NULL;
3222 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3223 int rc = 0;
3224 int bytes_returned;
3225 int name_len;
3226 __u16 params, byte_count;
3227
3228/* cFYI(1, ("In QPathInfo path %s", searchName)); */
3229QPathInfoRetry:
3230 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3231 (void **) &pSMBr);
3232 if (rc)
3233 return rc;
3234
3235 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3236 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003237 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003238 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239 name_len++; /* trailing null */
3240 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003241 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003242 name_len = strnlen(searchName, PATH_MAX);
3243 name_len++; /* trailing null */
3244 strncpy(pSMB->FileName, searchName, name_len);
3245 }
3246
Steve French50c2f752007-07-13 00:33:32 +00003247 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 pSMB->TotalDataCount = 0;
3249 pSMB->MaxParameterCount = cpu_to_le16(2);
3250 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3251 pSMB->MaxSetupCount = 0;
3252 pSMB->Reserved = 0;
3253 pSMB->Flags = 0;
3254 pSMB->Timeout = 0;
3255 pSMB->Reserved2 = 0;
3256 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003257 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 pSMB->DataCount = 0;
3259 pSMB->DataOffset = 0;
3260 pSMB->SetupCount = 1;
3261 pSMB->Reserved3 = 0;
3262 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3263 byte_count = params + 1 /* pad */ ;
3264 pSMB->TotalParameterCount = cpu_to_le16(params);
3265 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00003266 if (legacy)
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003267 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3268 else
3269 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 pSMB->Reserved4 = 0;
3271 pSMB->hdr.smb_buf_length += byte_count;
3272 pSMB->ByteCount = cpu_to_le16(byte_count);
3273
3274 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3275 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3276 if (rc) {
3277 cFYI(1, ("Send error in QPathInfo = %d", rc));
3278 } else { /* decode response */
3279 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3280
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003281 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3282 rc = -EIO;
Steve French50c2f752007-07-13 00:33:32 +00003283 else if (!legacy && (pSMBr->ByteCount < 40))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 rc = -EIO; /* bad smb */
Steve French790fe572007-07-07 19:25:05 +00003285 else if (legacy && (pSMBr->ByteCount < 24))
Steve French50c2f752007-07-13 00:33:32 +00003286 rc = -EIO; /* 24 or 26 expected but we do not read
3287 last field */
3288 else if (pFindData) {
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003289 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003291 if (legacy) /* we do not read the last field, EAsize,
3292 fortunately since it varies by subdialect
3293 and on Set vs. Get, is two bytes or 4
3294 bytes depending but we don't care here */
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003295 size = sizeof(FILE_INFO_STANDARD);
3296 else
3297 size = sizeof(FILE_ALL_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 memcpy((char *) pFindData,
3299 (char *) &pSMBr->hdr.Protocol +
Steve Frenchacf1a1b2006-10-12 03:28:28 +00003300 data_offset, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 } else
3302 rc = -ENOMEM;
3303 }
3304 cifs_buf_release(pSMB);
3305 if (rc == -EAGAIN)
3306 goto QPathInfoRetry;
3307
3308 return rc;
3309}
3310
3311int
3312CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
3313 const unsigned char *searchName,
3314 FILE_UNIX_BASIC_INFO * pFindData,
Steve French737b7582005-04-28 22:41:06 -07003315 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316{
3317/* SMB_QUERY_FILE_UNIX_BASIC */
3318 TRANSACTION2_QPI_REQ *pSMB = NULL;
3319 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3320 int rc = 0;
3321 int bytes_returned = 0;
3322 int name_len;
3323 __u16 params, byte_count;
3324
3325 cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
3326UnixQPathInfoRetry:
3327 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3328 (void **) &pSMBr);
3329 if (rc)
3330 return rc;
3331
3332 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3333 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003334 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003335 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336 name_len++; /* trailing null */
3337 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003338 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003339 name_len = strnlen(searchName, PATH_MAX);
3340 name_len++; /* trailing null */
3341 strncpy(pSMB->FileName, searchName, name_len);
3342 }
3343
Steve French50c2f752007-07-13 00:33:32 +00003344 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 pSMB->TotalDataCount = 0;
3346 pSMB->MaxParameterCount = cpu_to_le16(2);
3347 /* BB find exact max SMB PDU from sess structure BB */
Steve French50c2f752007-07-13 00:33:32 +00003348 pSMB->MaxDataCount = cpu_to_le16(4000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349 pSMB->MaxSetupCount = 0;
3350 pSMB->Reserved = 0;
3351 pSMB->Flags = 0;
3352 pSMB->Timeout = 0;
3353 pSMB->Reserved2 = 0;
3354 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003355 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356 pSMB->DataCount = 0;
3357 pSMB->DataOffset = 0;
3358 pSMB->SetupCount = 1;
3359 pSMB->Reserved3 = 0;
3360 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3361 byte_count = params + 1 /* pad */ ;
3362 pSMB->TotalParameterCount = cpu_to_le16(params);
3363 pSMB->ParameterCount = pSMB->TotalParameterCount;
3364 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
3365 pSMB->Reserved4 = 0;
3366 pSMB->hdr.smb_buf_length += byte_count;
3367 pSMB->ByteCount = cpu_to_le16(byte_count);
3368
3369 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3370 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3371 if (rc) {
3372 cFYI(1, ("Send error in QPathInfo = %d", rc));
3373 } else { /* decode response */
3374 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3375
3376 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
Steve French1e71f252007-09-20 15:30:07 +00003377 cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n"
3378 "Unix Extensions can be disabled on mount "
3379 "by specifying the nosfu mount option."));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003380 rc = -EIO; /* bad smb */
3381 } else {
3382 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3383 memcpy((char *) pFindData,
3384 (char *) &pSMBr->hdr.Protocol +
3385 data_offset,
3386 sizeof (FILE_UNIX_BASIC_INFO));
3387 }
3388 }
3389 cifs_buf_release(pSMB);
3390 if (rc == -EAGAIN)
3391 goto UnixQPathInfoRetry;
3392
3393 return rc;
3394}
3395
3396#if 0 /* function unused at present */
3397int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
3398 const char *searchName, FILE_ALL_INFO * findData,
3399 const struct nls_table *nls_codepage)
3400{
3401/* level 257 SMB_ */
3402 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3403 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3404 int rc = 0;
3405 int bytes_returned;
3406 int name_len;
3407 __u16 params, byte_count;
3408
3409 cFYI(1, ("In FindUnique"));
3410findUniqueRetry:
3411 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3412 (void **) &pSMBr);
3413 if (rc)
3414 return rc;
3415
3416 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3417 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003418 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3419 PATH_MAX, nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003420 name_len++; /* trailing null */
3421 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003422 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 name_len = strnlen(searchName, PATH_MAX);
3424 name_len++; /* trailing null */
3425 strncpy(pSMB->FileName, searchName, name_len);
3426 }
3427
3428 params = 12 + name_len /* includes null */ ;
3429 pSMB->TotalDataCount = 0; /* no EAs */
3430 pSMB->MaxParameterCount = cpu_to_le16(2);
3431 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3432 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(
Steve French50c2f752007-07-13 00:33:32 +00003438 offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 pSMB->DataCount = 0;
3440 pSMB->DataOffset = 0;
3441 pSMB->SetupCount = 1; /* one byte, no need to le convert */
3442 pSMB->Reserved3 = 0;
3443 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3444 byte_count = params + 1 /* pad */ ;
3445 pSMB->TotalParameterCount = cpu_to_le16(params);
3446 pSMB->ParameterCount = pSMB->TotalParameterCount;
3447 pSMB->SearchAttributes =
3448 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3449 ATTR_DIRECTORY);
3450 pSMB->SearchCount = cpu_to_le16(16); /* BB increase */
3451 pSMB->SearchFlags = cpu_to_le16(1);
3452 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3453 pSMB->SearchStorageType = 0; /* BB what should we set this to? BB */
3454 pSMB->hdr.smb_buf_length += byte_count;
3455 pSMB->ByteCount = cpu_to_le16(byte_count);
3456
3457 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3458 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3459
3460 if (rc) {
3461 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
3462 } else { /* decode response */
Steve Frencha4544342005-08-24 13:59:35 -07003463 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464 /* BB fill in */
3465 }
3466
3467 cifs_buf_release(pSMB);
3468 if (rc == -EAGAIN)
3469 goto findUniqueRetry;
3470
3471 return rc;
3472}
3473#endif /* end unused (temporarily) function */
3474
3475/* xid, tcon, searchName and codepage are input parms, rest are returned */
3476int
3477CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003478 const char *searchName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003479 const struct nls_table *nls_codepage,
Steve French50c2f752007-07-13 00:33:32 +00003480 __u16 *pnetfid,
3481 struct cifs_search_info *psrch_inf, int remap, const char dirsep)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482{
3483/* level 257 SMB_ */
3484 TRANSACTION2_FFIRST_REQ *pSMB = NULL;
3485 TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
3486 T2_FFIRST_RSP_PARMS * parms;
3487 int rc = 0;
3488 int bytes_returned = 0;
3489 int name_len;
3490 __u16 params, byte_count;
3491
Steve French50c2f752007-07-13 00:33:32 +00003492 cFYI(1, ("In FindFirst for %s", searchName));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493
3494findFirstRetry:
3495 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3496 (void **) &pSMBr);
3497 if (rc)
3498 return rc;
3499
3500 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3501 name_len =
Steve French50c2f752007-07-13 00:33:32 +00003502 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07003503 PATH_MAX, nls_codepage, remap);
3504 /* We can not add the asterik earlier in case
3505 it got remapped to 0xF03A as if it were part of the
3506 directory name instead of a wildcard */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 name_len *= 2;
Jeremy Allisonac670552005-06-22 17:26:35 -07003508 pSMB->FileName[name_len] = dirsep;
Steve French737b7582005-04-28 22:41:06 -07003509 pSMB->FileName[name_len+1] = 0;
3510 pSMB->FileName[name_len+2] = '*';
3511 pSMB->FileName[name_len+3] = 0;
3512 name_len += 4; /* now the trailing null */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003513 pSMB->FileName[name_len] = 0; /* null terminate just in case */
3514 pSMB->FileName[name_len+1] = 0;
Steve French737b7582005-04-28 22:41:06 -07003515 name_len += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516 } else { /* BB add check for overrun of SMB buf BB */
3517 name_len = strnlen(searchName, PATH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003518/* BB fix here and in unicode clause above ie
Steve French790fe572007-07-07 19:25:05 +00003519 if (name_len > buffersize-header)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 free buffer exit; BB */
3521 strncpy(pSMB->FileName, searchName, name_len);
Jeremy Allisonac670552005-06-22 17:26:35 -07003522 pSMB->FileName[name_len] = dirsep;
Steve French68575472005-04-30 11:10:57 -07003523 pSMB->FileName[name_len+1] = '*';
3524 pSMB->FileName[name_len+2] = 0;
3525 name_len += 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003526 }
3527
3528 params = 12 + name_len /* includes null */ ;
3529 pSMB->TotalDataCount = 0; /* no EAs */
3530 pSMB->MaxParameterCount = cpu_to_le16(10);
3531 pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
3532 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3533 pSMB->MaxSetupCount = 0;
3534 pSMB->Reserved = 0;
3535 pSMB->Flags = 0;
3536 pSMB->Timeout = 0;
3537 pSMB->Reserved2 = 0;
3538 byte_count = params + 1 /* pad */ ;
3539 pSMB->TotalParameterCount = cpu_to_le16(params);
3540 pSMB->ParameterCount = pSMB->TotalParameterCount;
3541 pSMB->ParameterOffset = cpu_to_le16(
Steve French88274812006-03-09 22:21:45 +00003542 offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes)
3543 - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003544 pSMB->DataCount = 0;
3545 pSMB->DataOffset = 0;
3546 pSMB->SetupCount = 1; /* one byte, no need to make endian neutral */
3547 pSMB->Reserved3 = 0;
3548 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
3549 pSMB->SearchAttributes =
3550 cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
3551 ATTR_DIRECTORY);
Steve French50c2f752007-07-13 00:33:32 +00003552 pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
3553 pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554 CIFS_SEARCH_RETURN_RESUME);
3555 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3556
3557 /* BB what should we set StorageType to? Does it matter? BB */
3558 pSMB->SearchStorageType = 0;
3559 pSMB->hdr.smb_buf_length += byte_count;
3560 pSMB->ByteCount = cpu_to_le16(byte_count);
3561
3562 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3563 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003564 cifs_stats_inc(&tcon->num_ffirst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003565
Steve French88274812006-03-09 22:21:45 +00003566 if (rc) {/* BB add logic to retry regular search if Unix search
3567 rejected unexpectedly by server */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003568 /* BB Add code to handle unsupported level rc */
3569 cFYI(1, ("Error in FindFirst = %d", rc));
Steve French1982c342005-08-17 12:38:22 -07003570
Steve French88274812006-03-09 22:21:45 +00003571 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003572
3573 /* BB eventually could optimize out free and realloc of buf */
3574 /* for this case */
3575 if (rc == -EAGAIN)
3576 goto findFirstRetry;
3577 } else { /* decode response */
3578 /* BB remember to free buffer if error BB */
3579 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French790fe572007-07-07 19:25:05 +00003580 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3582 psrch_inf->unicode = TRUE;
3583 else
3584 psrch_inf->unicode = FALSE;
3585
3586 psrch_inf->ntwrk_buf_start = (char *)pSMBr;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003587 psrch_inf->smallBuf = 0;
Steve French50c2f752007-07-13 00:33:32 +00003588 psrch_inf->srch_entries_start =
3589 (char *) &pSMBr->hdr.Protocol +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003590 le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003591 parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
3592 le16_to_cpu(pSMBr->t2.ParameterOffset));
3593
Steve French790fe572007-07-07 19:25:05 +00003594 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 psrch_inf->endOfSearch = TRUE;
3596 else
3597 psrch_inf->endOfSearch = FALSE;
3598
Steve French50c2f752007-07-13 00:33:32 +00003599 psrch_inf->entries_in_buffer =
3600 le16_to_cpu(parms->SearchCount);
Steve French60808232006-04-22 15:53:05 +00003601 psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
Linus Torvalds1da177e2005-04-16 15:20:36 -07003602 psrch_inf->entries_in_buffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003603 *pnetfid = parms->SearchHandle;
3604 } else {
3605 cifs_buf_release(pSMB);
3606 }
3607 }
3608
3609 return rc;
3610}
3611
3612int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003613 __u16 searchHandle, struct cifs_search_info *psrch_inf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003614{
3615 TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3616 TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3617 T2_FNEXT_RSP_PARMS * parms;
3618 char *response_data;
3619 int rc = 0;
3620 int bytes_returned, name_len;
3621 __u16 params, byte_count;
3622
3623 cFYI(1, ("In FindNext"));
3624
Steve French790fe572007-07-07 19:25:05 +00003625 if (psrch_inf->endOfSearch == TRUE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003626 return -ENOENT;
3627
3628 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3629 (void **) &pSMBr);
3630 if (rc)
3631 return rc;
3632
Steve French50c2f752007-07-13 00:33:32 +00003633 params = 14; /* includes 2 bytes of null string, converted to LE below*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003634 byte_count = 0;
3635 pSMB->TotalDataCount = 0; /* no EAs */
3636 pSMB->MaxParameterCount = cpu_to_le16(8);
3637 pSMB->MaxDataCount =
Steve French50c2f752007-07-13 00:33:32 +00003638 cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
3639 0xFFFFFF00);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003640 pSMB->MaxSetupCount = 0;
3641 pSMB->Reserved = 0;
3642 pSMB->Flags = 0;
3643 pSMB->Timeout = 0;
3644 pSMB->Reserved2 = 0;
3645 pSMB->ParameterOffset = cpu_to_le16(
3646 offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3647 pSMB->DataCount = 0;
3648 pSMB->DataOffset = 0;
3649 pSMB->SetupCount = 1;
3650 pSMB->Reserved3 = 0;
3651 pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3652 pSMB->SearchHandle = searchHandle; /* always kept as le */
3653 pSMB->SearchCount =
3654 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003655 pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3656 pSMB->ResumeKey = psrch_inf->resume_key;
3657 pSMB->SearchFlags =
3658 cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3659
3660 name_len = psrch_inf->resume_name_len;
3661 params += name_len;
Steve French790fe572007-07-07 19:25:05 +00003662 if (name_len < PATH_MAX) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3664 byte_count += name_len;
Steve Frenchef6724e2005-08-02 21:31:05 -07003665 /* 14 byte parm len above enough for 2 byte null terminator */
3666 pSMB->ResumeFileName[name_len] = 0;
3667 pSMB->ResumeFileName[name_len+1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003668 } else {
3669 rc = -EINVAL;
3670 goto FNext2_err_exit;
3671 }
3672 byte_count = params + 1 /* pad */ ;
3673 pSMB->TotalParameterCount = cpu_to_le16(params);
3674 pSMB->ParameterCount = pSMB->TotalParameterCount;
3675 pSMB->hdr.smb_buf_length += byte_count;
3676 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00003677
Linus Torvalds1da177e2005-04-16 15:20:36 -07003678 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3679 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
Steve Frencha4544342005-08-24 13:59:35 -07003680 cifs_stats_inc(&tcon->num_fnext);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681 if (rc) {
3682 if (rc == -EBADF) {
3683 psrch_inf->endOfSearch = TRUE;
Steve French50c2f752007-07-13 00:33:32 +00003684 rc = 0; /* search probably was closed at end of search*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07003685 } else
3686 cFYI(1, ("FindNext returned = %d", rc));
3687 } else { /* decode response */
3688 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Steve French50c2f752007-07-13 00:33:32 +00003689
Steve French790fe572007-07-07 19:25:05 +00003690 if (rc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691 /* BB fixme add lock for file (srch_info) struct here */
3692 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3693 psrch_inf->unicode = TRUE;
3694 else
3695 psrch_inf->unicode = FALSE;
3696 response_data = (char *) &pSMBr->hdr.Protocol +
3697 le16_to_cpu(pSMBr->t2.ParameterOffset);
3698 parms = (T2_FNEXT_RSP_PARMS *)response_data;
3699 response_data = (char *)&pSMBr->hdr.Protocol +
3700 le16_to_cpu(pSMBr->t2.DataOffset);
Steve French790fe572007-07-07 19:25:05 +00003701 if (psrch_inf->smallBuf)
Steve Frenchd47d7c12006-02-28 03:45:48 +00003702 cifs_small_buf_release(
3703 psrch_inf->ntwrk_buf_start);
3704 else
3705 cifs_buf_release(psrch_inf->ntwrk_buf_start);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003706 psrch_inf->srch_entries_start = response_data;
3707 psrch_inf->ntwrk_buf_start = (char *)pSMB;
Steve Frenchd47d7c12006-02-28 03:45:48 +00003708 psrch_inf->smallBuf = 0;
Steve French790fe572007-07-07 19:25:05 +00003709 if (parms->EndofSearch)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710 psrch_inf->endOfSearch = TRUE;
3711 else
3712 psrch_inf->endOfSearch = FALSE;
Steve French50c2f752007-07-13 00:33:32 +00003713 psrch_inf->entries_in_buffer =
3714 le16_to_cpu(parms->SearchCount);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003715 psrch_inf->index_of_last_entry +=
3716 psrch_inf->entries_in_buffer;
Steve French50c2f752007-07-13 00:33:32 +00003717/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
3718 psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003719
3720 /* BB fixme add unlock here */
3721 }
3722
3723 }
3724
3725 /* BB On error, should we leave previous search buf (and count and
3726 last entry fields) intact or free the previous one? */
3727
3728 /* Note: On -EAGAIN error only caller can retry on handle based calls
3729 since file handle passed in no longer valid */
3730FNext2_err_exit:
3731 if (rc != 0)
3732 cifs_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733 return rc;
3734}
3735
3736int
Steve French50c2f752007-07-13 00:33:32 +00003737CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
3738 const __u16 searchHandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739{
3740 int rc = 0;
3741 FINDCLOSE_REQ *pSMB = NULL;
3742 CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3743 int bytes_returned;
3744
3745 cFYI(1, ("In CIFSSMBFindClose"));
3746 rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3747
3748 /* no sense returning error if session restarted
3749 as file handle has been closed */
Steve French790fe572007-07-07 19:25:05 +00003750 if (rc == -EAGAIN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 return 0;
3752 if (rc)
3753 return rc;
3754
3755 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
3756 pSMB->FileID = searchHandle;
3757 pSMB->ByteCount = 0;
3758 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3759 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3760 if (rc) {
3761 cERROR(1, ("Send error in FindClose = %d", rc));
3762 }
Steve Frencha4544342005-08-24 13:59:35 -07003763 cifs_stats_inc(&tcon->num_fclose);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764 cifs_small_buf_release(pSMB);
3765
3766 /* Since session is dead, search handle closed on server already */
3767 if (rc == -EAGAIN)
3768 rc = 0;
3769
3770 return rc;
3771}
3772
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773int
3774CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00003775 const unsigned char *searchName,
3776 __u64 * inode_number,
3777 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003778{
3779 int rc = 0;
3780 TRANSACTION2_QPI_REQ *pSMB = NULL;
3781 TRANSACTION2_QPI_RSP *pSMBr = NULL;
3782 int name_len, bytes_returned;
3783 __u16 params, byte_count;
3784
Steve French50c2f752007-07-13 00:33:32 +00003785 cFYI(1, ("In GetSrvInodeNum for %s", searchName));
Steve French790fe572007-07-07 19:25:05 +00003786 if (tcon == NULL)
Steve French50c2f752007-07-13 00:33:32 +00003787 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788
3789GetInodeNumberRetry:
3790 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00003791 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003792 if (rc)
3793 return rc;
3794
Linus Torvalds1da177e2005-04-16 15:20:36 -07003795 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3796 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003797 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French50c2f752007-07-13 00:33:32 +00003798 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 name_len++; /* trailing null */
3800 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003801 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003802 name_len = strnlen(searchName, PATH_MAX);
3803 name_len++; /* trailing null */
3804 strncpy(pSMB->FileName, searchName, name_len);
3805 }
3806
3807 params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
3808 pSMB->TotalDataCount = 0;
3809 pSMB->MaxParameterCount = cpu_to_le16(2);
3810 /* BB find exact max data count below from sess structure BB */
3811 pSMB->MaxDataCount = cpu_to_le16(4000);
3812 pSMB->MaxSetupCount = 0;
3813 pSMB->Reserved = 0;
3814 pSMB->Flags = 0;
3815 pSMB->Timeout = 0;
3816 pSMB->Reserved2 = 0;
3817 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003818 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819 pSMB->DataCount = 0;
3820 pSMB->DataOffset = 0;
3821 pSMB->SetupCount = 1;
3822 pSMB->Reserved3 = 0;
3823 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3824 byte_count = params + 1 /* pad */ ;
3825 pSMB->TotalParameterCount = cpu_to_le16(params);
3826 pSMB->ParameterCount = pSMB->TotalParameterCount;
3827 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3828 pSMB->Reserved4 = 0;
3829 pSMB->hdr.smb_buf_length += byte_count;
3830 pSMB->ByteCount = cpu_to_le16(byte_count);
3831
3832 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3833 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3834 if (rc) {
3835 cFYI(1, ("error %d in QueryInternalInfo", rc));
3836 } else {
3837 /* decode response */
3838 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3839 if (rc || (pSMBr->ByteCount < 2))
3840 /* BB also check enough total bytes returned */
3841 /* If rc should we check for EOPNOSUPP and
3842 disable the srvino flag? or in caller? */
3843 rc = -EIO; /* bad smb */
Steve French50c2f752007-07-13 00:33:32 +00003844 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3846 __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
Steve French50c2f752007-07-13 00:33:32 +00003847 struct file_internal_info *pfinfo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003848 /* BB Do we need a cast or hash here ? */
Steve French790fe572007-07-07 19:25:05 +00003849 if (count < 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3851 rc = -EIO;
3852 goto GetInodeNumOut;
3853 }
3854 pfinfo = (struct file_internal_info *)
3855 (data_offset + (char *) &pSMBr->hdr.Protocol);
3856 *inode_number = pfinfo->UniqueId;
3857 }
3858 }
3859GetInodeNumOut:
3860 cifs_buf_release(pSMB);
3861 if (rc == -EAGAIN)
3862 goto GetInodeNumberRetry;
3863 return rc;
3864}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865
3866int
3867CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3868 const unsigned char *searchName,
3869 unsigned char **targetUNCs,
3870 unsigned int *number_of_UNC_in_array,
Steve French737b7582005-04-28 22:41:06 -07003871 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872{
3873/* TRANS2_GET_DFS_REFERRAL */
3874 TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3875 TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
Steve French50c2f752007-07-13 00:33:32 +00003876 struct dfs_referral_level_3 *referrals = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003877 int rc = 0;
3878 int bytes_returned;
3879 int name_len;
3880 unsigned int i;
Steve French50c2f752007-07-13 00:33:32 +00003881 char *temp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882 __u16 params, byte_count;
3883 *number_of_UNC_in_array = 0;
3884 *targetUNCs = NULL;
3885
3886 cFYI(1, ("In GetDFSRefer the path %s", searchName));
3887 if (ses == NULL)
3888 return -ENODEV;
3889getDFSRetry:
3890 rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3891 (void **) &pSMBr);
3892 if (rc)
3893 return rc;
Steve French50c2f752007-07-13 00:33:32 +00003894
3895 /* server pointer checked in called function,
Steve French1982c342005-08-17 12:38:22 -07003896 but should never be null here anyway */
3897 pSMB->hdr.Mid = GetNextMid(ses->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898 pSMB->hdr.Tid = ses->ipc_tid;
3899 pSMB->hdr.Uid = ses->Suid;
Steve French26f57362007-08-30 22:09:15 +00003900 if (ses->capabilities & CAP_STATUS32)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
Steve French26f57362007-08-30 22:09:15 +00003902 if (ses->capabilities & CAP_DFS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003903 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904
3905 if (ses->capabilities & CAP_UNICODE) {
3906 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3907 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05003908 cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
Steve French737b7582005-04-28 22:41:06 -07003909 searchName, PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003910 name_len++; /* trailing null */
3911 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00003912 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003913 name_len = strnlen(searchName, PATH_MAX);
3914 name_len++; /* trailing null */
3915 strncpy(pSMB->RequestFileName, searchName, name_len);
3916 }
3917
Steve French790fe572007-07-07 19:25:05 +00003918 if (ses->server) {
3919 if (ses->server->secMode &
Steve French1a4e15a2006-10-12 21:33:51 +00003920 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3921 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3922 }
3923
Steve French50c2f752007-07-13 00:33:32 +00003924 pSMB->hdr.Uid = ses->Suid;
Steve French1a4e15a2006-10-12 21:33:51 +00003925
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926 params = 2 /* level */ + name_len /*includes null */ ;
3927 pSMB->TotalDataCount = 0;
3928 pSMB->DataCount = 0;
3929 pSMB->DataOffset = 0;
3930 pSMB->MaxParameterCount = 0;
3931 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3932 pSMB->MaxSetupCount = 0;
3933 pSMB->Reserved = 0;
3934 pSMB->Flags = 0;
3935 pSMB->Timeout = 0;
3936 pSMB->Reserved2 = 0;
3937 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00003938 struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003939 pSMB->SetupCount = 1;
3940 pSMB->Reserved3 = 0;
3941 pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3942 byte_count = params + 3 /* pad */ ;
3943 pSMB->ParameterCount = cpu_to_le16(params);
3944 pSMB->TotalParameterCount = pSMB->ParameterCount;
3945 pSMB->MaxReferralLevel = cpu_to_le16(3);
3946 pSMB->hdr.smb_buf_length += byte_count;
3947 pSMB->ByteCount = cpu_to_le16(byte_count);
3948
3949 rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3950 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3951 if (rc) {
3952 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3953 } else { /* decode response */
3954/* BB Add logic to parse referrals here */
3955 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3956
Steve French50c2f752007-07-13 00:33:32 +00003957 /* BB Also check if enough total bytes returned? */
3958 if (rc || (pSMBr->ByteCount < 17))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 rc = -EIO; /* bad smb */
3960 else {
Steve French50c2f752007-07-13 00:33:32 +00003961 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003962 __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3963
3964 cFYI(1,
Steve French50c2f752007-07-13 00:33:32 +00003965 ("Decoding GetDFSRefer response BCC: %d Offset %d",
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 pSMBr->ByteCount, data_offset));
Steve French50c2f752007-07-13 00:33:32 +00003967 referrals =
3968 (struct dfs_referral_level_3 *)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 (8 /* sizeof start of data block */ +
3970 data_offset +
Steve French50c2f752007-07-13 00:33:32 +00003971 (char *) &pSMBr->hdr.Protocol);
Steve Frenchc18c8422007-07-18 23:21:09 +00003972 cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
Steve French63135e02007-07-17 17:34:02 +00003973 "for referral one refer size: 0x%x srv "
3974 "type: 0x%x refer flags: 0x%x ttl: 0x%x",
Steve French50c2f752007-07-13 00:33:32 +00003975 le16_to_cpu(pSMBr->NumberOfReferrals),
3976 le16_to_cpu(pSMBr->DFSFlags),
3977 le16_to_cpu(referrals->ReferralSize),
3978 le16_to_cpu(referrals->ServerType),
3979 le16_to_cpu(referrals->ReferralFlags),
3980 le16_to_cpu(referrals->TimeToLive)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981 /* BB This field is actually two bytes in from start of
3982 data block so we could do safety check that DataBlock
3983 begins at address of pSMBr->NumberOfReferrals */
Steve French50c2f752007-07-13 00:33:32 +00003984 *number_of_UNC_in_array =
3985 le16_to_cpu(pSMBr->NumberOfReferrals);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986
3987 /* BB Fix below so can return more than one referral */
Steve French790fe572007-07-07 19:25:05 +00003988 if (*number_of_UNC_in_array > 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 *number_of_UNC_in_array = 1;
3990
3991 /* get the length of the strings describing refs */
3992 name_len = 0;
Steve French50c2f752007-07-13 00:33:32 +00003993 for (i = 0; i < *number_of_UNC_in_array; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003994 /* make sure that DfsPathOffset not past end */
Steve French50c2f752007-07-13 00:33:32 +00003995 __u16 offset =
3996 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003997 if (offset > data_count) {
Steve French50c2f752007-07-13 00:33:32 +00003998 /* if invalid referral, stop here and do
Linus Torvalds1da177e2005-04-16 15:20:36 -07003999 not try to copy any more */
4000 *number_of_UNC_in_array = i;
4001 break;
Steve French50c2f752007-07-13 00:33:32 +00004002 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003 temp = ((char *)referrals) + offset;
4004
4005 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
Steve French50c2f752007-07-13 00:33:32 +00004006 name_len += UniStrnlen((wchar_t *)temp,
4007 data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004008 } else {
Steve French50c2f752007-07-13 00:33:32 +00004009 name_len += strnlen(temp, data_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004010 }
4011 referrals++;
Steve French50c2f752007-07-13 00:33:32 +00004012 /* BB add check that referral pointer does
4013 not fall off end PDU */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014 }
4015 /* BB add check for name_len bigger than bcc */
Steve French50c2f752007-07-13 00:33:32 +00004016 *targetUNCs =
4017 kmalloc(name_len+1+(*number_of_UNC_in_array),
4018 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00004019 if (*targetUNCs == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004020 rc = -ENOMEM;
4021 goto GetDFSRefExit;
4022 }
4023 /* copy the ref strings */
Steve French50c2f752007-07-13 00:33:32 +00004024 referrals = (struct dfs_referral_level_3 *)
4025 (8 /* sizeof data hdr */ + data_offset +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004026 (char *) &pSMBr->hdr.Protocol);
4027
Steve French50c2f752007-07-13 00:33:32 +00004028 for (i = 0; i < *number_of_UNC_in_array; i++) {
4029 temp = ((char *)referrals) +
4030 le16_to_cpu(referrals->DfsPathOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004031 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
4032 cifs_strfromUCS_le(*targetUNCs,
Steve French50c2f752007-07-13 00:33:32 +00004033 (__le16 *) temp,
4034 name_len,
4035 nls_codepage);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 } else {
Steve French50c2f752007-07-13 00:33:32 +00004037 strncpy(*targetUNCs, temp, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 }
4039 /* BB update target_uncs pointers */
4040 referrals++;
4041 }
4042 temp = *targetUNCs;
4043 temp[name_len] = 0;
4044 }
4045
4046 }
4047GetDFSRefExit:
4048 if (pSMB)
4049 cifs_buf_release(pSMB);
4050
4051 if (rc == -EAGAIN)
4052 goto getDFSRetry;
4053
4054 return rc;
4055}
4056
Steve French20962432005-09-21 22:05:57 -07004057/* Query File System Info such as free space to old servers such as Win 9x */
4058int
4059SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
4060{
4061/* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
4062 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4063 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4064 FILE_SYSTEM_ALLOC_INFO *response_data;
4065 int rc = 0;
4066 int bytes_returned = 0;
4067 __u16 params, byte_count;
4068
4069 cFYI(1, ("OldQFSInfo"));
4070oldQFSInfoRetry:
4071 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4072 (void **) &pSMBr);
4073 if (rc)
4074 return rc;
Steve French20962432005-09-21 22:05:57 -07004075
4076 params = 2; /* level */
4077 pSMB->TotalDataCount = 0;
4078 pSMB->MaxParameterCount = cpu_to_le16(2);
4079 pSMB->MaxDataCount = cpu_to_le16(1000);
4080 pSMB->MaxSetupCount = 0;
4081 pSMB->Reserved = 0;
4082 pSMB->Flags = 0;
4083 pSMB->Timeout = 0;
4084 pSMB->Reserved2 = 0;
4085 byte_count = params + 1 /* pad */ ;
4086 pSMB->TotalParameterCount = cpu_to_le16(params);
4087 pSMB->ParameterCount = pSMB->TotalParameterCount;
4088 pSMB->ParameterOffset = cpu_to_le16(offsetof(
4089 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
4090 pSMB->DataCount = 0;
4091 pSMB->DataOffset = 0;
4092 pSMB->SetupCount = 1;
4093 pSMB->Reserved3 = 0;
4094 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4095 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
4096 pSMB->hdr.smb_buf_length += byte_count;
4097 pSMB->ByteCount = cpu_to_le16(byte_count);
4098
4099 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4100 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4101 if (rc) {
4102 cFYI(1, ("Send error in QFSInfo = %d", rc));
4103 } else { /* decode response */
4104 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4105
4106 if (rc || (pSMBr->ByteCount < 18))
4107 rc = -EIO; /* bad smb */
4108 else {
4109 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00004110 cFYI(1, ("qfsinf resp BCC: %d Offset %d",
Steve French20962432005-09-21 22:05:57 -07004111 pSMBr->ByteCount, data_offset));
4112
Steve French50c2f752007-07-13 00:33:32 +00004113 response_data = (FILE_SYSTEM_ALLOC_INFO *)
Steve French20962432005-09-21 22:05:57 -07004114 (((char *) &pSMBr->hdr.Protocol) + data_offset);
4115 FSData->f_bsize =
4116 le16_to_cpu(response_data->BytesPerSector) *
4117 le32_to_cpu(response_data->
4118 SectorsPerAllocationUnit);
4119 FSData->f_blocks =
Steve French50c2f752007-07-13 00:33:32 +00004120 le32_to_cpu(response_data->TotalAllocationUnits);
Steve French20962432005-09-21 22:05:57 -07004121 FSData->f_bfree = FSData->f_bavail =
4122 le32_to_cpu(response_data->FreeAllocationUnits);
4123 cFYI(1,
4124 ("Blocks: %lld Free: %lld Block size %ld",
4125 (unsigned long long)FSData->f_blocks,
4126 (unsigned long long)FSData->f_bfree,
4127 FSData->f_bsize));
4128 }
4129 }
4130 cifs_buf_release(pSMB);
4131
4132 if (rc == -EAGAIN)
4133 goto oldQFSInfoRetry;
4134
4135 return rc;
4136}
4137
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138int
Steve French737b7582005-04-28 22:41:06 -07004139CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140{
4141/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
4142 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4143 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4144 FILE_SYSTEM_INFO *response_data;
4145 int rc = 0;
4146 int bytes_returned = 0;
4147 __u16 params, byte_count;
4148
4149 cFYI(1, ("In QFSInfo"));
4150QFSInfoRetry:
4151 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4152 (void **) &pSMBr);
4153 if (rc)
4154 return rc;
4155
4156 params = 2; /* level */
4157 pSMB->TotalDataCount = 0;
4158 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French20962432005-09-21 22:05:57 -07004159 pSMB->MaxDataCount = cpu_to_le16(1000);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 pSMB->MaxSetupCount = 0;
4161 pSMB->Reserved = 0;
4162 pSMB->Flags = 0;
4163 pSMB->Timeout = 0;
4164 pSMB->Reserved2 = 0;
4165 byte_count = params + 1 /* pad */ ;
4166 pSMB->TotalParameterCount = cpu_to_le16(params);
4167 pSMB->ParameterCount = pSMB->TotalParameterCount;
4168 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004169 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 pSMB->DataCount = 0;
4171 pSMB->DataOffset = 0;
4172 pSMB->SetupCount = 1;
4173 pSMB->Reserved3 = 0;
4174 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4175 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
4176 pSMB->hdr.smb_buf_length += byte_count;
4177 pSMB->ByteCount = cpu_to_le16(byte_count);
4178
4179 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4180 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4181 if (rc) {
Steve French20962432005-09-21 22:05:57 -07004182 cFYI(1, ("Send error in QFSInfo = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183 } else { /* decode response */
Steve French50c2f752007-07-13 00:33:32 +00004184 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004185
Steve French20962432005-09-21 22:05:57 -07004186 if (rc || (pSMBr->ByteCount < 24))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 rc = -EIO; /* bad smb */
4188 else {
4189 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190
4191 response_data =
4192 (FILE_SYSTEM_INFO
4193 *) (((char *) &pSMBr->hdr.Protocol) +
4194 data_offset);
4195 FSData->f_bsize =
4196 le32_to_cpu(response_data->BytesPerSector) *
4197 le32_to_cpu(response_data->
4198 SectorsPerAllocationUnit);
4199 FSData->f_blocks =
4200 le64_to_cpu(response_data->TotalAllocationUnits);
4201 FSData->f_bfree = FSData->f_bavail =
4202 le64_to_cpu(response_data->FreeAllocationUnits);
4203 cFYI(1,
4204 ("Blocks: %lld Free: %lld Block size %ld",
4205 (unsigned long long)FSData->f_blocks,
4206 (unsigned long long)FSData->f_bfree,
4207 FSData->f_bsize));
4208 }
4209 }
4210 cifs_buf_release(pSMB);
4211
4212 if (rc == -EAGAIN)
4213 goto QFSInfoRetry;
4214
4215 return rc;
4216}
4217
4218int
Steve French737b7582005-04-28 22:41:06 -07004219CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004220{
4221/* level 0x105 SMB_QUERY_FILE_SYSTEM_INFO */
4222 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4223 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4224 FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
4225 int rc = 0;
4226 int bytes_returned = 0;
4227 __u16 params, byte_count;
4228
4229 cFYI(1, ("In QFSAttributeInfo"));
4230QFSAttributeRetry:
4231 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4232 (void **) &pSMBr);
4233 if (rc)
4234 return rc;
4235
4236 params = 2; /* level */
4237 pSMB->TotalDataCount = 0;
4238 pSMB->MaxParameterCount = cpu_to_le16(2);
4239 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4240 pSMB->MaxSetupCount = 0;
4241 pSMB->Reserved = 0;
4242 pSMB->Flags = 0;
4243 pSMB->Timeout = 0;
4244 pSMB->Reserved2 = 0;
4245 byte_count = params + 1 /* pad */ ;
4246 pSMB->TotalParameterCount = cpu_to_le16(params);
4247 pSMB->ParameterCount = pSMB->TotalParameterCount;
4248 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004249 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004250 pSMB->DataCount = 0;
4251 pSMB->DataOffset = 0;
4252 pSMB->SetupCount = 1;
4253 pSMB->Reserved3 = 0;
4254 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4255 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
4256 pSMB->hdr.smb_buf_length += byte_count;
4257 pSMB->ByteCount = cpu_to_le16(byte_count);
4258
4259 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4260 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4261 if (rc) {
4262 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
4263 } else { /* decode response */
4264 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4265
Steve French50c2f752007-07-13 00:33:32 +00004266 if (rc || (pSMBr->ByteCount < 13)) {
4267 /* BB also check if enough bytes returned */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004268 rc = -EIO; /* bad smb */
4269 } else {
4270 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4271 response_data =
4272 (FILE_SYSTEM_ATTRIBUTE_INFO
4273 *) (((char *) &pSMBr->hdr.Protocol) +
4274 data_offset);
4275 memcpy(&tcon->fsAttrInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004276 sizeof(FILE_SYSTEM_ATTRIBUTE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277 }
4278 }
4279 cifs_buf_release(pSMB);
4280
4281 if (rc == -EAGAIN)
4282 goto QFSAttributeRetry;
4283
4284 return rc;
4285}
4286
4287int
Steve French737b7582005-04-28 22:41:06 -07004288CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289{
4290/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
4291 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4292 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4293 FILE_SYSTEM_DEVICE_INFO *response_data;
4294 int rc = 0;
4295 int bytes_returned = 0;
4296 __u16 params, byte_count;
4297
4298 cFYI(1, ("In QFSDeviceInfo"));
4299QFSDeviceRetry:
4300 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4301 (void **) &pSMBr);
4302 if (rc)
4303 return rc;
4304
4305 params = 2; /* level */
4306 pSMB->TotalDataCount = 0;
4307 pSMB->MaxParameterCount = cpu_to_le16(2);
4308 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4309 pSMB->MaxSetupCount = 0;
4310 pSMB->Reserved = 0;
4311 pSMB->Flags = 0;
4312 pSMB->Timeout = 0;
4313 pSMB->Reserved2 = 0;
4314 byte_count = params + 1 /* pad */ ;
4315 pSMB->TotalParameterCount = cpu_to_le16(params);
4316 pSMB->ParameterCount = pSMB->TotalParameterCount;
4317 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00004318 struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004319
4320 pSMB->DataCount = 0;
4321 pSMB->DataOffset = 0;
4322 pSMB->SetupCount = 1;
4323 pSMB->Reserved3 = 0;
4324 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4325 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
4326 pSMB->hdr.smb_buf_length += byte_count;
4327 pSMB->ByteCount = cpu_to_le16(byte_count);
4328
4329 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4330 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4331 if (rc) {
4332 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
4333 } else { /* decode response */
4334 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4335
4336 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
4337 rc = -EIO; /* bad smb */
4338 else {
4339 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4340 response_data =
Steve French737b7582005-04-28 22:41:06 -07004341 (FILE_SYSTEM_DEVICE_INFO *)
4342 (((char *) &pSMBr->hdr.Protocol) +
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343 data_offset);
4344 memcpy(&tcon->fsDevInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004345 sizeof(FILE_SYSTEM_DEVICE_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 }
4347 }
4348 cifs_buf_release(pSMB);
4349
4350 if (rc == -EAGAIN)
4351 goto QFSDeviceRetry;
4352
4353 return rc;
4354}
4355
4356int
Steve French737b7582005-04-28 22:41:06 -07004357CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358{
4359/* level 0x200 SMB_QUERY_CIFS_UNIX_INFO */
4360 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4361 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4362 FILE_SYSTEM_UNIX_INFO *response_data;
4363 int rc = 0;
4364 int bytes_returned = 0;
4365 __u16 params, byte_count;
4366
4367 cFYI(1, ("In QFSUnixInfo"));
4368QFSUnixRetry:
4369 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4370 (void **) &pSMBr);
4371 if (rc)
4372 return rc;
4373
4374 params = 2; /* level */
4375 pSMB->TotalDataCount = 0;
4376 pSMB->DataCount = 0;
4377 pSMB->DataOffset = 0;
4378 pSMB->MaxParameterCount = cpu_to_le16(2);
4379 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4380 pSMB->MaxSetupCount = 0;
4381 pSMB->Reserved = 0;
4382 pSMB->Flags = 0;
4383 pSMB->Timeout = 0;
4384 pSMB->Reserved2 = 0;
4385 byte_count = params + 1 /* pad */ ;
4386 pSMB->ParameterCount = cpu_to_le16(params);
4387 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004388 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4389 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 pSMB->SetupCount = 1;
4391 pSMB->Reserved3 = 0;
4392 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4393 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
4394 pSMB->hdr.smb_buf_length += byte_count;
4395 pSMB->ByteCount = cpu_to_le16(byte_count);
4396
4397 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4398 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4399 if (rc) {
4400 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
4401 } else { /* decode response */
4402 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4403
4404 if (rc || (pSMBr->ByteCount < 13)) {
4405 rc = -EIO; /* bad smb */
4406 } else {
4407 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4408 response_data =
4409 (FILE_SYSTEM_UNIX_INFO
4410 *) (((char *) &pSMBr->hdr.Protocol) +
4411 data_offset);
4412 memcpy(&tcon->fsUnixInfo, response_data,
Steve French26f57362007-08-30 22:09:15 +00004413 sizeof(FILE_SYSTEM_UNIX_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 }
4415 }
4416 cifs_buf_release(pSMB);
4417
4418 if (rc == -EAGAIN)
4419 goto QFSUnixRetry;
4420
4421
4422 return rc;
4423}
4424
Jeremy Allisonac670552005-06-22 17:26:35 -07004425int
Steve French45abc6e2005-06-23 13:42:03 -05004426CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
Jeremy Allisonac670552005-06-22 17:26:35 -07004427{
4428/* level 0x200 SMB_SET_CIFS_UNIX_INFO */
4429 TRANSACTION2_SETFSI_REQ *pSMB = NULL;
4430 TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
4431 int rc = 0;
4432 int bytes_returned = 0;
4433 __u16 params, param_offset, offset, byte_count;
4434
4435 cFYI(1, ("In SETFSUnixInfo"));
4436SETFSUnixRetry:
Steve Frenchf26282c2006-03-01 09:17:37 +00004437 /* BB switch to small buf init to save memory */
Jeremy Allisonac670552005-06-22 17:26:35 -07004438 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4439 (void **) &pSMBr);
4440 if (rc)
4441 return rc;
4442
4443 params = 4; /* 2 bytes zero followed by info level. */
4444 pSMB->MaxSetupCount = 0;
4445 pSMB->Reserved = 0;
4446 pSMB->Flags = 0;
4447 pSMB->Timeout = 0;
4448 pSMB->Reserved2 = 0;
Steve French50c2f752007-07-13 00:33:32 +00004449 param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
4450 - 4;
Jeremy Allisonac670552005-06-22 17:26:35 -07004451 offset = param_offset + params;
4452
4453 pSMB->MaxParameterCount = cpu_to_le16(4);
4454 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4455 pSMB->SetupCount = 1;
4456 pSMB->Reserved3 = 0;
4457 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
4458 byte_count = 1 /* pad */ + params + 12;
4459
4460 pSMB->DataCount = cpu_to_le16(12);
4461 pSMB->ParameterCount = cpu_to_le16(params);
4462 pSMB->TotalDataCount = pSMB->DataCount;
4463 pSMB->TotalParameterCount = pSMB->ParameterCount;
4464 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4465 pSMB->DataOffset = cpu_to_le16(offset);
4466
4467 /* Params. */
4468 pSMB->FileNum = 0;
4469 pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
4470
4471 /* Data. */
4472 pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
4473 pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
4474 pSMB->ClientUnixCap = cpu_to_le64(cap);
4475
4476 pSMB->hdr.smb_buf_length += byte_count;
4477 pSMB->ByteCount = cpu_to_le16(byte_count);
4478
4479 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4480 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4481 if (rc) {
4482 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
4483 } else { /* decode response */
4484 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4485 if (rc) {
4486 rc = -EIO; /* bad smb */
4487 }
4488 }
4489 cifs_buf_release(pSMB);
4490
4491 if (rc == -EAGAIN)
4492 goto SETFSUnixRetry;
4493
4494 return rc;
4495}
4496
4497
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498
4499int
4500CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
Steve French737b7582005-04-28 22:41:06 -07004501 struct kstatfs *FSData)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502{
4503/* level 0x201 SMB_QUERY_CIFS_POSIX_INFO */
4504 TRANSACTION2_QFSI_REQ *pSMB = NULL;
4505 TRANSACTION2_QFSI_RSP *pSMBr = NULL;
4506 FILE_SYSTEM_POSIX_INFO *response_data;
4507 int rc = 0;
4508 int bytes_returned = 0;
4509 __u16 params, byte_count;
4510
4511 cFYI(1, ("In QFSPosixInfo"));
4512QFSPosixRetry:
4513 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4514 (void **) &pSMBr);
4515 if (rc)
4516 return rc;
4517
4518 params = 2; /* level */
4519 pSMB->TotalDataCount = 0;
4520 pSMB->DataCount = 0;
4521 pSMB->DataOffset = 0;
4522 pSMB->MaxParameterCount = cpu_to_le16(2);
4523 pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */
4524 pSMB->MaxSetupCount = 0;
4525 pSMB->Reserved = 0;
4526 pSMB->Flags = 0;
4527 pSMB->Timeout = 0;
4528 pSMB->Reserved2 = 0;
4529 byte_count = params + 1 /* pad */ ;
4530 pSMB->ParameterCount = cpu_to_le16(params);
4531 pSMB->TotalParameterCount = pSMB->ParameterCount;
Steve French50c2f752007-07-13 00:33:32 +00004532 pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
4533 smb_com_transaction2_qfsi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004534 pSMB->SetupCount = 1;
4535 pSMB->Reserved3 = 0;
4536 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
4537 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
4538 pSMB->hdr.smb_buf_length += byte_count;
4539 pSMB->ByteCount = cpu_to_le16(byte_count);
4540
4541 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4542 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4543 if (rc) {
4544 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
4545 } else { /* decode response */
4546 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4547
4548 if (rc || (pSMBr->ByteCount < 13)) {
4549 rc = -EIO; /* bad smb */
4550 } else {
4551 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4552 response_data =
4553 (FILE_SYSTEM_POSIX_INFO
4554 *) (((char *) &pSMBr->hdr.Protocol) +
4555 data_offset);
4556 FSData->f_bsize =
4557 le32_to_cpu(response_data->BlockSize);
4558 FSData->f_blocks =
4559 le64_to_cpu(response_data->TotalBlocks);
4560 FSData->f_bfree =
4561 le64_to_cpu(response_data->BlocksAvail);
Steve French790fe572007-07-07 19:25:05 +00004562 if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004563 FSData->f_bavail = FSData->f_bfree;
4564 } else {
4565 FSData->f_bavail =
Steve French50c2f752007-07-13 00:33:32 +00004566 le64_to_cpu(response_data->UserBlocksAvail);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004567 }
Steve French790fe572007-07-07 19:25:05 +00004568 if (response_data->TotalFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 FSData->f_files =
Steve French50c2f752007-07-13 00:33:32 +00004570 le64_to_cpu(response_data->TotalFileNodes);
Steve French790fe572007-07-07 19:25:05 +00004571 if (response_data->FreeFileNodes != cpu_to_le64(-1))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 FSData->f_ffree =
Steve French50c2f752007-07-13 00:33:32 +00004573 le64_to_cpu(response_data->FreeFileNodes);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574 }
4575 }
4576 cifs_buf_release(pSMB);
4577
4578 if (rc == -EAGAIN)
4579 goto QFSPosixRetry;
4580
4581 return rc;
4582}
4583
4584
Steve French50c2f752007-07-13 00:33:32 +00004585/* We can not use write of zero bytes trick to
4586 set file size due to need for large file support. Also note that
4587 this SetPathInfo is preferred to SetFileInfo based method in next
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 routine which is only needed to work around a sharing violation bug
4589 in Samba which this routine can run into */
4590
4591int
4592CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004593 __u64 size, int SetAllocation,
Steve French737b7582005-04-28 22:41:06 -07004594 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595{
4596 struct smb_com_transaction2_spi_req *pSMB = NULL;
4597 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4598 struct file_end_of_file_info *parm_data;
4599 int name_len;
4600 int rc = 0;
4601 int bytes_returned = 0;
4602 __u16 params, byte_count, data_count, param_offset, offset;
4603
4604 cFYI(1, ("In SetEOF"));
4605SetEOFRetry:
4606 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4607 (void **) &pSMBr);
4608 if (rc)
4609 return rc;
4610
4611 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4612 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004613 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004614 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615 name_len++; /* trailing null */
4616 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07004617 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618 name_len = strnlen(fileName, PATH_MAX);
4619 name_len++; /* trailing null */
4620 strncpy(pSMB->FileName, fileName, name_len);
4621 }
4622 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004623 data_count = sizeof(struct file_end_of_file_info);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 pSMB->MaxParameterCount = cpu_to_le16(2);
Steve French3e87d802005-09-18 20:49:21 -07004625 pSMB->MaxDataCount = cpu_to_le16(4100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004626 pSMB->MaxSetupCount = 0;
4627 pSMB->Reserved = 0;
4628 pSMB->Flags = 0;
4629 pSMB->Timeout = 0;
4630 pSMB->Reserved2 = 0;
4631 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004632 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633 offset = param_offset + params;
Steve French790fe572007-07-07 19:25:05 +00004634 if (SetAllocation) {
Steve French50c2f752007-07-13 00:33:32 +00004635 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4636 pSMB->InformationLevel =
4637 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4638 else
4639 pSMB->InformationLevel =
4640 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4641 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004642 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4643 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004644 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645 else
4646 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004647 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 }
4649
4650 parm_data =
4651 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4652 offset);
4653 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4654 pSMB->DataOffset = cpu_to_le16(offset);
4655 pSMB->SetupCount = 1;
4656 pSMB->Reserved3 = 0;
4657 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4658 byte_count = 3 /* pad */ + params + data_count;
4659 pSMB->DataCount = cpu_to_le16(data_count);
4660 pSMB->TotalDataCount = pSMB->DataCount;
4661 pSMB->ParameterCount = cpu_to_le16(params);
4662 pSMB->TotalParameterCount = pSMB->ParameterCount;
4663 pSMB->Reserved4 = 0;
4664 pSMB->hdr.smb_buf_length += byte_count;
4665 parm_data->FileSize = cpu_to_le64(size);
4666 pSMB->ByteCount = cpu_to_le16(byte_count);
4667 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4668 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4669 if (rc) {
4670 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4671 }
4672
4673 cifs_buf_release(pSMB);
4674
4675 if (rc == -EAGAIN)
4676 goto SetEOFRetry;
4677
4678 return rc;
4679}
4680
4681int
Steve French50c2f752007-07-13 00:33:32 +00004682CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
4683 __u16 fid, __u32 pid_of_opener, int SetAllocation)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684{
4685 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4686 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4687 char *data_offset;
4688 struct file_end_of_file_info *parm_data;
4689 int rc = 0;
4690 int bytes_returned = 0;
4691 __u16 params, param_offset, offset, byte_count, count;
4692
4693 cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4694 (long long)size));
Steve Frenchcd634992005-04-28 22:41:10 -07004695 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4696
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697 if (rc)
4698 return rc;
4699
Steve Frenchcd634992005-04-28 22:41:10 -07004700 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4701
Linus Torvalds1da177e2005-04-16 15:20:36 -07004702 pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4703 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
Steve French50c2f752007-07-13 00:33:32 +00004704
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705 params = 6;
4706 pSMB->MaxSetupCount = 0;
4707 pSMB->Reserved = 0;
4708 pSMB->Flags = 0;
4709 pSMB->Timeout = 0;
4710 pSMB->Reserved2 = 0;
4711 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4712 offset = param_offset + params;
4713
Steve French50c2f752007-07-13 00:33:32 +00004714 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715
4716 count = sizeof(struct file_end_of_file_info);
4717 pSMB->MaxParameterCount = cpu_to_le16(2);
4718 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4719 pSMB->SetupCount = 1;
4720 pSMB->Reserved3 = 0;
4721 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4722 byte_count = 3 /* pad */ + params + count;
4723 pSMB->DataCount = cpu_to_le16(count);
4724 pSMB->ParameterCount = cpu_to_le16(params);
4725 pSMB->TotalDataCount = pSMB->DataCount;
4726 pSMB->TotalParameterCount = pSMB->ParameterCount;
4727 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4728 parm_data =
Steve French50c2f752007-07-13 00:33:32 +00004729 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
4730 + offset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004731 pSMB->DataOffset = cpu_to_le16(offset);
4732 parm_data->FileSize = cpu_to_le64(size);
4733 pSMB->Fid = fid;
Steve French790fe572007-07-07 19:25:05 +00004734 if (SetAllocation) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4736 pSMB->InformationLevel =
4737 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4738 else
4739 pSMB->InformationLevel =
4740 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
Steve French50c2f752007-07-13 00:33:32 +00004741 } else /* Set File Size */ {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4743 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004744 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 else
4746 pSMB->InformationLevel =
Steve French50c2f752007-07-13 00:33:32 +00004747 cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748 }
4749 pSMB->Reserved4 = 0;
4750 pSMB->hdr.smb_buf_length += byte_count;
4751 pSMB->ByteCount = cpu_to_le16(byte_count);
4752 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4753 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4754 if (rc) {
4755 cFYI(1,
4756 ("Send error in SetFileInfo (SetFileSize) = %d",
4757 rc));
4758 }
4759
4760 if (pSMB)
Steve Frenchcd634992005-04-28 22:41:10 -07004761 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762
Steve French50c2f752007-07-13 00:33:32 +00004763 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004764 since file handle passed in no longer valid */
4765
4766 return rc;
4767}
4768
Steve French50c2f752007-07-13 00:33:32 +00004769/* Some legacy servers such as NT4 require that the file times be set on
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770 an open handle, rather than by pathname - this is awkward due to
4771 potential access conflicts on the open, but it is unavoidable for these
4772 old servers since the only other choice is to go from 100 nanosecond DCE
4773 time and resort to the original setpathinfo level which takes the ancient
4774 DOS time format with 2 second granularity */
4775int
Steve French50c2f752007-07-13 00:33:32 +00004776CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
4777 const FILE_BASIC_INFO *data, __u16 fid)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778{
4779 struct smb_com_transaction2_sfi_req *pSMB = NULL;
4780 struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4781 char *data_offset;
4782 int rc = 0;
4783 int bytes_returned = 0;
4784 __u16 params, param_offset, offset, byte_count, count;
4785
4786 cFYI(1, ("Set Times (via SetFileInfo)"));
Steve Frenchcd634992005-04-28 22:41:10 -07004787 rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4788
Linus Torvalds1da177e2005-04-16 15:20:36 -07004789 if (rc)
4790 return rc;
4791
Steve Frenchcd634992005-04-28 22:41:10 -07004792 pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4793
Linus Torvalds1da177e2005-04-16 15:20:36 -07004794 /* At this point there is no need to override the current pid
4795 with the pid of the opener, but that could change if we someday
4796 use an existing handle (rather than opening one on the fly) */
4797 /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4798 pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
Steve French50c2f752007-07-13 00:33:32 +00004799
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 params = 6;
4801 pSMB->MaxSetupCount = 0;
4802 pSMB->Reserved = 0;
4803 pSMB->Flags = 0;
4804 pSMB->Timeout = 0;
4805 pSMB->Reserved2 = 0;
4806 param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4807 offset = param_offset + params;
4808
Steve French50c2f752007-07-13 00:33:32 +00004809 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004810
Steve French26f57362007-08-30 22:09:15 +00004811 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004812 pSMB->MaxParameterCount = cpu_to_le16(2);
4813 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4814 pSMB->SetupCount = 1;
4815 pSMB->Reserved3 = 0;
4816 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4817 byte_count = 3 /* pad */ + params + count;
4818 pSMB->DataCount = cpu_to_le16(count);
4819 pSMB->ParameterCount = cpu_to_le16(params);
4820 pSMB->TotalDataCount = pSMB->DataCount;
4821 pSMB->TotalParameterCount = pSMB->ParameterCount;
4822 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4823 pSMB->DataOffset = cpu_to_le16(offset);
4824 pSMB->Fid = fid;
4825 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4826 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4827 else
4828 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4829 pSMB->Reserved4 = 0;
4830 pSMB->hdr.smb_buf_length += byte_count;
4831 pSMB->ByteCount = cpu_to_le16(byte_count);
Steve French50c2f752007-07-13 00:33:32 +00004832 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4834 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4835 if (rc) {
Steve French50c2f752007-07-13 00:33:32 +00004836 cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 }
4838
Steve Frenchcd634992005-04-28 22:41:10 -07004839 cifs_small_buf_release(pSMB);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004840
Steve French50c2f752007-07-13 00:33:32 +00004841 /* Note: On -EAGAIN error only caller can retry on handle based calls
Linus Torvalds1da177e2005-04-16 15:20:36 -07004842 since file handle passed in no longer valid */
4843
4844 return rc;
4845}
4846
4847
4848int
4849CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00004850 const FILE_BASIC_INFO *data,
Steve French737b7582005-04-28 22:41:06 -07004851 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852{
4853 TRANSACTION2_SPI_REQ *pSMB = NULL;
4854 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4855 int name_len;
4856 int rc = 0;
4857 int bytes_returned = 0;
4858 char *data_offset;
4859 __u16 params, param_offset, offset, byte_count, count;
4860
4861 cFYI(1, ("In SetTimes"));
4862
4863SetTimesRetry:
4864 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4865 (void **) &pSMBr);
4866 if (rc)
4867 return rc;
4868
4869 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4870 name_len =
Steve Frenchb1a45692005-05-17 16:07:23 -05004871 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07004872 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004873 name_len++; /* trailing null */
4874 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004875 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004876 name_len = strnlen(fileName, PATH_MAX);
4877 name_len++; /* trailing null */
4878 strncpy(pSMB->FileName, fileName, name_len);
4879 }
4880
4881 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00004882 count = sizeof(FILE_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883 pSMB->MaxParameterCount = cpu_to_le16(2);
4884 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4885 pSMB->MaxSetupCount = 0;
4886 pSMB->Reserved = 0;
4887 pSMB->Flags = 0;
4888 pSMB->Timeout = 0;
4889 pSMB->Reserved2 = 0;
4890 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00004891 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892 offset = param_offset + params;
4893 data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4894 pSMB->ParameterOffset = cpu_to_le16(param_offset);
4895 pSMB->DataOffset = cpu_to_le16(offset);
4896 pSMB->SetupCount = 1;
4897 pSMB->Reserved3 = 0;
4898 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4899 byte_count = 3 /* pad */ + params + count;
4900
4901 pSMB->DataCount = cpu_to_le16(count);
4902 pSMB->ParameterCount = cpu_to_le16(params);
4903 pSMB->TotalDataCount = pSMB->DataCount;
4904 pSMB->TotalParameterCount = pSMB->ParameterCount;
4905 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4906 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4907 else
4908 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4909 pSMB->Reserved4 = 0;
4910 pSMB->hdr.smb_buf_length += byte_count;
Steve French26f57362007-08-30 22:09:15 +00004911 memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004912 pSMB->ByteCount = cpu_to_le16(byte_count);
4913 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4914 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4915 if (rc) {
4916 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4917 }
4918
4919 cifs_buf_release(pSMB);
4920
4921 if (rc == -EAGAIN)
4922 goto SetTimesRetry;
4923
4924 return rc;
4925}
4926
4927/* Can not be used to set time stamps yet (due to old DOS time format) */
4928/* Can be used to set attributes */
4929#if 0 /* Possibly not needed - since it turns out that strangely NT4 has a bug
4930 handling it anyway and NT4 was what we thought it would be needed for
4931 Do not delete it until we prove whether needed for Win9x though */
4932int
4933CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4934 __u16 dos_attrs, const struct nls_table *nls_codepage)
4935{
4936 SETATTR_REQ *pSMB = NULL;
4937 SETATTR_RSP *pSMBr = NULL;
4938 int rc = 0;
4939 int bytes_returned;
4940 int name_len;
4941
4942 cFYI(1, ("In SetAttrLegacy"));
4943
4944SetAttrLgcyRetry:
4945 rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4946 (void **) &pSMBr);
4947 if (rc)
4948 return rc;
4949
4950 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4951 name_len =
Steve French50c2f752007-07-13 00:33:32 +00004952 ConvertToUCS((__le16 *) pSMB->fileName, fileName,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004953 PATH_MAX, nls_codepage);
4954 name_len++; /* trailing null */
4955 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00004956 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004957 name_len = strnlen(fileName, PATH_MAX);
4958 name_len++; /* trailing null */
4959 strncpy(pSMB->fileName, fileName, name_len);
4960 }
4961 pSMB->attr = cpu_to_le16(dos_attrs);
4962 pSMB->BufferFormat = 0x04;
4963 pSMB->hdr.smb_buf_length += name_len + 1;
4964 pSMB->ByteCount = cpu_to_le16(name_len + 1);
4965 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4966 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4967 if (rc) {
4968 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4969 }
4970
4971 cifs_buf_release(pSMB);
4972
4973 if (rc == -EAGAIN)
4974 goto SetAttrLgcyRetry;
4975
4976 return rc;
4977}
4978#endif /* temporarily unneeded SetAttr legacy function */
4979
4980int
4981CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
Steve French50c2f752007-07-13 00:33:32 +00004982 char *fileName, __u64 mode, __u64 uid, __u64 gid,
4983 dev_t device, const struct nls_table *nls_codepage,
Steve French737b7582005-04-28 22:41:06 -07004984 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985{
4986 TRANSACTION2_SPI_REQ *pSMB = NULL;
4987 TRANSACTION2_SPI_RSP *pSMBr = NULL;
4988 int name_len;
4989 int rc = 0;
4990 int bytes_returned = 0;
4991 FILE_UNIX_BASIC_INFO *data_offset;
4992 __u16 params, param_offset, offset, count, byte_count;
4993
4994 cFYI(1, ("In SetUID/GID/Mode"));
4995setPermsRetry:
4996 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4997 (void **) &pSMBr);
4998 if (rc)
4999 return rc;
5000
5001 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5002 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005003 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005004 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005005 name_len++; /* trailing null */
5006 name_len *= 2;
Steve French3e87d802005-09-18 20:49:21 -07005007 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005008 name_len = strnlen(fileName, PATH_MAX);
5009 name_len++; /* trailing null */
5010 strncpy(pSMB->FileName, fileName, name_len);
5011 }
5012
5013 params = 6 + name_len;
Steve French26f57362007-08-30 22:09:15 +00005014 count = sizeof(FILE_UNIX_BASIC_INFO);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005015 pSMB->MaxParameterCount = cpu_to_le16(2);
5016 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
5017 pSMB->MaxSetupCount = 0;
5018 pSMB->Reserved = 0;
5019 pSMB->Flags = 0;
5020 pSMB->Timeout = 0;
5021 pSMB->Reserved2 = 0;
5022 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005023 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024 offset = param_offset + params;
5025 data_offset =
5026 (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
5027 offset);
5028 memset(data_offset, 0, count);
5029 pSMB->DataOffset = cpu_to_le16(offset);
5030 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5031 pSMB->SetupCount = 1;
5032 pSMB->Reserved3 = 0;
5033 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5034 byte_count = 3 /* pad */ + params + count;
5035 pSMB->ParameterCount = cpu_to_le16(params);
5036 pSMB->DataCount = cpu_to_le16(count);
5037 pSMB->TotalParameterCount = pSMB->ParameterCount;
5038 pSMB->TotalDataCount = pSMB->DataCount;
5039 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
5040 pSMB->Reserved4 = 0;
5041 pSMB->hdr.smb_buf_length += byte_count;
Steve Frenchc7af1852007-03-01 04:11:22 +00005042 /* Samba server ignores set of file size to zero due to bugs in some
5043 older clients, but we should be precise - we use SetFileSize to
5044 set file size and do not want to truncate file size to zero
5045 accidently as happened on one Samba server beta by putting
Steve French50c2f752007-07-13 00:33:32 +00005046 zero instead of -1 here */
Steve Frenchc7af1852007-03-01 04:11:22 +00005047 data_offset->EndOfFile = NO_CHANGE_64;
5048 data_offset->NumOfBytes = NO_CHANGE_64;
5049 data_offset->LastStatusChange = NO_CHANGE_64;
5050 data_offset->LastAccessTime = NO_CHANGE_64;
5051 data_offset->LastModificationTime = NO_CHANGE_64;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005052 data_offset->Uid = cpu_to_le64(uid);
5053 data_offset->Gid = cpu_to_le64(gid);
5054 /* better to leave device as zero when it is */
5055 data_offset->DevMajor = cpu_to_le64(MAJOR(device));
5056 data_offset->DevMinor = cpu_to_le64(MINOR(device));
5057 data_offset->Permissions = cpu_to_le64(mode);
Steve French50c2f752007-07-13 00:33:32 +00005058
Steve French790fe572007-07-07 19:25:05 +00005059 if (S_ISREG(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005060 data_offset->Type = cpu_to_le32(UNIX_FILE);
Steve French790fe572007-07-07 19:25:05 +00005061 else if (S_ISDIR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005062 data_offset->Type = cpu_to_le32(UNIX_DIR);
Steve French790fe572007-07-07 19:25:05 +00005063 else if (S_ISLNK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005064 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
Steve French790fe572007-07-07 19:25:05 +00005065 else if (S_ISCHR(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005066 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
Steve French790fe572007-07-07 19:25:05 +00005067 else if (S_ISBLK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005068 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
Steve French790fe572007-07-07 19:25:05 +00005069 else if (S_ISFIFO(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005070 data_offset->Type = cpu_to_le32(UNIX_FIFO);
Steve French790fe572007-07-07 19:25:05 +00005071 else if (S_ISSOCK(mode))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005072 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
5073
5074
5075 pSMB->ByteCount = cpu_to_le16(byte_count);
5076 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5077 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5078 if (rc) {
5079 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
5080 }
5081
5082 if (pSMB)
5083 cifs_buf_release(pSMB);
5084 if (rc == -EAGAIN)
5085 goto setPermsRetry;
5086 return rc;
5087}
5088
Steve French50c2f752007-07-13 00:33:32 +00005089int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
Steve French167a2512005-08-24 20:03:11 -07005090 const int notify_subdirs, const __u16 netfid,
Steve French50c2f752007-07-13 00:33:32 +00005091 __u32 filter, struct file *pfile, int multishot,
Steve French167a2512005-08-24 20:03:11 -07005092 const struct nls_table *nls_codepage)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005093{
5094 int rc = 0;
Steve French50c2f752007-07-13 00:33:32 +00005095 struct smb_com_transaction_change_notify_req *pSMB = NULL;
5096 struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
Steve Frenchabb15b82005-08-24 18:51:02 -07005097 struct dir_notify_req *dnotify_req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005098 int bytes_returned;
5099
Steve French50c2f752007-07-13 00:33:32 +00005100 cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005101 rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
Steve French50c2f752007-07-13 00:33:32 +00005102 (void **) &pSMBr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005103 if (rc)
5104 return rc;
5105
5106 pSMB->TotalParameterCount = 0 ;
5107 pSMB->TotalDataCount = 0;
5108 pSMB->MaxParameterCount = cpu_to_le32(2);
5109 /* BB find exact data count max from sess structure BB */
5110 pSMB->MaxDataCount = 0; /* same in little endian or be */
Steve French0a4b92c2006-01-12 15:44:21 -08005111/* BB VERIFY verify which is correct for above BB */
5112 pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
5113 MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
5114
Linus Torvalds1da177e2005-04-16 15:20:36 -07005115 pSMB->MaxSetupCount = 4;
5116 pSMB->Reserved = 0;
5117 pSMB->ParameterOffset = 0;
5118 pSMB->DataCount = 0;
5119 pSMB->DataOffset = 0;
5120 pSMB->SetupCount = 4; /* single byte does not need le conversion */
5121 pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
5122 pSMB->ParameterCount = pSMB->TotalParameterCount;
Steve French790fe572007-07-07 19:25:05 +00005123 if (notify_subdirs)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005124 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
5125 pSMB->Reserved2 = 0;
5126 pSMB->CompletionFilter = cpu_to_le32(filter);
5127 pSMB->Fid = netfid; /* file handle always le */
5128 pSMB->ByteCount = 0;
5129
5130 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5131 (struct smb_hdr *) pSMBr, &bytes_returned, -1);
5132 if (rc) {
5133 cFYI(1, ("Error in Notify = %d", rc));
Steve Frenchff5dbd92005-08-24 17:10:36 -07005134 } else {
5135 /* Add file to outstanding requests */
Steve French50c2f752007-07-13 00:33:32 +00005136 /* BB change to kmem cache alloc */
Robert P. J. Day5cbded52006-12-13 00:35:56 -08005137 dnotify_req = kmalloc(
Steve French47c786e2005-10-11 20:03:18 -07005138 sizeof(struct dir_notify_req),
5139 GFP_KERNEL);
Steve French790fe572007-07-07 19:25:05 +00005140 if (dnotify_req) {
Steve French47c786e2005-10-11 20:03:18 -07005141 dnotify_req->Pid = pSMB->hdr.Pid;
5142 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
5143 dnotify_req->Mid = pSMB->hdr.Mid;
5144 dnotify_req->Tid = pSMB->hdr.Tid;
5145 dnotify_req->Uid = pSMB->hdr.Uid;
5146 dnotify_req->netfid = netfid;
5147 dnotify_req->pfile = pfile;
5148 dnotify_req->filter = filter;
5149 dnotify_req->multishot = multishot;
5150 spin_lock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005151 list_add_tail(&dnotify_req->lhead,
Steve French47c786e2005-10-11 20:03:18 -07005152 &GlobalDnotifyReqList);
5153 spin_unlock(&GlobalMid_Lock);
Steve French50c2f752007-07-13 00:33:32 +00005154 } else
Steve French47c786e2005-10-11 20:03:18 -07005155 rc = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005156 }
5157 cifs_buf_release(pSMB);
Steve French50c2f752007-07-13 00:33:32 +00005158 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005159}
5160#ifdef CONFIG_CIFS_XATTR
5161ssize_t
5162CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
5163 const unsigned char *searchName,
Steve French50c2f752007-07-13 00:33:32 +00005164 char *EAData, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005165 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005166{
5167 /* BB assumes one setup word */
5168 TRANSACTION2_QPI_REQ *pSMB = NULL;
5169 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5170 int rc = 0;
5171 int bytes_returned;
5172 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005173 struct fea *temp_fea;
5174 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005175 __u16 params, byte_count;
5176
5177 cFYI(1, ("In Query All EAs path %s", searchName));
5178QAllEAsRetry:
5179 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5180 (void **) &pSMBr);
5181 if (rc)
5182 return rc;
5183
5184 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5185 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005186 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005187 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005188 name_len++; /* trailing null */
5189 name_len *= 2;
5190 } else { /* BB improve the check for buffer overruns BB */
5191 name_len = strnlen(searchName, PATH_MAX);
5192 name_len++; /* trailing null */
5193 strncpy(pSMB->FileName, searchName, name_len);
5194 }
5195
Steve French50c2f752007-07-13 00:33:32 +00005196 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005197 pSMB->TotalDataCount = 0;
5198 pSMB->MaxParameterCount = cpu_to_le16(2);
5199 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5200 pSMB->MaxSetupCount = 0;
5201 pSMB->Reserved = 0;
5202 pSMB->Flags = 0;
5203 pSMB->Timeout = 0;
5204 pSMB->Reserved2 = 0;
5205 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005206 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005207 pSMB->DataCount = 0;
5208 pSMB->DataOffset = 0;
5209 pSMB->SetupCount = 1;
5210 pSMB->Reserved3 = 0;
5211 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5212 byte_count = params + 1 /* pad */ ;
5213 pSMB->TotalParameterCount = cpu_to_le16(params);
5214 pSMB->ParameterCount = pSMB->TotalParameterCount;
5215 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5216 pSMB->Reserved4 = 0;
5217 pSMB->hdr.smb_buf_length += byte_count;
5218 pSMB->ByteCount = cpu_to_le16(byte_count);
5219
5220 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5221 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5222 if (rc) {
5223 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
5224 } else { /* decode response */
5225 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5226
5227 /* BB also check enough total bytes returned */
5228 /* BB we need to improve the validity checking
5229 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005230 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005231 rc = -EIO; /* bad smb */
5232 /* else if (pFindData){
5233 memcpy((char *) pFindData,
5234 (char *) &pSMBr->hdr.Protocol +
5235 data_offset, kl);
5236 }*/ else {
5237 /* check that length of list is not more than bcc */
5238 /* check that each entry does not go beyond length
5239 of list */
5240 /* check that each element of each entry does not
5241 go beyond end of list */
5242 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005243 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244 rc = 0;
5245 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005246 /* BB check if start of smb + data_offset > &bcc+ bcc */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247 ea_response_data = (struct fealist *)
5248 (((char *) &pSMBr->hdr.Protocol) +
5249 data_offset);
5250 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005251 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005252 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005253 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005254 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005255 } else {
5256 /* account for ea list len */
5257 name_len -= 4;
5258 temp_fea = ea_response_data->list;
5259 temp_ptr = (char *)temp_fea;
Steve French50c2f752007-07-13 00:33:32 +00005260 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005261 __u16 value_len;
5262 name_len -= 4;
5263 temp_ptr += 4;
5264 rc += temp_fea->name_len;
5265 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005266 rc = rc + 5 + 1;
5267 if (rc < (int)buf_size) {
Steve French50c2f752007-07-13 00:33:32 +00005268 memcpy(EAData, "user.", 5);
5269 EAData += 5;
5270 memcpy(EAData, temp_ptr,
5271 temp_fea->name_len);
5272 EAData += temp_fea->name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005273 /* null terminate name */
5274 *EAData = 0;
5275 EAData = EAData + 1;
Steve French790fe572007-07-07 19:25:05 +00005276 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005277 /* skip copy - calc size only */
5278 } else {
5279 /* stop before overrun buffer */
5280 rc = -ERANGE;
5281 break;
5282 }
5283 name_len -= temp_fea->name_len;
5284 temp_ptr += temp_fea->name_len;
5285 /* account for trailing null */
5286 name_len--;
5287 temp_ptr++;
Steve French50c2f752007-07-13 00:33:32 +00005288 value_len =
5289 le16_to_cpu(temp_fea->value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005290 name_len -= value_len;
5291 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005292 /* BB check that temp_ptr is still
5293 within the SMB BB*/
5294
5295 /* no trailing null to account for
5296 in value len */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005297 /* go on to next EA */
5298 temp_fea = (struct fea *)temp_ptr;
5299 }
5300 }
5301 }
5302 }
5303 if (pSMB)
5304 cifs_buf_release(pSMB);
5305 if (rc == -EAGAIN)
5306 goto QAllEAsRetry;
5307
5308 return (ssize_t)rc;
5309}
5310
Steve French50c2f752007-07-13 00:33:32 +00005311ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
5312 const unsigned char *searchName, const unsigned char *ea_name,
5313 unsigned char *ea_value, size_t buf_size,
Steve French737b7582005-04-28 22:41:06 -07005314 const struct nls_table *nls_codepage, int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005315{
5316 TRANSACTION2_QPI_REQ *pSMB = NULL;
5317 TRANSACTION2_QPI_RSP *pSMBr = NULL;
5318 int rc = 0;
5319 int bytes_returned;
5320 int name_len;
Steve French50c2f752007-07-13 00:33:32 +00005321 struct fea *temp_fea;
5322 char *temp_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005323 __u16 params, byte_count;
5324
5325 cFYI(1, ("In Query EA path %s", searchName));
5326QEARetry:
5327 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5328 (void **) &pSMBr);
5329 if (rc)
5330 return rc;
5331
5332 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5333 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005334 cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
Steve French737b7582005-04-28 22:41:06 -07005335 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005336 name_len++; /* trailing null */
5337 name_len *= 2;
5338 } else { /* BB improve the check for buffer overruns BB */
5339 name_len = strnlen(searchName, PATH_MAX);
5340 name_len++; /* trailing null */
5341 strncpy(pSMB->FileName, searchName, name_len);
5342 }
5343
Steve French50c2f752007-07-13 00:33:32 +00005344 params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005345 pSMB->TotalDataCount = 0;
5346 pSMB->MaxParameterCount = cpu_to_le16(2);
5347 pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
5348 pSMB->MaxSetupCount = 0;
5349 pSMB->Reserved = 0;
5350 pSMB->Flags = 0;
5351 pSMB->Timeout = 0;
5352 pSMB->Reserved2 = 0;
5353 pSMB->ParameterOffset = cpu_to_le16(offsetof(
Steve French50c2f752007-07-13 00:33:32 +00005354 struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005355 pSMB->DataCount = 0;
5356 pSMB->DataOffset = 0;
5357 pSMB->SetupCount = 1;
5358 pSMB->Reserved3 = 0;
5359 pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
5360 byte_count = params + 1 /* pad */ ;
5361 pSMB->TotalParameterCount = cpu_to_le16(params);
5362 pSMB->ParameterCount = pSMB->TotalParameterCount;
5363 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
5364 pSMB->Reserved4 = 0;
5365 pSMB->hdr.smb_buf_length += byte_count;
5366 pSMB->ByteCount = cpu_to_le16(byte_count);
5367
5368 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5369 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5370 if (rc) {
5371 cFYI(1, ("Send error in Query EA = %d", rc));
5372 } else { /* decode response */
5373 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
5374
5375 /* BB also check enough total bytes returned */
5376 /* BB we need to improve the validity checking
5377 of these trans2 responses */
Steve French50c2f752007-07-13 00:33:32 +00005378 if (rc || (pSMBr->ByteCount < 4))
Linus Torvalds1da177e2005-04-16 15:20:36 -07005379 rc = -EIO; /* bad smb */
5380 /* else if (pFindData){
5381 memcpy((char *) pFindData,
5382 (char *) &pSMBr->hdr.Protocol +
5383 data_offset, kl);
5384 }*/ else {
5385 /* check that length of list is not more than bcc */
5386 /* check that each entry does not go beyond length
5387 of list */
5388 /* check that each element of each entry does not
5389 go beyond end of list */
5390 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
Steve French50c2f752007-07-13 00:33:32 +00005391 struct fealist *ea_response_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005392 rc = -ENODATA;
5393 /* validate_trans2_offsets() */
Steve French790fe572007-07-07 19:25:05 +00005394 /* BB check if start of smb + data_offset > &bcc+ bcc*/
Linus Torvalds1da177e2005-04-16 15:20:36 -07005395 ea_response_data = (struct fealist *)
5396 (((char *) &pSMBr->hdr.Protocol) +
5397 data_offset);
5398 name_len = le32_to_cpu(ea_response_data->list_len);
Steve French50c2f752007-07-13 00:33:32 +00005399 cFYI(1, ("ea length %d", name_len));
Steve French790fe572007-07-07 19:25:05 +00005400 if (name_len <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005401 /* returned EA size zeroed at top of function */
Steve French50c2f752007-07-13 00:33:32 +00005402 cFYI(1, ("empty EA list returned from server"));
Linus Torvalds1da177e2005-04-16 15:20:36 -07005403 } else {
5404 /* account for ea list len */
5405 name_len -= 4;
5406 temp_fea = ea_response_data->list;
5407 temp_ptr = (char *)temp_fea;
5408 /* loop through checking if we have a matching
5409 name and then return the associated value */
Steve French50c2f752007-07-13 00:33:32 +00005410 while (name_len > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005411 __u16 value_len;
5412 name_len -= 4;
5413 temp_ptr += 4;
Steve French50c2f752007-07-13 00:33:32 +00005414 value_len =
5415 le16_to_cpu(temp_fea->value_len);
5416 /* BB validate that value_len falls within SMB,
5417 even though maximum for name_len is 255 */
Steve French790fe572007-07-07 19:25:05 +00005418 if (memcmp(temp_fea->name, ea_name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005419 temp_fea->name_len) == 0) {
5420 /* found a match */
5421 rc = value_len;
5422 /* account for prefix user. and trailing null */
Steve French790fe572007-07-07 19:25:05 +00005423 if (rc <= (int)buf_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424 memcpy(ea_value,
5425 temp_fea->name+temp_fea->name_len+1,
5426 rc);
Steve French50c2f752007-07-13 00:33:32 +00005427 /* ea values, unlike ea
5428 names, are not null
5429 terminated */
Steve French790fe572007-07-07 19:25:05 +00005430 } else if (buf_size == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005431 /* skip copy - calc size only */
5432 } else {
Steve French50c2f752007-07-13 00:33:32 +00005433 /* stop before overrun buffer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434 rc = -ERANGE;
5435 }
5436 break;
5437 }
5438 name_len -= temp_fea->name_len;
5439 temp_ptr += temp_fea->name_len;
5440 /* account for trailing null */
5441 name_len--;
5442 temp_ptr++;
5443 name_len -= value_len;
5444 temp_ptr += value_len;
Steve French50c2f752007-07-13 00:33:32 +00005445 /* No trailing null to account for in
5446 value_len. Go on to next EA */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447 temp_fea = (struct fea *)temp_ptr;
5448 }
Steve French50c2f752007-07-13 00:33:32 +00005449 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005450 }
5451 }
5452 if (pSMB)
5453 cifs_buf_release(pSMB);
5454 if (rc == -EAGAIN)
5455 goto QEARetry;
5456
5457 return (ssize_t)rc;
5458}
5459
5460int
5461CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
Steve French50c2f752007-07-13 00:33:32 +00005462 const char *ea_name, const void *ea_value,
5463 const __u16 ea_value_len, const struct nls_table *nls_codepage,
5464 int remap)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005465{
5466 struct smb_com_transaction2_spi_req *pSMB = NULL;
5467 struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
5468 struct fealist *parm_data;
5469 int name_len;
5470 int rc = 0;
5471 int bytes_returned = 0;
5472 __u16 params, param_offset, byte_count, offset, count;
5473
5474 cFYI(1, ("In SetEA"));
5475SetEARetry:
5476 rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
5477 (void **) &pSMBr);
5478 if (rc)
5479 return rc;
5480
5481 if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
5482 name_len =
Steve French50c2f752007-07-13 00:33:32 +00005483 cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
Steve French737b7582005-04-28 22:41:06 -07005484 PATH_MAX, nls_codepage, remap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 name_len++; /* trailing null */
5486 name_len *= 2;
Steve French50c2f752007-07-13 00:33:32 +00005487 } else { /* BB improve the check for buffer overruns BB */
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488 name_len = strnlen(fileName, PATH_MAX);
5489 name_len++; /* trailing null */
5490 strncpy(pSMB->FileName, fileName, name_len);
5491 }
5492
5493 params = 6 + name_len;
5494
5495 /* done calculating parms using name_len of file name,
5496 now use name_len to calculate length of ea name
5497 we are going to create in the inode xattrs */
Steve French790fe572007-07-07 19:25:05 +00005498 if (ea_name == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499 name_len = 0;
5500 else
Steve French50c2f752007-07-13 00:33:32 +00005501 name_len = strnlen(ea_name, 255);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005502
5503 count = sizeof(*parm_data) + ea_value_len + name_len + 1;
5504 pSMB->MaxParameterCount = cpu_to_le16(2);
5505 pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
5506 pSMB->MaxSetupCount = 0;
5507 pSMB->Reserved = 0;
5508 pSMB->Flags = 0;
5509 pSMB->Timeout = 0;
5510 pSMB->Reserved2 = 0;
5511 param_offset = offsetof(struct smb_com_transaction2_spi_req,
Steve French50c2f752007-07-13 00:33:32 +00005512 InformationLevel) - 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005513 offset = param_offset + params;
5514 pSMB->InformationLevel =
5515 cpu_to_le16(SMB_SET_FILE_EA);
5516
5517 parm_data =
5518 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
5519 offset);
5520 pSMB->ParameterOffset = cpu_to_le16(param_offset);
5521 pSMB->DataOffset = cpu_to_le16(offset);
5522 pSMB->SetupCount = 1;
5523 pSMB->Reserved3 = 0;
5524 pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
5525 byte_count = 3 /* pad */ + params + count;
5526 pSMB->DataCount = cpu_to_le16(count);
5527 parm_data->list_len = cpu_to_le32(count);
5528 parm_data->list[0].EA_flags = 0;
5529 /* we checked above that name len is less than 255 */
Alexey Dobriyan53b35312006-03-24 03:16:13 -08005530 parm_data->list[0].name_len = (__u8)name_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 /* EA names are always ASCII */
Steve French790fe572007-07-07 19:25:05 +00005532 if (ea_name)
Steve French50c2f752007-07-13 00:33:32 +00005533 strncpy(parm_data->list[0].name, ea_name, name_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534 parm_data->list[0].name[name_len] = 0;
5535 parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
5536 /* caller ensures that ea_value_len is less than 64K but
5537 we need to ensure that it fits within the smb */
5538
Steve French50c2f752007-07-13 00:33:32 +00005539 /*BB add length check to see if it would fit in
5540 negotiated SMB buffer size BB */
Steve French790fe572007-07-07 19:25:05 +00005541 /* if (ea_value_len > buffer_size - 512 (enough for header)) */
5542 if (ea_value_len)
Steve French50c2f752007-07-13 00:33:32 +00005543 memcpy(parm_data->list[0].name+name_len+1,
5544 ea_value, ea_value_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545
5546 pSMB->TotalDataCount = pSMB->DataCount;
5547 pSMB->ParameterCount = cpu_to_le16(params);
5548 pSMB->TotalParameterCount = pSMB->ParameterCount;
5549 pSMB->Reserved4 = 0;
5550 pSMB->hdr.smb_buf_length += byte_count;
5551 pSMB->ByteCount = cpu_to_le16(byte_count);
5552 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
5553 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
5554 if (rc) {
5555 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
5556 }
5557
5558 cifs_buf_release(pSMB);
5559
5560 if (rc == -EAGAIN)
5561 goto SetEARetry;
5562
5563 return rc;
5564}
5565
5566#endif